Page MenuHomedesp's stash

No OneTemporary

diff --git a/Scylla/ApiReader.cpp b/Scylla/ApiReader.cpp
index 3975f31..9133f4d 100644
--- a/Scylla/ApiReader.cpp
+++ b/Scylla/ApiReader.cpp
@@ -1,1325 +1,1325 @@
#include "ApiReader.h"
#include "Scylla.h"
#include "Architecture.h"
#include "SystemInformation.h"
+#include "StringConversion.h"
-stdext::hash_multimap<DWORD_PTR, ApiInfo *> ApiReader::apiList; //api look up table
+std::unordered_map<DWORD_PTR, ApiInfo *> ApiReader::apiList; //api look up table
std::map<DWORD_PTR, ImportModuleThunk> * ApiReader::moduleThunkList; //store found apis
DWORD_PTR ApiReader::minApiAddress = 0xFFFFFFFF;
DWORD_PTR ApiReader::maxApiAddress = 0;
//#define DEBUG_COMMENTS
void ApiReader::readApisFromModuleList()
{
for (unsigned int i = 0; i < moduleList.size();i++)
{
setModulePriority(&moduleList[i]);
if (moduleList[i].modBaseAddr + moduleList[i].modBaseSize > maxValidAddress)
{
maxValidAddress = moduleList[i].modBaseAddr + moduleList[i].modBaseSize;
}
Scylla::windowLog.log(L"Module parsing: %s",moduleList[i].fullPath);
if (!moduleList[i].isAlreadyParsed)
{
parseModule(&moduleList[i]);
}
}
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"Address Min " PRINTF_DWORD_PTR_FULL L" Max " PRINTF_DWORD_PTR_FULL L"\nimagebase " PRINTF_DWORD_PTR_FULL L" maxValidAddress " PRINTF_DWORD_PTR_FULL, minApiAddress, maxApiAddress, targetImageBase ,maxValidAddress);
#endif
}
void ApiReader::parseModule(ModuleInfo *module)
{
module->parsing = true;
if (isWinSxSModule(module))
{
parseModuleWithMapping(module);
}
else if (isModuleLoadedInOwnProcess(module))
{
parseModuleWithOwnProcess(module);
}
else
{
parseModuleWithProcess(module);
}
module->isAlreadyParsed = true;
}
void ApiReader::parseModuleWithMapping(ModuleInfo *moduleInfo)
{
LPVOID fileMapping = 0;
PIMAGE_NT_HEADERS pNtHeader = 0;
PIMAGE_DOS_HEADER pDosHeader = 0;
fileMapping = createFileMappingViewRead(moduleInfo->fullPath);
if (fileMapping == 0)
return;
pDosHeader = (PIMAGE_DOS_HEADER)fileMapping;
pNtHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)fileMapping + (DWORD_PTR)(pDosHeader->e_lfanew));
if (isPeAndExportTableValid(pNtHeader))
{
parseExportTable(moduleInfo, pNtHeader, (PIMAGE_EXPORT_DIRECTORY)((DWORD_PTR)fileMapping + pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress), (DWORD_PTR)fileMapping);
}
UnmapViewOfFile(fileMapping);
}
inline bool ApiReader::isApiForwarded(DWORD_PTR rva, PIMAGE_NT_HEADERS pNtHeader)
{
if ((rva > pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress) && (rva < (pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size)))
{
return true;
}
else
{
return false;
}
}
void ApiReader::handleForwardedApi(DWORD_PTR vaStringPointer,char * functionNameParent, DWORD_PTR rvaParent, WORD ordinalParent, ModuleInfo *moduleParent)
{
size_t dllNameLength = 0;
WORD ordinal = 0;
ModuleInfo *module = 0;
DWORD_PTR vaApi = 0;
DWORD_PTR rvaApi = 0;
char dllName[100] = {0};
WCHAR dllNameW[100] = {0};
char *fordwardedString = (char *)vaStringPointer;
char *searchFunctionName = strchr(fordwardedString, '.');
if (!searchFunctionName)
return;
dllNameLength = searchFunctionName - fordwardedString;
if (dllNameLength >= 99)
{
return;
}
else
{
strncpy_s(dllName,sizeof(dllName),fordwardedString,dllNameLength);
}
searchFunctionName++;
//Windows 7
if (!strncmp(dllName,"api-ms-win-", 11))
{
/*
Info: http://www.nirsoft.net/articles/windows_7_kernel_architecture_changes.html
*/
FARPROC addy = GetProcAddress(GetModuleHandleA(dllName), searchFunctionName);
if (addy != 0)
{
addApi(functionNameParent,0, ordinalParent, (DWORD_PTR)addy, (DWORD_PTR)addy - (DWORD_PTR)GetModuleHandleA(dllName), true, moduleParent);
}
return;
}
- strcat_s(dllName,sizeof(dllName),".dll");
+ strcat_s(dllName, sizeof(dllName), ".dll");
- size_t convertedChars = 0;
- mbstowcs_s(&convertedChars, dllNameW, strlen(dllName) + 1, dllName, _TRUNCATE);
+ StringConversion::ToUTF16(dllName, dllNameW, _countof(dllNameW));
if (!_wcsicmp(dllNameW, moduleParent->getFilename()))
{
module = moduleParent;
}
else
{
module = findModuleByName(dllNameW);
}
if (module != 0) // module == 0 -> can be ignored
{
/*if ((module->isAlreadyParsed == false) && (module != moduleParent))
{
//do API extract
if (module->parsing == true)
{
//some stupid circle dependency
printf("stupid circle dependency %s\n",module->getFilename());
}
else
{
parseModule(module);
}
}*/
if (strchr(searchFunctionName,'#'))
{
//forwarding by ordinal
searchFunctionName++;
ordinal = (WORD)atoi(searchFunctionName);
findApiByModuleAndOrdinal(module, ordinal, &vaApi, &rvaApi);
}
else
{
findApiByModuleAndName(module, searchFunctionName, &vaApi, &rvaApi);
}
if (rvaApi == 0)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"handleForwardedApi :: Api not found, this is really BAD! %S",fordwardedString);
#endif
}
else
{
addApi(functionNameParent,0, ordinalParent, vaApi, rvaApi, true, moduleParent);
}
}
}
ModuleInfo * ApiReader::findModuleByName(WCHAR *name)
{
for (unsigned int i = 0; i < moduleList.size(); i++) {
if (!_wcsicmp(moduleList[i].getFilename(), name))
{
return &moduleList[i];
}
}
return 0;
}
void ApiReader::addApiWithoutName(WORD ordinal, DWORD_PTR va, DWORD_PTR rva,bool isForwarded, ModuleInfo *moduleInfo)
{
addApi(0, 0, ordinal, va, rva, isForwarded, moduleInfo);
}
void ApiReader::addApi(char *functionName, WORD hint, WORD ordinal, DWORD_PTR va, DWORD_PTR rva, bool isForwarded, ModuleInfo *moduleInfo)
{
ApiInfo *apiInfo = new ApiInfo();
if ((functionName != 0) && (strlen(functionName) < _countof(apiInfo->name)))
{
strcpy_s(apiInfo->name, _countof(apiInfo->name), functionName);
}
else
{
apiInfo->name[0] = 0x00;
}
apiInfo->ordinal = ordinal;
apiInfo->isForwarded = isForwarded;
apiInfo->module = moduleInfo;
apiInfo->rva = rva;
apiInfo->va = va;
apiInfo->hint = hint;
setMinMaxApiAddress(va);
moduleInfo->apiList.push_back(apiInfo);
apiList.insert(API_Pair(va, apiInfo));
}
BYTE * ApiReader::getHeaderFromProcess(ModuleInfo * module)
{
BYTE *bufferHeader = 0;
DWORD readSize = 0;
if (module->modBaseSize < PE_HEADER_BYTES_COUNT)
{
readSize = module->modBaseSize;
}
else
{
readSize = PE_HEADER_BYTES_COUNT;
}
bufferHeader = new BYTE[readSize];
if(!readMemoryFromProcess(module->modBaseAddr, readSize, bufferHeader))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"getHeaderFromProcess :: Error reading header");
#endif
delete[] bufferHeader;
return 0;
}
else
{
return bufferHeader;
}
}
BYTE * ApiReader::getExportTableFromProcess(ModuleInfo * module, PIMAGE_NT_HEADERS pNtHeader)
{
DWORD readSize = 0;
BYTE *bufferExportTable = 0;
readSize = pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
if (readSize < (sizeof(IMAGE_EXPORT_DIRECTORY) + 8))
{
//Something is wrong with the PE Header
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"Something is wrong with the PE Header here Export table size %d", readSize);
#endif
readSize = sizeof(IMAGE_EXPORT_DIRECTORY) + 100;
}
if (readSize)
{
bufferExportTable = new BYTE[readSize];
if(!readMemoryFromProcess(module->modBaseAddr + pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress, readSize, bufferExportTable))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"getExportTableFromProcess :: Error reading export table from process");
#endif
delete[] bufferExportTable;
return 0;
}
else
{
return bufferExportTable;
}
}
else
{
return 0;
}
}
void ApiReader::parseModuleWithProcess(ModuleInfo * module)
{
PIMAGE_NT_HEADERS pNtHeader = 0;
PIMAGE_DOS_HEADER pDosHeader = 0;
BYTE *bufferHeader = 0;
BYTE *bufferExportTable = 0;
bufferHeader = getHeaderFromProcess(module);
if (bufferHeader == 0)
return;
pDosHeader = (PIMAGE_DOS_HEADER)bufferHeader;
pNtHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)bufferHeader + (DWORD_PTR)(pDosHeader->e_lfanew));
if (isPeAndExportTableValid(pNtHeader))
{
bufferExportTable = getExportTableFromProcess(module, pNtHeader);
if(bufferExportTable)
{
parseExportTable(module,pNtHeader,(PIMAGE_EXPORT_DIRECTORY)bufferExportTable, (DWORD_PTR)bufferExportTable - pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
delete[] bufferExportTable;
}
}
delete[] bufferHeader;
}
void ApiReader::parseExportTable(ModuleInfo *module, PIMAGE_NT_HEADERS pNtHeader, PIMAGE_EXPORT_DIRECTORY pExportDir, DWORD_PTR deltaAddress)
{
DWORD *addressOfFunctionsArray = 0,*addressOfNamesArray = 0;
WORD *addressOfNameOrdinalsArray = 0;
char *functionName = 0;
DWORD_PTR RVA = 0, VA = 0;
WORD ordinal = 0;
WORD i = 0, j = 0;
bool withoutName;
addressOfFunctionsArray = (DWORD *)((DWORD_PTR)pExportDir->AddressOfFunctions + deltaAddress);
addressOfNamesArray = (DWORD *)((DWORD_PTR)pExportDir->AddressOfNames + deltaAddress);
addressOfNameOrdinalsArray = (WORD *)((DWORD_PTR)pExportDir->AddressOfNameOrdinals + deltaAddress);
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"parseExportTable :: module %s NumberOfNames %X", module->fullPath, pExportDir->NumberOfNames);
#endif
for (i = 0; i < pExportDir->NumberOfNames; i++)
{
functionName = (char*)(addressOfNamesArray[i] + deltaAddress);
ordinal = (WORD)(addressOfNameOrdinalsArray[i] + pExportDir->Base);
RVA = addressOfFunctionsArray[addressOfNameOrdinalsArray[i]];
VA = addressOfFunctionsArray[addressOfNameOrdinalsArray[i]] + module->modBaseAddr;
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"parseExportTable :: api %S ordinal %d imagebase " PRINTF_DWORD_PTR_FULL L" RVA " PRINTF_DWORD_PTR_FULL L" VA " PRINTF_DWORD_PTR_FULL, functionName, ordinal, module->modBaseAddr, RVA, VA);
#endif
if (!isApiBlacklisted(functionName))
{
if (!isApiForwarded(RVA,pNtHeader))
{
addApi(functionName, i, ordinal,VA,RVA,false,module);
}
else
{
//printf("Forwarded: %s\n",functionName);
handleForwardedApi(RVA + deltaAddress,functionName,RVA,ordinal,module);
}
}
}
/*Exports without name*/
if (pExportDir->NumberOfNames != pExportDir->NumberOfFunctions)
{
for (i = 0; i < pExportDir->NumberOfFunctions; i++)
{
withoutName = true;
for (j = 0; j < pExportDir->NumberOfNames; j++)
{
if(addressOfNameOrdinalsArray[j] == i)
{
withoutName = false;
break;
}
}
if (withoutName && addressOfFunctionsArray[i] != 0)
{
ordinal = (WORD)(i+pExportDir->Base);
RVA = addressOfFunctionsArray[i];
VA = (addressOfFunctionsArray[i] + module->modBaseAddr);
if (!isApiForwarded(RVA,pNtHeader))
{
addApiWithoutName(ordinal,VA,RVA,false,module);
}
else
{
handleForwardedApi(RVA + deltaAddress,0,RVA,ordinal,module);
}
}
}
}
}
void ApiReader::findApiByModuleAndOrdinal(ModuleInfo * module, WORD ordinal, DWORD_PTR * vaApi, DWORD_PTR * rvaApi)
{
findApiByModule(module,0,ordinal,vaApi,rvaApi);
}
void ApiReader::findApiByModuleAndName(ModuleInfo * module, char * searchFunctionName, DWORD_PTR * vaApi, DWORD_PTR * rvaApi)
{
findApiByModule(module,searchFunctionName,0,vaApi,rvaApi);
}
void ApiReader::findApiByModule(ModuleInfo * module, char * searchFunctionName, WORD ordinal, DWORD_PTR * vaApi, DWORD_PTR * rvaApi)
{
if (isModuleLoadedInOwnProcess(module))
{
HMODULE hModule = GetModuleHandle(module->getFilename());
if (hModule)
{
if (ordinal)
{
*vaApi = (DWORD_PTR)GetProcAddress(hModule, (LPCSTR)ordinal);
}
else
{
*vaApi = (DWORD_PTR)GetProcAddress(hModule, searchFunctionName);
}
if (vaApi)
{
*rvaApi = (*vaApi) - (DWORD_PTR)hModule;
*vaApi = (*rvaApi) + module->modBaseAddr;
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"findApiByModule :: vaApi == NULL, should never happen %S", searchFunctionName);
#endif
}
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"findApiByModule :: hModule == NULL, should never happen %s", module->getFilename());
#endif
}
}
else
{
//search api in extern process
findApiInProcess(module,searchFunctionName,ordinal,vaApi,rvaApi);
}
}
bool ApiReader::isModuleLoadedInOwnProcess(ModuleInfo * module)
{
for (unsigned int i = 0; i < ownModuleList.size(); i++)
{
if (!_wcsicmp(module->fullPath, ownModuleList[i].fullPath))
{
//printf("isModuleLoadedInOwnProcess :: %s %s\n",module->fullPath,ownModuleList[i].fullPath);
return true;
}
}
return false;
}
void ApiReader::parseModuleWithOwnProcess( ModuleInfo * module )
{
PIMAGE_NT_HEADERS pNtHeader = 0;
PIMAGE_DOS_HEADER pDosHeader = 0;
HMODULE hModule = GetModuleHandle(module->getFilename());
if (hModule)
{
pDosHeader = (PIMAGE_DOS_HEADER)hModule;
pNtHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)hModule + (DWORD_PTR)(pDosHeader->e_lfanew));
if (isPeAndExportTableValid(pNtHeader))
{
parseExportTable(module, pNtHeader, (PIMAGE_EXPORT_DIRECTORY)((DWORD_PTR)hModule + pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress), (DWORD_PTR)hModule);
}
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"parseModuleWithOwnProcess :: hModule is NULL");
#endif
}
}
bool ApiReader::isPeAndExportTableValid(PIMAGE_NT_HEADERS pNtHeader)
{
if (pNtHeader->Signature != IMAGE_NT_SIGNATURE)
{
Scylla::windowLog.log(L"-> IMAGE_NT_SIGNATURE doesn't match.");
return false;
}
else if ((pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress == 0) || (pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size == 0))
{
Scylla::windowLog.log(L"-> No export table.");
return false;
}
else
{
return true;
}
}
void ApiReader::findApiInProcess(ModuleInfo * module, char * searchFunctionName, WORD ordinal, DWORD_PTR * vaApi, DWORD_PTR * rvaApi)
{
PIMAGE_NT_HEADERS pNtHeader = 0;
PIMAGE_DOS_HEADER pDosHeader = 0;
BYTE *bufferHeader = 0;
BYTE *bufferExportTable = 0;
bufferHeader = getHeaderFromProcess(module);
if (bufferHeader == 0)
return;
pDosHeader = (PIMAGE_DOS_HEADER)bufferHeader;
pNtHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)bufferHeader + (DWORD_PTR)(pDosHeader->e_lfanew));
if (isPeAndExportTableValid(pNtHeader))
{
bufferExportTable = getExportTableFromProcess(module, pNtHeader);
if(bufferExportTable)
{
findApiInExportTable(module,(PIMAGE_EXPORT_DIRECTORY)bufferExportTable, (DWORD_PTR)bufferExportTable - pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress,searchFunctionName,ordinal,vaApi,rvaApi);
delete[] bufferExportTable;
}
}
delete[] bufferHeader;
}
bool ApiReader::findApiInExportTable(ModuleInfo *module, PIMAGE_EXPORT_DIRECTORY pExportDir, DWORD_PTR deltaAddress, char * searchFunctionName, WORD ordinal, DWORD_PTR * vaApi, DWORD_PTR * rvaApi)
{
DWORD *addressOfFunctionsArray = 0,*addressOfNamesArray = 0;
WORD *addressOfNameOrdinalsArray = 0;
char *functionName = 0;
DWORD i = 0, j = 0;
addressOfFunctionsArray = (DWORD *)((DWORD_PTR)pExportDir->AddressOfFunctions + deltaAddress);
addressOfNamesArray = (DWORD *)((DWORD_PTR)pExportDir->AddressOfNames + deltaAddress);
addressOfNameOrdinalsArray = (WORD *)((DWORD_PTR)pExportDir->AddressOfNameOrdinals + deltaAddress);
if (searchFunctionName)
{
for (i = 0; i < pExportDir->NumberOfNames; i++)
{
functionName = (char*)(addressOfNamesArray[i] + deltaAddress);
if (!strcmp(functionName,searchFunctionName))
{
*rvaApi = addressOfFunctionsArray[addressOfNameOrdinalsArray[i]];
*vaApi = addressOfFunctionsArray[addressOfNameOrdinalsArray[i]] + module->modBaseAddr;
return true;
}
}
}
else
{
for (i = 0; i < pExportDir->NumberOfFunctions; i++)
{
if (ordinal == (i+pExportDir->Base))
{
*rvaApi = addressOfFunctionsArray[i];
*vaApi = (addressOfFunctionsArray[i] + module->modBaseAddr);
return true;
}
}
}
return false;
}
void ApiReader::setModulePriority(ModuleInfo * module)
{
const WCHAR *moduleFileName = module->getFilename();
//imports by kernelbase don't exist
if (!_wcsicmp(moduleFileName, L"kernelbase.dll"))
{
module->priority = -1;
}
else if (!_wcsicmp(moduleFileName, L"ntdll.dll"))
{
module->priority = 0;
}
else if (!_wcsicmp(moduleFileName, L"shlwapi.dll"))
{
module->priority = 0;
}
else if (!_wcsicmp(moduleFileName, L"ShimEng.dll"))
{
module->priority = 0;
}
else if (!_wcsicmp(moduleFileName, L"kernel32.dll"))
{
module->priority = 2;
}
else
{
module->priority = 1;
}
}
bool ApiReader::isApiAddressValid(DWORD_PTR virtualAddress)
{
return apiList.count(virtualAddress) > 0;
}
ApiInfo * ApiReader::getApiByVirtualAddress(DWORD_PTR virtualAddress, bool * isSuspect)
{
- stdext::hash_multimap<DWORD_PTR, ApiInfo *>::iterator it1, it2;
+ std::unordered_map<DWORD_PTR, ApiInfo *>::iterator it1, it2;
size_t c = 0;
size_t countDuplicates = apiList.count(virtualAddress);
int countHighPriority = 0;
ApiInfo *apiFound = 0;
if (countDuplicates == 0)
{
Scylla::windowLog.log(L"getApiByVirtualAddress :: No Api found " PRINTF_DWORD_PTR_FULL, virtualAddress);
return 0;
}
else if (countDuplicates == 1)
{
//API is 100% correct
*isSuspect = false;
it1 = apiList.find(virtualAddress); // Find first match.
return (ApiInfo *)((*it1).second);
}
else
{
it1 = apiList.find(virtualAddress); // Find first match.
//any high priority with a name
apiFound = getScoredApi(it1,countDuplicates,true,false,false,true,false,false,false,false);
if (apiFound)
return apiFound;
*isSuspect = true;
//high priority with a name and ansi/unicode name
apiFound = getScoredApi(it1,countDuplicates,true,true,false,true,false,false,false,false);
if (apiFound)
return apiFound;
//priority 2 with no underline in name
apiFound = getScoredApi(it1,countDuplicates,true,false,true,false,false,false,true,false);
if (apiFound)
return apiFound;
//priority 1 with a name
apiFound = getScoredApi(it1,countDuplicates,true,false,false,false,false,true,false,false);
if (apiFound)
return apiFound;
//With a name
apiFound = getScoredApi(it1,countDuplicates,true,false,false,false,false,false,false,false);
if (apiFound)
return apiFound;
//any with priority, name, ansi/unicode
apiFound = getScoredApi(it1,countDuplicates,true,true,false,true,false,false,false,true);
if (apiFound)
return apiFound;
//any with priority
apiFound = getScoredApi(it1,countDuplicates,false,false,false,true,false,false,false,true);
if (apiFound)
return apiFound;
//has prio 0 and name
apiFound = getScoredApi(it1,countDuplicates,false,false,false,false,true,false,false,true);
if (apiFound)
return apiFound;
}
//is never reached
Scylla::windowLog.log(L"getApiByVirtualAddress :: There is a api resolving bug, VA: " PRINTF_DWORD_PTR_FULL, virtualAddress);
for (size_t c = 0; c < countDuplicates; c++, it1++)
{
apiFound = (ApiInfo *)((*it1).second);
Scylla::windowLog.log(L"-> Possible API: %S ord: %d ", apiFound->name, apiFound->ordinal);
}
return (ApiInfo *) 1;
}
/*ApiInfo * ApiReader::getApiByVirtualAddress(DWORD_PTR virtualAddress, bool * isSuspect)
{
- stdext::hash_multimap<DWORD_PTR, ApiInfo *>::iterator it1, it2;
+ std::unordered_map<DWORD_PTR, ApiInfo *>::iterator it1, it2;
size_t c = 0;
size_t countDuplicates = apiList.count(virtualAddress);
int countHighPriority = 0;
ApiInfo *apiFound = 0;
if (countDuplicates == 0)
{
Scylla::windowLog.log(L"getApiByVirtualAddress :: No Api found " PRINTF_DWORD_PTR_FULL, virtualAddress);
return 0;
}
else if (countDuplicates == 1)
{
//API is 100% correct
*isSuspect = false;
it1 = apiList.find(virtualAddress); // Find first match.
return (ApiInfo *)((*it1).second);
}
else
{
it1 = apiList.find(virtualAddress); // Find first match.
it2 = it1;
for (c = 0; c < countDuplicates; c++, it1++)
{
apiFound = (ApiInfo *)((*it1).second);
if (apiFound->module->priority >= 1) //1 == high priority
{
countHighPriority++;
}
}
it1 = it2;
This is flawed:
It chooses api(prio:1, name:no) over api(prio:0, name:yes)
(e.g. SHLWAPI.PathCombineW vs SHELL32.#25)
Maybe there should be a check higher up in the code, to see if this API is surrounded
by APIs of a DLL and pick the duplicate from that DLL
if (countHighPriority == 0)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"getApiByVirtualAddress :: countHighPriority == 0 " PRINTF_DWORD_PTR_FULL, virtualAddress);
#endif
*isSuspect = true;
return (ApiInfo *)((*it1).second);
}
else if (countHighPriority == 1) // what about kernel32, it has priority 2
{
//API is 100% correct if countHighPriority == 1 and name export
*isSuspect = false;
for (c = 0; c < countDuplicates; c++, it1++)
{
apiFound = (ApiInfo *)((*it1).second);
if (apiFound->module->priority >= 1 && apiFound->name[0] != 0x00) //1 == high priority
{
return apiFound;
}
}
}
//else // fall through for case api1(priority:1, name:false) <> api2(priority:0, name:true)
{
//API not 100% correct
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"getApiByVirtualAddress :: countHighPriority == %d " PRINTF_DWORD_PTR_FULL, countHighPriority, virtualAddress);
#endif
*isSuspect = true;
for (c = 0; c < countDuplicates; c++, it1++)
{
apiFound = (ApiInfo *)((*it1).second);
Scylla::windowLog.log(L"%s - %s %X %X\n",apiFound->name, apiFound->module->getFilename(), apiFound->rva, apiFound->ordinal);
}
it1 = it2;
for (c = 0; c < countDuplicates; c++, it1++)
{
apiFound = (ApiInfo *)((*it1).second);
//prefer APIs with a name
if (apiFound->module->priority >= 1 && apiFound->name[0] != 0x00) //1 == high priority
{
//prefer ANSI/UNICODE APIs
if (strrchr(apiFound->name, 'W') || strrchr(apiFound->name, 'A'))
{
return apiFound;
}
}
}
it1 = it2;
for (c = 0; c < countDuplicates; c++, it1++)
{
apiFound = (ApiInfo *)((*it1).second);
//prefer APIs with a name
if (apiFound->module->priority == 2 && !strrchr(apiFound->name, '_')) //1 == high priority
{
return apiFound;
}
}
it1 = it2;
for (c = 0; c < countDuplicates; c++, it1++)
{
apiFound = (ApiInfo *)((*it1).second);
if (apiFound->module->priority == 1 && apiFound->name[0] != 0x00) //1 == high priority
{
return apiFound;
}
}
it1 = it2;
for (c = 0; c < countDuplicates; c++, it1++)
{
apiFound = (ApiInfo *)((*it1).second);
if (apiFound->module->priority == 1) //1 == high priority
{
return apiFound;
}
}
}
}
//is never reached
Scylla::windowLog.log(L"getApiByVirtualAddress :: There is a big bug");
return (ApiInfo *) 1;
}*/
-ApiInfo * ApiReader::getScoredApi(stdext::hash_multimap<DWORD_PTR, ApiInfo *>::iterator it1,size_t countDuplicates, bool hasName, bool hasUnicodeAnsiName, bool hasNoUnderlineInName, bool hasPrioDll,bool hasPrio0Dll,bool hasPrio1Dll, bool hasPrio2Dll, bool firstWin )
+ApiInfo * ApiReader::getScoredApi(std::unordered_map<DWORD_PTR, ApiInfo *>::iterator it1,size_t countDuplicates, bool hasName, bool hasUnicodeAnsiName, bool hasNoUnderlineInName, bool hasPrioDll,bool hasPrio0Dll,bool hasPrio1Dll, bool hasPrio2Dll, bool firstWin )
{
ApiInfo * foundApi = 0;
ApiInfo * foundMatchingApi = 0;
int countFoundApis = 0;
int scoreNeeded = 0;
int scoreValue = 0;
size_t apiNameLength = 0;
if (hasUnicodeAnsiName || hasNoUnderlineInName)
{
hasName = true;
}
if (hasName)
scoreNeeded++;
if (hasUnicodeAnsiName)
scoreNeeded++;
if (hasNoUnderlineInName)
scoreNeeded++;
if (hasPrioDll)
scoreNeeded++;
if (hasPrio0Dll)
scoreNeeded++;
if (hasPrio1Dll)
scoreNeeded++;
if (hasPrio2Dll)
scoreNeeded++;
for (size_t c = 0; c < countDuplicates; c++, it1++)
{
foundApi = (ApiInfo *)((*it1).second);
scoreValue = 0;
if (hasName)
{
if (foundApi->name[0] != 0x00)
{
scoreValue++;
if (hasUnicodeAnsiName)
{
apiNameLength = strlen(foundApi->name);
if ((foundApi->name[apiNameLength - 1] == 'W') || (foundApi->name[apiNameLength - 1] == 'A'))
{
scoreValue++;
}
}
if (hasNoUnderlineInName)
{
if (!strrchr(foundApi->name, '_'))
{
scoreValue++;
}
}
}
}
if (hasPrioDll)
{
if (foundApi->module->priority >= 1)
{
scoreValue++;
}
}
if (hasPrio0Dll)
{
if (foundApi->module->priority == 0)
{
scoreValue++;
}
}
if (hasPrio1Dll)
{
if (foundApi->module->priority == 1)
{
scoreValue++;
}
}
if (hasPrio2Dll)
{
if (foundApi->module->priority == 2)
{
scoreValue++;
}
}
if (scoreValue == scoreNeeded)
{
foundMatchingApi = foundApi;
countFoundApis++;
if (firstWin)
{
return foundMatchingApi;
}
}
}
if (countFoundApis == 1)
{
return foundMatchingApi;
}
else
{
return (ApiInfo *)0;
}
}
void ApiReader::setMinMaxApiAddress(DWORD_PTR virtualAddress)
{
if (virtualAddress < minApiAddress)
{
minApiAddress = virtualAddress - 1;
}
if (virtualAddress > maxApiAddress)
{
maxApiAddress = virtualAddress + 1;
}
}
void ApiReader::readAndParseIAT(DWORD_PTR addressIAT, DWORD sizeIAT, std::map<DWORD_PTR, ImportModuleThunk> &moduleListNew)
{
moduleThunkList = &moduleListNew;
BYTE *dataIat = new BYTE[sizeIAT];
if (readMemoryFromProcess(addressIAT,sizeIAT,dataIat))
{
parseIAT(addressIAT,dataIat,sizeIAT);
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"ApiReader::readAndParseIAT :: error reading iat " PRINTF_DWORD_PTR_FULL, addressIAT);
#endif
}
delete[] dataIat;
}
void ApiReader::parseIAT(DWORD_PTR addressIAT, BYTE * iatBuffer, SIZE_T size)
{
ApiInfo *apiFound = 0;
ModuleInfo *module = 0;
bool isSuspect = false;
int countApiFound = 0, countApiNotFound = 0;
DWORD_PTR * pIATAddress = (DWORD_PTR *)iatBuffer;
SIZE_T sizeIAT = size / sizeof(DWORD_PTR);
bool foundModuleBreak = false;
for (SIZE_T i = 0; i < sizeIAT; i++)
{
//Scylla::windowLog.log(L"%08X %08X %d von %d", addressIAT + (DWORD_PTR)&pIATAddress[i] - (DWORD_PTR)iatBuffer, pIATAddress[i],i,sizeIAT);
if (pIATAddress[i] == 0 || pIATAddress[i] == -1)
{
/*if (pIATAddress[i+1] != 0)
{
printf("parseIAT :: Module break\n");
}*/
/*else
{
printf("parseIAT :: IAT finished\n");
break;
}*/
foundModuleBreak = true;
}
else if ( (pIATAddress[i] > minApiAddress) && (pIATAddress[i] < maxApiAddress) )
{
apiFound = getApiByVirtualAddress(pIATAddress[i], &isSuspect);
if (apiFound == (ApiInfo *)1)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"apiFound == (ApiInfo *)1 -> " PRINTF_DWORD_PTR_FULL, pIATAddress[i]);
#endif
}
else if (apiFound)
{
countApiFound++;
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(PRINTF_DWORD_PTR_FULL L" %s %d %s", apiFound->va, apiFound->module->getFilename(), apiFound->ordinal, apiFound->name);
#endif
if (module != apiFound->module)
{
module = apiFound->module;
addFoundApiToModuleList(addressIAT + (DWORD_PTR)&pIATAddress[i] - (DWORD_PTR)iatBuffer, apiFound, true, isSuspect);
}
else
{
addFoundApiToModuleList(addressIAT + (DWORD_PTR)&pIATAddress[i] - (DWORD_PTR)iatBuffer, apiFound, false, isSuspect);
}
}
else
{
countApiNotFound++;
addNotFoundApiToModuleList(addressIAT + (DWORD_PTR)&pIATAddress[i] - (DWORD_PTR)iatBuffer, pIATAddress[i]);
//printf("parseIAT :: API not found %08X\n", pIATAddress[i]);
}
}
else
{
//printf("parseIAT :: API not found %08X\n", pIATAddress[i]);
countApiNotFound++;
addNotFoundApiToModuleList(addressIAT + (DWORD_PTR)&pIATAddress[i] - (DWORD_PTR)iatBuffer, pIATAddress[i]);
}
}
Scylla::windowLog.log(L"IAT parsing finished, found %d valid APIs, missed %d APIs", countApiFound, countApiNotFound);
}
void ApiReader::addFoundApiToModuleList(DWORD_PTR iatAddressVA, ApiInfo * apiFound, bool isNewModule, bool isSuspect)
{
if (isNewModule)
{
addModuleToModuleList(apiFound->module->getFilename(), iatAddressVA - targetImageBase);
}
addFunctionToModuleList(apiFound, iatAddressVA, iatAddressVA - targetImageBase, apiFound->ordinal, true, isSuspect);
}
bool ApiReader::addModuleToModuleList(const WCHAR * moduleName, DWORD_PTR firstThunk)
{
ImportModuleThunk module;
module.firstThunk = firstThunk;
wcscpy_s(module.moduleName, _countof(module.moduleName), moduleName);
(*moduleThunkList).insert(std::pair<DWORD_PTR,ImportModuleThunk>(firstThunk,module));
return true;
}
void ApiReader::addUnknownModuleToModuleList(DWORD_PTR firstThunk)
{
ImportModuleThunk module;
module.firstThunk = firstThunk;
wcscpy_s(module.moduleName, _countof(module.moduleName), L"?");
(*moduleThunkList).insert(std::pair<DWORD_PTR,ImportModuleThunk>(firstThunk,module));
}
bool ApiReader::addFunctionToModuleList(ApiInfo * apiFound, DWORD_PTR va, DWORD_PTR rva, WORD ordinal, bool valid, bool suspect)
{
ImportThunk import;
ImportModuleThunk * module = 0;
std::map<DWORD_PTR, ImportModuleThunk>::iterator iterator1;
if ((*moduleThunkList).size() > 1)
{
iterator1 = (*moduleThunkList).begin();
while (iterator1 != (*moduleThunkList).end())
{
if (rva >= iterator1->second.firstThunk)
{
iterator1++;
if (iterator1 == (*moduleThunkList).end())
{
iterator1--;
module = &(iterator1->second);
break;
}
else if (rva < iterator1->second.firstThunk)
{
iterator1--;
module = &(iterator1->second);
break;
}
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"Error iterator1 != (*moduleThunkList).end()");
#endif
break;
}
}
}
else
{
iterator1 = (*moduleThunkList).begin();
module = &(iterator1->second);
}
if (!module)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"ImportsHandling::addFunction module not found rva " PRINTF_DWORD_PTR_FULL, rva);
#endif
return false;
}
import.suspect = suspect;
import.valid = valid;
import.va = va;
import.rva = rva;
import.apiAddressVA = apiFound->va;
import.ordinal = ordinal;
import.hint = (WORD)apiFound->hint;
wcscpy_s(import.moduleName, _countof(import.moduleName), apiFound->module->getFilename());
strcpy_s(import.name, _countof(import.name), apiFound->name);
module->thunkList.insert(std::pair<DWORD_PTR,ImportThunk>(import.rva, import));
return true;
}
void ApiReader::clearAll()
{
minApiAddress = -1;
maxApiAddress = 0;
- for ( stdext::hash_multimap<DWORD_PTR, ApiInfo *>::iterator it = apiList.begin(); it != apiList.end(); ++it )
+ for ( std::unordered_map<DWORD_PTR, ApiInfo *>::iterator it = apiList.begin(); it != apiList.end(); ++it )
{
delete it->second;
}
apiList.clear();
if (moduleThunkList != 0)
{
(*moduleThunkList).clear();
}
}
bool ApiReader::addNotFoundApiToModuleList(DWORD_PTR iatAddressVA, DWORD_PTR apiAddress)
{
ImportThunk import;
ImportModuleThunk * module = 0;
std::map<DWORD_PTR, ImportModuleThunk>::iterator iterator1;
DWORD_PTR rva = iatAddressVA - targetImageBase;
if ((*moduleThunkList).size() > 0)
{
iterator1 = (*moduleThunkList).begin();
while (iterator1 != (*moduleThunkList).end())
{
if (rva >= iterator1->second.firstThunk)
{
iterator1++;
if (iterator1 == (*moduleThunkList).end())
{
iterator1--;
//new unknown module
if (iterator1->second.moduleName[0] == L'?')
{
module = &(iterator1->second);
}
else
{
addUnknownModuleToModuleList(rva);
module = &((*moduleThunkList).find(rva)->second);
}
break;
}
else if (rva < iterator1->second.firstThunk)
{
iterator1--;
module = &(iterator1->second);
break;
}
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"Error iterator1 != (*moduleThunkList).end()\r\n");
#endif
break;
}
}
}
else
{
//new unknown module
addUnknownModuleToModuleList(rva);
module = &((*moduleThunkList).find(rva)->second);
}
if (!module)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"ImportsHandling::addFunction module not found rva " PRINTF_DWORD_PTR_FULL,rva);
#endif
return false;
}
import.suspect = true;
import.valid = false;
import.va = iatAddressVA;
import.rva = rva;
import.apiAddressVA = apiAddress;
import.ordinal = 0;
wcscpy_s(import.moduleName, _countof(import.moduleName), L"?");
strcpy_s(import.name, _countof(import.name), "?");
module->thunkList.insert(std::pair<DWORD_PTR,ImportThunk>(import.rva, import));
return true;
}
bool ApiReader::isApiBlacklisted( const char * functionName )
{
if (SystemInformation::currenOS < WIN_VISTA_32)
{
if (!strcmp(functionName, "RestoreLastError"))
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
/*#ifdef _WIN64
else if (SystemInformation::currenOS == WIN_XP_64 && !strcmp(functionName, "DecodePointer"))
{
return true;
}
#endif*/
}
bool ApiReader::isWinSxSModule( ModuleInfo * module )
{
if (wcsstr(module->fullPath, L"\\WinSxS\\"))
{
return true;
}
else if (wcsstr(module->fullPath, L"\\winsxs\\"))
{
return true;
}
else
{
return false;
}
}
diff --git a/Scylla/ApiReader.h b/Scylla/ApiReader.h
index ebcc6f2..81e4bea 100644
--- a/Scylla/ApiReader.h
+++ b/Scylla/ApiReader.h
@@ -1,72 +1,74 @@
#pragma once
+#include <windows.h>
+#include <map>
+#include <unordered_map>
#include "ProcessAccessHelp.h"
#include "Thunks.h"
typedef std::pair<DWORD_PTR, ApiInfo *> API_Pair;
-class ApiReader : public ProcessAccessHelp {
+class ApiReader : public ProcessAccessHelp
+{
public:
- static stdext::hash_multimap<DWORD_PTR, ApiInfo *> apiList; //api look up table
+ static std::unordered_map<DWORD_PTR, ApiInfo *> apiList; //api look up table
static std::map<DWORD_PTR, ImportModuleThunk> * moduleThunkList; //store found apis
static DWORD_PTR minApiAddress;
static DWORD_PTR maxApiAddress;
/*
* Read all APIs from target process
*/
void readApisFromModuleList();
-
bool isApiAddressValid(DWORD_PTR virtualAddress);
ApiInfo * getApiByVirtualAddress(DWORD_PTR virtualAddress, bool * isSuspect);
- void readAndParseIAT(DWORD_PTR addressIAT, DWORD sizeIAT,std::map<DWORD_PTR, ImportModuleThunk> &moduleListNew );
+ void readAndParseIAT(DWORD_PTR addressIAT, DWORD sizeIAT, std::map<DWORD_PTR, ImportModuleThunk> &moduleListNew );
void clearAll();
private:
+
void parseIAT(DWORD_PTR addressIAT, BYTE * iatBuffer, SIZE_T size);
void addApi(char *functionName, WORD hint, WORD ordinal, DWORD_PTR va, DWORD_PTR rva, bool isForwarded, ModuleInfo *moduleInfo);
void addApiWithoutName(WORD ordinal, DWORD_PTR va, DWORD_PTR rva,bool isForwarded, ModuleInfo *moduleInfo);
inline bool isApiForwarded(DWORD_PTR rva, PIMAGE_NT_HEADERS pNtHeader);
void handleForwardedApi(DWORD_PTR vaStringPointer,char *functionNameParent,DWORD_PTR rvaParent, WORD ordinalParent, ModuleInfo *moduleParent);
void parseModule(ModuleInfo *module);
void parseModuleWithProcess(ModuleInfo * module);
-
void parseExportTable(ModuleInfo *module, PIMAGE_NT_HEADERS pNtHeader, PIMAGE_EXPORT_DIRECTORY pExportDir, DWORD_PTR deltaAddress);
ModuleInfo * findModuleByName(WCHAR *name);
void findApiByModuleAndOrdinal(ModuleInfo * module, WORD ordinal, DWORD_PTR * vaApi, DWORD_PTR * rvaApi);
void findApiByModuleAndName(ModuleInfo * module, char * searchFunctionName, DWORD_PTR * vaApi, DWORD_PTR * rvaApi);
void findApiByModule(ModuleInfo * module, char * searchFunctionName, WORD ordinal, DWORD_PTR * vaApi, DWORD_PTR * rvaApi);
bool isModuleLoadedInOwnProcess( ModuleInfo * module );
void parseModuleWithOwnProcess( ModuleInfo * module );
bool isPeAndExportTableValid(PIMAGE_NT_HEADERS pNtHeader);
void findApiInProcess( ModuleInfo * module, char * searchFunctionName, WORD ordinal, DWORD_PTR * vaApi, DWORD_PTR * rvaApi );
bool findApiInExportTable(ModuleInfo *module, PIMAGE_EXPORT_DIRECTORY pExportDir, DWORD_PTR deltaAddress, char * searchFunctionName, WORD ordinal, DWORD_PTR * vaApi, DWORD_PTR * rvaApi);
BYTE * getHeaderFromProcess(ModuleInfo * module);
BYTE * getExportTableFromProcess(ModuleInfo * module, PIMAGE_NT_HEADERS pNtHeader);
void setModulePriority(ModuleInfo * module);
void setMinMaxApiAddress(DWORD_PTR virtualAddress);
-
void parseModuleWithMapping(ModuleInfo *moduleInfo); //not used
void addFoundApiToModuleList(DWORD_PTR iatAddress, ApiInfo * apiFound, bool isNewModule, bool isSuspect);
bool addModuleToModuleList(const WCHAR * moduleName, DWORD_PTR firstThunk);
bool addFunctionToModuleList(ApiInfo * apiFound, DWORD_PTR va, DWORD_PTR rva, WORD ordinal, bool valid, bool suspect);
bool addNotFoundApiToModuleList(DWORD_PTR iatAddressVA, DWORD_PTR apiAddress);
void addUnknownModuleToModuleList(DWORD_PTR firstThunk);
bool isApiBlacklisted( const char * functionName );
bool isWinSxSModule( ModuleInfo * module );
- ApiInfo * getScoredApi(stdext::hash_multimap<DWORD_PTR, ApiInfo *>::iterator it1,size_t countDuplicates, bool hasName, bool hasUnicodeAnsiName, bool hasNoUnderlineInName, bool hasPrioDll,bool hasPrio0Dll,bool hasPrio1Dll, bool hasPrio2Dll, bool firstWin );
-};
\ No newline at end of file
+ ApiInfo * getScoredApi(std::unordered_map<DWORD_PTR, ApiInfo *>::iterator it1,size_t countDuplicates, bool hasName, bool hasUnicodeAnsiName, bool hasNoUnderlineInName, bool hasPrioDll,bool hasPrio0Dll,bool hasPrio1Dll, bool hasPrio2Dll, bool firstWin );
+};
diff --git a/Scylla/ConfigurationHolder.cpp b/Scylla/ConfigurationHolder.cpp
index 52ab836..c04838f 100644
--- a/Scylla/ConfigurationHolder.cpp
+++ b/Scylla/ConfigurationHolder.cpp
@@ -1,205 +1,202 @@
#include "ConfigurationHolder.h"
#include <shlwapi.h>
-#include <stdio.h>
#include "Architecture.h"
const WCHAR ConfigurationHolder::CONFIG_FILE_SECTION_NAME[] = L"SCYLLA_CONFIG";
//#define DEBUG_COMMENTS
ConfigurationHolder::ConfigurationHolder(const WCHAR* fileName)
{
config[USE_PE_HEADER_FROM_DISK] = Configuration(L"USE_PE_HEADER_FROM_DISK", Configuration::Boolean);
config[DEBUG_PRIVILEGE] = Configuration(L"DEBUG_PRIVILEGE", Configuration::Boolean);
config[CREATE_BACKUP] = Configuration(L"CREATE_BACKUP", Configuration::Boolean);
config[DLL_INJECTION_AUTO_UNLOAD] = Configuration(L"DLL_INJECTION_AUTO_UNLOAD", Configuration::Boolean);
config[UPDATE_HEADER_CHECKSUM] = Configuration(L"UPDATE_HEADER_CHECKSUM", Configuration::Boolean);
config[IAT_SECTION_NAME] = Configuration(L"IAT_SECTION_NAME", Configuration::String);
buildConfigFilePath(fileName);
}
bool ConfigurationHolder::loadConfiguration()
{
std::map<ConfigOption, Configuration>::iterator mapIter;
if (configPath[0] == '\0')
{
return false;
}
for (mapIter = config.begin() ; mapIter != config.end(); mapIter++)
{
Configuration& configObject = mapIter->second;
if (!loadConfig(configObject))
{
return false;
}
}
return true;
}
bool ConfigurationHolder::saveConfiguration() const
{
std::map<ConfigOption, Configuration>::const_iterator mapIter;
if (configPath[0] == '\0')
{
return false;
}
for (mapIter = config.begin() ; mapIter != config.end(); mapIter++)
{
const Configuration& configObject = mapIter->second;
if (!saveConfig(configObject))
{
return false;
}
}
return true;
}
Configuration& ConfigurationHolder::operator[](ConfigOption option)
{
return config[option];
}
const Configuration& ConfigurationHolder::operator[](ConfigOption option) const
{
static const Configuration dummy;
std::map<ConfigOption, Configuration>::const_iterator found = config.find(option);
if(found != config.end())
{
return found->second;
}
else
{
return dummy;
}
}
bool ConfigurationHolder::saveNumericToConfigFile(const Configuration & configObject, int nBase) const
{
WCHAR buf[21]; // UINT64_MAX in dec has 20 digits
if (nBase == 16)
{
swprintf_s(buf, PRINTF_DWORD_PTR_FULL, configObject.getNumeric());
}
else
{
swprintf_s(buf, PRINTF_INTEGER, configObject.getNumeric());
}
BOOL ret = WritePrivateProfileString(CONFIG_FILE_SECTION_NAME, configObject.getName(), buf, configPath);
return ret == TRUE;
}
bool ConfigurationHolder::readNumericFromConfigFile(Configuration & configObject, int nBase)
{
WCHAR buf[21]; // UINT64_MAX in dec has 20 digits
DWORD read = GetPrivateProfileString(CONFIG_FILE_SECTION_NAME, configObject.getName(), L"", buf, _countof(buf), configPath);
if (read > 0 && wcslen(buf) > 0)
{
#ifdef _WIN64
configObject.setNumeric(_wcstoui64(buf, NULL, nBase));
#else
configObject.setNumeric(wcstoul(buf, NULL, nBase));
#endif
return true;
}
return false;
}
bool ConfigurationHolder::saveStringToConfigFile(const Configuration & configObject) const
{
BOOL ret = WritePrivateProfileString(CONFIG_FILE_SECTION_NAME, configObject.getName(), configObject.getString(), configPath);
return ret == TRUE;
}
bool ConfigurationHolder::readStringFromConfigFile(Configuration & configObject)
{
WCHAR buf[Configuration::CONFIG_STRING_LENGTH];
DWORD read = GetPrivateProfileString(CONFIG_FILE_SECTION_NAME, configObject.getName(), L"", buf, _countof(buf), configPath);
if(read > 0 && wcslen(buf) > 0)
{
configObject.setString(buf);
return true;
}
return false;
}
bool ConfigurationHolder::readBooleanFromConfigFile(Configuration & configObject)
{
UINT val = GetPrivateProfileInt(CONFIG_FILE_SECTION_NAME, configObject.getName(), 0, configPath);
configObject.setBool(val != 0);
return true;
}
bool ConfigurationHolder::saveBooleanToConfigFile(const Configuration & configObject) const
{
const WCHAR *boolValue = configObject.isTrue() ? L"1" : L"0";
BOOL ret = WritePrivateProfileString(CONFIG_FILE_SECTION_NAME, configObject.getName(), boolValue, configPath);
return ret == TRUE;
}
bool ConfigurationHolder::loadConfig(Configuration & configObject)
{
switch (configObject.getType())
{
case Configuration::String:
return readStringFromConfigFile(configObject);
case Configuration::Boolean:
return readBooleanFromConfigFile(configObject);
case Configuration::Decimal:
return readNumericFromConfigFile(configObject, 10);
case Configuration::Hexadecimal:
return readNumericFromConfigFile(configObject, 16);
default:
return false;
}
}
bool ConfigurationHolder::saveConfig(const Configuration & configObject) const
{
switch (configObject.getType())
{
case Configuration::String:
return saveStringToConfigFile(configObject);
case Configuration::Boolean:
return saveBooleanToConfigFile(configObject);
case Configuration::Decimal:
return saveNumericToConfigFile(configObject, 10);
case Configuration::Hexadecimal:
return saveNumericToConfigFile(configObject, 16);
default:
return false;
}
}
bool ConfigurationHolder::buildConfigFilePath(const WCHAR* fileName)
{
ZeroMemory(configPath, sizeof(configPath));
if (!GetModuleFileName(0, configPath, _countof(configPath)))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"buildConfigFilePath :: GetModuleFileName failed %d", GetLastError());
#endif
return false;
}
PathRemoveFileSpec(configPath);
PathAppend(configPath, fileName);
- //wprintf(L"configPath %s\n\n", configPath);
-
return true;
}
diff --git a/Scylla/DllInjection.cpp b/Scylla/DllInjection.cpp
index d309309..c8f5fed 100644
--- a/Scylla/DllInjection.cpp
+++ b/Scylla/DllInjection.cpp
@@ -1,246 +1,246 @@
#include "DllInjection.h"
-#include "Logger.h"
#include <Psapi.h>
+#include "Scylla.h"
#include "NativeWinApi.h"
//#define DEBUG_COMMENTS
HMODULE DllInjection::dllInjection(HANDLE hProcess, const WCHAR * filename)
{
LPVOID remoteMemory = 0;
SIZE_T memorySize = 0;
HANDLE hThread = 0;
HMODULE hModule = 0;
memorySize = (wcslen(filename) + 1) * sizeof(WCHAR);
if (memorySize < 7)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"dllInjection :: memorySize invalid");
#endif
return 0;
}
remoteMemory = VirtualAllocEx(hProcess, NULL, memorySize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (remoteMemory == 0)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"dllInjection :: VirtualAllocEx failed 0x%X", GetLastError());
#endif
return 0;
}
if (WriteProcessMemory(hProcess, remoteMemory, filename, memorySize, &memorySize))
{
hThread = startRemoteThread(hProcess,LoadLibraryW,remoteMemory);
if (hThread)
{
WaitForSingleObject(hThread, INFINITE);
#ifdef _WIN64
hModule = getModuleHandleByFilename(hProcess, filename);
#else
//returns only 32 bit values -> design bug by microsoft
if (!GetExitCodeThread(hThread, (LPDWORD) &hModule))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"dllInjection :: GetExitCodeThread failed 0x%X", GetLastError());
#endif
hModule = 0;
}
#endif
CloseHandle(hThread);
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"dllInjection :: CreateRemoteThread failed 0x%X", GetLastError());
#endif
}
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"dllInjection :: WriteProcessMemory failed 0x%X", GetLastError());
#endif
}
VirtualFreeEx(hProcess, remoteMemory, 0, MEM_RELEASE);
return hModule;
}
bool DllInjection::unloadDllInProcess(HANDLE hProcess, HMODULE hModule)
{
HANDLE hThread = 0;
DWORD lpThreadId = 0;
BOOL freeLibraryRet = 0;
hThread = startRemoteThread(hProcess,FreeLibrary,hModule);
if (hThread)
{
WaitForSingleObject(hThread, INFINITE);
if (!GetExitCodeThread(hThread, (LPDWORD) &freeLibraryRet))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"unloadDllInProcess :: GetExitCodeThread failed 0x%X", GetLastError());
#endif
freeLibraryRet = 0;
}
CloseHandle(hThread);
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"unloadDllInProcess :: CreateRemoteThread failed 0x%X", GetLastError());
#endif
}
return freeLibraryRet != 0;
}
HMODULE DllInjection::getModuleHandleByFilename( HANDLE hProcess, const WCHAR * filename )
{
HMODULE * hMods = 0;
HMODULE hModResult = 0;
DWORD count = 0;
WCHAR target[MAX_PATH];
DWORD cbNeeded = 0;
bool notEnough = true;
count = 100;
hMods = new HMODULE[count];
do
{
if (!EnumProcessModules(hProcess, hMods, count * sizeof(HMODULE), &cbNeeded))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"DllInjection::getModuleHandle :: EnumProcessModules failed count %d", count);
#endif
delete [] hMods;
return 0;
}
if ( (count * sizeof(HMODULE)) < cbNeeded )
{
delete [] hMods;
count += 100;
hMods = new HMODULE[count];
}
else
{
notEnough = false;
}
} while (notEnough);
for (DWORD i = 0; i < (cbNeeded / sizeof(HMODULE)); i++ )
{
if (GetModuleFileNameExW(hProcess, hMods[i], target, _countof(target)))
{
if (!_wcsicmp(target,filename))
{
hModResult = hMods[i];
break;
}
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"DllInjection::getModuleHandle :: GetModuleFileNameExW failed 0x%X", GetLastError());
#endif
}
}
if (!hModResult)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"DllInjection::getModuleHandle :: Handle not found");
#endif
}
delete [] hMods;
return hModResult;
}
void DllInjection::specialThreadSettings( HANDLE hThread )
{
if (hThread)
{
if (!SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"specialThreadSettings :: SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL) failed 0x%X", GetLastError());
#endif
}
if (NativeWinApi::NtSetInformationThread)
{
if (NativeWinApi::NtSetInformationThread(hThread, ThreadHideFromDebugger, 0, 0) != STATUS_SUCCESS)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"specialThreadSettings :: NtSetInformationThread ThreadHideFromDebugger failed");
#endif
}
}
}
}
HANDLE DllInjection::startRemoteThread(HANDLE hProcess, LPVOID lpStartAddress, LPVOID lpParameter)
{
HANDLE hThread = 0;
hThread = customCreateRemoteThread(hProcess, lpStartAddress, lpParameter);
if (hThread)
{
specialThreadSettings(hThread);
ResumeThread(hThread);
}
return hThread;
}
HANDLE DllInjection::customCreateRemoteThread(HANDLE hProcess, LPVOID lpStartAddress, LPVOID lpParameter)
{
DWORD lpThreadId = 0;
HANDLE hThread = 0;
NTSTATUS ntStatus = 0;
if (NativeWinApi::NtCreateThreadEx)
{
#define THREAD_ALL_ACCESS_VISTA_7 (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFFF)
//for windows vista/7
ntStatus = NativeWinApi::NtCreateThreadEx(&hThread, THREAD_ALL_ACCESS_VISTA_7, 0, hProcess, (LPTHREAD_START_ROUTINE)lpStartAddress, (LPVOID)lpParameter, TRUE, 0, 0, 0, 0);
if (NT_SUCCESS(ntStatus))
{
return hThread;
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"customCreateRemoteThread :: NtCreateThreadEx failed 0x%X", NativeWinApi::RtlNtStatusToDosError(ntStatus));
#endif
return 0;
}
}
else
{
return CreateRemoteThread(hProcess,NULL,NULL,(LPTHREAD_START_ROUTINE)lpStartAddress,lpParameter,CREATE_SUSPENDED,&lpThreadId);
}
}
diff --git a/Scylla/DllInjection.h b/Scylla/DllInjection.h
index ddd0a6d..a7af9e6 100644
--- a/Scylla/DllInjection.h
+++ b/Scylla/DllInjection.h
@@ -1,17 +1,18 @@
-#include <windows.h>
-#include <Commctrl.h>
-#include <stdio.h>
-#include <map>
+#pragma once
+#include <windows.h>
-class DllInjection {
+class DllInjection
+{
public:
+
HMODULE dllInjection(HANDLE hProcess, const WCHAR * filename);
bool unloadDllInProcess(HANDLE hProcess, HMODULE hModule);
HANDLE startRemoteThread(HANDLE hProcess, LPVOID lpStartAddress, LPVOID lpParameter);
private:
+
HANDLE customCreateRemoteThread(HANDLE hProcess, LPVOID lpStartAddress, LPVOID lpParameter);
- void specialThreadSettings( HANDLE hThread );
- HMODULE getModuleHandleByFilename( HANDLE hProcess, const WCHAR * filename );
-};
\ No newline at end of file
+ void specialThreadSettings(HANDLE hThread);
+ HMODULE getModuleHandleByFilename(HANDLE hProcess, const WCHAR * filename);
+};
diff --git a/Scylla/DllInjectionPlugin.h b/Scylla/DllInjectionPlugin.h
index 1f22613..131970c 100644
--- a/Scylla/DllInjectionPlugin.h
+++ b/Scylla/DllInjectionPlugin.h
@@ -1,65 +1,66 @@
+#pragma once
+
#include "DllInjection.h"
#include "PluginLoader.h"
#include "Thunks.h"
#include "ApiReader.h"
-
#define PLUGIN_IMPREC_EXCHANGE_DLL_PATH "ScyllaImprecPluginExchangePath"
#define SCYLLA_STATUS_SUCCESS 0
#define SCYLLA_STATUS_UNKNOWN_ERROR 1
#define SCYLLA_STATUS_UNSUPPORTED_PROTECTION 2
#define SCYLLA_STATUS_IMPORT_RESOLVING_FAILED 3
#define SCYLLA_STATUS_MAPPING_FAILED 0xFF
/* Important note:
*
* If you write a plugin for the x86 (32-Bit) edition: DWORD_PTR address has 32 bit (4 byte)
* If you write a plugin for the x64 (64-Bit) edition: DWORD_PTR address has 64 bit (8 byte)
*/
typedef struct _UNRESOLVED_IMPORT { // Scylla Plugin exchange format
DWORD_PTR ImportTableAddressPointer; //in VA, address in IAT which points to an invalid api address
DWORD_PTR InvalidApiAddress; //in VA, invalid api address that needs to be resolved
} UNRESOLVED_IMPORT, *PUNRESOLVED_IMPORT;
typedef struct _SCYLLA_EXCHANGE {
BYTE status; //return a status, default 0xFF
DWORD_PTR imageBase; //image base
DWORD_PTR imageSize; //size of the image
DWORD_PTR numberOfUnresolvedImports; //number of unresolved imports in this structure
BYTE offsetUnresolvedImportsArray;
} SCYLLA_EXCHANGE, *PSCYLLA_EXCHANGE;
class DllInjectionPlugin : public DllInjection {
public:
static const WCHAR * FILE_MAPPING_NAME;
static HANDLE hProcess;
ApiReader * apiReader;
HANDLE hMapFile;
LPVOID lpViewOfFile;
DllInjectionPlugin()
{
hMapFile = 0;
lpViewOfFile = 0;
apiReader = 0;
}
~DllInjectionPlugin()
{
closeAllHandles();
}
void injectPlugin(Plugin & plugin, std::map<DWORD_PTR, ImportModuleThunk> & moduleList, DWORD_PTR imageBase, DWORD_PTR imageSize);
void injectImprecPlugin(Plugin & plugin, std::map<DWORD_PTR, ImportModuleThunk> & moduleList, DWORD_PTR imageBase, DWORD_PTR imageSize);
private:
bool createFileMapping(DWORD mappingSize);
void closeAllHandles();
DWORD_PTR getNumberOfUnresolvedImports( std::map<DWORD_PTR, ImportModuleThunk> & moduleList );
void addUnresolvedImports( PUNRESOLVED_IMPORT firstUnresImp, std::map<DWORD_PTR, ImportModuleThunk> & moduleList );
void handlePluginResults( PSCYLLA_EXCHANGE scyllaExchange, std::map<DWORD_PTR, ImportModuleThunk> & moduleList );
void updateImportsWithPluginResult( PUNRESOLVED_IMPORT firstUnresImp, std::map<DWORD_PTR, ImportModuleThunk> & moduleList );
-};
\ No newline at end of file
+};
diff --git a/Scylla/IATSearch.h b/Scylla/IATSearch.h
index 781eaba..633527e 100644
--- a/Scylla/IATSearch.h
+++ b/Scylla/IATSearch.h
@@ -1,29 +1,29 @@
#pragma once
#include "ApiReader.h"
-
-class IATSearch : protected ApiReader {
+class IATSearch : protected ApiReader
+{
public:
DWORD_PTR memoryAddress;
SIZE_T memorySize;
bool searchImportAddressTableInProcess(DWORD_PTR startAddress, DWORD_PTR* addressIAT, DWORD* sizeIAT);
private:
DWORD_PTR findAPIAddressInIAT(DWORD_PTR startAddress);
DWORD_PTR findNextFunctionAddress();
DWORD_PTR findIATPointer();
//DWORD_PTR findAddressFromWORDString(char * stringBuffer);
//DWORD_PTR findAddressFromNormalCALLString(char * stringBuffer);
bool isIATPointerValid(DWORD_PTR iatPointer);
bool findIATStartAndSize(DWORD_PTR address, DWORD_PTR * addressIAT, DWORD * sizeIAT);
DWORD_PTR findIATStartAddress( DWORD_PTR baseAddress, DWORD_PTR startAddress, BYTE * dataBuffer );
DWORD findIATSize( DWORD_PTR baseAddress, DWORD_PTR iatAddress, BYTE * dataBuffer, DWORD bufferSize );
bool isAddressAccessable(DWORD_PTR address);
-};
\ No newline at end of file
+};
diff --git a/Scylla/ImportRebuild.cpp b/Scylla/ImportRebuild.cpp
index 38c56ff..03111e6 100644
--- a/Scylla/ImportRebuild.cpp
+++ b/Scylla/ImportRebuild.cpp
@@ -1,715 +1,713 @@
#include "ImportRebuild.h"
#include "Scylla.h"
-//#include "ConfigurationHolder.h"
+#include "StringConversion.h"
//#define DEBUG_COMMENTS
ImportRebuild::ImportRebuild()
{
imageData = NULL;
sizeOfFile = 0;
pDosStub = NULL;
pOverlay = NULL;
sizeOfOverlay = 0;
pImportDescriptor = NULL;
pThunkData = NULL;
pImportByName = NULL;
numberOfImportDescriptors = 0;
sizeOfImportSection = 0;
sizeOfApiAndModuleNames = 0;
importSectionIndex = 0;
}
ImportRebuild::~ImportRebuild()
{
delete [] pDosStub;
delete [] imageData;
for (size_t i = 0; i < vecSectionData.size(); i++)
{
delete [] vecSectionData[i];
}
delete [] pOverlay;
}
bool ImportRebuild::splitTargetFile()
{
PIMAGE_SECTION_HEADER pSecHeader = 0;
BYTE * data = 0;
DWORD alignment = 0;
DosHeader = *(IMAGE_DOS_HEADER*)imageData;
if (DosHeader.e_magic != IMAGE_DOS_SIGNATURE)
{
return false;
}
NTHeader = *(IMAGE_NT_HEADERS*)(imageData + DosHeader.e_lfanew);
if (NTHeader.Signature != IMAGE_NT_SIGNATURE)
{
return false;
}
if (DosHeader.e_lfanew > sizeof(IMAGE_DOS_HEADER))
{
size_t sizeOfStub = DosHeader.e_lfanew - sizeof(IMAGE_DOS_HEADER);
pDosStub = new BYTE[sizeOfStub];
CopyMemory(pDosStub, imageData + sizeof(IMAGE_DOS_HEADER), sizeOfStub);
}
pSecHeader = IMAGE_FIRST_SECTION((IMAGE_NT_HEADERS*)(imageData + DosHeader.e_lfanew));
for (WORD i = 0; i < NTHeader.FileHeader.NumberOfSections; i++)
{
const DWORD SECTION_SIZE_MAX = 300000000;
DWORD sizeOfSection = pSecHeader->SizeOfRawData;
if (sizeOfSection > SECTION_SIZE_MAX)
{
sizeOfSection = SECTION_SIZE_MAX;
}
//TODO better use section alignment because it is better?
alignment = alignValue(sizeOfSection, NTHeader.OptionalHeader.SectionAlignment);
data = new BYTE[alignment];
ZeroMemory(data, alignment);
CopyMemory(data, imageData + pSecHeader->PointerToRawData, sizeOfSection);
vecSectionData.push_back(data);
vecSectionHeaders.push_back(*pSecHeader);
pSecHeader++;
}
if(NTHeader.FileHeader.NumberOfSections > 0) // ??
{
const IMAGE_SECTION_HEADER* pLastSec = &(*vecSectionHeaders.rbegin());
DWORD calcSize = pLastSec->PointerToRawData + pLastSec->SizeOfRawData;
if (calcSize < sizeOfFile)
{
sizeOfOverlay = sizeOfFile - calcSize;
pOverlay = new BYTE[sizeOfOverlay];
memcpy(pOverlay, imageData + calcSize, sizeOfOverlay);
}
}
delete [] imageData;
imageData = 0;
return true;
}
bool ImportRebuild::alignSectionHeaders()
{
for (WORD i = 0; i < vecSectionHeaders.size(); i++)
{
vecSectionHeaders[i].VirtualAddress = alignValue(vecSectionHeaders[i].VirtualAddress, NTHeader.OptionalHeader.SectionAlignment);
vecSectionHeaders[i].Misc.VirtualSize = alignValue(vecSectionHeaders[i].Misc.VirtualSize, NTHeader.OptionalHeader.SectionAlignment);
vecSectionHeaders[i].PointerToRawData = alignValue(vecSectionHeaders[i].PointerToRawData, NTHeader.OptionalHeader.FileAlignment);
vecSectionHeaders[i].SizeOfRawData = alignValue(vecSectionHeaders[i].SizeOfRawData, NTHeader.OptionalHeader.FileAlignment);
}
return true;
}
bool ImportRebuild::saveNewFile(const WCHAR * filepath)
{
DWORD fileOffset = 0;
DWORD dwWriteSize = 0;
size_t i = 0;
if (vecSectionHeaders.size() != vecSectionData.size())
{
return false;
}
HANDLE hFile = CreateFile(filepath, GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, 0,CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if(hFile == INVALID_HANDLE_VALUE)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"saveNewFile :: INVALID_HANDLE_VALUE %u", GetLastError());
#endif
return false;
}
//alignSectionHeaders();
updatePeHeader();
fileOffset = 0;
dwWriteSize = sizeof(IMAGE_DOS_HEADER);
ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, dwWriteSize, &DosHeader);
fileOffset += dwWriteSize;
dwWriteSize = DosHeader.e_lfanew - sizeof(IMAGE_DOS_HEADER);
ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, dwWriteSize, pDosStub);
fileOffset += dwWriteSize;
dwWriteSize = sizeof(IMAGE_NT_HEADERS);
ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, dwWriteSize, &NTHeader);
fileOffset += dwWriteSize;
dwWriteSize = sizeof(IMAGE_SECTION_HEADER);
for (i = 0; i < vecSectionHeaders.size(); i++)
{
if (!ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, dwWriteSize, &vecSectionHeaders[i]))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"saveNewFile :: writeMemoryToFile failed offset %X size %X", fileOffset, dwWriteSize);
#endif
CloseHandle(hFile);
return false;
}
fileOffset += dwWriteSize;
}
for (i = 0; i < vecSectionHeaders.size(); i++)
{
dwWriteSize = vecSectionHeaders[i].PointerToRawData - fileOffset;
if (dwWriteSize)
{
if (!writeZeroMemoryToFile(hFile, fileOffset, dwWriteSize))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"saveNewFile :: writeZeroMemoryToFile failed offset %X size %X", fileOffset, dwWriteSize);
#endif
CloseHandle(hFile);
return false;
}
fileOffset += dwWriteSize;
}
dwWriteSize = vecSectionHeaders[i].SizeOfRawData;
ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, dwWriteSize, vecSectionData[i]);
fileOffset += dwWriteSize;
}
if(pOverlay)
{
ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, sizeOfOverlay, pOverlay);
fileOffset += sizeOfOverlay;
}
CloseHandle(hFile);
return true;
}
bool ImportRebuild::writeZeroMemoryToFile(HANDLE hFile, DWORD fileOffset, DWORD size)
{
bool retValue = false;
PVOID zeromemory = calloc(size, 1);
if (zeromemory)
{
retValue = ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, size, zeromemory);
free(zeromemory);
}
else
{
retValue = false;
}
return retValue;
}
bool ImportRebuild::addNewSection(char * sectionName, DWORD sectionSize, BYTE * sectionData)
{
BYTE * newBuffer = 0;
IMAGE_SECTION_HEADER pNewSection = {0};
size_t lastSectionIndex = vecSectionHeaders.size() - 1;
size_t nameLength = strlen(sectionName);
if (nameLength > IMAGE_SIZEOF_SHORT_NAME)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"addNewSection :: sectionname is too long %d", nameLength);
#endif
return false;
}
memcpy_s(pNewSection.Name, IMAGE_SIZEOF_SHORT_NAME, sectionName, nameLength);
pNewSection.SizeOfRawData = alignValue(sectionSize, NTHeader.OptionalHeader.FileAlignment);
pNewSection.Misc.VirtualSize = alignValue(sectionSize, NTHeader.OptionalHeader.SectionAlignment);
pNewSection.PointerToRawData = alignValue(vecSectionHeaders[lastSectionIndex].PointerToRawData + vecSectionHeaders[lastSectionIndex].SizeOfRawData, NTHeader.OptionalHeader.FileAlignment);
pNewSection.VirtualAddress = alignValue(vecSectionHeaders[lastSectionIndex].VirtualAddress + vecSectionHeaders[lastSectionIndex].Misc.VirtualSize, NTHeader.OptionalHeader.SectionAlignment);
pNewSection.Characteristics = IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE|IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA;
vecSectionHeaders.push_back(pNewSection);
if ( (sectionSize != pNewSection.SizeOfRawData) || (sectionData == 0) )
{
newBuffer = new BYTE[pNewSection.SizeOfRawData];
ZeroMemory(newBuffer, pNewSection.SizeOfRawData);
if (sectionData)
{
CopyMemory(newBuffer, sectionData, sectionSize);
}
}
else
{
newBuffer = sectionData;
}
vecSectionData.push_back(newBuffer);
return true;
}
bool ImportRebuild::loadTargetFile(const WCHAR * filepath)
{
HANDLE hTargetFile = INVALID_HANDLE_VALUE;
DWORD fileSize = 0;
bool retValue = false;
hTargetFile = CreateFile(filepath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if(hTargetFile == INVALID_HANDLE_VALUE)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"loadTargetFile :: INVALID_HANDLE_VALUE %u", GetLastError());
#endif
return false;
}
fileSize = (DWORD)ProcessAccessHelp::getFileSize(hTargetFile);
if (!fileSize)
{
CloseHandle(hTargetFile);
hTargetFile = 0;
return false;
}
imageData = new BYTE[fileSize];
if (!imageData)
{
retValue = false;
}
else
{
sizeOfFile = fileSize;
retValue = ProcessAccessHelp::readMemoryFromFile(hTargetFile, 0, fileSize, imageData);
}
CloseHandle(hTargetFile);
hTargetFile = 0;
return retValue;
}
DWORD ImportRebuild::alignValue(DWORD badValue, DWORD alignTo)
{
return (((badValue + alignTo - 1) / alignTo) * alignTo);
}
DWORD ImportRebuild::convertRVAToOffsetVector(DWORD dwRVA)
{
for (size_t i = 0; i < vecSectionHeaders.size(); i++)
{
if ((vecSectionHeaders[i].VirtualAddress <= dwRVA) && ((vecSectionHeaders[i].VirtualAddress + vecSectionHeaders[i].Misc.VirtualSize) > dwRVA))
{
return ((dwRVA - vecSectionHeaders[i].VirtualAddress) + vecSectionHeaders[i].PointerToRawData);
}
}
return 0;
}
/*
DWORD ImportRebuild::convertRVAToOffset(DWORD dwRVA)
{
PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(&NTHeader);
for (WORD i = 0; i < NTHeader.FileHeader.NumberOfSections; i++)
{
if ((pSectionHeader->VirtualAddress <= dwRVA) && ((pSectionHeader->VirtualAddress + pSectionHeader->Misc.VirtualSize) > dwRVA))
{
return ((dwRVA - pSectionHeader->VirtualAddress) + pSectionHeader->PointerToRawData);
}
pSectionHeader++;
}
return 0;
}
*/
DWORD_PTR ImportRebuild::convertOffsetToRVAVector(DWORD dwOffset)
{
for (size_t i = 0; i < vecSectionHeaders.size(); i++)
{
if ((vecSectionHeaders[i].PointerToRawData <= dwOffset) && ((vecSectionHeaders[i].PointerToRawData + vecSectionHeaders[i].SizeOfRawData) > dwOffset))
{
return ((dwOffset - vecSectionHeaders[i].PointerToRawData) + vecSectionHeaders[i].VirtualAddress);
}
}
return 0;
}
/*
DWORD ImportRebuild::convertOffsetToRVA(DWORD dwOffset)
{
PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(&NTHeader);
for (WORD i = 0; i < NTHeader.FileHeader.NumberOfSections; i++)
{
if ((pSectionHeader->PointerToRawData <= dwOffset) && ((pSectionHeader->PointerToRawData + pSectionHeader->SizeOfRawData) > dwOffset))
{
return ((dwOffset - pSectionHeader->PointerToRawData) + pSectionHeader->VirtualAddress);
}
pSectionHeader++;
}
return 0;
}
*/
void ImportRebuild::updatePeHeader()
{
size_t lastSectionIndex = vecSectionHeaders.size() - 1;
NTHeader.FileHeader.NumberOfSections = (WORD)(lastSectionIndex + 1);
NTHeader.OptionalHeader.SizeOfImage = vecSectionHeaders[lastSectionIndex].VirtualAddress + vecSectionHeaders[lastSectionIndex].Misc.VirtualSize;
NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0;
NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0;
if (NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress)
{
for (size_t i = 0; i < vecSectionHeaders.size(); i++)
{
if ((vecSectionHeaders[i].VirtualAddress <= NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress) && ((vecSectionHeaders[i].VirtualAddress + vecSectionHeaders[i].Misc.VirtualSize) > NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress))
{
//section must be read and writeable
vecSectionHeaders[i].Characteristics |= IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
}
}
NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = 0;
NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = 0;
}
NTHeader.OptionalHeader.NumberOfRvaAndSizes = 0x10;
NTHeader.OptionalHeader.SizeOfHeaders = alignValue(DosHeader.e_lfanew + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + NTHeader.FileHeader.SizeOfOptionalHeader + (NTHeader.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER)), NTHeader.OptionalHeader.FileAlignment);
}
bool ImportRebuild::buildNewImportTable(std::map<DWORD_PTR, ImportModuleThunk> & moduleList)
{
createNewImportSection(moduleList);
importSectionIndex = vecSectionHeaders.size() - 1;
DWORD dwSize = fillImportSection(moduleList);
if (!dwSize)
{
return false;
}
setFlagToIATSection((*moduleList.begin()).second.firstThunk);
NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = vecSectionHeaders[importSectionIndex].VirtualAddress;
NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = (DWORD)(numberOfImportDescriptors * sizeof(IMAGE_IMPORT_DESCRIPTOR));
return true;
}
bool ImportRebuild::createNewImportSection(std::map<DWORD_PTR, ImportModuleThunk> & moduleList)
{
char sectionName[9] = {0};
- size_t i = 0;
//DWORD sectionSize = calculateMinSize(moduleList);
calculateImportSizes(moduleList);
if (wcslen(Scylla::config[IAT_SECTION_NAME].getString()) > IMAGE_SIZEOF_SHORT_NAME)
{
strcpy_s(sectionName, sizeof(sectionName), ".SCY");
}
else
{
- wcstombs_s(&i, sectionName, sizeof(sectionName), Scylla::config[IAT_SECTION_NAME].getString(), _TRUNCATE);
+ StringConversion::ToASCII(Scylla::config[IAT_SECTION_NAME].getString(), sectionName, _countof(sectionName));
}
-
return addNewSection(sectionName, (DWORD)sizeOfImportSection, 0);
}
/*DWORD ImportRebuild::calculateMinSize(std::map<DWORD_PTR, ImportModuleThunk> & moduleList)
{
DWORD dwSize = 0;
std::map<DWORD_PTR, ImportModuleThunk>::iterator mapIt;
std::map<DWORD_PTR, ImportThunk>::iterator mapIt2;
dwSize = (DWORD)((moduleList.size() + 1) * sizeof(IMAGE_IMPORT_DESCRIPTOR)); //last is zero'ed
for ( mapIt = moduleList.begin() ; mapIt != moduleList.end(); mapIt++ )
{
//dwSize += (DWORD)((*mapIt).second.thunkList.size() + sizeof(IMAGE_IMPORT_BY_NAME));
dwSize += (DWORD)(wcslen((*mapIt).second.moduleName) + 1);
for ( mapIt2 = (*mapIt).second.thunkList.begin() ; mapIt2 != (*mapIt).second.thunkList.end(); mapIt2++ )
{
if((*mapIt2).second.name[0] != '\0')
{
dwSize += sizeof(IMAGE_IMPORT_BY_NAME);
dwSize += (DWORD)strlen((*mapIt2).second.name);
}
}
}
return dwSize;
}*/
BYTE * ImportRebuild::getMemoryPointerFromRVA(DWORD_PTR dwRVA)
{
DWORD_PTR offset = convertRVAToOffsetVector((DWORD)dwRVA);
for (size_t i = 0; i < vecSectionHeaders.size(); i++)
{
if ((vecSectionHeaders[i].PointerToRawData <= offset) && ((vecSectionHeaders[i].PointerToRawData + vecSectionHeaders[i].SizeOfRawData) > offset))
{
return (BYTE *)((DWORD_PTR)vecSectionData[i] + (offset - vecSectionHeaders[i].PointerToRawData));
}
}
return 0;
}
DWORD ImportRebuild::fillImportSection( std::map<DWORD_PTR, ImportModuleThunk> & moduleList )
{
std::map<DWORD_PTR, ImportModuleThunk>::iterator mapIt;
std::map<DWORD_PTR, ImportThunk>::iterator mapIt2;
PIMAGE_IMPORT_DESCRIPTOR pImportDesc = 0;
PIMAGE_IMPORT_BY_NAME pImportByName = 0;
PIMAGE_THUNK_DATA pThunk = 0;
ImportModuleThunk * importModuleThunk = 0;
ImportThunk * importThunk = 0;
size_t stringLength = 0;
DWORD_PTR lastRVA = 0;
BYTE * sectionData = vecSectionData[importSectionIndex];
DWORD offset = 0;
pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)(sectionData);
//skip the IMAGE_IMPORT_DESCRIPTOR
offset += (DWORD)(numberOfImportDescriptors * sizeof(IMAGE_IMPORT_DESCRIPTOR));
for ( mapIt = moduleList.begin() ; mapIt != moduleList.end(); mapIt++ )
{
importModuleThunk = &((*mapIt).second);
stringLength = addImportDescriptor(importModuleThunk, offset);
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"fillImportSection :: importDesc.Name %X", pImportDescriptor->Name);
#endif
offset += (DWORD)stringLength; //stringLength has null termination char
pImportByName = (PIMAGE_IMPORT_BY_NAME)((DWORD_PTR)sectionData + offset);
//pThunk = (PIMAGE_THUNK_DATA)(getMemoryPointerFromRVA(importModuleThunk->firstThunk));
lastRVA = importModuleThunk->firstThunk - sizeof(DWORD_PTR);
for ( mapIt2 = (*mapIt).second.thunkList.begin() ; mapIt2 != (*mapIt).second.thunkList.end(); mapIt2++ )
{
importThunk = &((*mapIt2).second);
pThunk = (PIMAGE_THUNK_DATA)(getMemoryPointerFromRVA(importThunk->rva));
//check wrong iat pointer
if (!pThunk)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"fillImportSection :: Failed to get pThunk RVA: %X", importThunk->rva);
#endif
return 0;
}
if ((lastRVA + sizeof(DWORD_PTR)) != importThunk->rva)
{
//add additional import desc
addSpecialImportDescriptor(importThunk->rva);
}
lastRVA = importThunk->rva;
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"fillImportSection :: importThunk %X pThunk %X pImportByName %X offset %X", importThunk,pThunk,pImportByName,offset);
#endif
stringLength = addImportToImportTable(importThunk, pThunk, pImportByName, offset);
offset += (DWORD)stringLength; //is 0 bei import by ordinal
pImportByName = (PIMAGE_IMPORT_BY_NAME)((DWORD_PTR)pImportByName + stringLength);
}
pImportDescriptor++;
}
return offset;
}
bool ImportRebuild::rebuildImportTable(const WCHAR * targetFilePath, const WCHAR * newFilePath, std::map<DWORD_PTR, ImportModuleThunk> & moduleList)
{
bool retValue = false;
if (loadTargetFile(targetFilePath))
{
splitTargetFile();
retValue = buildNewImportTable(moduleList);
if (retValue)
{
retValue = saveNewFile(newFilePath);
}
return retValue;
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"rebuildImportTable ::Failed to load target %s", targetFilePath);
#endif
return false;
}
}
void ImportRebuild::setFlagToIATSection(DWORD_PTR iatAddress)
{
for (size_t i = 0; i < vecSectionHeaders.size(); i++)
{
if ((vecSectionHeaders[i].VirtualAddress <= iatAddress) && ((vecSectionHeaders[i].VirtualAddress + vecSectionHeaders[i].Misc.VirtualSize) > iatAddress))
{
//section must be read and writeable
vecSectionHeaders[i].Characteristics |= IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
}
}
}
size_t ImportRebuild::addImportToImportTable( ImportThunk * pImport, PIMAGE_THUNK_DATA pThunk, PIMAGE_IMPORT_BY_NAME pImportByName, DWORD sectionOffset)
{
size_t stringLength = 0;
if(pImport->name[0] == '\0')
{
pThunk->u1.AddressOfData = (IMAGE_ORDINAL(pImport->ordinal) | IMAGE_ORDINAL_FLAG);
}
else
{
pImportByName->Hint = pImport->hint;
stringLength = strlen(pImport->name) + 1;
memcpy(pImportByName->Name, pImport->name, stringLength);
pThunk->u1.AddressOfData = convertOffsetToRVAVector(vecSectionHeaders[importSectionIndex].PointerToRawData + sectionOffset);
if (!pThunk->u1.AddressOfData)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"addImportToImportTable :: failed to get AddressOfData %X %X", vecSectionHeaders[importSectionIndex].PointerToRawData, sectionOffset);
#endif
}
//next import should be nulled
pThunk++;
pThunk->u1.AddressOfData = 0;
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"addImportToImportTable :: pThunk->u1.AddressOfData %X %X %X", pThunk->u1.AddressOfData, pThunk, vecSectionHeaders[importSectionIndex].PointerToRawData + sectionOffset);
#endif
stringLength += sizeof(WORD);
}
return stringLength;
}
size_t ImportRebuild::addImportDescriptor(ImportModuleThunk * pImportModule, DWORD sectionOffset)
{
char dllName[MAX_PATH];
- size_t stringLength = 0;
- wcstombs_s(&stringLength, dllName, (size_t)_countof(dllName), pImportModule->moduleName, (size_t)_countof(pImportModule->moduleName));
+ StringConversion::ToASCII(pImportModule->moduleName, dllName, _countof(dllName));
+ size_t stringLength = strlen(dllName);
memcpy((vecSectionData[importSectionIndex] + sectionOffset), dllName, stringLength); //copy module name to section
pImportDescriptor->FirstThunk = (DWORD)pImportModule->firstThunk;
pImportDescriptor->Name = (DWORD)convertOffsetToRVAVector(vecSectionHeaders[importSectionIndex].PointerToRawData + sectionOffset);
return stringLength;
}
void ImportRebuild::addSpecialImportDescriptor(DWORD_PTR rvaFirstThunk)
{
PIMAGE_IMPORT_DESCRIPTOR oldID = pImportDescriptor;
pImportDescriptor++;
pImportDescriptor->FirstThunk = (DWORD)rvaFirstThunk;
pImportDescriptor->Name = oldID->Name;
}
void ImportRebuild::calculateImportSizes(std::map<DWORD_PTR, ImportModuleThunk> & moduleList)
{
std::map<DWORD_PTR, ImportModuleThunk>::iterator mapIt;
std::map<DWORD_PTR, ImportThunk>::iterator mapIt2;
DWORD_PTR lastRVA = 0;
numberOfImportDescriptors = 0;
sizeOfImportSection = 0;
sizeOfApiAndModuleNames = 0;
numberOfImportDescriptors = moduleList.size() + 1; //last is zero'd
for ( mapIt = moduleList.begin() ; mapIt != moduleList.end(); mapIt++ )
{
lastRVA = (*mapIt).second.firstThunk - sizeof(DWORD_PTR);
sizeOfApiAndModuleNames += (DWORD)(wcslen((*mapIt).second.moduleName) + 1);
for ( mapIt2 = (*mapIt).second.thunkList.begin() ; mapIt2 != (*mapIt).second.thunkList.end(); mapIt2++ )
{
if ((lastRVA + sizeof(DWORD_PTR)) != (*mapIt2).second.rva)
{
numberOfImportDescriptors++; //add additional import desc
}
if((*mapIt2).second.name[0] != '\0')
{
sizeOfApiAndModuleNames += sizeof(WORD); //Hint from IMAGE_IMPORT_BY_NAME
sizeOfApiAndModuleNames += (DWORD)(strlen((*mapIt2).second.name) + 1);
}
lastRVA = (*mapIt2).second.rva;
}
}
sizeOfImportSection = sizeOfApiAndModuleNames + (numberOfImportDescriptors * sizeof(IMAGE_IMPORT_DESCRIPTOR));
}
\ No newline at end of file
diff --git a/Scylla/ImportRebuild.h b/Scylla/ImportRebuild.h
index f4fff23..27bad7f 100644
--- a/Scylla/ImportRebuild.h
+++ b/Scylla/ImportRebuild.h
@@ -1,71 +1,73 @@
#pragma once
+#include <map>
#include "ProcessAccessHelp.h"
#include "Thunks.h"
-class ImportRebuild {
+class ImportRebuild
+{
public:
ImportRebuild();
~ImportRebuild();
bool rebuildImportTable(const WCHAR * targetFilePath, const WCHAR * newFilePath, std::map<DWORD_PTR, ImportModuleThunk> & moduleList);
//DWORD convertRVAToOffset(DWORD dwRVA);
//DWORD convertOffsetToRVA(DWORD dwOffset);
bool addNewSection(char * sectionName, DWORD sectionSize, BYTE * sectionData);
bool writeZeroMemoryToFile(HANDLE hFile, DWORD fileOffset, DWORD size);
private:
std::vector<IMAGE_SECTION_HEADER> vecSectionHeaders;
std::vector<BYTE *> vecSectionData;
BYTE * imageData;
size_t sizeOfFile;
BYTE * pDosStub;
IMAGE_DOS_HEADER DosHeader;
IMAGE_NT_HEADERS NTHeader;
BYTE * pOverlay;
size_t sizeOfOverlay;
PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor;
PIMAGE_THUNK_DATA pThunkData;
PIMAGE_IMPORT_BY_NAME pImportByName;
size_t numberOfImportDescriptors;
size_t sizeOfImportSection;
size_t sizeOfApiAndModuleNames;
size_t importSectionIndex;
DWORD getOffsetLastSection();
void updatePeHeader();
DWORD fillImportSection( std::map<DWORD_PTR, ImportModuleThunk> & moduleList );
bool splitTargetFile();
DWORD convertRVAToOffsetVector(DWORD dwRVA);
DWORD_PTR convertOffsetToRVAVector(DWORD dwOffset);
BYTE * getMemoryPointerFromRVA(DWORD_PTR dwRVA);
DWORD alignValue(DWORD badValue, DWORD alignTo);
bool alignSectionHeaders();
bool saveNewFile(const WCHAR * filepath);
bool loadTargetFile(const WCHAR * filepath);
bool createNewImportSection(std::map<DWORD_PTR, ImportModuleThunk> & moduleList);
bool buildNewImportTable(std::map<DWORD_PTR, ImportModuleThunk> & moduleList);
void setFlagToIATSection( DWORD_PTR iatAddress );
size_t addImportToImportTable( ImportThunk * pImport, PIMAGE_THUNK_DATA pThunk, PIMAGE_IMPORT_BY_NAME pImportByName, DWORD sectionOffset);
size_t addImportDescriptor(ImportModuleThunk * pImportModule, DWORD sectionOffset);
void calculateImportSizes(std::map<DWORD_PTR, ImportModuleThunk> & moduleList);
void addSpecialImportDescriptor(DWORD_PTR rvaFirstThunk);
};
\ No newline at end of file
diff --git a/Scylla/MainGui.h b/Scylla/MainGui.h
index 592ba90..abc758e 100644
--- a/Scylla/MainGui.h
+++ b/Scylla/MainGui.h
@@ -1,301 +1,295 @@
#pragma once
#include <windows.h>
#include "resource.h"
// WTL
#include <atlbase.h> // base ATL classes
#include <atlapp.h> // base WTL classes
#include <atlwin.h> // ATL GUI classes
#include <atlframe.h> // WTL window frame helpers
#include <atlmisc.h> // WTL utility classes
#include <atlcrack.h> // WTL enhanced msg map macros
#include <atlctrls.h> // WTL controls
#include <atlddx.h> // WTL dialog data exchange
#include "multitree.h"
#include "hexedit.h"
-//#define _CRTDBG_MAP_ALLOC
-//#include <cstdlib>
-//#include <crtdbg.h>
-
-//#include <cstdio>
-
#include "Logger.h"
#include "ProcessLister.h"
#include "IATSearch.h"
#include "PickDllGui.h"
#include "ImportsHandling.h"
class MainGui : public CDialogImpl<MainGui>, public CWinDataExchange<MainGui>, public CDialogResize<MainGui>, public CMessageFilter
{
public:
enum { IDD = IDD_DLG_MAIN };
// Dialog Data eXchange, attaches/subclasses child controls to wrappers
// DDX_CONTROL : subclass
// DDX_CONTROL_HANDLE : attach
BEGIN_DDX_MAP(MainGui)
DDX_CONTROL(IDC_TREE_IMPORTS, TreeImportsSubclass) // needed for message reflection
DDX_CONTROL(IDC_TREE_IMPORTS, TreeImports)
DDX_CONTROL_HANDLE(IDC_CBO_PROCESSLIST, ComboProcessList)
DDX_CONTROL_HANDLE(IDC_LIST_LOG, ListLog)
DDX_CONTROL(IDC_EDIT_OEPADDRESS, EditOEPAddress)
DDX_CONTROL(IDC_EDIT_IATADDRESS, EditIATAddress)
DDX_CONTROL(IDC_EDIT_IATSIZE, EditIATSize)
END_DDX_MAP()
// Our message map
// Messages are passed from top to bottom
// The first handler that doesn't call SetMsgHandled(FALSE) aborts the chain
// If none signals the message as handled, it will be passed to mixins (CHAIN_MSG_MAP)
// or ultimately passed to DefWindowProc
BEGIN_MSG_MAP_EX(MainGui)
MSG_WM_INITDIALOG(OnInitDialog)
MSG_WM_DESTROY(OnDestroy)
MSG_WM_SIZE(OnSize)
MSG_WM_CONTEXTMENU(OnContextMenu)
MSG_WM_COMMAND(OnCommand)
NOTIFY_HANDLER_EX(IDC_TREE_IMPORTS, NM_DBLCLK, OnTreeImportsDoubleClick)
NOTIFY_HANDLER_EX(IDC_TREE_IMPORTS, TVN_KEYDOWN, OnTreeImportsKeyDown)
COMMAND_HANDLER_EX(IDC_CBO_PROCESSLIST, CBN_DROPDOWN, OnProcessListDrop)
COMMAND_HANDLER_EX(IDC_CBO_PROCESSLIST, CBN_SELENDOK, OnProcessListSelected)
COMMAND_ID_HANDLER_EX(IDC_BTN_PICKDLL, OnPickDLL)
COMMAND_ID_HANDLER_EX(IDC_BTN_OPTIONS, OnOptions)
COMMAND_ID_HANDLER_EX(IDC_BTN_DUMP, OnDump)
COMMAND_ID_HANDLER_EX(IDC_BTN_FIXDUMP, OnFixDump)
COMMAND_ID_HANDLER_EX(IDC_BTN_PEREBUILD, OnPERebuild)
COMMAND_ID_HANDLER_EX(IDC_BTN_IATAUTOSEARCH, OnIATAutoSearch)
COMMAND_ID_HANDLER_EX(IDC_BTN_GETIMPORTS, OnGetImports)
COMMAND_ID_HANDLER_EX(IDC_BTN_INVALIDIMPORTS, OnInvalidImports)
COMMAND_ID_HANDLER_EX(IDC_BTN_SUSPECTIMPORTS, OnSuspectImports)
COMMAND_ID_HANDLER_EX(IDC_BTN_CLEARIMPORTS, OnClearImports)
COMMAND_ID_HANDLER_EX(ID_FILE_DUMP, OnDump)
COMMAND_ID_HANDLER_EX(ID_FILE_PEREBUILD, OnPERebuild)
COMMAND_ID_HANDLER_EX(ID_FILE_FIXDUMP, OnFixDump)
COMMAND_ID_HANDLER_EX(ID_FILE_EXIT, OnExit)
COMMAND_ID_HANDLER_EX(ID_IMPORTS_SHOWINVALID, OnInvalidImports)
COMMAND_ID_HANDLER_EX(ID_IMPORTS_SHOWSUSPECT, OnSuspectImports)
COMMAND_ID_HANDLER_EX(ID_IMPORTS_INVALIDATESELECTED, OnInvalidateSelected)
COMMAND_ID_HANDLER_EX(ID_IMPORTS_CUTSELECTED, OnCutSelected)
COMMAND_ID_HANDLER_EX(ID_IMPORTS_CLEARIMPORTS, OnClearImports)
COMMAND_ID_HANDLER_EX(ID_IMPORTS_SAVETREE, OnSaveTree)
COMMAND_ID_HANDLER_EX(ID_IMPORTS_LOADTREE, OnLoadTree)
COMMAND_ID_HANDLER_EX(ID_TRACE_AUTOTRACE, OnAutotrace)
COMMAND_ID_HANDLER_EX(ID_MISC_DLLINJECTION, OnDLLInject)
COMMAND_ID_HANDLER_EX(ID_MISC_OPTIONS, OnOptions)
COMMAND_ID_HANDLER_EX(ID_HELP_ABOUT, OnAbout)
COMMAND_ID_HANDLER_EX(IDCANCEL, OnExit)
REFLECT_NOTIFY_ID(IDC_TREE_IMPORTS) // pass WM_NOTIFY to child control
CHAIN_MSG_MAP(CDialogResize<MainGui>)
// Message map for subclassed treeview
// CContainedWindow forwards all messages to this map
ALT_MSG_MAP(IDC_TREE_IMPORTS)
MSG_WM_GETDLGCODE(OnTreeImportsSubclassGetDlgCode)
MSG_WM_CHAR(OnTreeImportsSubclassChar)
END_MSG_MAP()
// Dialog resize 'table'
// States if child controls move or resize or center in a specific direction
// when the parent dialog is resized
BEGIN_DLGRESIZE_MAP(MainGui)
DLGRESIZE_CONTROL(IDC_GROUP_ATTACH, DLSZ_SIZE_X)
DLGRESIZE_CONTROL(IDC_CBO_PROCESSLIST, DLSZ_SIZE_X)
DLGRESIZE_CONTROL(IDC_BTN_PICKDLL, DLSZ_MOVE_X)
DLGRESIZE_CONTROL(IDC_GROUP_IMPORTS, DLSZ_SIZE_X | DLSZ_SIZE_Y)
DLGRESIZE_CONTROL(IDC_TREE_IMPORTS, DLSZ_SIZE_X | DLSZ_SIZE_Y)
DLGRESIZE_CONTROL(IDC_BTN_INVALIDIMPORTS, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_BTN_SUSPECTIMPORTS, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_BTN_CLEARIMPORTS, DLSZ_MOVE_X | DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_GROUP_IATINFO, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_STATIC_OEPADDRESS, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_STATIC_IATADDRESS, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_STATIC_IATSIZE, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_EDIT_OEPADDRESS, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_EDIT_IATADDRESS, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_EDIT_IATSIZE, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_BTN_IATAUTOSEARCH, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_BTN_GETIMPORTS, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_GROUP_ACTIONS, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_BTN_AUTOTRACE, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_GROUP_DUMP, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_BTN_DUMP, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_BTN_PEREBUILD, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_BTN_FIXDUMP, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_GROUP_LOG, DLSZ_MOVE_Y | DLSZ_SIZE_X)
DLGRESIZE_CONTROL(IDC_LIST_LOG, DLSZ_MOVE_Y | DLSZ_SIZE_X)
END_DLGRESIZE_MAP()
MainGui();
//void addTextToOutputLog(const WCHAR * text);
//CWindow getLogListboxHandle() const { return ListLog; }
protected:
// Variables
WCHAR stringBuffer[600];
ImportsHandling importsHandling;
//ProcessAccessHelp processAccessHelp;
ApiReader apiReader;
Process * selectedProcess;
// File selection filters
static const WCHAR filterExe[];
static const WCHAR filterDll[];
static const WCHAR filterExeDll[];
static const WCHAR filterTxt[];
static const WCHAR filterXml[];
// Controls
CMultiSelectTreeViewCtrl TreeImports;
CComboBox ComboProcessList;
CHexEdit<DWORD_PTR> EditOEPAddress;
CHexEdit<DWORD_PTR> EditIATAddress;
CHexEdit<DWORD> EditIATSize;
CListBox ListLog;
CStatusBarCtrl StatusBar;
enum StatusParts {
PART_COUNT = 0,
PART_INVALID,
PART_IMAGEBASE,
PART_MODULE
};
CContainedWindow TreeImportsSubclass;
// Handles
CIcon hIcon;
CMenu hMenuImports;
CMenu hMenuLog;
CAccelerator accelerators;
CIcon hIconCheck;
CIcon hIconWarning;
CIcon hIconError;
static const int MenuImportsOffsetTrace = 2;
static const int MenuImportsTraceOffsetScylla = 2;
static const int MenuImportsTraceOffsetImpRec = 4;
static const int PLUGIN_MENU_BASE_ID = 0x10;
protected:
virtual BOOL PreTranslateMessage(MSG* pMsg);
// Message handlers
BOOL OnInitDialog(CWindow wndFocus, LPARAM lInitParam);
void OnDestroy();
void OnSize(UINT nType, CSize size);
void OnContextMenu(CWindow wnd, CPoint point);
void OnCommand(UINT uNotifyCode, int nID, CWindow wndCtl);
// WM_NOTIFY handlers
LRESULT OnTreeImportsDoubleClick(const NMHDR* pnmh);
LRESULT OnTreeImportsKeyDown(const NMHDR* pnmh);
// Forwarded messages from subclassed treeview
UINT OnTreeImportsSubclassGetDlgCode(const MSG * lpMsg);
void OnTreeImportsSubclassChar(UINT nChar, UINT nRepCnt, UINT nFlags);
// WM_COMMAND handlers
void OnProcessListDrop(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnProcessListSelected(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnPickDLL(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnOptions(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnDump(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnFixDump(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnPERebuild(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnDLLInject(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnIATAutoSearch(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnGetImports(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnInvalidImports(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnSuspectImports(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnClearImports(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnInvalidateSelected(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnCutSelected(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnSaveTree(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnLoadTree(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnAutotrace(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnExit(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnAbout(UINT uNotifyCode, int nID, CWindow wndCtl);
// GUI functions
bool showFileDialog(WCHAR * selectedFile, bool save, const WCHAR * defFileName, const WCHAR * filter = NULL, const WCHAR * defExtension = NULL, const WCHAR * directory = NULL);
void setupStatusBar();
void updateStatusBar();
void fillProcessListComboBox(CComboBox& hCombo);
void setIconAndDialogCaption();
void enableDialogControls(BOOL value);
CTreeItem findTreeItem(CPoint pt, bool screenCoordinates);
// Actions
void pickDllActionHandler();
void pickApiActionHandler(CTreeItem item);
void processSelectedActionHandler(int index);
void showInvalidImportsActionHandler();
void showSuspectImportsActionHandler();
void deleteSelectedImportsActionHandler();
void invalidateSelectedImportsActionHandler();
void loadTreeActionHandler();
void saveTreeActionHandler();
void iatAutosearchActionHandler();
void getImportsActionHandler();
void dumpActionHandler();
void peRebuildActionHandler();
void startDisassemblerGui(CTreeItem selectedTreeNode);
void dumpFixActionHandler();
void showAboutDialog();
void dllInjectActionHandler();
void optionsActionHandler();
void clearImportsActionHandler();
void pluginActionHandler(int menuItem);
// Popup menu functions
void SetupImportsMenuItems(CTreeItem item);
void appendPluginListToMenu(CMenuHandle hMenuTrackPopup);
void DisplayContextMenuImports(CWindow, CPoint);
void DisplayContextMenuLog(CWindow, CPoint);
// Log
void clearOutputLog();
bool saveLogToFile(const WCHAR * file);
// Misc
bool getCurrentModulePath(TCHAR * buffer, size_t bufferSize);
};
diff --git a/Scylla/PeDump.h b/Scylla/PeDump.h
index 6f0bcfd..6f7785e 100644
--- a/Scylla/PeDump.h
+++ b/Scylla/PeDump.h
@@ -1,63 +1,67 @@
+#pragma once
#include <windows.h>
-class PeDump {
+class PeDump
+{
public:
+
DWORD_PTR entryPoint; //VA
DWORD_PTR imageBase; //VA
DWORD sizeOfImage;
WCHAR fullpath[MAX_PATH];
//Settings
static bool useHeaderFromDisk;
static bool appendOverlayData;
PeDump()
{
imageBase = 0;
sizeOfImage = 0;
dumpData = 0;
headerData = 0;
pNTHeader = 0;
pDOSHeader = 0;
pSectionHeader = 0;
}
~PeDump()
{
if (dumpData != 0)
{
delete [] dumpData;
}
if (headerData != 0)
{
delete [] headerData;
}
}
bool dumpCompleteProcessToDisk(const WCHAR * dumpFilePath);
bool saveDumpToDisk(const WCHAR * dumpFilePath, BYTE *dumpBuffer, DWORD dumpSize);
bool copyFileDataFromOffset(const WCHAR * sourceFile, const WCHAR * destFile, DWORD_PTR fileOffset, DWORD dwSize);
bool appendOverlayDataToDump(const WCHAR * dumpFilePath);
bool getOverlayData(const WCHAR * filepath, DWORD_PTR * overlayFileOffset, DWORD * overlaySize);
private:
+
BYTE * dumpData;
BYTE * headerData;
PIMAGE_DOS_HEADER pDOSHeader;
PIMAGE_NT_HEADERS pNTHeader;
PIMAGE_SECTION_HEADER pSectionHeader;
bool validateHeaders();
bool fillPeHeaderStructs(bool fromDisk);
void fixDump(BYTE * dumpBuffer);
void fixBadNtHeaderValues(PIMAGE_NT_HEADERS pNtHead);
void fixSectionHeaderForDump(PIMAGE_SECTION_HEADER oldSecHead, PIMAGE_SECTION_HEADER newSecHead);
void fixNtHeaderForDump(PIMAGE_NT_HEADERS oldNtHead, PIMAGE_NT_HEADERS newNtHead);
-};
\ No newline at end of file
+};
diff --git a/Scylla/PeRebuild.cpp b/Scylla/PeRebuild.cpp
index 0d50ec6..a8ea49a 100644
--- a/Scylla/PeRebuild.cpp
+++ b/Scylla/PeRebuild.cpp
@@ -1,736 +1,732 @@
#include "PeRebuild.h"
#include <imagehlp.h>
-#pragma comment(lib,"imagehlp.lib")
-
#include "ProcessAccessHelp.h"
-
#include "Scylla.h"
-//#include "ConfigurationHolder.h"
//#define DEBUG_COMMENTS
bool PeRebuild::truncateFile(WCHAR * szFilePath, DWORD dwNewFsize)
{
bool retValue = true;
HANDLE hFile = CreateFile(szFilePath,GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (hFile == INVALID_HANDLE_VALUE)
{
return false;
}
if (SetFilePointer(hFile, dwNewFsize, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
{
if (GetLastError() == NO_ERROR)
{
retValue = true;
}
else
{
retValue = false;
}
}
else
{
retValue = true;
}
if (!SetEndOfFile(hFile))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"SetEndOfFile failed error %d", GetLastError());
#endif
retValue = false;
}
CloseHandle(hFile);
return retValue;
}
DWORD PeRebuild::validAlignment(DWORD BadSize)
{
div_t DivRes;
DivRes = div(BadSize, FileAlignmentConstant);
if (DivRes.rem == 0)
return BadSize;
return ((DivRes.quot+1) * FileAlignmentConstant);
}
DWORD PeRebuild::validAlignmentNew(DWORD badAddress)
{
DWORD moduloResult = badAddress % FileAlignmentConstant;
if (moduloResult)
{
return (FileAlignmentConstant - moduloResult);
}
else
{
return 0;
}
}
bool PeRebuild::isRoundedTo(DWORD_PTR dwTarNum, DWORD_PTR dwRoundNum)
{
return (dwTarNum % dwRoundNum) == 0;
// WTF:
/*
#ifdef _WIN64
lldiv_t d;
d = div((__int64)dwTarNum, (__int64)dwRoundNum);
#else
ldiv_t d;
d = div((long)dwTarNum, (long)dwRoundNum);
#endif
return (d.rem == 0);
*/
}
void PeRebuild::cleanSectionPointer()
{
if (pSections)
{
for (int j = 0; j < MAX_SEC_NUM; j++)
{
if (pSections[j])
{
free(pSections[j]);
pSections[j] = 0;
}
}
}
}
DWORD PeRebuild::realignPE(LPVOID AddressOfMapFile, DWORD dwFsize)
{
PIMAGE_DOS_HEADER pDosh = 0;
PIMAGE_NT_HEADERS pPeh = 0;
PIMAGE_SECTION_HEADER pSectionh = 0;
int i = 0;
DWORD extraAlign = 0;
ZeroMemory(&pSections, sizeof(pSections));
// get the other parameters
pMap = AddressOfMapFile;
dwMapBase = (DWORD_PTR)pMap;
if (dwFsize == 0 || pMap == NULL)
return 1;
// access the PE Header and check whether it's a valid one
pDosh = (PIMAGE_DOS_HEADER)(pMap);
pPeh = (PIMAGE_NT_HEADERS)((DWORD_PTR)pDosh+pDosh->e_lfanew);
if (!validatePeHeaders(pDosh))
{
return 0;
}
if (pPeh->FileHeader.NumberOfSections > MAX_SEC_NUM)
{
return 3;
}
__try
{
/* START */
pPeh->OptionalHeader.FileAlignment = FileAlignmentConstant;
/* Realign the PE Header */
// get the size of all headers
dwTmpNum = FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) + pPeh->FileHeader.SizeOfOptionalHeader + (pPeh->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER));
// kill room between the "win32 pls" message and the PE signature
// find the end of the message
pW = (WORD*)(dwMapBase + ScanStartDS);
while (*pW != 0 || (!isRoundedTo((DWORD_PTR)pW, 0x10)))
{
pW = (WORD*)((DWORD_PTR)pW + 1);
}
wTmpNum = (WORD)((DWORD_PTR)pW - dwMapBase);
if (wTmpNum < pDosh->e_lfanew)
{
CopyMemory((LPVOID)pW,(VOID*)pPeh,dwTmpNum); // copy the Header to the right place
pDosh->e_lfanew = wTmpNum;
}
dwSectionBase = validAlignment(dwTmpNum + pDosh->e_lfanew);
pPeh = (PIMAGE_NT_HEADERS)(dwMapBase + pDosh->e_lfanew); // because the NT header moved
// correct the SizeOfHeaders
pPeh->OptionalHeader.SizeOfHeaders = dwSectionBase;
/* Realign all sections */
// make a copy of all sections
// this is needed if the sections aren't sorted by their RawOffset (e.g. Petite)
pSectionh = IMAGE_FIRST_SECTION(pPeh);
for (i=0; i<pPeh->FileHeader.NumberOfSections; i++)
{
if (pSectionh->SizeOfRawData == 0 || pSectionh->PointerToRawData == 0)
{
++pSectionh;
continue;
}
// get a valid size
dwTmpNum = pSectionh->SizeOfRawData;
if ((pSectionh->SizeOfRawData + pSectionh->PointerToRawData) > dwFsize)
{
dwTmpNum = dwFsize - pSectionh->PointerToRawData;
}
//dwTmpNum -= 1;
// copy the section into some memory
// limit max section size to 300 MB = 300000 KB = 300000000 B
if (dwTmpNum > 300000000)
{
dwTmpNum = 300000000;
}
//because of validAlignment we need some extra space, max 0x200 extra
extraAlign = validAlignmentNew(dwTmpNum);
pSections[i] = malloc(dwTmpNum + extraAlign);
ZeroMemory(pSections[i], dwTmpNum + extraAlign);
if (pSections[i] == NULL) // fatal error !!!
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"realignPE :: malloc failed with dwTmpNum %08X %08X", dwTmpNum, extraAlign);
#endif
cleanSectionPointer();
return 4;
}
CopyMemory(pSections[i],(LPVOID)(pSectionh->PointerToRawData+dwMapBase),dwTmpNum);
++pSectionh;
}
// start realigning the sections
pSectionh = IMAGE_FIRST_SECTION(pPeh);
for (i=0;i<pPeh->FileHeader.NumberOfSections;i++)
{
// some anti crash code :P
if (pSectionh->SizeOfRawData == 0 || pSectionh->PointerToRawData == 0)
{
++pSectionh;
if (pSectionh->PointerToRawData == 0)
{
continue;
}
pSectionh->PointerToRawData = dwSectionBase;
continue;
}
// let pCH point to the end of the current section
if ((pSectionh->PointerToRawData+pSectionh->SizeOfRawData) <= dwFsize)
{
pCH = (char*)(dwMapBase+pSectionh->PointerToRawData+pSectionh->SizeOfRawData-1);
}
else
{
pCH = (char*)(dwMapBase+dwFsize-1);
}
// look for the end of this section
while (*pCH == 0)
{
--pCH;
}
// calculate the new RawSize
dwTmpNum = (DWORD)(((DWORD_PTR)pCH - dwMapBase) + MinSectionTerm - pSectionh->PointerToRawData);
if (dwTmpNum < pSectionh->SizeOfRawData)
{
pSectionh->SizeOfRawData = dwTmpNum;
}
else // the new size is too BIG
{
dwTmpNum = pSectionh->SizeOfRawData;
}
// copy the section to the new place
if (i != pPeh->FileHeader.NumberOfSections-1)
{
dwTmpNum = validAlignment(dwTmpNum);
}
CopyMemory((LPVOID)(dwMapBase+dwSectionBase), pSections[i], dwTmpNum);
// set the RawOffset
pSectionh->PointerToRawData = dwSectionBase;
// get the RawOffset for the next section
dwSectionBase = dwTmpNum+dwSectionBase; // the last section doesn't need to be aligned
// go to the next section
++pSectionh;
}
// delete bound import directories because it is destroyed if present
pPeh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0;
pPeh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0;
// clean up
cleanSectionPointer();
}
__except(1)
{
// clean up
cleanSectionPointer();
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"realignPE :: Exception occured");
#endif
return 0;
}
if (Scylla::config[UPDATE_HEADER_CHECKSUM].isTrue())
{
updatePeHeaderChecksum(AddressOfMapFile, dwSectionBase);
}
return dwSectionBase; // return the new filesize
}
// returns:
// -1 - access violation
// -2 - no relocation found
// -3 - no own section
// -4 - dll characteristics found
// -5 - invalid PE file
// else the new raw size
DWORD PeRebuild::wipeReloc(void* pMap, DWORD dwFsize)
{
PIMAGE_DOS_HEADER pDosH;
PIMAGE_NT_HEADERS pNTH;
PIMAGE_SECTION_HEADER pSecH;
PIMAGE_SECTION_HEADER pSH, pSH2;
DWORD dwRelocRVA, i;
BOOL bOwnSec = FALSE;
DWORD dwNewFsize;
__try // =)
{
// get pe header pointers
pDosH = (PIMAGE_DOS_HEADER)pMap;
if (pDosH->e_magic != IMAGE_DOS_SIGNATURE)
return -5;
pNTH = (PIMAGE_NT_HEADERS)((DWORD_PTR)pDosH + pDosH->e_lfanew);
if (pNTH->Signature != IMAGE_NT_SIGNATURE)
return -5;
pSecH = IMAGE_FIRST_SECTION(pNTH);
// has PE dll characteristics ?
if (pNTH->FileHeader.Characteristics & IMAGE_FILE_DLL)
return -4;
// is there a reloc section ?
dwRelocRVA = pNTH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;
if (!dwRelocRVA)
return -2;
// check whether the relocation has an own section
pSH = pSecH;
for (i=0; i < pNTH->FileHeader.NumberOfSections; i++)
{
if (pSH->VirtualAddress == dwRelocRVA)
{
bOwnSec = TRUE;
break; // pSH -> reloc section header and i == section index
}
++pSH;
}
if (!bOwnSec)
return -3;
if (i+1 == pNTH->FileHeader.NumberOfSections)
{
//--- relocation is the last section ---
// truncate at the start of the reloc section
dwNewFsize = pSH->PointerToRawData;
}
else
{
//--- relocation isn't the last section ---
dwNewFsize = dwFsize - pSH->SizeOfRawData;
//-> copy the section(s) after the relocation to the start of the relocation
pSH2 = pSH;
++pSH2; // pSH2 -> pointer to first section after relocation
memcpy(
(void*)(pSH->PointerToRawData + (DWORD)pMap),
(const void*)(pSH2->PointerToRawData + (DWORD)pMap),
dwFsize - pSH2->PointerToRawData);
//-> fix the section headers
// (pSH -> reloc section header)
// (pSH2 -> first section after reloc section)
for (++i; i < pNTH->FileHeader.NumberOfSections; i++)
{
// apply important values
pSH->SizeOfRawData = pSH2->SizeOfRawData;
pSH->VirtualAddress = pSH2->VirtualAddress;
pSH->Misc.VirtualSize = pSH2->Misc.VirtualSize;
// apply section name
memcpy(
(void*)(pSH->Name),
(const void*)(pSH2->Name),
sizeof(pSH2->Name));
++pSH;
++pSH2;
}
}
// dec section number
--pNTH->FileHeader.NumberOfSections;
// kill reloc directory entry
pNTH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = 0;
pNTH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = 0;
// fix virtual parts of the PE Header (a must for win2k)
pSH2 = pSH = pSecH;
++pSH2;
for (i=0; i < (DWORD)pNTH->FileHeader.NumberOfSections-1; i++)
{
pSH->Misc.VirtualSize = pSH2->VirtualAddress - pSH->VirtualAddress;
++pSH;
++pSH2;
}
// (pSH -> pointer to last section)
if (pSH->Misc.PhysicalAddress)
pNTH->OptionalHeader.SizeOfImage = pSH->VirtualAddress + pSH->Misc.VirtualSize;
else // WATCOM is always a bit special >:-)
pNTH->OptionalHeader.SizeOfImage = pSH->VirtualAddress + pSH->SizeOfRawData;
}
__except(1)
{
// an access violation occurred :(
return -1;
}
return dwNewFsize;
}
bool PeRebuild::validatePE(void* pPEImage, DWORD dwFileSize)
{
PIMAGE_NT_HEADERS pNTh;
PIMAGE_SECTION_HEADER pSech,pSH, pSH2, pLastSH;
UINT i;
DWORD dwHeaderSize;
// get PE base information
pNTh = ImageNtHeader(pPEImage);
if (!pNTh)
return FALSE;
pSech = IMAGE_FIRST_SECTION(pNTh);
// FIX:
// ... the SizeOfHeaders
pSH = pSech;
dwHeaderSize = 0xFFFFFFFF;
for(i=0; i < pNTh->FileHeader.NumberOfSections; i++)
{
if (pSH->PointerToRawData && pSH->PointerToRawData < dwHeaderSize)
{
dwHeaderSize = pSH->PointerToRawData;
}
++pSH;
}
pNTh->OptionalHeader.SizeOfHeaders = dwHeaderSize;
// ...Virtual Sizes
pSH2 = pSH = pSech;
++pSH2;
for (i=0; i < (DWORD)pNTh->FileHeader.NumberOfSections-1; i++)
{
pSH->Misc.VirtualSize = pSH2->VirtualAddress - pSH->VirtualAddress;
++pSH;
++pSH2;
}
// (pSH -> pointer to last section)
pLastSH = pSH;
// ...RawSize of the last section
pLastSH->SizeOfRawData = dwFileSize - pLastSH->PointerToRawData;
// ...SizeOfImage
if (pLastSH->Misc.PhysicalAddress)
{
pNTh->OptionalHeader.SizeOfImage = pLastSH->VirtualAddress + pLastSH->Misc.VirtualSize;
}
else // WATCOM is always a bit special >:-)
{
pNTh->OptionalHeader.SizeOfImage = pLastSH->VirtualAddress + pLastSH->SizeOfRawData;
}
return true;
}
ReBaseErr PeRebuild::reBasePEImage(void* pPE, DWORD_PTR dwNewBase)
{
PIMAGE_NT_HEADERS pNT;
PIMAGE_RELOCATION pR;
ReBaseErr ret;
DWORD_PTR dwDelta;
DWORD *pdwAddr, dwRva, dwType;
UINT iItems, i;
WORD *pW;
// dwNewBase valid ?
if (dwNewBase & 0xFFFF)
{
ret = RB_INVALIDNEWBASE;
goto Exit; // ERR
}
//
// get relocation dir ptr
//
pNT = ImageNtHeader(pPE);
if (!pNT)
{
ret = RB_INVALIDPE;
goto Exit; // ERR
}
// new base = old base ?
if (pNT->OptionalHeader.ImageBase == dwNewBase)
{
ret = RB_OK;
goto Exit; // OK
}
if (!pNT->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress)
{
ret = RB_NORELOCATIONINFO;
goto Exit; // ERR
}
pR = (PIMAGE_RELOCATION)ImageRvaToVa(
pNT,
pPE,
pNT->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress,
NULL);
if (!pR)
{
ret = RB_INVALIDRVA;
goto Exit; // ERR
}
//
// add delta to relocation items
//
dwDelta = dwNewBase - pNT->OptionalHeader.ImageBase;
__try
{
do
{
// get number of items
if (pR->SymbolTableIndex)
iItems = (pR->SymbolTableIndex - 8) / 2;
else
break; // no items in this block
// trace/list block items...
pW = (WORD*)((DWORD_PTR)pR + 8);
for (i = 0; i < iItems; i++)
{
dwRva = (*pW & 0xFFF) + pR->VirtualAddress;
dwType = *pW >> 12;
if (dwType != 0) // fully compatible ???
{
// add delta
pdwAddr = (PDWORD)ImageRvaToVa(
pNT,
pPE,
dwRva,
NULL);
if (!pdwAddr)
{
ret = RB_INVALIDRVA;
goto Exit; // ERR
}
*pdwAddr += dwDelta;
}
// next item
++pW;
}
pR = (PIMAGE_RELOCATION)pW; // pR -> next block header
} while ( *(DWORD*)pW );
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
ret = RB_ACCESSVIOLATION;
goto Exit; // ERR
}
// apply new base to header
pNT->OptionalHeader.ImageBase = dwNewBase;
ret = RB_OK; // OK
Exit:
return ret;
}
bool PeRebuild::updatePeHeaderChecksum(LPVOID AddressOfMapFile, DWORD dwFsize)
{
PIMAGE_NT_HEADERS32 pNTHeader32 = 0;
PIMAGE_NT_HEADERS64 pNTHeader64 = 0;
DWORD headerSum = 0;
DWORD checkSum = 0;
pNTHeader32 = (PIMAGE_NT_HEADERS32)CheckSumMappedFile(AddressOfMapFile, dwFsize, &headerSum, &checkSum);
if (!pNTHeader32)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"updatePeHeaderChecksum :: CheckSumMappedFile failed error %X", GetLastError());
#endif
return false;
}
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"Old checksum %08X new checksum %08X", headerSum, checkSum);
#endif
if (pNTHeader32->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
{
pNTHeader64 = (PIMAGE_NT_HEADERS64)pNTHeader32;
pNTHeader64->OptionalHeader.CheckSum = checkSum;
}
else
{
pNTHeader32->OptionalHeader.CheckSum = checkSum;
}
return true;
}
LPVOID PeRebuild::createFileMappingViewFull(const WCHAR * filePath)
{
hFileToMap = CreateFile(filePath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if( hFileToMap == INVALID_HANDLE_VALUE )
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"createFileMappingView :: INVALID_HANDLE_VALUE %u", GetLastError());
#endif
hMappedFile = 0;
hFileToMap = 0;
addrMappedDll = 0;
return NULL;
}
hMappedFile = CreateFileMapping(hFileToMap, 0, PAGE_READWRITE, 0, 0, NULL);
if( hMappedFile == NULL )
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"createFileMappingViewFull :: hMappedFile == NULL");
#endif
CloseHandle(hFileToMap);
hMappedFile = 0;
hFileToMap = 0;
addrMappedDll = 0;
return NULL;
}
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"createFileMappingView :: GetLastError() == ERROR_ALREADY_EXISTS");
#endif
CloseHandle(hFileToMap);
hMappedFile = 0;
hFileToMap = 0;
addrMappedDll = 0;
return NULL;
}
addrMappedDll = MapViewOfFile(hMappedFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if(!addrMappedDll)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"createFileMappingView :: addrMappedDll == NULL");
#endif
CloseHandle(hFileToMap);
CloseHandle(hMappedFile);
hMappedFile = 0;
hFileToMap = 0;
return NULL;
}
return addrMappedDll;
}
void PeRebuild::closeAllMappingHandles()
{
if (addrMappedDll)
{
if (!FlushViewOfFile(addrMappedDll, 0))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"closeAllMappingHandles :: Could not flush memory to disk (%d)", GetLastError());
#endif
}
UnmapViewOfFile(addrMappedDll);
addrMappedDll = 0;
}
if (hMappedFile)
{
CloseHandle(hMappedFile);
hMappedFile = 0;
}
if (hFileToMap)
{
CloseHandle(hFileToMap);
hFileToMap = 0;
}
}
bool PeRebuild::validatePeHeaders( PIMAGE_DOS_HEADER pDosh )
{
PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)pDosh + pDosh->e_lfanew);
if ((pDosh != 0) && (pDosh->e_magic == IMAGE_DOS_SIGNATURE) && (pNTHeader->Signature == IMAGE_NT_SIGNATURE))
{
#ifdef _WIN64
if (pNTHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
#else
if (pNTHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
#endif
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
diff --git a/Scylla/PeRebuild.h b/Scylla/PeRebuild.h
index a180cf4..032eb43 100644
--- a/Scylla/PeRebuild.h
+++ b/Scylla/PeRebuild.h
@@ -1,62 +1,66 @@
+#pragma once
+
#include <Windows.h>
-#include <stdlib.h>
+#include <cstdlib>
-typedef enum _ReBaseErr
+enum ReBaseErr
{
RB_OK = 0,
RB_INVALIDPE,
RB_NORELOCATIONINFO,
RB_INVALIDRVA,
RB_INVALIDNEWBASE,
RB_ACCESSVIOLATION
-} ReBaseErr;
-
-class PeRebuild {
+};
/*****************************************************************************
Improved Realign DLL version 1.5 by yoda
*****************************************************************************/
+
+class PeRebuild
+{
public:
+
bool truncateFile(WCHAR * szFilePath, DWORD dwNewFsize);
DWORD realignPE(LPVOID AddressOfMapFile,DWORD dwFsize);
DWORD wipeReloc(void* pMap, DWORD dwFsize);
bool validatePE(void* pPEImage, DWORD dwFileSize);
ReBaseErr reBasePEImage(void* pPE, DWORD_PTR dwNewBase);
bool updatePeHeaderChecksum(LPVOID AddressOfMapFile, DWORD dwFsize);
LPVOID createFileMappingViewFull(const WCHAR * filePath);
void closeAllMappingHandles();
-
private:
+
// constants
-#define MAX_SEC_NUM 30
+ static const size_t MAX_SEC_NUM = 30;
- const static DWORD ScanStartDS = 0x40;
- const static int MinSectionTerm = 5;
- const static int FileAlignmentConstant = 0x200;
+ static const DWORD ScanStartDS = 0x40;
+ static const int MinSectionTerm = 5;
+ static const int FileAlignmentConstant = 0x200;
// variables
DWORD_PTR dwMapBase;
LPVOID pMap;
DWORD dwTmpNum,dwSectionBase;
WORD wTmpNum;
CHAR * pCH;
WORD * pW;
DWORD * pDW;
LPVOID pSections[MAX_SEC_NUM];
//my vars
HANDLE hFileToMap;
HANDLE hMappedFile;
LPVOID addrMappedDll;
DWORD validAlignment(DWORD BadSize);
DWORD validAlignmentNew(DWORD badAddress);
bool isRoundedTo(DWORD_PTR dwTarNum, DWORD_PTR dwRoundNum);
void cleanSectionPointer();
bool validatePeHeaders( PIMAGE_DOS_HEADER pDosh );
-};
\ No newline at end of file
+};
diff --git a/Scylla/PickApiGui.h b/Scylla/PickApiGui.h
index a8f8e19..912fa4b 100644
--- a/Scylla/PickApiGui.h
+++ b/Scylla/PickApiGui.h
@@ -1,94 +1,94 @@
#pragma once
#include <windows.h>
#include "resource.h"
// WTL
#include <atlbase.h> // base ATL classes
#include <atlapp.h> // base WTL classes
#include <atlwin.h> // ATL GUI classes
#include <atlframe.h> // WTL window frame helpers
#include <atlmisc.h> // WTL utility classes
#include <atlcrack.h> // WTL enhanced msg map macros
#include <atlctrls.h> // WTL controls
#include <atlddx.h> // WTL dialog data exchange
#include <vector>
-#include "ProcessAccessHelp.h"
+#include "ProcessAccessHelp.h" // ModuleInfo, ApiInfo
class PickApiGui : public CDialogImpl<PickApiGui>, public CWinDataExchange<PickApiGui>, public CDialogResize<PickApiGui>
{
public:
enum { IDD = IDD_DLG_PICKAPI };
BEGIN_DDX_MAP(PickApiGui)
DDX_CONTROL_HANDLE(IDC_CBO_DLLSELECT, ComboDllSelect)
DDX_CONTROL_HANDLE(IDC_LIST_APISELECT, ListApiSelect)
DDX_CONTROL_HANDLE(IDC_EDIT_APIFILTER, EditApiFilter)
END_DDX_MAP()
BEGIN_MSG_MAP(PickDllGui)
MSG_WM_INITDIALOG(OnInitDialog)
COMMAND_HANDLER_EX(IDC_CBO_DLLSELECT, CBN_SELENDOK, OnDllListSelected)
COMMAND_HANDLER_EX(IDC_LIST_APISELECT, LBN_DBLCLK, OnApiListDoubleClick)
COMMAND_HANDLER_EX(IDC_EDIT_APIFILTER, EN_UPDATE, OnApiFilterUpdated)
COMMAND_ID_HANDLER_EX(IDC_BTN_PICKAPI_OK, OnOK)
COMMAND_ID_HANDLER_EX(IDC_BTN_PICKAPI_CANCEL, OnCancel)
COMMAND_ID_HANDLER_EX(IDCANCEL, OnCancel)
CHAIN_MSG_MAP(CDialogResize<PickApiGui>)
END_MSG_MAP()
BEGIN_DLGRESIZE_MAP(PickApiGui)
DLGRESIZE_CONTROL(IDC_GROUP_DLL, DLSZ_SIZE_X)
DLGRESIZE_CONTROL(IDC_CBO_DLLSELECT, DLSZ_SIZE_X)
DLGRESIZE_CONTROL(IDC_GROUP_APIS, DLSZ_SIZE_X | DLSZ_SIZE_Y)
DLGRESIZE_CONTROL(IDC_LIST_APISELECT, DLSZ_SIZE_X | DLSZ_SIZE_Y)
DLGRESIZE_CONTROL(IDC_STATIC_APIFILTER, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_EDIT_APIFILTER, DLSZ_MOVE_Y | DLSZ_SIZE_X)
DLGRESIZE_CONTROL(IDC_BTN_PICKAPI_OK, DLSZ_MOVE_X | DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_BTN_PICKAPI_CANCEL, DLSZ_MOVE_X | DLSZ_MOVE_Y)
END_DLGRESIZE_MAP()
PickApiGui(const std::vector<ModuleInfo> &moduleList);
ApiInfo* getSelectedApi() const { return selectedApi; }
protected:
// Variables
const std::vector<ModuleInfo> &moduleList;
ApiInfo* selectedApi;
// Controls
CComboBox ComboDllSelect;
CListBox ListApiSelect;
CEdit EditApiFilter;
protected:
// Message handlers
BOOL OnInitDialog(CWindow wndFocus, LPARAM lInitParam);
void OnOK(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnCancel(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnDllListSelected(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnApiListDoubleClick(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnApiFilterUpdated(UINT uNotifyCode, int nID, CWindow wndCtl);
// Actions
void actionApiSelected();
// GUI functions
void fillDllComboBox(CComboBox& combo);
void fillApiListBox(CListBox& list, const std::vector<ApiInfo *> &apis);
};
diff --git a/Scylla/PickDllGui.h b/Scylla/PickDllGui.h
index 1814440..99fd1e5 100644
--- a/Scylla/PickDllGui.h
+++ b/Scylla/PickDllGui.h
@@ -1,89 +1,89 @@
#pragma once
#include <windows.h>
#include "resource.h"
// WTL
#include <atlbase.h> // base ATL classes
#include <atlapp.h> // base WTL classes
#include <atlwin.h> // ATL GUI classes
#include <atlframe.h> // WTL window frame helpers
#include <atlmisc.h> // WTL utility classes
#include <atlcrack.h> // WTL enhanced msg map macros
#include <atlctrls.h> // WTL controls
#include <atlddx.h> // WTL dialog data exchange
#include <vector>
-#include "ProcessAccessHelp.h"
+#include "ProcessAccessHelp.h" // ModuleInfo
class PickDllGui : public CDialogImpl<PickDllGui>, public CWinDataExchange<PickDllGui>, public CDialogResize<PickDllGui>
{
public:
enum { IDD = IDD_DLG_PICKDLL };
BEGIN_DDX_MAP(PickDllGui)
DDX_CONTROL_HANDLE(IDC_LIST_DLLSELECT, ListDLLSelect)
END_DDX_MAP()
BEGIN_MSG_MAP(PickDllGui)
MSG_WM_INITDIALOG(OnInitDialog)
NOTIFY_HANDLER_EX(IDC_LIST_DLLSELECT, LVN_COLUMNCLICK, OnListDllColumnClicked)
NOTIFY_HANDLER_EX(IDC_LIST_DLLSELECT, NM_DBLCLK, OnListDllDoubleClick)
COMMAND_ID_HANDLER_EX(IDC_BTN_PICKDLL_OK, OnOK)
COMMAND_ID_HANDLER_EX(IDC_BTN_PICKDLL_CANCEL, OnCancel)
COMMAND_ID_HANDLER_EX(IDCANCEL, OnCancel)
CHAIN_MSG_MAP(CDialogResize<PickDllGui>)
END_MSG_MAP()
BEGIN_DLGRESIZE_MAP(PickDllGui)
DLGRESIZE_CONTROL(IDC_LIST_DLLSELECT, DLSZ_SIZE_X | DLSZ_SIZE_Y)
DLGRESIZE_CONTROL(IDC_BTN_PICKDLL_OK, DLSZ_MOVE_X | DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_BTN_PICKDLL_CANCEL, DLSZ_MOVE_X | DLSZ_MOVE_Y)
END_DLGRESIZE_MAP()
PickDllGui(std::vector<ModuleInfo> &moduleList);
ModuleInfo* getSelectedModule() const { return selectedModule; }
protected:
// Variables
std::vector<ModuleInfo> &moduleList;
ModuleInfo* selectedModule;
// Controls
CListViewCtrl ListDLLSelect;
enum ListColumns {
COL_NAME = 0,
COL_IMAGEBASE,
COL_IMAGESIZE,
COL_PATH
};
int prevColumn;
bool ascending;
protected:
// Message handlers
BOOL OnInitDialog(CWindow wndFocus, LPARAM lInitParam);
LRESULT OnListDllColumnClicked(NMHDR* pnmh);
LRESULT OnListDllDoubleClick(NMHDR* pnmh);
void OnOK(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnCancel(UINT uNotifyCode, int nID, CWindow wndCtl);
// GUI functions
void addColumnsToModuleList(CListViewCtrl& list);
void displayModuleList(CListViewCtrl& list);
static int CALLBACK listviewCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
};
diff --git a/Scylla/PluginLoader.cpp b/Scylla/PluginLoader.cpp
index f39a829..3e03b8c 100644
--- a/Scylla/PluginLoader.cpp
+++ b/Scylla/PluginLoader.cpp
@@ -1,361 +1,360 @@
#include "PluginLoader.h"
#include "Logger.h"
#include "ProcessAccessHelp.h"
+#include "StringConversion.h"
#include <shlwapi.h>
-#include <stdio.h>
const WCHAR PluginLoader::PLUGIN_DIR[] = L"Plugins\\";
const WCHAR PluginLoader::PLUGIN_SEARCH_STRING[] = L"*.dll";
const WCHAR PluginLoader::PLUGIN_IMPREC_DIR[] = L"ImpRec_Plugins\\";
const WCHAR PluginLoader::PLUGIN_IMPREC_WRAPPER_DLL[] = L"Imprec_Wrapper_DLL.dll";
//#define DEBUG_COMMENTS
std::vector<Plugin> & PluginLoader::getScyllaPluginList()
{
return scyllaPluginList;
}
std::vector<Plugin> & PluginLoader::getImprecPluginList()
{
return imprecPluginList;
}
bool PluginLoader::findAllPlugins()
{
if (!scyllaPluginList.empty())
{
scyllaPluginList.clear();
}
if (!imprecPluginList.empty())
{
imprecPluginList.clear();
}
if (!buildSearchString())
{
return false;
}
if (!searchForPlugin(scyllaPluginList, dirSearchString, true))
{
return false;
}
#ifndef _WIN64
if (!buildSearchStringImprecPlugins())
{
return false;
}
if (!searchForPlugin(imprecPluginList, dirSearchString, false))
{
return false;
}
#endif
return true;
}
bool PluginLoader::searchForPlugin(std::vector<Plugin> & newPluginList, const WCHAR * searchPath, bool isScyllaPlugin)
{
WIN32_FIND_DATA ffd;
HANDLE hFind = 0;
DWORD dwError = 0;
Plugin pluginData;
hFind = FindFirstFile(searchPath, &ffd);
dwError = GetLastError();
if (dwError == ERROR_FILE_NOT_FOUND)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"findAllPlugins :: No files found");
#endif
return true;
}
if (hFind == INVALID_HANDLE_VALUE)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"findAllPlugins :: FindFirstFile failed %d", dwError);
#endif
return false;
}
do
{
if ( !(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
{
if ((ffd.nFileSizeHigh != 0) || (ffd.nFileSizeLow < 200))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"findAllPlugins :: Plugin invalid file size: %s", ffd.cFileName);
#endif
}
else
{
pluginData.fileSize = ffd.nFileSizeLow;
wcscpy_s(pluginData.fullpath, _countof(baseDirPath), baseDirPath);
wcscat_s(pluginData.fullpath, _countof(baseDirPath), ffd.cFileName);
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"findAllPlugins :: Plugin %s", pluginData.fullpath);
#endif
if (isValidDllFile(pluginData.fullpath))
{
if (isScyllaPlugin)
{
if (getScyllaPluginName(&pluginData))
{
//add valid plugin
newPluginList.push_back(pluginData);
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"Cannot get scylla plugin name %s", pluginData.fullpath);
#endif
}
}
else
{
if (isValidImprecPlugin(pluginData.fullpath))
{
wcscpy_s(pluginData.pluginName, MAX_PATH, ffd.cFileName);
newPluginList.push_back(pluginData);
}
}
}
}
}
}
while (FindNextFile(hFind, &ffd) != 0);
dwError = GetLastError();
FindClose(hFind);
if (dwError == ERROR_NO_MORE_FILES)
{
return true;
}
else
{
return false;
}
}
bool PluginLoader::getScyllaPluginName(Plugin * pluginData)
{
bool retValue = false;
char * pluginName = 0;
- size_t convertedChars = 0;
def_ScyllaPluginNameW ScyllaPluginNameW = 0;
def_ScyllaPluginNameA ScyllaPluginNameA = 0;
HMODULE hModule = LoadLibraryEx(pluginData->fullpath, 0, DONT_RESOLVE_DLL_REFERENCES); //do not call DllMain
if (hModule)
{
ScyllaPluginNameW = (def_ScyllaPluginNameW)GetProcAddress(hModule, "ScyllaPluginNameW");
if (ScyllaPluginNameW)
{
wcscpy_s(pluginData->pluginName, MAX_PATH, ScyllaPluginNameW());
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"getPluginName :: Plugin name %s", pluginData->pluginName);
#endif
retValue = true;
}
else
{
ScyllaPluginNameA = (def_ScyllaPluginNameA)GetProcAddress(hModule, "ScyllaPluginNameA");
if (ScyllaPluginNameA)
{
pluginName = ScyllaPluginNameA();
- mbstowcs_s(&convertedChars, pluginData->pluginName, strlen(pluginName) + 1, pluginName, _TRUNCATE);
+ StringConversion::ToUTF16(pluginName, pluginData->pluginName, _countof(pluginData->pluginName));
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"getPluginName :: Plugin name mbstowcs_s %s", pluginData->pluginName);
#endif
- if (convertedChars > 1)
+ if (wcslen(pluginData->pluginName) > 1)
{
retValue = true;
}
else
{
retValue = false;
}
}
else
{
retValue = false;
}
}
FreeLibrary(hModule);
return retValue;
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"getPluginName :: LoadLibraryEx failed %s", pluginData->fullpath);
#endif
return false;
}
}
bool PluginLoader::buildSearchString()
{
ZeroMemory(dirSearchString, sizeof(dirSearchString));
ZeroMemory(baseDirPath, sizeof(baseDirPath));
if (!GetModuleFileName(0, dirSearchString, _countof(dirSearchString)))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"buildSearchString :: GetModuleFileName failed %d", GetLastError());
#endif
return false;
}
//wprintf(L"dirSearchString 1 %s\n\n", dirSearchString);
PathRemoveFileSpec(dirSearchString);
//wprintf(L"dirSearchString 2 %s\n\n", dirSearchString);
PathAppend(dirSearchString, PLUGIN_DIR);
wcscpy_s(baseDirPath, _countof(baseDirPath), dirSearchString);
wcscat_s(dirSearchString, _countof(dirSearchString), PLUGIN_SEARCH_STRING);
//wprintf(L"dirSearchString 3 %s\n\n", dirSearchString);
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"dirSearchString final %s", dirSearchString);
#endif
return true;
}
bool PluginLoader::isValidDllFile( const WCHAR * fullpath )
{
BYTE * data = 0;
DWORD lpNumberOfBytesRead = 0;
PIMAGE_DOS_HEADER pDos = 0;
PIMAGE_NT_HEADERS pNT = 0;
bool retValue = false;
HANDLE hFile = CreateFile(fullpath, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
data = new BYTE[sizeof(IMAGE_DOS_HEADER) + sizeof(IMAGE_NT_HEADERS) + 0x100];
if (ReadFile(hFile, data, sizeof(IMAGE_DOS_HEADER) + sizeof(IMAGE_NT_HEADERS) + 0x100, &lpNumberOfBytesRead, 0))
{
pDos = (PIMAGE_DOS_HEADER)data;
if (pDos->e_magic == IMAGE_DOS_SIGNATURE)
{
pNT = (PIMAGE_NT_HEADERS)((DWORD_PTR)pDos + pDos->e_lfanew);
if (pNT->Signature == IMAGE_NT_SIGNATURE)
{
#ifdef _WIN64
if (pNT->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
#else
if (pNT->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
#endif
{
retValue = true;
}
}
}
}
delete [] data;
CloseHandle(hFile);
}
return retValue;
}
bool PluginLoader::isValidImprecPlugin(const WCHAR * fullpath)
{
def_Imprec_Trace Imprec_Trace = 0;
bool retValue = false;
HMODULE hModule = LoadLibraryEx(fullpath, 0, DONT_RESOLVE_DLL_REFERENCES); //do not call DllMain
if (hModule)
{
Imprec_Trace = (def_Imprec_Trace)GetProcAddress(hModule, "Trace");
if (Imprec_Trace)
{
retValue = true;
}
else
{
retValue = false;
}
FreeLibrary(hModule);
return retValue;
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"isValidImprecPlugin :: LoadLibraryEx failed %s", pluginData->fullpath);
#endif
return false;
}
}
bool PluginLoader::buildSearchStringImprecPlugins()
{
wcscpy_s(dirSearchString, _countof(dirSearchString), baseDirPath);
wcscat_s(dirSearchString, _countof(dirSearchString), PLUGIN_IMPREC_DIR);
wcscpy_s(baseDirPath, _countof(baseDirPath), dirSearchString);
//build imprec wrapper dll path
wcscpy_s(imprecWrapperDllPath, _countof(imprecWrapperDllPath), dirSearchString);
wcscat_s(imprecWrapperDllPath, _countof(imprecWrapperDllPath), PLUGIN_IMPREC_WRAPPER_DLL);
if (!fileExists(imprecWrapperDllPath))
{
return false;
}
wcscat_s(dirSearchString, _countof(dirSearchString), PLUGIN_SEARCH_STRING);
return true;
}
bool PluginLoader::fileExists(const WCHAR * fileName)
{
if (GetFileAttributesW(fileName) == INVALID_FILE_ATTRIBUTES)
{
return false;
}
else
{
return true;
}
}
diff --git a/Scylla/ProcessAccessHelp.cpp b/Scylla/ProcessAccessHelp.cpp
index 01e1464..cfb7f3d 100644
--- a/Scylla/ProcessAccessHelp.cpp
+++ b/Scylla/ProcessAccessHelp.cpp
@@ -1,715 +1,715 @@
#include "ProcessAccessHelp.h"
-#include "Logger.h"
+#include "Scylla.h"
#include "NativeWinApi.h"
HANDLE ProcessAccessHelp::hProcess = 0;
ModuleInfo * ProcessAccessHelp::selectedModule;
DWORD_PTR ProcessAccessHelp::targetImageBase = 0;
DWORD_PTR ProcessAccessHelp::targetSizeOfImage = 0;
DWORD_PTR ProcessAccessHelp::maxValidAddress = 0;
std::vector<ModuleInfo> ProcessAccessHelp::moduleList; //target process module list
std::vector<ModuleInfo> ProcessAccessHelp::ownModuleList; //own module list
_DInst ProcessAccessHelp::decomposerResult[MAX_INSTRUCTIONS];
unsigned int ProcessAccessHelp::decomposerInstructionsCount = 0;
_CodeInfo ProcessAccessHelp::decomposerCi = {0};
_DecodedInst ProcessAccessHelp::decodedInstructions[MAX_INSTRUCTIONS];
unsigned int ProcessAccessHelp::decodedInstructionsCount = 0;
BYTE ProcessAccessHelp::fileHeaderFromDisk[PE_HEADER_BYTES_COUNT];
//#define DEBUG_COMMENTS
bool ProcessAccessHelp::openProcessHandle(DWORD dwPID)
{
if (dwPID > 0)
{
if (hProcess)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"openProcessHandle :: There is already a process handle, HANDLE %X", hProcess);
#endif
return false;
}
else
{
//hProcess = OpenProcess(PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_QUERY_INFORMATION|PROCESS_VM_READ|PROCESS_VM_WRITE, 0, dwPID);
//if (!NT_SUCCESS(NativeWinApi::NtOpenProcess(&hProcess,PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_QUERY_INFORMATION|PROCESS_VM_READ|PROCESS_VM_WRITE,&ObjectAttributes, &cid)))
hProcess = NativeOpenProcess(PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_QUERY_INFORMATION|PROCESS_VM_READ|PROCESS_VM_WRITE, dwPID);
if (hProcess)
{
return true;
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"openProcessHandle :: Failed to open handle, PID %X", dwPID);
#endif
return false;
}
}
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"openProcessHandle :: Wrong PID, PID %X", dwPID);
#endif
return false;
}
}
HANDLE ProcessAccessHelp::NativeOpenProcess(DWORD dwDesiredAccess, DWORD dwProcessId)
{
HANDLE hProcess = 0;
CLIENT_ID cid = {0};
OBJECT_ATTRIBUTES ObjectAttributes;
NTSTATUS ntStatus = 0;
InitializeObjectAttributes(&ObjectAttributes, 0, 0, 0, 0);
cid.UniqueProcess = (HANDLE)dwProcessId;
ntStatus = NativeWinApi::NtOpenProcess(&hProcess,dwDesiredAccess,&ObjectAttributes, &cid);
if (NT_SUCCESS(ntStatus))
{
return hProcess;
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"NativeOpenProcess :: Failed to open handle, PID %X Error 0x%X", dwProcessId, NativeWinApi::RtlNtStatusToDosError(ntStatus));
#endif
return 0;
}
}
void ProcessAccessHelp::closeProcessHandle()
{
CloseHandle(hProcess);
hProcess = 0;
moduleList.clear();
targetImageBase = 0;
selectedModule = 0;
}
bool ProcessAccessHelp::readMemoryFromProcess(DWORD_PTR address, SIZE_T size, LPVOID dataBuffer)
{
SIZE_T lpNumberOfBytesRead = 0;
DWORD dwProtect = 0;
bool returnValue = false;
if (!hProcess)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"readMemoryFromProcess :: hProcess == NULL");
#endif
return returnValue;
}
if (!ReadProcessMemory(hProcess, (LPVOID)address, dataBuffer, size, &lpNumberOfBytesRead))
{
if (!VirtualProtectEx(hProcess, (LPVOID)address, size, PAGE_READWRITE, &dwProtect))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"readMemoryFromProcess :: Error VirtualProtectEx %X %X err: %u", address,size, GetLastError());
#endif
returnValue = false;
}
else
{
if (!ReadProcessMemory(hProcess, (LPVOID)address, dataBuffer, size, &lpNumberOfBytesRead))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"readMemoryFromProcess :: Error ReadProcessMemory %X %X err: %u", address, size, GetLastError());
#endif
returnValue = false;
}
else
{
returnValue = true;
}
VirtualProtectEx(hProcess, (LPVOID)address, size, dwProtect, &dwProtect);
}
}
else
{
returnValue = true;
}
if (returnValue)
{
if (size != lpNumberOfBytesRead)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"readMemoryFromProcess :: Error ReadProcessMemory read %d bytes requested %d bytes", lpNumberOfBytesRead, size);
#endif
returnValue = false;
}
else
{
returnValue = true;
}
}
return returnValue;
}
bool ProcessAccessHelp::decomposeMemory(BYTE * dataBuffer, SIZE_T bufferSize, DWORD_PTR startAddress)
{
ZeroMemory(&decomposerCi, sizeof(_CodeInfo));
decomposerCi.code = dataBuffer;
decomposerCi.codeLen = (int)bufferSize;
decomposerCi.dt = dt;
decomposerCi.codeOffset = startAddress;
decomposerInstructionsCount = 0;
if (distorm_decompose(&decomposerCi, decomposerResult, sizeof(decomposerResult)/sizeof(decomposerResult[0]), &decomposerInstructionsCount) == DECRES_INPUTERR)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"decomposeMemory :: distorm_decompose == DECRES_INPUTERR");
#endif
return false;
}
else
{
return true;
}
}
bool ProcessAccessHelp::disassembleMemory(BYTE * dataBuffer, SIZE_T bufferSize, DWORD_PTR startOffset)
{
// Holds the result of the decoding.
_DecodeResult res;
// next is used for instruction's offset synchronization.
// decodedInstructionsCount holds the count of filled instructions' array by the decoder.
decodedInstructionsCount = 0;
_OffsetType offset = startOffset;
res = distorm_decode(offset, dataBuffer, (int)bufferSize, dt, decodedInstructions, MAX_INSTRUCTIONS, &decodedInstructionsCount);
/* for (unsigned int i = 0; i < decodedInstructionsCount; i++) {
#ifdef SUPPORT_64BIT_OFFSET
printf("%0*I64x (%02d) %-24s %s%s%s\n", dt != Decode64Bits ? 8 : 16, decodedInstructions[i].offset, decodedInstructions[i].size, (char*)decodedInstructions[i].instructionHex.p, (char*)decodedInstructions[i].mnemonic.p, decodedInstructions[i].operands.length != 0 ? " " : "", (char*)decodedInstructions[i].operands.p);
#else
printf("%08x (%02d) %-24s %s%s%s\n", decodedInstructions[i].offset, decodedInstructions[i].size, (char*)decodedInstructions[i].instructionHex.p, (char*)decodedInstructions[i].mnemonic.p, decodedInstructions[i].operands.length != 0 ? " " : "", (char*)decodedInstructions[i].operands.p);
#endif
}*/
if (res == DECRES_INPUTERR)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"disassembleMemory :: res == DECRES_INPUTERR");
#endif
return false;
}
else if (res == DECRES_SUCCESS)
{
//printf("disassembleMemory :: res == DECRES_SUCCESS\n");
return true;
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"disassembleMemory :: res == %d", res);
#endif
return false;
}
}
DWORD_PTR ProcessAccessHelp::findPattern(DWORD_PTR startOffset, DWORD size, BYTE * pattern, const char * mask)
{
DWORD pos = 0;
size_t searchLen = strlen(mask) - 1;
for(DWORD_PTR retAddress = startOffset; retAddress < startOffset + size; retAddress++)
{
if( *(BYTE*)retAddress == pattern[pos] || mask[pos] == '?' )
{
if(mask[pos+1] == 0x00)
{
return (retAddress - searchLen);
}
pos++;
} else {
pos = 0;
}
}
return 0;
}
bool ProcessAccessHelp::readHeaderFromCurrentFile(const WCHAR * filePath)
{
return readHeaderFromFile(fileHeaderFromDisk, sizeof(fileHeaderFromDisk), filePath);
}
LONGLONG ProcessAccessHelp::getFileSize(const WCHAR * filePath)
{
LONGLONG fileSize = 0;
HANDLE hFile = CreateFile(filePath, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
fileSize = getFileSize(hFile);
CloseHandle(hFile);
hFile = 0;
}
return fileSize;
}
LONGLONG ProcessAccessHelp::getFileSize(HANDLE hFile)
{
LARGE_INTEGER lpFileSize = {0};
if ((hFile != INVALID_HANDLE_VALUE) && (hFile != 0))
{
if (!GetFileSizeEx(hFile, &lpFileSize))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"ProcessAccessHelp::getFileSize :: GetFileSizeEx failed %u", GetLastError());
#endif
return 0;
}
else
{
return lpFileSize.QuadPart;
}
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"ProcessAccessHelp::getFileSize hFile invalid");
#endif
return 0;
}
}
bool ProcessAccessHelp::readMemoryFromFile(HANDLE hFile, LONG offset, DWORD size, LPVOID dataBuffer)
{
DWORD lpNumberOfBytesRead = 0;
DWORD retValue = 0;
DWORD dwError = 0;
if ((hFile != INVALID_HANDLE_VALUE) && (hFile != 0))
{
retValue = SetFilePointer(hFile, offset, NULL, FILE_BEGIN);
dwError = GetLastError();
if ((retValue == INVALID_SET_FILE_POINTER) && (dwError != NO_ERROR))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"readMemoryFromFile :: SetFilePointer failed error %u", dwError);
#endif
return false;
}
else
{
if (ReadFile(hFile, dataBuffer, size, &lpNumberOfBytesRead, 0))
{
return true;
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"readMemoryFromFile :: ReadFile failed - size %d - error %u", size, GetLastError());
#endif
return false;
}
}
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"readMemoryFromFile :: hFile invalid");
#endif
return false;
}
}
bool ProcessAccessHelp::writeMemoryToFile(HANDLE hFile, LONG offset, DWORD size, LPCVOID dataBuffer)
{
DWORD lpNumberOfBytesWritten = 0;
DWORD retValue = 0;
DWORD dwError = 0;
if ((hFile != INVALID_HANDLE_VALUE) && (hFile != 0))
{
retValue = SetFilePointer(hFile, offset, NULL, FILE_BEGIN);
dwError = GetLastError();
if ((retValue == INVALID_SET_FILE_POINTER) && (dwError != NO_ERROR))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"writeMemoryToFile :: SetFilePointer failed error %u", dwError);
#endif
return false;
}
else
{
if (WriteFile(hFile, dataBuffer, size, &lpNumberOfBytesWritten, 0))
{
return true;
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"writeMemoryToFile :: WriteFile failed - size %d - error %u", size, GetLastError());
#endif
return false;
}
}
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"writeMemoryToFile :: hFile invalid");
#endif
return false;
}
}
bool ProcessAccessHelp::writeMemoryToFileEnd(HANDLE hFile, DWORD size, LPCVOID dataBuffer)
{
DWORD lpNumberOfBytesWritten = 0;
DWORD retValue = 0;
if ((hFile != INVALID_HANDLE_VALUE) && (hFile != 0))
{
SetFilePointer(hFile, 0, 0, FILE_END);
if (WriteFile(hFile, dataBuffer, size, &lpNumberOfBytesWritten, 0))
{
return true;
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"writeMemoryToFileEnd :: WriteFile failed - size %d - error %u", size, GetLastError());
#endif
return false;
}
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"writeMemoryToFileEnd :: hFile invalid");
#endif
return false;
}
}
bool ProcessAccessHelp::readHeaderFromFile(BYTE * buffer, DWORD bufferSize, const WCHAR * filePath)
{
DWORD lpNumberOfBytesRead = 0;
LONGLONG fileSize = 0;
DWORD dwSize = 0;
bool returnValue = 0;
HANDLE hFile = CreateFile(filePath, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
if( hFile == INVALID_HANDLE_VALUE )
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"readHeaderFromFile :: INVALID_HANDLE_VALUE %u", GetLastError());
#endif
returnValue = false;
}
else
{
fileSize = getFileSize(hFile);
if (fileSize > 0)
{
if (fileSize > bufferSize)
{
dwSize = bufferSize;
}
else
{
dwSize = (DWORD)(fileSize - 1);
}
returnValue = readMemoryFromFile(hFile, 0, dwSize, buffer);
}
CloseHandle(hFile);
}
return returnValue;
}
LPVOID ProcessAccessHelp::createFileMappingViewRead(const WCHAR * filePath)
{
return createFileMappingView(filePath, GENERIC_READ, PAGE_READONLY | SEC_IMAGE, FILE_MAP_READ);
}
LPVOID ProcessAccessHelp::createFileMappingViewFull(const WCHAR * filePath)
{
return createFileMappingView(filePath, GENERIC_ALL, PAGE_EXECUTE_READWRITE, FILE_MAP_ALL_ACCESS);
}
LPVOID ProcessAccessHelp::createFileMappingView(const WCHAR * filePath, DWORD accessFile, DWORD flProtect, DWORD accessMap)
{
HANDLE hFile = CreateFile(filePath, accessFile, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
if( hFile == INVALID_HANDLE_VALUE )
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"createFileMappingView :: INVALID_HANDLE_VALUE %u", GetLastError());
#endif
return NULL;
}
HANDLE hMappedFile = CreateFileMapping(hFile, NULL, flProtect, 0, 0, NULL);
CloseHandle(hFile);
if( hMappedFile == NULL )
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"createFileMappingView :: hMappedFile == NULL");
#endif
return NULL;
}
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"createFileMappingView :: GetLastError() == ERROR_ALREADY_EXISTS);
#endif
return NULL;
}
LPVOID addrMappedDll = MapViewOfFile(hMappedFile, accessMap, 0, 0, 0);
if( addrMappedDll == NULL )
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"createFileMappingView :: addrMappedDll == NULL");
#endif
CloseHandle(hMappedFile);
return NULL;
}
CloseHandle(hMappedFile);
return addrMappedDll;
}
DWORD ProcessAccessHelp::getProcessByName(const WCHAR * processName)
{
DWORD dwPID = 0;
HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32W pe32;
pe32.dwSize = sizeof(PROCESSENTRY32W);
if( !Process32FirstW( hProcessSnap, &pe32 ) )
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"getProcessByName :: Error getting first Process");
#endif
CloseHandle( hProcessSnap );
return 0;
}
do
{
if(!_wcsicmp(pe32.szExeFile, processName))
{
dwPID = pe32.th32ProcessID;
break;
}
} while(Process32NextW(hProcessSnap, &pe32));
CloseHandle(hProcessSnap);
return dwPID;
}
bool ProcessAccessHelp::getProcessModules(DWORD dwPID, std::vector<ModuleInfo> &moduleList)
{
HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
MODULEENTRY32 me32;
ModuleInfo module;
// Take a snapshot of all modules in the specified process.
hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, dwPID );
if( hModuleSnap == INVALID_HANDLE_VALUE )
{
return false;
}
// Set the size of the structure before using it.
me32.dwSize = sizeof( MODULEENTRY32 );
// Retrieve information about the first module,
// and exit if unsuccessful
if( !Module32First( hModuleSnap, &me32 ) )
{
CloseHandle( hModuleSnap );
return false;
}
// Now walk the module list of the process,
// and display information about each module
//the first is always the .exe
if (!Module32Next(hModuleSnap, &me32))
{
CloseHandle( hModuleSnap );
return false;
}
moduleList.reserve(20);
do
{
//printf(L"\n MODULE NAME: %s", me32.szModule);
module.modBaseAddr = (DWORD_PTR)me32.modBaseAddr;
module.modBaseSize = me32.modBaseSize;
module.isAlreadyParsed = false;
module.parsing = false;
wcscpy_s(module.fullPath, MAX_PATH, me32.szExePath);
moduleList.push_back(module);
} while(Module32Next(hModuleSnap, &me32));
CloseHandle( hModuleSnap );
return true;
}
bool ProcessAccessHelp::getMemoryRegionFromAddress(DWORD_PTR address, DWORD_PTR * memoryRegionBase, SIZE_T * memoryRegionSize)
{
MEMORY_BASIC_INFORMATION memBasic;
if (VirtualQueryEx(hProcess,(LPCVOID)address,&memBasic,sizeof(MEMORY_BASIC_INFORMATION)) != sizeof(MEMORY_BASIC_INFORMATION))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"getMemoryRegionFromAddress :: VirtualQueryEx error %u", GetLastError());
#endif
return false;
}
else
{
*memoryRegionBase = (DWORD_PTR)memBasic.BaseAddress;
*memoryRegionSize = memBasic.RegionSize;
return true;
}
}
bool ProcessAccessHelp::getSizeOfImageCurrentProcess()
{
DWORD_PTR newSizeOfImage = getSizeOfImageProcess(ProcessAccessHelp::hProcess, ProcessAccessHelp::targetImageBase);
if (newSizeOfImage != 0)
{
ProcessAccessHelp::targetSizeOfImage = newSizeOfImage;
return true;
}
else
{
return false;
}
}
SIZE_T ProcessAccessHelp::getSizeOfImageProcess(HANDLE processHandle, DWORD_PTR moduleBase)
{
SIZE_T sizeOfImage = 0;
MEMORY_BASIC_INFORMATION lpBuffer = {0};
SIZE_T dwLength = sizeof(MEMORY_BASIC_INFORMATION);
do
{
moduleBase = (DWORD_PTR)((SIZE_T)moduleBase + lpBuffer.RegionSize);
sizeOfImage += lpBuffer.RegionSize;
//printf("Query 0x"PRINTF_DWORD_PTR_FULL" size 0x%08X\n",moduleBase,sizeOfImage);
if (!VirtualQueryEx(processHandle, (LPCVOID)moduleBase, &lpBuffer, dwLength))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"getSizeOfImageProcess :: VirtualQuery failed %X", GetLastError());
#endif
lpBuffer.Type = 0;
sizeOfImage = 0;
}
/*else
{
printf("\nAllocationBase %X\n",lpBuffer.AllocationBase);
printf("AllocationProtect %X\n",lpBuffer.AllocationProtect);
printf("BaseAddress %X\n",lpBuffer.BaseAddress);
printf("Protect %X\n",lpBuffer.Protect);
printf("RegionSize %X\n",lpBuffer.RegionSize);
printf("State %X\n",lpBuffer.State);
printf("Type %X\n",lpBuffer.Type);
}*/
} while (lpBuffer.Type == MEM_IMAGE);
//printf("Real sizeOfImage %X\n",sizeOfImage);
return sizeOfImage;
}
DWORD ProcessAccessHelp::getEntryPointFromFile(const WCHAR * filePath)
{
PIMAGE_NT_HEADERS pNtHeader = 0;
PIMAGE_DOS_HEADER pDosHeader = 0;
readHeaderFromCurrentFile(filePath);
pDosHeader = (PIMAGE_DOS_HEADER)fileHeaderFromDisk;
if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
{
return 0;
}
pNtHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)fileHeaderFromDisk + (DWORD_PTR)(pDosHeader->e_lfanew));
if (pNtHeader->Signature != IMAGE_NT_SIGNATURE)
{
return 0;
}
return pNtHeader->OptionalHeader.AddressOfEntryPoint;
}
bool ProcessAccessHelp::createBackupFile(const WCHAR * filePath)
{
size_t fileNameLength = wcslen(filePath) + 5; //.bak + null
BOOL retValue = 0;
WCHAR * backupFile = new WCHAR[fileNameLength];
wcscpy_s(backupFile, fileNameLength, filePath);
wcscat_s(backupFile, fileNameLength, L".bak");
retValue = CopyFile(filePath, backupFile, FALSE);
if (!retValue)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"createBackupFile :: CopyFile failed with error 0x%X", GetLastError());
#endif
}
delete [] backupFile;
return retValue != 0;
}
diff --git a/Scylla/ProcessAccessHelp.h b/Scylla/ProcessAccessHelp.h
index 5eb3a93..a219673 100644
--- a/Scylla/ProcessAccessHelp.h
+++ b/Scylla/ProcessAccessHelp.h
@@ -1,202 +1,206 @@
#pragma once
-#include <stdio.h>
#include <windows.h>
#include <tlhelp32.h>
-#include <hash_map>
-#include <map>
+#include <vector>
/************************************************************************/
/* distorm */
/************************************************************************/
-#include "distorm.h"
+#include <distorm.h>
// The number of the array of instructions the decoder function will use to return the disassembled instructions.
// Play with this value for performance...
#define MAX_INSTRUCTIONS (200)
/************************************************************************/
class ApiInfo;
-class ModuleInfo {
+class ModuleInfo
+{
public:
+
WCHAR fullPath[MAX_PATH];
DWORD_PTR modBaseAddr;
DWORD modBaseSize;
bool isAlreadyParsed;
bool parsing;
/*
for iat rebuilding with duplicate entries:
ntdll = low priority
kernelbase = low priority
SHLWAPI = low priority
kernel32 = high priority
priority = 1 -> normal/high priority
priority = 0 -> low priority
*/
int priority;
std::vector<ApiInfo *> apiList;
ModuleInfo()
{
modBaseAddr = 0;
modBaseSize = 0;
priority = 1;
isAlreadyParsed = false;
parsing = false;
}
const WCHAR * getFilename() const
{
const WCHAR* slash = wcsrchr(fullPath, L'\\');
if(slash)
{
return slash+1;
}
return fullPath;
}
};
-class ApiInfo {
- public:
- char name[MAX_PATH];
- WORD hint;
- DWORD_PTR va;
- DWORD_PTR rva;
- WORD ordinal;
- bool isForwarded;
- ModuleInfo * module;
+class ApiInfo
+{
+public:
+
+ char name[MAX_PATH];
+ WORD hint;
+ DWORD_PTR va;
+ DWORD_PTR rva;
+ WORD ordinal;
+ bool isForwarded;
+ ModuleInfo * module;
};
-class ProcessAccessHelp {
+class ProcessAccessHelp
+{
public:
+
static HANDLE hProcess; //OpenProcess handle to target process
static DWORD_PTR targetImageBase;
static DWORD_PTR targetSizeOfImage;
static DWORD_PTR maxValidAddress;
static ModuleInfo * selectedModule;
static std::vector<ModuleInfo> moduleList; //target process module list
static std::vector<ModuleInfo> ownModuleList; //own module list
- static const int PE_HEADER_BYTES_COUNT = 2000;
+ static const size_t PE_HEADER_BYTES_COUNT = 2000;
static BYTE fileHeaderFromDisk[PE_HEADER_BYTES_COUNT];
//for decomposer
static _DInst decomposerResult[MAX_INSTRUCTIONS];
static unsigned int decomposerInstructionsCount;
static _CodeInfo decomposerCi;
//distorm :: Decoded instruction information.
static _DecodedInst decodedInstructions[MAX_INSTRUCTIONS];
static unsigned int decodedInstructionsCount;
#ifdef _WIN64
static const _DecodeType dt = Decode64Bits;
#else
static const _DecodeType dt = Decode32Bits;
#endif
/*
* Open a new process handle
*/
static bool openProcessHandle(DWORD dwPID);
static HANDLE NativeOpenProcess(DWORD dwDesiredAccess, DWORD dwProcessId);
static void closeProcessHandle();
/*
* Get all modules from a process
*/
static bool getProcessModules(DWORD dwPID, std::vector<ModuleInfo> &moduleList);
/*
* file mapping view with different access level
*/
static LPVOID createFileMappingViewRead(const WCHAR * filePath);
static LPVOID createFileMappingViewFull(const WCHAR * filePath);
/*
* Create a file mapping view of a file
*/
static LPVOID createFileMappingView(const WCHAR * filePath, DWORD accessFile, DWORD flProtect, DWORD accessMap);
/*
* Read memory from target process
*/
static bool readMemoryFromProcess(DWORD_PTR address, SIZE_T size, LPVOID dataBuffer);
/*
* Read memory from file
*/
static bool readMemoryFromFile(HANDLE hFile, LONG offset, DWORD size, LPVOID dataBuffer);
/*
* Write memory to file
*/
static bool writeMemoryToFile(HANDLE hFile, LONG offset, DWORD size, LPCVOID dataBuffer);
/*
* Write memory to file end
*/
static bool writeMemoryToFileEnd(HANDLE hFile, DWORD size, LPCVOID dataBuffer);
/*
* Disassemble Memory
*/
static bool disassembleMemory(BYTE * dataBuffer, SIZE_T bufferSize, DWORD_PTR startOffset);
static bool decomposeMemory(BYTE * dataBuffer, SIZE_T bufferSize, DWORD_PTR startAddress);
/*
* Search for pattern
*/
static DWORD_PTR findPattern(DWORD_PTR startOffset, DWORD size, BYTE * pattern, const char * mask);
/*
* Get process ID by process name
*/
static DWORD getProcessByName(const WCHAR * processName);
/*
* Get memory region from address
*/
static bool getMemoryRegionFromAddress(DWORD_PTR address, DWORD_PTR * memoryRegionBase, SIZE_T * memoryRegionSize);
/*
* Read PE Header from file
*/
static bool readHeaderFromFile(BYTE * buffer, DWORD bufferSize, const WCHAR * filePath);
static bool readHeaderFromCurrentFile(const WCHAR * filePath);
/*
* Get real sizeOfImage value
*/
static SIZE_T getSizeOfImageProcess(HANDLE processHandle, DWORD_PTR moduleBase);
/*
* Get real sizeOfImage value current process
*/
static bool getSizeOfImageCurrentProcess();
static LONGLONG getFileSize(HANDLE hFile);
static LONGLONG getFileSize(const WCHAR * filePath);
static DWORD getEntryPointFromFile(const WCHAR * filePath);
static bool createBackupFile(const WCHAR * filePath);
};
diff --git a/Scylla/ProcessLister.h b/Scylla/ProcessLister.h
index 4a61362..a93630e 100644
--- a/Scylla/ProcessLister.h
+++ b/Scylla/ProcessLister.h
@@ -1,73 +1,70 @@
#pragma once
#include <windows.h>
#include <tlhelp32.h>
#include <vector>
-#include <Psapi.h>
-
-#pragma comment(lib, "Psapi.lib")
-
+#include <psapi.h>
typedef BOOL (WINAPI *def_IsWow64Process)(HANDLE hProcess,PBOOL Wow64Process);
class Process {
public:
DWORD PID;
DWORD_PTR imageBase;
DWORD entryPoint; //without imagebase
DWORD imageSize;
WCHAR filename[MAX_PATH];
WCHAR fullPath[MAX_PATH];
Process()
{
PID = 0;
}
};
class HardDisk {
public:
WCHAR shortName[3];
WCHAR longName[MAX_PATH];
size_t longNameLength;
};
enum ProcessType {
PROCESS_UNKNOWN,
PROCESS_MISSING_RIGHTS,
PROCESS_32,
PROCESS_64
};
class ProcessLister {
public:
static def_IsWow64Process _IsWow64Process;
ProcessLister()
{
initDeviceNameList();
_IsWow64Process = (def_IsWow64Process)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "IsWow64Process");
}
std::vector<Process>& getProcessList();
static bool isWindows64();
static DWORD setDebugPrivileges();
std::vector<Process>& ProcessLister::getProcessListSnapshot();
private:
std::vector<Process> processList;
std::vector<HardDisk> deviceNameList;
ProcessType checkIsProcess64(DWORD dwPID);
void initDeviceNameList();
bool getAbsoluteFilePath(Process * process);
void getAllModuleInformation();
void getModuleInformationByProcess(Process *process);
bool resolveDeviceLongNameToShort( WCHAR * sourcePath, WCHAR * targetPath );
};
\ No newline at end of file
diff --git a/Scylla/SystemInformation.cpp b/Scylla/SystemInformation.cpp
index da8918d..efc9f1c 100644
--- a/Scylla/SystemInformation.cpp
+++ b/Scylla/SystemInformation.cpp
@@ -1,76 +1,76 @@
#include "SystemInformation.h"
OPERATING_SYSTEM SystemInformation::currenOS = UNKNOWN_OS;
bool SystemInformation::getSystemInformation()
{
OSVERSIONINFOEX osvi = {0};
SYSTEM_INFO si = {0};
def_GetNativeSystemInfo _GetNativeSystemInfo = 0;
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
if (!GetVersionEx((OSVERSIONINFO*) &osvi))
{
return false;
}
if ((osvi.dwMajorVersion < 5) || ((osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion == 0)))
{
return false;
}
_GetNativeSystemInfo = (def_GetNativeSystemInfo)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "GetNativeSystemInfo");
if (_GetNativeSystemInfo)
{
_GetNativeSystemInfo(&si);
}
else
{
GetSystemInfo(&si);
}
bool isX64 = si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64;
bool isX86 = si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL;
DWORD major = osvi.dwMajorVersion;
DWORD minor = osvi.dwMinorVersion;
if(isX64 && major == 5 && minor == 2)
{
currenOS = WIN_XP_64;
}
else if(isX86 && major == 5 && minor == 1)
{
currenOS = WIN_XP_32;
}
- if(isX64 && major == 6 && minor == 0)
+ else if(isX64 && major == 6 && minor == 0)
{
currenOS = WIN_VISTA_64;
}
else if(isX86 && major == 6 && minor == 0)
{
currenOS = WIN_VISTA_32;
}
else if(isX64 && major == 6 && minor == 1)
{
currenOS = WIN_7_64;
}
else if(isX86 && major == 6 && minor == 1)
{
currenOS = WIN_7_32;
}
else if(isX64 && major == 6 && minor == 2)
{
currenOS = WIN_8_64;
}
else if(isX86 && major == 6 && minor == 2)
{
currenOS = WIN_8_32;
}
else
{
currenOS = UNKNOWN_OS;
}
return (currenOS != UNKNOWN_OS);
}
diff --git a/Scylla/SystemInformation.h b/Scylla/SystemInformation.h
index e687a6a..aef7f69 100644
--- a/Scylla/SystemInformation.h
+++ b/Scylla/SystemInformation.h
@@ -1,24 +1,25 @@
#pragma once
#include <windows.h>
enum OPERATING_SYSTEM {
UNKNOWN_OS,
WIN_XP_32,
WIN_XP_64,
WIN_VISTA_32,
WIN_VISTA_64,
WIN_7_32,
WIN_7_64,
WIN_8_32,
WIN_8_64
};
typedef void (WINAPI *def_GetNativeSystemInfo)(LPSYSTEM_INFO lpSystemInfo);
-class SystemInformation {
+class SystemInformation
+{
public:
+
static OPERATING_SYSTEM currenOS;
static bool getSystemInformation();
-private:
};
diff --git a/Scylla/Thunks.h b/Scylla/Thunks.h
index 9cb935b..5c31d19 100644
--- a/Scylla/Thunks.h
+++ b/Scylla/Thunks.h
@@ -1,44 +1,43 @@
#pragma once
#include <windows.h>
-#include <Commctrl.h>
#include <map>
// WTL
#include <atlbase.h>
#include <atlapp.h>
-#include <atlctrls.h> //CTreeItem
+#include <atlctrls.h> // CTreeItem
class ImportThunk
{
public:
WCHAR moduleName[MAX_PATH];
char name[MAX_PATH];
DWORD_PTR va;
DWORD_PTR rva;
WORD ordinal;
DWORD_PTR apiAddressVA;
WORD hint;
bool valid;
bool suspect;
CTreeItem hTreeItem;
DWORD_PTR key;
void invalidate();
};
class ImportModuleThunk
{
public:
WCHAR moduleName[MAX_PATH];
std::map<DWORD_PTR, ImportThunk> thunkList;
DWORD_PTR firstThunk;
CTreeItem hTreeItem;
DWORD_PTR key;
DWORD_PTR getFirstThunk() const;
bool isValid() const;
};
diff --git a/Scylla/TreeImportExport.cpp b/Scylla/TreeImportExport.cpp
index a6cf3e2..43eb64c 100644
--- a/Scylla/TreeImportExport.cpp
+++ b/Scylla/TreeImportExport.cpp
@@ -1,346 +1,337 @@
-
#include "TreeImportExport.h"
#include "Architecture.h"
#include "Scylla.h"
-
-#define DEBUG_COMMENTS
+#include "StringConversion.h"
bool TreeImportExport::exportTreeList(const WCHAR * targetXmlFile, std::map<DWORD_PTR, ImportModuleThunk> & moduleList, const Process * process, const DWORD_PTR addressOEP, const DWORD_PTR addressIAT, const DWORD sizeIAT)
{
TiXmlDocument doc;
- TiXmlDeclaration * decl = new TiXmlDeclaration( "1.0", "", "" );
+ TiXmlDeclaration * decl = new TiXmlDeclaration( "1.0", "", "");
doc.LinkEndChild(decl);
TiXmlElement * rootElement = new TiXmlElement("target");
setTargetInformation(rootElement, process,addressOEP,addressIAT,sizeIAT);
addModuleListToRootElement(rootElement, moduleList);
doc.LinkEndChild(rootElement);
return saveXmlToFile(doc,targetXmlFile);
}
bool TreeImportExport::importTreeList(const WCHAR * targetXmlFile, std::map<DWORD_PTR, ImportModuleThunk> & moduleList, DWORD_PTR * addressOEP, DWORD_PTR * addressIAT, DWORD * sizeIAT)
{
TiXmlElement * targetElement;
TiXmlDocument doc;
char * buffer = readXmlFile(targetXmlFile);
int count = 0;
moduleList.clear();
if (buffer)
{
doc.Parse(buffer);
if (doc.Error())
{
Scylla::windowLog.log(L"Load Tree :: Error parsing xml %S: %S\r\n", doc.Value(), doc.ErrorDesc());
delete [] buffer;
return false;
}
targetElement = doc.FirstChildElement();
*addressOEP = ConvertStringToDwordPtr(targetElement->Attribute("oep_va"));
*addressIAT = ConvertStringToDwordPtr(targetElement->Attribute("iat_va"));
*sizeIAT = (DWORD)ConvertStringToDwordPtr(targetElement->Attribute("iat_size"));
//test = targetElement->Attribute("filename");
parseAllElementModules(targetElement, moduleList);
delete [] buffer;
}
return true;
}
void TreeImportExport::setTargetInformation(TiXmlElement * rootElement, const Process * process, const DWORD_PTR addressOEP, const DWORD_PTR addressIAT, const DWORD sizeIAT)
{
- size_t stringLength = 0;
-
- wcstombs_s(&stringLength, xmlStringBuffer, (size_t)_countof(xmlStringBuffer), process->filename, (size_t)_countof(process->filename));
-
-
+ StringConversion::ToASCII(process->filename, xmlStringBuffer, _countof(xmlStringBuffer));
rootElement->SetAttribute("filename", xmlStringBuffer);
ConvertDwordPtrToString(addressOEP);
- rootElement->SetAttribute("oep_va",xmlStringBuffer);
+ rootElement->SetAttribute("oep_va", xmlStringBuffer);
ConvertDwordPtrToString(addressIAT);
- rootElement->SetAttribute("iat_va",xmlStringBuffer);
+ rootElement->SetAttribute("iat_va", xmlStringBuffer);
ConvertDwordPtrToString(sizeIAT);
- rootElement->SetAttribute("iat_size",xmlStringBuffer);
+ rootElement->SetAttribute("iat_size", xmlStringBuffer);
}
char * TreeImportExport::readXmlFile(const WCHAR * xmlFilePath)
{
FILE * pFile = 0;
long lSize = 0;
char * buffer = 0;
if (_wfopen_s(&pFile,xmlFilePath,L"r") == NULL)
{
fseek(pFile, 0, SEEK_END);
lSize = ftell(pFile);
fseek(pFile, 0, SEEK_SET);
if (lSize > 2)
{
buffer = new char[lSize + sizeof(char)];
ZeroMemory(buffer, lSize + sizeof(char));
fread(buffer, sizeof(char), lSize, pFile);
if (!feof(pFile) || ferror(pFile))
{
delete [] buffer;
buffer = 0;
}
}
fclose (pFile);
return buffer;
}
else
{
return 0;
}
}
bool TreeImportExport::saveXmlToFile(TiXmlDocument doc, const WCHAR * xmlFilePath)
{
FILE * pFile = 0;
if (_wfopen_s(&pFile,xmlFilePath,L"w") == NULL)
{
doc.Print(pFile);
fclose (pFile);
return true;
}
else
{
return false;
}
}
void TreeImportExport::addModuleListToRootElement( TiXmlElement * rootElement, std::map<DWORD_PTR, ImportModuleThunk> & moduleList )
{
std::map<DWORD_PTR, ImportModuleThunk>::iterator mapIt;
std::map<DWORD_PTR, ImportThunk>::iterator mapIt2;
ImportModuleThunk * importModuleThunk = 0;
ImportThunk * importThunk = 0;
TiXmlElement * moduleElement;
TiXmlElement * importElement;
for ( mapIt = moduleList.begin() ; mapIt != moduleList.end(); mapIt++ )
{
importModuleThunk = &((*mapIt).second);
moduleElement = getModuleXmlElement(importModuleThunk);
for ( mapIt2 = (*mapIt).second.thunkList.begin() ; mapIt2 != (*mapIt).second.thunkList.end(); mapIt2++ )
{
importThunk = &((*mapIt2).second);
importElement = getImportXmlElement(importThunk);
moduleElement->LinkEndChild(importElement);
}
rootElement->LinkEndChild(moduleElement);
}
}
TiXmlElement * TreeImportExport::getModuleXmlElement(const ImportModuleThunk * importModuleThunk)
{
- size_t stringLength = 0;
TiXmlElement * moduleElement = new TiXmlElement("module");
- wcstombs_s(&stringLength, xmlStringBuffer, (size_t)_countof(xmlStringBuffer), importModuleThunk->moduleName, (size_t)_countof(importModuleThunk->moduleName));
-
+ StringConversion::ToASCII(importModuleThunk->moduleName, xmlStringBuffer, _countof(xmlStringBuffer));
moduleElement->SetAttribute("filename", xmlStringBuffer);
ConvertDwordPtrToString(importModuleThunk->getFirstThunk());
moduleElement->SetAttribute("first_thunk_rva",xmlStringBuffer);
return moduleElement;
}
TiXmlElement * TreeImportExport::getImportXmlElement(const ImportThunk * importThunk)
{
TiXmlElement * importElement = 0;
if (importThunk->valid)
{
importElement = new TiXmlElement("import_valid");
if(importThunk->name[0] != '\0')
{
importElement->SetAttribute("name",importThunk->name);
}
ConvertWordToString(importThunk->ordinal);
importElement->SetAttribute("ordinal",xmlStringBuffer);
ConvertWordToString(importThunk->hint);
importElement->SetAttribute("hint",xmlStringBuffer);
ConvertBoolToString(importThunk->suspect);
importElement->SetAttribute("suspect", xmlStringBuffer);
}
else
{
importElement = new TiXmlElement("import_invalid");
}
ConvertDwordPtrToString(importThunk->rva);
importElement->SetAttribute("iat_rva", xmlStringBuffer);
ConvertDwordPtrToString(importThunk->apiAddressVA);
importElement->SetAttribute("address_va",xmlStringBuffer);
return importElement;
}
void TreeImportExport::ConvertBoolToString(const bool boolValue)
{
if (boolValue)
{
- strcpy_s(xmlStringBuffer,_countof(xmlStringBuffer),"1");
+ strcpy_s(xmlStringBuffer,_countof(xmlStringBuffer), "1");
}
else
{
- strcpy_s(xmlStringBuffer,_countof(xmlStringBuffer),"0");
+ strcpy_s(xmlStringBuffer,_countof(xmlStringBuffer), "0");
}
}
bool TreeImportExport::ConvertStringToBool(const char * strValue)
{
if (strValue)
{
if (strValue[0] == '1')
{
return true;
}
}
return false;
}
void TreeImportExport::ConvertDwordPtrToString(const DWORD_PTR dwValue)
{
sprintf_s(xmlStringBuffer, _countof(xmlStringBuffer), PRINTF_DWORD_PTR_FULL_S, dwValue);
}
DWORD_PTR TreeImportExport::ConvertStringToDwordPtr(const char * strValue)
{
DWORD_PTR result = 0;
if (strValue)
{
#ifdef _WIN64
result = _strtoi64(strValue, NULL, 16);
#else
result = strtoul(strValue, NULL, 16);
#endif
}
return result;
}
void TreeImportExport::ConvertWordToString(const WORD dwValue)
{
sprintf_s(xmlStringBuffer, _countof(xmlStringBuffer), "%04X", dwValue);
}
WORD TreeImportExport::ConvertStringToWord(const char * strValue)
{
WORD result = 0;
if (strValue)
{
result = (WORD)strtoul(strValue, NULL, 16);
}
return result;
}
void TreeImportExport::parseAllElementModules( TiXmlElement * targetElement, std::map<DWORD_PTR, ImportModuleThunk> & moduleList )
{
TiXmlElement * moduleElement = 0;
ImportModuleThunk importModuleThunk;
- size_t convertedChars = 0;
const char * filename = 0;
for(moduleElement = targetElement->FirstChildElement(); moduleElement; moduleElement = moduleElement->NextSiblingElement())
{
filename = moduleElement->Attribute("filename");
if (filename)
{
+ StringConversion::ToUTF16(filename, importModuleThunk.moduleName, _countof(importModuleThunk.moduleName));
- mbstowcs_s(&convertedChars, importModuleThunk.moduleName, _countof(importModuleThunk.moduleName), filename, _TRUNCATE);
importModuleThunk.firstThunk = ConvertStringToDwordPtr(moduleElement->Attribute("first_thunk_rva"));
importModuleThunk.thunkList.clear();
parseAllElementImports(moduleElement, &importModuleThunk);
moduleList.insert(std::pair<DWORD_PTR,ImportModuleThunk>(importModuleThunk.firstThunk, importModuleThunk));
}
}
}
void TreeImportExport::parseAllElementImports( TiXmlElement * moduleElement, ImportModuleThunk * importModuleThunk )
{
TiXmlElement * importElement = 0;
ImportThunk importThunk;
const char * temp = 0;
for(importElement = moduleElement->FirstChildElement(); importElement; importElement = importElement->NextSiblingElement())
{
temp = importElement->Value();
if (!strcmp(temp, "import_valid"))
{
temp = importElement->Attribute("name");
if (temp)
{
strcpy_s(importThunk.name, _countof(importThunk.name),temp);
}
else
{
importThunk.name[0] = 0;
}
wcscpy_s(importThunk.moduleName,_countof(importThunk.moduleName), importModuleThunk->moduleName);
importThunk.suspect = ConvertStringToBool(importElement->Attribute("suspect"));
importThunk.ordinal = ConvertStringToWord(importElement->Attribute("ordinal"));
importThunk.hint = ConvertStringToWord(importElement->Attribute("hint"));
importThunk.valid = true;
}
else
{
importThunk.valid = false;
importThunk.suspect = true;
}
importThunk.apiAddressVA = ConvertStringToDwordPtr(importElement->Attribute("address_va"));
importThunk.rva = ConvertStringToDwordPtr(importElement->Attribute("iat_rva"));
if (importThunk.rva != 0)
{
importModuleThunk->thunkList.insert(std::pair<DWORD_PTR,ImportThunk>(importThunk.rva, importThunk));
}
}
}
diff --git a/Scylla/TreeImportExport.h b/Scylla/TreeImportExport.h
index 33c3893..443807a 100644
--- a/Scylla/TreeImportExport.h
+++ b/Scylla/TreeImportExport.h
@@ -1,42 +1,38 @@
-
#pragma once
-#include <Windows.h>
+#include <windows.h>
#include "ProcessLister.h"
#include "Thunks.h"
-#include "tinyxml.h"
-
-
+#include <tinyxml.h>
class TreeImportExport
{
public:
+
bool exportTreeList(const WCHAR * targetXmlFile, std::map<DWORD_PTR, ImportModuleThunk> & moduleList, const Process * process, const DWORD_PTR addressOEP, const DWORD_PTR addressIAT, const DWORD sizeIAT);
-
bool importTreeList(const WCHAR * targetXmlFile, std::map<DWORD_PTR, ImportModuleThunk> & moduleList, DWORD_PTR * addressOEP, DWORD_PTR * addressIAT, DWORD * sizeIAT);
private:
+
char xmlStringBuffer[100];
void addModuleListToRootElement( TiXmlElement * rootElement, std::map<DWORD_PTR, ImportModuleThunk> & moduleList );
TiXmlElement * getModuleXmlElement(const ImportModuleThunk * importModuleThunk);
TiXmlElement * getImportXmlElement(const ImportThunk * importThunk);
bool saveXmlToFile(TiXmlDocument doc, const WCHAR * xmlFilePath);
char * readXmlFile(const WCHAR * xmlFilePath);
void setTargetInformation(TiXmlElement * rootElement, const Process * process, const DWORD_PTR addressOEP, const DWORD_PTR addressIAT, const DWORD sizeIAT);
void ConvertBoolToString(const bool boolValue);
void ConvertWordToString(const WORD dwValue);
void ConvertDwordPtrToString(const DWORD_PTR dwValue);
DWORD_PTR ConvertStringToDwordPtr(const char * strValue);
WORD ConvertStringToWord(const char * strValue);
bool ConvertStringToBool(const char * strValue);
-
-
void parseAllElementModules( TiXmlElement * targetElement, std::map<DWORD_PTR, ImportModuleThunk> & moduleList );
void parseAllElementImports( TiXmlElement * moduleElement, ImportModuleThunk * importModuleThunk );
-};
\ No newline at end of file
+};
diff --git a/Scylla/hexedit.h b/Scylla/hexedit.h
index 0e68680..dabdf6e 100644
--- a/Scylla/hexedit.h
+++ b/Scylla/hexedit.h
@@ -1,235 +1,235 @@
#pragma once
#ifndef __cplusplus
#error WTL requires C++ compilation (use a .cpp suffix)
#endif
#ifndef __ATLMISC_H__
#error hexedit.h requires atlmisc.h to be included first
#endif
#ifndef __ATLCTRLS_H__
- #error hexedit.h requires atlmisc.h to be included first requires atlctrls.h to be included first
+ #error hexedit.h requires atlctrls.h to be included first
#endif
/*
#ifdef _WIN64
address = _wcstoui64(hexString, NULL, 16);
#else
address = wcstoul(hexString, NULL, 16);
#endif
*/
template< class T, typename NUM_T, class TBase = CEdit, class TWinTraits = CControlWinTraits >
class ATL_NO_VTABLE CHexEditImpl : public CWindowImpl< T, TBase, TWinTraits >
{
public:
static const short int BASE = 16;
static const size_t DIGITS = sizeof(NUM_T) * 2; // 2 digits / byte
static const size_t STRSIZE = DIGITS + 1;
static const TCHAR Digits[];
static const TCHAR OldProcProp[];
// Operations
BOOL SubclassWindow(HWND hWnd)
{
ATLASSERT(m_hWnd == NULL);
ATLASSERT(::IsWindow(hWnd));
BOOL bRet = CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd);
if( bRet ) _Init();
return bRet;
}
NUM_T GetValue() const
{
ATLASSERT(::IsWindow(m_hWnd));
TCHAR String[STRSIZE] = { 0 };
GetWindowText(String, _countof(String));
return _StringToNum(String);
}
void SetValue(NUM_T Num, bool Fill = true)
{
ATLASSERT(::IsWindow(m_hWnd));
TCHAR String[STRSIZE] = { 0 };
_NumToString(Num, String, Fill);
SetWindowText(String);
}
// Implementation
void _Init()
{
ATLASSERT(::IsWindow(m_hWnd));
LimitText(DIGITS);
}
bool _IsValidChar(TCHAR Char) const
{
return ((NUM_T)-1 != _CharToNum(Char));
}
bool _IsValidString(const TCHAR String[STRSIZE]) const
{
for(int i = 0; String[i]; i++)
{
if(!_IsValidChar(String[i]))
return false;
}
return true;
}
NUM_T _CharToNum(TCHAR Char) const
{
Char = _totupper(Char);
for(int i = 0; Digits[i]; i++)
{
if(Char == Digits[i])
return i;
}
return -1;
}
NUM_T _StringToNum(const TCHAR String[STRSIZE]) const
{
NUM_T CharNum;
NUM_T Num = 0;
for(int i = 0; String[i]; i++)
{
CharNum = _CharToNum(String[i]);
if(CharNum == (NUM_T)-1)
break;
Num *= BASE;
Num += CharNum;
}
return Num;
}
TCHAR _NumToChar(NUM_T Num) const
{
return Digits[Num % BASE];
}
void _NumToString(NUM_T Num, TCHAR String[STRSIZE], bool Fill) const
{
NUM_T Nums[DIGITS];
int i, j;
for(i = DIGITS-1; i >= 0; i--)
{
Nums[i] = Num % BASE;
Num /= BASE;
}
for(i = j = 0; i < DIGITS; i++)
{
// Only copy num if : non-null OR Fill OR non-null encountered before OR last num
if(Nums[i] || Fill || j || i == DIGITS-1)
{
String[j++] = _NumToChar(Nums[i]);
}
}
String[j] = '\0';
}
bool _GetClipboardText(TCHAR String[STRSIZE])
{
#ifdef UNICODE
const UINT Format = CF_UNICODETEXT;
#else
const UINT Format = CF_TEXT;
#endif
bool RetVal = false;
if(IsClipboardFormatAvailable(Format) && OpenClipboard())
{
HANDLE HMem = GetClipboardData(Format);
if(HMem)
{
_tcsncpy_s(String, STRSIZE, (TCHAR *)GlobalLock(HMem), STRSIZE-1);
String[STRSIZE-1] = '\0';
GlobalUnlock(HMem);
RetVal = true;
}
CloseClipboard();
}
return RetVal;
}
// Message map and handlers
BEGIN_MSG_MAP_EX(CHexEditImpl)
MESSAGE_HANDLER_EX(WM_CREATE, OnCreate)
MSG_WM_SETTEXT(OnSetText)
MSG_WM_PASTE(OnPaste)
MSG_WM_CHAR(OnChar)
END_MSG_MAP()
LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LRESULT lRes = DefWindowProc();
_Init();
return lRes;
}
int OnSetText(LPCTSTR lpstrText)
{
bool PassThrough = (_tcslen(lpstrText) <= DIGITS) && _IsValidString(lpstrText);
if(!PassThrough)
{
MessageBeep(-1);
return FALSE;
}
SetMsgHandled(FALSE);
return TRUE;
}
void OnPaste()
{
TCHAR String[STRSIZE];
bool PassThrough = !_GetClipboardText(String) || _IsValidString(String);
if(!PassThrough)
{
MessageBeep(-1);
return;
}
SetMsgHandled(FALSE);
return;
}
void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// ignore all printable chars (incl. space) which are not valid digits
bool PassThrough = !_istprint((TCHAR)nChar) || _IsValidChar((TCHAR)nChar);
if(!PassThrough)
{
MessageBeep(-1);
return;
}
SetMsgHandled(FALSE);
return;
}
};
template< class T, typename NUM_T, class TBase, class TWinTraits > const TCHAR CHexEditImpl< T, NUM_T, TBase, TWinTraits >::Digits[] = _T("0123456789ABCDEF");
template<typename NUM_T> class CHexEdit : public CHexEditImpl<CHexEdit<NUM_T>, NUM_T>
{
public:
DECLARE_WND_CLASS(_T("WTL_HexEdit"))
};

File Metadata

Mime Type
text/x-diff
Expires
Sat, Jul 5, 8:03 PM (1 d, 12 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
01/a5/91b85befbe87dbaa46e8adcef984

Event Timeline