diff --git a/Scylla/ApiReader.cpp b/Scylla/ApiReader.cpp index 9b9092b..66a7b4a 100644 --- a/Scylla/ApiReader.cpp +++ b/Scylla/ApiReader.cpp @@ -1,1201 +1,1209 @@ #include "ApiReader.h" #include "Scylla.h" #include "Architecture.h" #include "SystemInformation.h" #include "StringConversion.h" +#include "PeParser.h" stdext::hash_multimap ApiReader::apiList; //api look up table std::map * ApiReader::moduleThunkList; //store found apis DWORD_PTR ApiReader::minApiAddress = 0xFFFFFFFF; DWORD_PTR ApiReader::maxApiAddress = 0; -//#define DEBUG_COMMENTS +#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, 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, ".dll"); 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, 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 (!bufferExportTable) + { +#ifdef DEBUG_COMMENTS + Scylla::debugLog.log(L"Something is wrong with the PE Header here Export table size %d", readSize); +#endif + return 0; + } + 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; + PeParser peParser(module->fullPath, false); + if (!peParser.isValidPeFile()) + return; - bufferHeader = getHeaderFromProcess(module); + pNtHeader = peParser.getCurrentNtHeader(); - if (bufferHeader == 0) - return; - - pDosHeader = (PIMAGE_DOS_HEADER)bufferHeader; - pNtHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)bufferHeader + (DWORD_PTR)(pDosHeader->e_lfanew)); - - if (isPeAndExportTableValid(pNtHeader)) + if (peParser.hasExportDirectory()) { 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 (vaApi) { if (ordinal) { *vaApi = (DWORD_PTR)GetProcAddress(hModule, (LPCSTR)ordinal); } else { *vaApi = (DWORD_PTR)GetProcAddress(hModule, searchFunctionName); } *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 if (!_wcsnicmp(moduleFileName, L"api-ms-win-", 11)) + { + module->priority = 0; + } 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::iterator it1, it2; size_t c = 0; size_t countDuplicates = apiList.count(virtualAddress); int countHighPriority = 0; ApiInfo *apiFound = 0; if (countDuplicates == 0) { 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::getScoredApi(stdext::hash_multimap::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 &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); 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 (!isInvalidMemoryForIat(pIATAddress[i])) { if ( (pIATAddress[i] > minApiAddress) && (pIATAddress[i] < maxApiAddress) ) { apiFound = getApiByVirtualAddress(pIATAddress[i], &isSuspect); if (apiFound == 0) { Scylla::windowLog.log(L"getApiByVirtualAddress :: No Api found " PRINTF_DWORD_PTR_FULL, pIATAddress[i]); } 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, moduleName); (*moduleThunkList).insert(std::pair(firstThunk,module)); return true; } void ApiReader::addUnknownModuleToModuleList(DWORD_PTR firstThunk) { ImportModuleThunk module; module.firstThunk = firstThunk; wcscpy_s(module.moduleName, L"?"); (*moduleThunkList).insert(std::pair(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::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, apiFound->module->getFilename()); strcpy_s(import.name, apiFound->name); module->thunkList.insert(std::pair(import.rva, import)); return true; } void ApiReader::clearAll() { minApiAddress = -1; maxApiAddress = 0; for ( stdext::hash_map::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::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, L"?"); strcpy_s(import.name, "?"); module->thunkList.insert(std::pair(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; } } bool ApiReader::isInvalidMemoryForIat( DWORD_PTR address ) { if (address == 0) return true; if (address == -1) return true; MEMORY_BASIC_INFORMATION memBasic = {0}; if (VirtualQueryEx(ProcessAccessHelp::hProcess, (LPCVOID)address, &memBasic, sizeof(MEMORY_BASIC_INFORMATION))) { if((memBasic.State == MEM_COMMIT) && ProcessAccessHelp::isPageExecutable(memBasic.Protect)) { return false; } else { return true; } } else { return true; } } diff --git a/Scylla/ApiReader.h b/Scylla/ApiReader.h index 425083b..955640a 100644 --- a/Scylla/ApiReader.h +++ b/Scylla/ApiReader.h @@ -1,75 +1,75 @@ #pragma once #include #include #include #include "ProcessAccessHelp.h" #include "Thunks.h" typedef std::pair API_Pair; class ApiReader : public ProcessAccessHelp { public: static stdext::hash_multimap apiList; //api look up table static std::map * 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 &moduleListNew ); void addFoundApiToModuleList(DWORD_PTR iatAddress, ApiInfo * apiFound, bool isNewModule, bool isSuspect); void clearAll(); - + bool isInvalidMemoryForIat( DWORD_PTR address ); 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 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_map::iterator it1,size_t countDuplicates, bool hasName, bool hasUnicodeAnsiName, bool hasNoUnderlineInName, bool hasPrioDll,bool hasPrio0Dll,bool hasPrio1Dll, bool hasPrio2Dll, bool firstWin ); - bool isInvalidMemoryForIat( DWORD_PTR address ); + }; diff --git a/Scylla/IATSearch.cpp b/Scylla/IATSearch.cpp index 130f3f1..404fb97 100644 --- a/Scylla/IATSearch.cpp +++ b/Scylla/IATSearch.cpp @@ -1,509 +1,545 @@ #include "IATSearch.h" #include "Scylla.h" #include "Architecture.h" //#define DEBUG_COMMENTS bool IATSearch::searchImportAddressTableInProcess( DWORD_PTR startAddress, DWORD_PTR* addressIAT, DWORD* sizeIAT, bool advanced ) { DWORD_PTR addressInIAT = 0; *addressIAT = 0; *sizeIAT = 0; if (advanced) { return findIATAdvanced(startAddress, addressIAT, sizeIAT); } addressInIAT = findAPIAddressInIAT(startAddress); if(!addressInIAT) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"searchImportAddressTableInProcess :: addressInIAT not found, startAddress " PRINTF_DWORD_PTR_FULL, startAddress); #endif return false; } else { return findIATStartAndSize(addressInIAT, addressIAT,sizeIAT); } } bool IATSearch::findIATAdvanced( DWORD_PTR startAddress, DWORD_PTR* addressIAT, DWORD* sizeIAT ) { BYTE *dataBuffer; DWORD_PTR baseAddress; SIZE_T memorySize; findExecutableMemoryPagesByStartAddress(startAddress, &baseAddress, &memorySize); if (memorySize == 0) return false; dataBuffer = new BYTE[memorySize]; if (!readMemoryFromProcess((DWORD_PTR)baseAddress, memorySize,dataBuffer)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"findAPIAddressInIAT2 :: error reading memory"); #endif return false; } std::set iatPointers; DWORD_PTR next; BYTE * tempBuf = dataBuffer; while(decomposeMemory(tempBuf, memorySize, (DWORD_PTR)baseAddress) && decomposerInstructionsCount != 0) { findIATPointers(iatPointers); next = (DWORD_PTR)(decomposerResult[decomposerInstructionsCount - 1].addr - baseAddress); next += decomposerResult[decomposerInstructionsCount - 1].size; // Advance ptr and recalc offset. tempBuf += next; if (memorySize <= next) { break; } memorySize -= next; baseAddress += next; } if (iatPointers.size() == 0) return false; filterIATPointersList(iatPointers); *addressIAT = *(iatPointers.begin()); *sizeIAT = (DWORD)(*(--iatPointers.end()) - *(iatPointers.begin()) + sizeof(DWORD_PTR)); - Scylla::windowLog.log(L"IAT Search Advanced: Found %d (0x%X) possible IAT entries.", iatPointers.size(), iatPointers.size()); - Scylla::windowLog.log(L"IAT Search Advanced: Possible IAT first " PRINTF_DWORD_PTR_FULL L" last " PRINTF_DWORD_PTR_FULL L" entry.", *(iatPointers.begin()), *(--iatPointers.end())); + Scylla::windowLog.log(L"IAT Search Adv: Found %d (0x%X) possible IAT entries.", iatPointers.size(), iatPointers.size()); + Scylla::windowLog.log(L"IAT Search Adv: Possible IAT first " PRINTF_DWORD_PTR_FULL L" last " PRINTF_DWORD_PTR_FULL L" entry.", *(iatPointers.begin()), *(--iatPointers.end())); delete [] dataBuffer; return true; } DWORD_PTR IATSearch::findAPIAddressInIAT(DWORD_PTR startAddress) { const size_t MEMORY_READ_SIZE = 200; BYTE dataBuffer[MEMORY_READ_SIZE]; DWORD_PTR iatPointer = 0; int counter = 0; // to detect stolen api memoryAddress = 0; memorySize = 0; do { counter++; if (!readMemoryFromProcess(startAddress, sizeof(dataBuffer), dataBuffer)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"findAPIAddressInIAT :: error reading memory " PRINTF_DWORD_PTR_FULL, startAddress); #endif return 0; } if (decomposeMemory(dataBuffer, sizeof(dataBuffer), startAddress)) { iatPointer = findIATPointer(); if (iatPointer) { - if (isIATPointerValid(iatPointer)) + if (isIATPointerValid(iatPointer, true)) { return iatPointer; } } } startAddress = findNextFunctionAddress(); //printf("startAddress %08X\n",startAddress); } while (startAddress != 0 && counter != 8); return 0; } DWORD_PTR IATSearch::findNextFunctionAddress() { #ifdef DEBUG_COMMENTS _DecodedInst inst; #endif for (unsigned int i = 0; i < decomposerInstructionsCount; i++) { if (decomposerResult[i].flags != FLAG_NOT_DECODABLE) { if (META_GET_FC(decomposerResult[i].meta) == FC_CALL || META_GET_FC(decomposerResult[i].meta) == FC_UNC_BRANCH) { if (decomposerResult[i].size >= 5) { if (decomposerResult[i].ops[0].type == O_PC) { #ifdef DEBUG_COMMENTS distorm_format(&decomposerCi, &decomposerResult[i], &inst); Scylla::debugLog.log(L"%S %S %d %d - target address: " PRINTF_DWORD_PTR_FULL, inst.mnemonic.p, inst.operands.p, decomposerResult[i].ops[0].type, decomposerResult[i].size, INSTRUCTION_GET_TARGET(&decomposerResult[i])); #endif return (DWORD_PTR)INSTRUCTION_GET_TARGET(&decomposerResult[i]); } } } } } return 0; } DWORD_PTR IATSearch::findIATPointer() { #ifdef DEBUG_COMMENTS _DecodedInst inst; #endif for (unsigned int i = 0; i < decomposerInstructionsCount; i++) { if (decomposerResult[i].flags != FLAG_NOT_DECODABLE) { if (META_GET_FC(decomposerResult[i].meta) == FC_CALL || META_GET_FC(decomposerResult[i].meta) == FC_UNC_BRANCH) { if (decomposerResult[i].size >= 5) { #ifdef _WIN64 if (decomposerResult[i].flags & FLAG_RIP_RELATIVE) { #ifdef DEBUG_COMMENTS distorm_format(&decomposerCi, &decomposerResult[i], &inst); Scylla::debugLog.log(L"%S %S %d %d - target address: " PRINTF_DWORD_PTR_FULL, inst.mnemonic.p, inst.operands.p, decomposerResult[i].ops[0].type, decomposerResult[i].size, INSTRUCTION_GET_RIP_TARGET(&decomposerResult[i])); #endif return INSTRUCTION_GET_RIP_TARGET(&decomposerResult[i]); } #else if (decomposerResult[i].ops[0].type == O_DISP) { //jmp dword ptr || call dword ptr #ifdef DEBUG_COMMENTS distorm_format(&decomposerCi, &decomposerResult[i], &inst); Scylla::debugLog.log(L"%S %S %d %d - target address: " PRINTF_DWORD_PTR_FULL, inst.mnemonic.p, inst.operands.p, decomposerResult[i].ops[0].type, decomposerResult[i].size, decomposerResult[i].disp); #endif return (DWORD_PTR)decomposerResult[i].disp; } #endif } } } } return 0; } -bool IATSearch::isIATPointerValid(DWORD_PTR iatPointer) +bool IATSearch::isIATPointerValid(DWORD_PTR iatPointer, bool checkRedirects) { DWORD_PTR apiAddress = 0; if (!readMemoryFromProcess(iatPointer,sizeof(DWORD_PTR),&apiAddress)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"isIATPointerValid :: error reading memory"); #endif return false; } //printf("Win api ? %08X\n",apiAddress); if (isApiAddressValid(apiAddress) != 0) { return true; } else { - //maybe redirected import? - //if the address is 2 times inside a memory region it is possible a redirected api - if (apiAddress > memoryAddress && apiAddress < (memoryAddress+memorySize)) - { - return true; - } - else - { - getMemoryRegionFromAddress(apiAddress, &memoryAddress, &memorySize); - return false; - } - + + if (checkRedirects) + { + //maybe redirected import? + //if the address is 2 times inside a memory region it is possible a redirected api + if (apiAddress > memoryAddress && apiAddress < (memoryAddress+memorySize)) + { + return true; + } + else + { + getMemoryRegionFromAddress(apiAddress, &memoryAddress, &memorySize); + } + } } + + return false; } bool IATSearch::findIATStartAndSize(DWORD_PTR address, DWORD_PTR * addressIAT, DWORD * sizeIAT) { - MEMORY_BASIC_INFORMATION memBasic = {0}; BYTE *dataBuffer = 0; + DWORD_PTR baseAddress = 0; + DWORD baseSize = 0; - if (VirtualQueryEx(hProcess,(LPCVOID)address, &memBasic, sizeof(MEMORY_BASIC_INFORMATION)) != sizeof(MEMORY_BASIC_INFORMATION)) - { -#ifdef DEBUG_COMMENTS - Scylla::debugLog.log(L"findIATStartAddress :: VirtualQueryEx error %u", GetLastError()); -#endif - return false; - } + getMemoryBaseAndSizeForIat(address, &baseAddress, &baseSize); + + if (!baseAddress) + return false; + dataBuffer = new BYTE[baseSize * (sizeof(DWORD_PTR)*3)]; - //(sizeof(DWORD_PTR) * 3) added to prevent buffer overflow - dataBuffer = new BYTE[memBasic.RegionSize + (sizeof(DWORD_PTR) * 3)]; + if (!dataBuffer) + return false; - ZeroMemory(dataBuffer, memBasic.RegionSize + (sizeof(DWORD_PTR) * 3)); + ZeroMemory(dataBuffer, baseSize * (sizeof(DWORD_PTR)*3)); - if (!readMemoryFromProcess((DWORD_PTR)memBasic.BaseAddress, memBasic.RegionSize, dataBuffer)) + if (!readMemoryFromProcess(baseAddress, baseSize, dataBuffer)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"findIATStartAddress :: error reading memory"); #endif return false; } //printf("address %X memBasic.BaseAddress %X memBasic.RegionSize %X\n",address,memBasic.BaseAddress,memBasic.RegionSize); - *addressIAT = findIATStartAddress((DWORD_PTR)memBasic.BaseAddress, address, dataBuffer); + *addressIAT = findIATStartAddress(baseAddress, address, dataBuffer); - *sizeIAT = findIATSize((DWORD_PTR)memBasic.BaseAddress, *addressIAT, dataBuffer, (DWORD)memBasic.RegionSize); + *sizeIAT = findIATSize(baseAddress, *addressIAT, dataBuffer, baseSize); delete [] dataBuffer; return true; } DWORD_PTR IATSearch::findIATStartAddress(DWORD_PTR baseAddress, DWORD_PTR startAddress, BYTE * dataBuffer) { DWORD_PTR *pIATAddress = 0; pIATAddress = (DWORD_PTR *)((startAddress - baseAddress) + (DWORD_PTR)dataBuffer); while((DWORD_PTR)pIATAddress != (DWORD_PTR)dataBuffer) { - if ( (*pIATAddress < 0xFFFF) || !isAddressAccessable(*pIATAddress) ) + if (isInvalidMemoryForIat(*pIATAddress)) { - if ( (*(pIATAddress - 1) < 0xFFFF) || !isAddressAccessable(*(pIATAddress - 1)) ) - { - //IAT end - - if ((DWORD_PTR)(pIATAddress - 2) >= (DWORD_PTR)dataBuffer) - { - if (!isApiAddressValid(*(pIATAddress - 2))) - { - return (((DWORD_PTR)pIATAddress - (DWORD_PTR)dataBuffer) + baseAddress); - } - } - else - { - return (((DWORD_PTR)pIATAddress - (DWORD_PTR)dataBuffer) + baseAddress); - } - } + if ((DWORD_PTR)(pIATAddress - 1) >= (DWORD_PTR)dataBuffer) + { + if (isInvalidMemoryForIat(*(pIATAddress - 1))) + { + if ((DWORD_PTR)(pIATAddress - 2) >= (DWORD_PTR)dataBuffer) + { + if (!isApiAddressValid(*(pIATAddress - 2))) + { + return (((DWORD_PTR)pIATAddress - (DWORD_PTR)dataBuffer) + baseAddress); + } + } + } + } } pIATAddress--; } return baseAddress; } DWORD IATSearch::findIATSize(DWORD_PTR baseAddress, DWORD_PTR iatAddress, BYTE * dataBuffer, DWORD bufferSize) { DWORD_PTR *pIATAddress = 0; pIATAddress = (DWORD_PTR *)((iatAddress - baseAddress) + (DWORD_PTR)dataBuffer); #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"findIATSize :: baseAddress %X iatAddress %X dataBuffer %X pIATAddress %X", baseAddress, iatAddress, dataBuffer, pIATAddress); #endif while((DWORD_PTR)pIATAddress < ((DWORD_PTR)dataBuffer + bufferSize - 1)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"findIATSize :: %X %X %X", pIATAddress, *pIATAddress, *(pIATAddress + 1)); #endif - if ( (*pIATAddress < 0xFFFF) || !isAddressAccessable(*pIATAddress) ) //normal is 0 + if (isInvalidMemoryForIat(*pIATAddress)) //normal is 0 { - if ( (*(pIATAddress + 1) < 0xFFFF) || !isAddressAccessable(*(pIATAddress + 1)) ) + if (isInvalidMemoryForIat(*(pIATAddress + 1))) { //IAT end if (!isApiAddressValid(*(pIATAddress + 2))) { return (DWORD)((DWORD_PTR)pIATAddress - (DWORD_PTR)dataBuffer - (iatAddress - baseAddress)); } } } pIATAddress++; } return bufferSize; } -bool IATSearch::isAddressAccessable(DWORD_PTR address) -{ - BYTE junk[3]; - SIZE_T numberOfBytesRead = 0; - - if (ReadProcessMemory(hProcess, (LPCVOID)address, junk, sizeof(junk), &numberOfBytesRead)) - { - if (numberOfBytesRead == sizeof(junk)) - { - if (junk[0] != 0x00) - { - return true; - } - } - } - - return false; -} - void IATSearch::findIATPointers(std::set & iatPointers) { #ifdef DEBUG_COMMENTS _DecodedInst inst; #endif for (unsigned int i = 0; i < decomposerInstructionsCount; i++) { if (decomposerResult[i].flags != FLAG_NOT_DECODABLE) { if (META_GET_FC(decomposerResult[i].meta) == FC_CALL || META_GET_FC(decomposerResult[i].meta) == FC_UNC_BRANCH) { if (decomposerResult[i].size >= 5) { #ifdef _WIN64 if (decomposerResult[i].flags & FLAG_RIP_RELATIVE) { #ifdef DEBUG_COMMENTS distorm_format(&decomposerCi, &decomposerResult[i], &inst); Scylla::debugLog.log(L"%S %S %d %d - target address: " PRINTF_DWORD_PTR_FULL, inst.mnemonic.p, inst.operands.p, decomposerResult[i].ops[0].type, decomposerResult[i].size, INSTRUCTION_GET_RIP_TARGET(&decomposerResult[i])); #endif iatPointers.insert(INSTRUCTION_GET_RIP_TARGET(&decomposerResult[i])); } #else if (decomposerResult[i].ops[0].type == O_DISP) { //jmp dword ptr || call dword ptr #ifdef DEBUG_COMMENTS distorm_format(&decomposerCi, &decomposerResult[i], &inst); Scylla::debugLog.log(L"%S %S %d %d - target address: " PRINTF_DWORD_PTR_FULL, inst.mnemonic.p, inst.operands.p, decomposerResult[i].ops[0].type, decomposerResult[i].size, decomposerResult[i].disp); #endif iatPointers.insert((DWORD_PTR)decomposerResult[i].disp); } #endif } } } } } void IATSearch::findExecutableMemoryPagesByStartAddress( DWORD_PTR startAddress, DWORD_PTR* baseAddress, SIZE_T* memorySize ) { MEMORY_BASIC_INFORMATION memBasic = {0}; DWORD_PTR tempAddress; *memorySize = 0; *baseAddress = 0; if (VirtualQueryEx(hProcess,(LPCVOID)startAddress, &memBasic, sizeof(MEMORY_BASIC_INFORMATION)) != sizeof(MEMORY_BASIC_INFORMATION)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"findIATStartAddress :: VirtualQueryEx error %u", GetLastError()); #endif return; } //search down do { *memorySize = memBasic.RegionSize; *baseAddress = (DWORD_PTR)memBasic.BaseAddress; tempAddress = (DWORD_PTR)memBasic.BaseAddress - 1; if (VirtualQueryEx(hProcess, (LPCVOID)tempAddress, &memBasic, sizeof(MEMORY_BASIC_INFORMATION)) != sizeof(MEMORY_BASIC_INFORMATION)) { break; } } while (isPageExecutable(memBasic.Protect)); tempAddress = *baseAddress; memBasic.RegionSize = *memorySize; *memorySize = 0; //search up do { tempAddress += memBasic.RegionSize; *memorySize += memBasic.RegionSize; if (VirtualQueryEx(hProcess, (LPCVOID)tempAddress, &memBasic, sizeof(MEMORY_BASIC_INFORMATION)) != sizeof(MEMORY_BASIC_INFORMATION)) { break; } } while (isPageExecutable(memBasic.Protect)); } void IATSearch::filterIATPointersList( std::set & iatPointers ) { std::set::iterator iter; if (iatPointers.size() <= 2) { return; } iter = iatPointers.begin(); std::advance(iter, iatPointers.size() / 2); //start in the middle, important! DWORD_PTR lastPointer = *iter; iter++; for (; iter != iatPointers.end(); iter++) { if ((*iter - lastPointer) > 0x100) //check difference { - iatPointers.erase(iter, iatPointers.end()); - break; + if (isIATPointerValid(lastPointer, false) == false || isIATPointerValid(*iter, false) == false) + { + iatPointers.erase(iter, iatPointers.end()); + break; + } + else + { + lastPointer = *iter; + } } else { lastPointer = *iter; } } bool erased = true; while(erased) { iter = iatPointers.begin(); lastPointer = *iter; iter++; for (; iter != iatPointers.end(); iter++) { if ((*iter - lastPointer) > 0x100) //check difference { - iter--; - iatPointers.erase(iter); - erased = true; - break; + if (isIATPointerValid(lastPointer, false) == false || isIATPointerValid(*iter, false) == false) + { + iter--; + iatPointers.erase(iter); + erased = true; + break; + } + else + { + erased = false; + lastPointer = *iter; + } } else { erased = false; lastPointer = *iter; } } } } + +void IATSearch::getMemoryBaseAndSizeForIat( DWORD_PTR address, DWORD_PTR* baseAddress, DWORD* baseSize ) +{ + MEMORY_BASIC_INFORMATION memBasic1 = {0}; + MEMORY_BASIC_INFORMATION memBasic2 = {0}; + MEMORY_BASIC_INFORMATION memBasic3 = {0}; + + DWORD_PTR start = 0, end = 0; + *baseAddress = 0; + *baseSize = 0; + + if (!VirtualQueryEx(hProcess,(LPCVOID)address, &memBasic2, sizeof(MEMORY_BASIC_INFORMATION))) + { + return; + } + + *baseAddress = (DWORD_PTR)memBasic2.BaseAddress; + *baseSize = (DWORD)memBasic2.RegionSize; + + //Get the neighbours + if (!VirtualQueryEx(hProcess,(LPCVOID)((DWORD_PTR)memBasic2.BaseAddress - 1), &memBasic1, sizeof(MEMORY_BASIC_INFORMATION))) + { + return; + } + if (!VirtualQueryEx(hProcess,(LPCVOID)((DWORD_PTR)memBasic2.BaseAddress + (DWORD_PTR)memBasic2.RegionSize), &memBasic3, sizeof(MEMORY_BASIC_INFORMATION))) + { + return; + } + + if (memBasic3.State != MEM_COMMIT || memBasic1.State != MEM_COMMIT) + { + return; + } + + start = (DWORD_PTR)memBasic1.BaseAddress; + end = (DWORD_PTR)memBasic3.BaseAddress + (DWORD_PTR)memBasic3.RegionSize; + + *baseAddress = start; + *baseSize = (DWORD)(end - start); +} diff --git a/Scylla/IATSearch.h b/Scylla/IATSearch.h index 46acc95..05f35e0 100644 --- a/Scylla/IATSearch.h +++ b/Scylla/IATSearch.h @@ -1,34 +1,34 @@ #pragma once #include "ApiReader.h" #include class IATSearch : protected ApiReader { public: DWORD_PTR memoryAddress; SIZE_T memorySize; bool searchImportAddressTableInProcess(DWORD_PTR startAddress, DWORD_PTR* addressIAT, DWORD* sizeIAT, bool advanced); private: DWORD_PTR findAPIAddressInIAT(DWORD_PTR startAddress); bool findIATAdvanced(DWORD_PTR startAddress,DWORD_PTR* addressIAT, DWORD* sizeIAT); DWORD_PTR findNextFunctionAddress(); DWORD_PTR findIATPointer(); //DWORD_PTR findAddressFromWORDString(char * stringBuffer); //DWORD_PTR findAddressFromNormalCALLString(char * stringBuffer); - bool isIATPointerValid(DWORD_PTR iatPointer); + bool isIATPointerValid(DWORD_PTR iatPointer, bool checkRedirects); 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); void findIATPointers(std::set & iatPointers); void findExecutableMemoryPagesByStartAddress( DWORD_PTR startAddress, DWORD_PTR* baseAddress, SIZE_T* memorySize ); void filterIATPointersList( std::set & iatPointers ); + void getMemoryBaseAndSizeForIat( DWORD_PTR address, DWORD_PTR* baseAddress, DWORD* baseSize ); }; diff --git a/Scylla/MainGui.cpp b/Scylla/MainGui.cpp index 2e14d9a..6d91608 100644 --- a/Scylla/MainGui.cpp +++ b/Scylla/MainGui.cpp @@ -1,1709 +1,1709 @@ #include "MainGui.h" #include "Architecture.h" //#include "PluginLoader.h" //#include "ConfigurationHolder.h" #include "PeParser.h" #include "DllInjectionPlugin.h" #include "DisassemblerGui.h" #include "PickApiGui.h" //#include "NativeWinApi.h" #include "ImportRebuilder.h" #include "SystemInformation.h" #include "Scylla.h" #include "AboutGui.h" #include "DonateGui.h" #include "OptionsGui.h" #include "TreeImportExport.h" extern CAppModule _Module; // o_O const WCHAR MainGui::filterExe[] = L"Executable (*.exe)\0*.exe\0All files\0*.*\0"; const WCHAR MainGui::filterDll[] = L"Dynamic Link Library (*.dll)\0*.dll\0All files\0*.*\0"; const WCHAR MainGui::filterExeDll[] = L"Executable (*.exe)\0*.exe\0Dynamic Link Library (*.dll)\0*.dll\0All files\0*.*\0"; const WCHAR MainGui::filterTxt[] = L"Text file (*.txt)\0*.txt\0All files\0*.*\0"; const WCHAR MainGui::filterXml[] = L"XML file (*.xml)\0*.xml\0All files\0*.*\0"; const WCHAR MainGui::filterMem[] = L"MEM file (*.mem)\0*.mem\0All files\0*.*\0"; MainGui::MainGui() : selectedProcess(0), isProcessSuspended(false), importsHandling(TreeImports), TreeImportsSubclass(this, IDC_TREE_IMPORTS) { /* Logger::getDebugLogFilePath(); ConfigurationHolder::loadConfiguration(); PluginLoader::findAllPlugins(); NativeWinApi::initialize(); SystemInformation::getSystemInformation(); if(ConfigurationHolder::getConfigObject(DEBUG_PRIVILEGE)->isTrue()) { processLister.setDebugPrivileges(); } ProcessAccessHelp::getProcessModules(GetCurrentProcessId(), ProcessAccessHelp::ownModuleList); */ hIcon.LoadIcon(IDI_ICON_SCYLLA); hMenuImports.LoadMenu(IDR_MENU_IMPORTS); hMenuLog.LoadMenu(IDR_MENU_LOG); accelerators.LoadAccelerators(IDR_ACCELERATOR_MAIN); hIconCheck.LoadIcon(IDI_ICON_CHECK, 16, 16); hIconWarning.LoadIcon(IDI_ICON_WARNING, 16, 16); hIconError.LoadIcon(IDI_ICON_ERROR, 16, 16); } BOOL MainGui::PreTranslateMessage(MSG* pMsg) { if(accelerators.TranslateAccelerator(m_hWnd, pMsg)) { return TRUE; // handled keyboard shortcuts } else if(IsDialogMessage(pMsg)) { return TRUE; // handled dialog messages } return FALSE; } void MainGui::InitDllStartWithPreSelect( PGUI_DLL_PARAMETER guiParam ) { ComboProcessList.ResetContent(); std::vector& processList = Scylla::processLister.getProcessListSnapshotNative(); int newSel = -1; for (size_t i = 0; i < processList.size(); i++) { if (processList[i].PID == guiParam->dwProcessId) newSel = (int)i; swprintf_s(stringBuffer, L"%04d - %s - %s", processList[i].PID, processList[i].filename, processList[i].fullPath); ComboProcessList.AddString(stringBuffer); } if (newSel != -1) { ComboProcessList.SetCurSel(newSel); processSelectedActionHandler(newSel); if (guiParam->mod) //init mod { //select DLL size_t len = ProcessAccessHelp::moduleList.size(); newSel = -1; for (size_t i = 0; i < len; i++) { if (ProcessAccessHelp::moduleList.at(i).modBaseAddr == (DWORD_PTR)guiParam->mod) { newSel = (int)i; break; } } if (newSel != -1) { //get selected module ProcessAccessHelp::selectedModule = &ProcessAccessHelp::moduleList.at(newSel); ProcessAccessHelp::targetImageBase = ProcessAccessHelp::selectedModule->modBaseAddr; ProcessAccessHelp::targetSizeOfImage = ProcessAccessHelp::selectedModule->modBaseSize; DWORD modEntryPoint = ProcessAccessHelp::getEntryPointFromFile(ProcessAccessHelp::selectedModule->fullPath); EditOEPAddress.SetValue(modEntryPoint + ProcessAccessHelp::targetImageBase); Scylla::windowLog.log(L"->>> Module %s selected.", ProcessAccessHelp::selectedModule->getFilename()); Scylla::windowLog.log(L"Imagebase: " PRINTF_DWORD_PTR_FULL L" Size: %08X EntryPoint: %08X", ProcessAccessHelp::selectedModule->modBaseAddr, ProcessAccessHelp::selectedModule->modBaseSize, modEntryPoint); } } } } BOOL MainGui::OnInitDialog(CWindow wndFocus, LPARAM lInitParam) { if (SystemInformation::currenOS == UNKNOWN_OS) { if(IDCANCEL == MessageBox(L"Operating System is not supported\r\nContinue anyway?", L"Scylla", MB_ICONWARNING | MB_OKCANCEL)) { SendMessage(WM_CLOSE); return FALSE; } } // register ourselves to receive PreTranslateMessage CMessageLoop* pLoop = _Module.GetMessageLoop(); pLoop->AddMessageFilter(this); setupStatusBar(); DoDataExchange(); // attach controls DlgResize_Init(true, true); // init CDialogResize Scylla::windowLog.setWindow(ListLog); appendPluginListToMenu(hMenuImports.GetSubMenu(0)); appendPluginListToMenu(CMenuHandle(GetMenu()).GetSubMenu(MenuImportsOffsetTrace)); enableDialogControls(FALSE); setIconAndDialogCaption(); if (lInitParam) { InitDllStartWithPreSelect((PGUI_DLL_PARAMETER)lInitParam); } return TRUE; } void MainGui::OnDestroy() { PostQuitMessage(0); } void MainGui::OnSize(UINT nType, CSize size) { StatusBar.SendMessage(WM_SIZE); SetMsgHandled(FALSE); } void MainGui::OnContextMenu(CWindow wnd, CPoint point) { switch(wnd.GetDlgCtrlID()) { case IDC_TREE_IMPORTS: DisplayContextMenuImports(wnd, point); return; case IDC_LIST_LOG: DisplayContextMenuLog(wnd, point); return; } SetMsgHandled(FALSE); } void MainGui::OnCommand(UINT uNotifyCode, int nID, CWindow wndCtl) { // Handle plugin trace menu selection if(uNotifyCode == 0 && !wndCtl.IsWindow()) // make sure it's a menu { if ((nID >= PLUGIN_MENU_BASE_ID) && (nID <= (int)(Scylla::plugins.getScyllaPluginList().size() + Scylla::plugins.getImprecPluginList().size() + PLUGIN_MENU_BASE_ID))) { pluginActionHandler(nID); return; } } SetMsgHandled(FALSE); } LRESULT MainGui::OnTreeImportsDoubleClick(const NMHDR* pnmh) { if(TreeImports.GetCount() < 1) return 0; // Get item under cursor CTreeItem over = findTreeItem(CPoint(GetMessagePos()), true); if(over && importsHandling.isImport(over)) { pickApiActionHandler(over); } return 0; } LRESULT MainGui::OnTreeImportsKeyDown(const NMHDR* pnmh) { const NMTVKEYDOWN * tkd = (NMTVKEYDOWN *)pnmh; switch(tkd->wVKey) { case VK_RETURN: { CTreeItem selected = TreeImports.GetFocusItem(); if(!selected.IsNull() && importsHandling.isImport(selected)) { pickApiActionHandler(selected); } } return 1; case VK_DELETE: deleteSelectedImportsActionHandler(); return 1; } SetMsgHandled(FALSE); return 0; } UINT MainGui::OnTreeImportsSubclassGetDlgCode(const MSG * lpMsg) { if(lpMsg) { switch(lpMsg->wParam) { case VK_RETURN: return DLGC_WANTMESSAGE; } } SetMsgHandled(FALSE); return 0; } void MainGui::OnTreeImportsSubclassChar(UINT nChar, UINT nRepCnt, UINT nFlags) { switch(nChar) { case VK_RETURN: break; default: SetMsgHandled(FALSE); break; } } void MainGui::OnProcessListDrop(UINT uNotifyCode, int nID, CWindow wndCtl) { fillProcessListComboBox(ComboProcessList); } void MainGui::OnProcessListSelected(UINT uNotifyCode, int nID, CWindow wndCtl) { int index = ComboProcessList.GetCurSel(); if (index != CB_ERR) { processSelectedActionHandler(index); } } void MainGui::OnPickDLL(UINT uNotifyCode, int nID, CWindow wndCtl) { pickDllActionHandler(); } void MainGui::OnOptions(UINT uNotifyCode, int nID, CWindow wndCtl) { optionsActionHandler(); } void MainGui::OnDump(UINT uNotifyCode, int nID, CWindow wndCtl) { dumpActionHandler(); } void MainGui::OnDumpMemory(UINT uNotifyCode, int nID, CWindow wndCtl) { dumpMemoryActionHandler(); } void MainGui::OnDumpSection(UINT uNotifyCode, int nID, CWindow wndCtl) { dumpSectionActionHandler(); } void MainGui::OnFixDump(UINT uNotifyCode, int nID, CWindow wndCtl) { dumpFixActionHandler(); } void MainGui::OnPERebuild(UINT uNotifyCode, int nID, CWindow wndCtl) { peRebuildActionHandler(); } void MainGui::OnDLLInject(UINT uNotifyCode, int nID, CWindow wndCtl) { dllInjectActionHandler(); } void MainGui::OnDisassembler(UINT uNotifyCode, int nID, CWindow wndCtl) { disassemblerActionHandler(); } void MainGui::OnIATAutoSearch(UINT uNotifyCode, int nID, CWindow wndCtl) { iatAutosearchActionHandler(); } void MainGui::OnGetImports(UINT uNotifyCode, int nID, CWindow wndCtl) { getImportsActionHandler(); } void MainGui::OnInvalidImports(UINT uNotifyCode, int nID, CWindow wndCtl) { showInvalidImportsActionHandler(); } void MainGui::OnSuspectImports(UINT uNotifyCode, int nID, CWindow wndCtl) { showSuspectImportsActionHandler(); } void MainGui::OnClearImports(UINT uNotifyCode, int nID, CWindow wndCtl) { clearImportsActionHandler(); } void MainGui::OnInvalidateSelected(UINT uNotifyCode, int nID, CWindow wndCtl) { invalidateSelectedImportsActionHandler(); } void MainGui::OnCutSelected(UINT uNotifyCode, int nID, CWindow wndCtl) { deleteSelectedImportsActionHandler(); } void MainGui::OnSaveTree(UINT uNotifyCode, int nID, CWindow wndCtl) { saveTreeActionHandler(); } void MainGui::OnLoadTree(UINT uNotifyCode, int nID, CWindow wndCtl) { loadTreeActionHandler(); } void MainGui::OnAutotrace(UINT uNotifyCode, int nID, CWindow wndCtl) { // TODO } void MainGui::OnExit(UINT uNotifyCode, int nID, CWindow wndCtl) { if (isProcessSuspended) { int msgboxID = MessageBox(L"Process is suspended. Do you want to terminate the process?\r\n\r\nYES = Terminate Process\r\nNO = Try to resume the process\r\nCancel = Do nothing", L"Information", MB_YESNOCANCEL|MB_ICONINFORMATION); switch (msgboxID) { case IDYES: ProcessAccessHelp::terminateProcess(); break; case IDNO: ProcessAccessHelp::resumeProcess(); break; default: break; } } DestroyWindow(); } void MainGui::OnAbout(UINT uNotifyCode, int nID, CWindow wndCtl) { showAboutDialog(); } void MainGui::OnDonate(UINT uNotifyCode, int nID, CWindow wndCtl) { showDonateDialog(); } void MainGui::setupStatusBar() { StatusBar.Create(m_hWnd, NULL, L"", WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_TOOLTIPS, NULL, IDC_STATUS_BAR); CRect rcMain, rcStatus; GetClientRect(&rcMain); StatusBar.GetWindowRect(&rcStatus); const int PARTS = 4; int widths[PARTS]; widths[PART_COUNT] = rcMain.Width() / 5; widths[PART_INVALID] = widths[PART_COUNT] + rcMain.Width() / 5; widths[PART_IMAGEBASE] = widths[PART_INVALID] + rcMain.Width() / 3; widths[PART_MODULE] = -1; StatusBar.SetParts(PARTS, widths); ResizeClient(rcMain.Width(), rcMain.Height() + rcStatus.Height(), FALSE); } void MainGui::updateStatusBar() { // Rewrite ImportsHandling so we get these easily unsigned int totalImports = importsHandling.thunkCount(); unsigned int invalidImports = importsHandling.invalidThunkCount(); // \t = center, \t\t = right-align swprintf_s(stringBuffer, L"\tImports: %u", totalImports); StatusBar.SetText(PART_COUNT, stringBuffer); if(invalidImports > 0) { StatusBar.SetIcon(PART_INVALID, hIconError); } else { StatusBar.SetIcon(PART_INVALID, hIconCheck); } swprintf_s(stringBuffer, L"\tInvalid: %u", invalidImports); StatusBar.SetText(PART_INVALID, stringBuffer); if(selectedProcess) { DWORD_PTR imageBase = 0; const WCHAR * fileName = 0; if(ProcessAccessHelp::selectedModule) { imageBase = ProcessAccessHelp::selectedModule->modBaseAddr; fileName = ProcessAccessHelp::selectedModule->getFilename(); } else { imageBase = selectedProcess->imageBase; fileName = selectedProcess->filename; } swprintf_s(stringBuffer, L"\tImagebase: " PRINTF_DWORD_PTR_FULL, imageBase); StatusBar.SetText(PART_IMAGEBASE, stringBuffer); StatusBar.SetText(PART_MODULE, fileName); StatusBar.SetTipText(PART_MODULE, fileName); } else { StatusBar.SetText(PART_IMAGEBASE, L""); StatusBar.SetText(PART_MODULE, L""); } } bool MainGui::showFileDialog(WCHAR * selectedFile, bool save, const WCHAR * defFileName, const WCHAR * filter, const WCHAR * defExtension, const WCHAR * directory) { OPENFILENAME ofn = {0}; // WTL doesn't support new explorer styles on Vista and up // This is because it uses a custom hook, we could remove it or derive // from CFileDialog but this solution is easier and allows more control anyway (e.g. initial dir) if(defFileName) { wcscpy_s(selectedFile, MAX_PATH, defFileName); } else { selectedFile[0] = L'\0'; } ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = m_hWnd; ofn.lpstrFilter = filter; ofn.lpstrDefExt = defExtension; // only first 3 chars are used, no dots! ofn.lpstrFile = selectedFile; ofn.lpstrInitialDir = directory; ofn.nMaxFile = MAX_PATH; ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY; /* *OFN_EXPLORER is automatically used, it only has to be specified *if using a custom hook *OFN_LONGNAMES is automatically used by explorer-style dialogs */ if(save) ofn.Flags |= OFN_OVERWRITEPROMPT; else ofn.Flags |= OFN_FILEMUSTEXIST; if(save) return 0 != GetSaveFileName(&ofn); else return 0 != GetOpenFileName(&ofn); } void MainGui::setIconAndDialogCaption() { SetIcon(hIcon, TRUE); SetIcon(hIcon, FALSE); SetWindowText(APPNAME L" " ARCHITECTURE L" " APPVERSION); } void MainGui::pickDllActionHandler() { if(!selectedProcess) return; PickDllGui dlgPickDll(ProcessAccessHelp::moduleList); if(dlgPickDll.DoModal()) { //get selected module ProcessAccessHelp::selectedModule = dlgPickDll.getSelectedModule(); ProcessAccessHelp::targetImageBase = ProcessAccessHelp::selectedModule->modBaseAddr; ProcessAccessHelp::targetSizeOfImage = ProcessAccessHelp::selectedModule->modBaseSize; DWORD modEntryPoint = ProcessAccessHelp::getEntryPointFromFile(ProcessAccessHelp::selectedModule->fullPath); EditOEPAddress.SetValue(modEntryPoint + ProcessAccessHelp::targetImageBase); Scylla::windowLog.log(L"->>> Module %s selected.", ProcessAccessHelp::selectedModule->getFilename()); Scylla::windowLog.log(L"Imagebase: " PRINTF_DWORD_PTR_FULL L" Size: %08X EntryPoint: %08X", ProcessAccessHelp::selectedModule->modBaseAddr, ProcessAccessHelp::selectedModule->modBaseSize, modEntryPoint); } else { ProcessAccessHelp::selectedModule = 0; } updateStatusBar(); } void MainGui::pickApiActionHandler(CTreeItem item) { if(!importsHandling.isImport(item)) return; // TODO: new node when user picked an API from another DLL? PickApiGui dlgPickApi(ProcessAccessHelp::moduleList); if(dlgPickApi.DoModal()) { const ApiInfo* api = dlgPickApi.getSelectedApi(); if(api && api->module) { importsHandling.setImport(item, api->module->getFilename(), api->name, api->ordinal, api->hint, true, api->isForwarded); } } updateStatusBar(); } void MainGui::startDisassemblerGui(CTreeItem selectedTreeNode) { if(!selectedProcess) return; DWORD_PTR address = importsHandling.getApiAddressByNode(selectedTreeNode); if (address) { BYTE test; if(!ProcessAccessHelp::readMemoryFromProcess(address, sizeof(test), &test)) { swprintf_s(stringBuffer, L"Can't read memory at " PRINTF_DWORD_PTR_FULL, address); MessageBox(stringBuffer, L"Failure", MB_ICONERROR); } else { DisassemblerGui dlgDisassembler(address, &apiReader); dlgDisassembler.DoModal(); } } } void MainGui::processSelectedActionHandler(int index) { std::vector& processList = Scylla::processLister.getProcessList(); Process &process = processList.at(index); selectedProcess = 0; clearImportsActionHandler(); Scylla::windowLog.log(L"Analyzing %s", process.fullPath); if (ProcessAccessHelp::hProcess != 0) { ProcessAccessHelp::closeProcessHandle(); apiReader.clearAll(); } if (!ProcessAccessHelp::openProcessHandle(process.PID)) { enableDialogControls(FALSE); Scylla::windowLog.log(L"Error: Cannot open process handle."); updateStatusBar(); return; } ProcessAccessHelp::getProcessModules(ProcessAccessHelp::hProcess, ProcessAccessHelp::moduleList); apiReader.readApisFromModuleList(); Scylla::windowLog.log(L"Loading modules done."); //TODO improve ProcessAccessHelp::selectedModule = 0; ProcessAccessHelp::targetImageBase = process.imageBase; ProcessAccessHelp::targetSizeOfImage = process.imageSize; process.imageSize = (DWORD)ProcessAccessHelp::targetSizeOfImage; Scylla::windowLog.log(L"Imagebase: " PRINTF_DWORD_PTR_FULL L" Size: %08X", process.imageBase, process.imageSize); process.entryPoint = ProcessAccessHelp::getEntryPointFromFile(process.fullPath); EditOEPAddress.SetValue(process.entryPoint + process.imageBase); selectedProcess = &process; enableDialogControls(TRUE); updateStatusBar(); } void MainGui::fillProcessListComboBox(CComboBox& hCombo) { hCombo.ResetContent(); std::vector& processList = Scylla::processLister.getProcessListSnapshotNative(); for (size_t i = 0; i < processList.size(); i++) { swprintf_s(stringBuffer, L"%04d - %s - %s", processList[i].PID, processList[i].filename, processList[i].fullPath); hCombo.AddString(stringBuffer); } } /* void MainGui::addTextToOutputLog(const WCHAR * text) { if (m_hWnd) { ListLog.SetCurSel(ListLog.AddString(text)); } } */ void MainGui::clearOutputLog() { if (m_hWnd) { ListLog.ResetContent(); } } bool MainGui::saveLogToFile(const WCHAR * file) { const BYTE BOM[] = {0xFF, 0xFE}; // UTF-16 little-endian const WCHAR newLine[] = L"\r\n"; bool success = true; HANDLE hFile = CreateFile(file, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); if(hFile != INVALID_HANDLE_VALUE) { ProcessAccessHelp::writeMemoryToFileEnd(hFile, sizeof(BOM), BOM); WCHAR * buffer = 0; size_t bufsize = 0; for(int i = 0; i < ListLog.GetCount(); i++) { size_t size = ListLog.GetTextLen(i); size += _countof(newLine)-1; if(size+1 > bufsize) { bufsize = size+1; delete[] buffer; try { buffer = new WCHAR[bufsize]; } catch(std::bad_alloc&) { buffer = 0; success = false; break; } } ListLog.GetText(i, buffer); wcscat_s(buffer, bufsize, newLine); ProcessAccessHelp::writeMemoryToFileEnd(hFile, (DWORD)(size * sizeof(WCHAR)), buffer); } delete[] buffer; CloseHandle(hFile); } return success; } void MainGui::showInvalidImportsActionHandler() { importsHandling.selectImports(true, false); GotoDlgCtrl(TreeImports); } void MainGui::showSuspectImportsActionHandler() { importsHandling.selectImports(false, true); GotoDlgCtrl(TreeImports); } void MainGui::deleteSelectedImportsActionHandler() { CTreeItem selected = TreeImports.GetFirstSelectedItem(); while(!selected.IsNull()) { if(importsHandling.isModule(selected)) { importsHandling.cutModule(selected); } else { importsHandling.cutImport(selected); } selected = TreeImports.GetNextSelectedItem(selected); } updateStatusBar(); } void MainGui::invalidateSelectedImportsActionHandler() { CTreeItem selected = TreeImports.GetFirstSelectedItem(); while(!selected.IsNull()) { if(importsHandling.isImport(selected)) { importsHandling.invalidateImport(selected); } selected = TreeImports.GetNextSelectedItem(selected); } updateStatusBar(); } void MainGui::loadTreeActionHandler() { if(!selectedProcess) return; WCHAR selectedFilePath[MAX_PATH]; getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if(showFileDialog(selectedFilePath, false, NULL, filterXml, NULL, stringBuffer)) { TreeImportExport treeIO(selectedFilePath); DWORD_PTR addrOEP = 0; DWORD_PTR addrIAT = 0; DWORD sizeIAT = 0; if(!treeIO.importTreeList(importsHandling.moduleList, &addrOEP, &addrIAT, &sizeIAT)) { Scylla::windowLog.log(L"Loading tree file failed %s", selectedFilePath); MessageBox(L"Loading tree file failed.", L"Failure", MB_ICONERROR); } else { EditOEPAddress.SetValue(addrOEP); EditIATAddress.SetValue(addrIAT); EditIATSize.SetValue(sizeIAT); importsHandling.displayAllImports(); updateStatusBar(); Scylla::windowLog.log(L"Loaded tree file %s", selectedFilePath); Scylla::windowLog.log(L"-> OEP: " PRINTF_DWORD_PTR_FULL, addrOEP); Scylla::windowLog.log(L"-> IAT: " PRINTF_DWORD_PTR_FULL L" Size: " PRINTF_DWORD_PTR, addrIAT, sizeIAT); } } } void MainGui::saveTreeActionHandler() { if(!selectedProcess) return; WCHAR selectedFilePath[MAX_PATH]; getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if(showFileDialog(selectedFilePath, true, NULL, filterXml, L"xml", stringBuffer)) { TreeImportExport treeIO(selectedFilePath); DWORD_PTR addrOEP = EditOEPAddress.GetValue(); DWORD_PTR addrIAT = EditIATAddress.GetValue(); DWORD sizeIAT = EditIATSize.GetValue(); if(!treeIO.exportTreeList(importsHandling.moduleList, selectedProcess, addrOEP, addrIAT, sizeIAT)) { Scylla::windowLog.log(L"Saving tree file failed %s", selectedFilePath); MessageBox(L"Saving tree file failed.", L"Failure", MB_ICONERROR); } else { Scylla::windowLog.log(L"Saved tree file %s", selectedFilePath); } } } void MainGui::iatAutosearchActionHandler() { DWORD_PTR searchAddress = 0; DWORD_PTR addressIAT = 0, addressIATAdv = 0; DWORD sizeIAT = 0, sizeIATAdv = 0; IATSearch iatSearch; if(!selectedProcess) return; if(EditOEPAddress.GetWindowTextLength() > 0) { searchAddress = EditOEPAddress.GetValue(); if (searchAddress) { if (Scylla::config[USE_ADVANCED_IAT_SEARCH].isTrue()) { if (iatSearch.searchImportAddressTableInProcess(searchAddress, &addressIATAdv, &sizeIATAdv, true)) { - Scylla::windowLog.log(L"IAT Search Advanced: IAT VA " PRINTF_DWORD_PTR_FULL L" RVA " PRINTF_DWORD_PTR_FULL L" Size 0x%04X (%d)", addressIATAdv, addressIATAdv - ProcessAccessHelp::targetImageBase, sizeIATAdv, sizeIATAdv); + Scylla::windowLog.log(L"IAT Search Adv: IAT VA " PRINTF_DWORD_PTR_FULL L" RVA " PRINTF_DWORD_PTR_FULL L" Size 0x%04X (%d)", addressIATAdv, addressIATAdv - ProcessAccessHelp::targetImageBase, sizeIATAdv, sizeIATAdv); } else { - Scylla::windowLog.log(L"IAT Search Advanced: IAT not found at OEP " PRINTF_DWORD_PTR_FULL L"!", searchAddress); + Scylla::windowLog.log(L"IAT Search Adv: IAT not found at OEP " PRINTF_DWORD_PTR_FULL L"!", searchAddress); } } if (iatSearch.searchImportAddressTableInProcess(searchAddress, &addressIAT, &sizeIAT, false)) { - Scylla::windowLog.log(L"IAT Search Normal: IAT VA " PRINTF_DWORD_PTR_FULL L" RVA " PRINTF_DWORD_PTR_FULL L" Size 0x%04X (%d)", addressIAT, addressIAT - ProcessAccessHelp::targetImageBase, sizeIAT, sizeIAT); + Scylla::windowLog.log(L"IAT Search Nor: IAT VA " PRINTF_DWORD_PTR_FULL L" RVA " PRINTF_DWORD_PTR_FULL L" Size 0x%04X (%d)", addressIAT, addressIAT - ProcessAccessHelp::targetImageBase, sizeIAT, sizeIAT); } else { - Scylla::windowLog.log(L"IAT Search Normal: IAT not found at OEP " PRINTF_DWORD_PTR_FULL L"!", searchAddress); + Scylla::windowLog.log(L"IAT Search Nor: IAT not found at OEP " PRINTF_DWORD_PTR_FULL L"!", searchAddress); } if (addressIAT != 0 && addressIATAdv == 0) { setDialogIATAddressAndSize(addressIAT, sizeIAT); } else if (addressIAT == 0 && addressIATAdv != 0) { setDialogIATAddressAndSize(addressIATAdv, sizeIATAdv); } else if (addressIAT != 0 && addressIATAdv != 0) { if (addressIATAdv != addressIAT || sizeIAT != sizeIATAdv) { int msgboxID = MessageBox(L"Result of advanced and normal search is different. Do you want to use the IAT Search Advanced result?", L"Information", MB_YESNO|MB_ICONINFORMATION); if (msgboxID == IDYES) { setDialogIATAddressAndSize(addressIATAdv, sizeIATAdv); } else { setDialogIATAddressAndSize(addressIAT, sizeIAT); } } else { setDialogIATAddressAndSize(addressIAT, sizeIAT); } } } } } void MainGui::getImportsActionHandler() { if(!selectedProcess) return; DWORD_PTR addressIAT = EditIATAddress.GetValue(); DWORD sizeIAT = EditIATSize.GetValue(); if (addressIAT && sizeIAT) { apiReader.readAndParseIAT(addressIAT, sizeIAT, importsHandling.moduleList); importsHandling.displayAllImports(); updateStatusBar(); if (Scylla::config[SCAN_DIRECT_IMPORTS].isTrue()) { iatReferenceScan.ScanForDirectImports = true; iatReferenceScan.ScanForNormalImports = false; iatReferenceScan.apiReader = &apiReader; iatReferenceScan.startScan(ProcessAccessHelp::targetImageBase, (DWORD)ProcessAccessHelp::targetSizeOfImage, addressIAT, sizeIAT); Scylla::windowLog.log(L"DIRECT IMPORTS - Found %d possible direct imports with %d unique APIs!", iatReferenceScan.numberOfFoundDirectImports(), iatReferenceScan.numberOfFoundUniqueDirectImports()); if (iatReferenceScan.numberOfFoundDirectImports() > 0) { if (iatReferenceScan.numberOfDirectImportApisNotInIat() > 0) { Scylla::windowLog.log(L"DIRECT IMPORTS - Found %d additional api addresses!", iatReferenceScan.numberOfDirectImportApisNotInIat()); DWORD sizeIatNew = iatReferenceScan.addAdditionalApisToList(); Scylla::windowLog.log(L"DIRECT IMPORTS - Old IAT size 0x%08X new IAT size 0x%08X!", sizeIAT, sizeIatNew); EditIATSize.SetValue(sizeIatNew); importsHandling.scanAndFixModuleList(); importsHandling.displayAllImports(); } iatReferenceScan.printDirectImportLog(); if (Scylla::config[FIX_DIRECT_IMPORTS_NORMAL].isTrue() && (Scylla::config[FIX_DIRECT_IMPORTS_UNIVERSAL].isTrue() == false)) { int msgboxID = MessageBox(L"Direct Imports found. I can patch only direct imports by JMP/CALL (use universal method if you don't like this) but where is the junk byte?\r\n\r\nYES = After Instruction\r\nNO = Before the Instruction\r\nCancel = Do nothing", L"Information", MB_YESNOCANCEL|MB_ICONINFORMATION); if (msgboxID != IDCANCEL) { bool isAfter; if (msgboxID == IDYES) { isAfter = true; } else { isAfter = false; } iatReferenceScan.patchDirectImportsMemory(isAfter); Scylla::windowLog.log(L"DIRECT IMPORTS - Patched! Please dump target."); } } } } if (isIATOutsidePeImage(addressIAT)) { Scylla::windowLog.log(L"WARNING! IAT is not inside the PE image, requires rebasing!"); } } } void MainGui::SetupImportsMenuItems(CTreeItem item) { bool isItem, isImport = false; isItem = !item.IsNull(); if(isItem) { isImport = importsHandling.isImport(item); } CMenuHandle hSub = hMenuImports.GetSubMenu(0); UINT itemOnly = isItem ? MF_ENABLED : MF_GRAYED; UINT importOnly = isImport ? MF_ENABLED : MF_GRAYED; hSub.EnableMenuItem(ID__INVALIDATE, itemOnly); hSub.EnableMenuItem(ID__DISASSEMBLE, importOnly); hSub.EnableMenuItem(ID__CUTTHUNK, importOnly); hSub.EnableMenuItem(ID__DELETETREENODE, itemOnly); } void MainGui::DisplayContextMenuImports(CWindow hwnd, CPoint pt) { if(TreeImports.GetCount() < 1) return; CTreeItem over, parent; if(pt.x == -1 && pt.y == -1) // invoked by keyboard { CRect pos; over = TreeImports.GetFocusItem(); if(over) { over.EnsureVisible(); over.GetRect(&pos, TRUE); TreeImports.ClientToScreen(&pos); } else { TreeImports.GetWindowRect(&pos); } pt = pos.TopLeft(); } else { // Get item under cursor over = findTreeItem(pt, true); } SetupImportsMenuItems(over); CMenuHandle hSub = hMenuImports.GetSubMenu(0); BOOL menuItem = hSub.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD, pt.x, pt.y, hwnd); if (menuItem) { if ((menuItem >= PLUGIN_MENU_BASE_ID) && (menuItem <= (int)(Scylla::plugins.getScyllaPluginList().size() + Scylla::plugins.getImprecPluginList().size() + PLUGIN_MENU_BASE_ID))) { //wsprintf(stringBuffer, L"%d %s\n",menuItem,pluginList[menuItem - PLUGIN_MENU_BASE_ID].pluginName); //MessageBox(stringBuffer, L"plugin selection"); pluginActionHandler(menuItem); return; } switch (menuItem) { case ID__INVALIDATE: if(importsHandling.isModule(over)) importsHandling.invalidateModule(over); else importsHandling.invalidateImport(over); break; case ID__DISASSEMBLE: startDisassemblerGui(over); break; case ID__EXPANDALLNODES: importsHandling.expandAllTreeNodes(); break; case ID__COLLAPSEALLNODES: importsHandling.collapseAllTreeNodes(); break; case ID__CUTTHUNK: importsHandling.cutImport(over); break; case ID__DELETETREENODE: importsHandling.cutModule(importsHandling.isImport(over) ? over.GetParent() : over); break; } } updateStatusBar(); } void MainGui::DisplayContextMenuLog(CWindow hwnd, CPoint pt) { if(pt.x == -1 && pt.y == -1) // invoked by keyboard { CRect pos; ListLog.GetWindowRect(&pos); pt = pos.TopLeft(); } CMenuHandle hSub = hMenuLog.GetSubMenu(0); BOOL menuItem = hSub.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD, pt.x, pt.y, hwnd); if (menuItem) { switch (menuItem) { case ID__SAVE: WCHAR selectedFilePath[MAX_PATH]; getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if(showFileDialog(selectedFilePath, true, NULL, filterTxt, L"txt", stringBuffer)) { saveLogToFile(selectedFilePath); } break; case ID__CLEAR: clearOutputLog(); break; } } } void MainGui::appendPluginListToMenu(CMenuHandle hMenu) { std::vector &scyllaPluginList = Scylla::plugins.getScyllaPluginList(); std::vector &imprecPluginList = Scylla::plugins.getImprecPluginList(); if (scyllaPluginList.size() > 0) { CMenuHandle newMenu; newMenu.CreatePopupMenu(); for (size_t i = 0; i < scyllaPluginList.size(); i++) { newMenu.AppendMenu(MF_STRING, i + PLUGIN_MENU_BASE_ID, scyllaPluginList[i].pluginName); } hMenu.AppendMenu(MF_MENUBARBREAK); hMenu.AppendMenu(MF_POPUP, newMenu, L"Scylla Plugins"); } if (imprecPluginList.size() > 0) { CMenuHandle newMenu; newMenu.CreatePopupMenu(); for (size_t i = 0; i < imprecPluginList.size(); i++) { newMenu.AppendMenu(MF_STRING, scyllaPluginList.size() + i + PLUGIN_MENU_BASE_ID, imprecPluginList[i].pluginName); } hMenu.AppendMenu(MF_MENUBARBREAK); hMenu.AppendMenu(MF_POPUP, newMenu, L"ImpREC Plugins"); } } void MainGui::dumpMemoryActionHandler() { WCHAR selectedFilePath[MAX_PATH]; DumpMemoryGui dlgDumpMemory; if(dlgDumpMemory.DoModal()) { getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if(showFileDialog(selectedFilePath, true, dlgDumpMemory.dumpFilename, filterMem, L"mem", stringBuffer)) { if (ProcessAccessHelp::writeMemoryToNewFile(selectedFilePath,dlgDumpMemory.dumpedMemorySize,dlgDumpMemory.dumpedMemory)) { Scylla::windowLog.log(L"Memory dump saved %s", selectedFilePath); } else { Scylla::windowLog.log(L"Error! Cannot write memory dump to disk"); } } } } void MainGui::dumpSectionActionHandler() { WCHAR selectedFilePath[MAX_PATH] = {0}; WCHAR defaultFilename[MAX_PATH] = {0}; DumpSectionGui dlgDumpSection; const WCHAR * fileFilter; const WCHAR * defExtension; PeParser * peFile = 0; dlgDumpSection.entryPoint = EditOEPAddress.GetValue(); if (ProcessAccessHelp::selectedModule) { //dump DLL fileFilter = filterDll; defExtension = L"dll"; dlgDumpSection.imageBase = ProcessAccessHelp::selectedModule->modBaseAddr; //get it from gui wcscpy_s(dlgDumpSection.fullpath, ProcessAccessHelp::selectedModule->fullPath); } else { fileFilter = filterExe; defExtension = L"exe"; dlgDumpSection.imageBase = ProcessAccessHelp::targetImageBase; //get it from gui wcscpy_s(dlgDumpSection.fullpath, selectedProcess->fullPath); } if(dlgDumpSection.DoModal()) { getCurrentDefaultDumpFilename(defaultFilename, _countof(defaultFilename)); getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if(showFileDialog(selectedFilePath, true, defaultFilename, fileFilter, defExtension, stringBuffer)) { checkSuspendProcess(); if (Scylla::config[USE_PE_HEADER_FROM_DISK].isTrue()) { peFile = new PeParser(dlgDumpSection.fullpath, true); } else { peFile = new PeParser(dlgDumpSection.imageBase, true); } std::vector & sectionList = dlgDumpSection.getSectionList(); if (peFile->dumpProcess(dlgDumpSection.imageBase, dlgDumpSection.entryPoint, selectedFilePath, sectionList)) { Scylla::windowLog.log(L"Dump success %s", selectedFilePath); } else { Scylla::windowLog.log(L"Error: Cannot dump image."); MessageBox(L"Cannot dump image.", L"Failure", MB_ICONERROR); } delete peFile; } } } void MainGui::dumpActionHandler() { if(!selectedProcess) return; WCHAR selectedFilePath[MAX_PATH] = {0}; WCHAR defaultFilename[MAX_PATH] = {0}; const WCHAR * fileFilter; const WCHAR * defExtension; DWORD_PTR modBase = 0; DWORD_PTR entrypoint = 0; WCHAR * filename = 0; PeParser * peFile = 0; if (ProcessAccessHelp::selectedModule) { fileFilter = filterDll; defExtension = L"dll"; } else { fileFilter = filterExe; defExtension = L"exe"; } getCurrentModulePath(stringBuffer, _countof(stringBuffer)); getCurrentDefaultDumpFilename(defaultFilename, _countof(defaultFilename)); if(showFileDialog(selectedFilePath, true, defaultFilename, fileFilter, defExtension, stringBuffer)) { entrypoint = EditOEPAddress.GetValue(); checkSuspendProcess(); if (ProcessAccessHelp::selectedModule) { //dump DLL modBase = ProcessAccessHelp::selectedModule->modBaseAddr; filename = ProcessAccessHelp::selectedModule->fullPath; } else { //dump exe modBase = ProcessAccessHelp::targetImageBase; filename = selectedProcess->fullPath; } if (Scylla::config[USE_PE_HEADER_FROM_DISK].isTrue()) { peFile = new PeParser(filename, true); } else { peFile = new PeParser(modBase, true); } if (peFile->dumpProcess(modBase, entrypoint, selectedFilePath)) { Scylla::windowLog.log(L"Dump success %s", selectedFilePath); } else { Scylla::windowLog.log(L"Error: Cannot dump image."); MessageBox(L"Cannot dump image.", L"Failure", MB_ICONERROR); } delete peFile; } } void MainGui::peRebuildActionHandler() { DWORD newSize = 0; WCHAR selectedFilePath[MAX_PATH]; getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if(showFileDialog(selectedFilePath, false, NULL, filterExeDll, NULL, stringBuffer)) { if (Scylla::config[CREATE_BACKUP].isTrue()) { if (!ProcessAccessHelp::createBackupFile(selectedFilePath)) { Scylla::windowLog.log(L"Creating backup file failed %s", selectedFilePath); } } DWORD fileSize = (DWORD)ProcessAccessHelp::getFileSize(selectedFilePath); PeParser peFile(selectedFilePath, true); if (!peFile.isValidPeFile()) { Scylla::windowLog.log(L"This is not a valid PE file %s", selectedFilePath); MessageBox(L"Not a valid PE file.", L"Failure", MB_ICONERROR); return; } if (peFile.readPeSectionsFromFile()) { peFile.setDefaultFileAlignment(); if (Scylla::config[REMOVE_DOS_HEADER_STUB].isTrue()) { peFile.removeDosStub(); } peFile.alignAllSectionHeaders(); peFile.fixPeHeader(); if (peFile.savePeFileToDisk(selectedFilePath)) { newSize = (DWORD)ProcessAccessHelp::getFileSize(selectedFilePath); if (Scylla::config[UPDATE_HEADER_CHECKSUM].isTrue()) { Scylla::windowLog.log(L"Generating PE header checksum"); if (!PeParser::updatePeHeaderChecksum(selectedFilePath, newSize)) { Scylla::windowLog.log(L"Generating PE header checksum FAILED!"); } } Scylla::windowLog.log(L"Rebuild success %s", selectedFilePath); Scylla::windowLog.log(L"-> Old file size 0x%08X new file size 0x%08X (%d %%)", fileSize, newSize, ((newSize * 100) / fileSize) ); } else { Scylla::windowLog.log(L"Rebuild failed, cannot save file %s", selectedFilePath); MessageBox(L"Rebuild failed. Cannot save file.", L"Failure", MB_ICONERROR); } } else { Scylla::windowLog.log(L"Rebuild failed, cannot read file %s", selectedFilePath); MessageBox(L"Rebuild failed. Cannot read file.", L"Failure", MB_ICONERROR); } } } void MainGui::dumpFixActionHandler() { if(!selectedProcess) return; if (TreeImports.GetCount() < 2) { Scylla::windowLog.log(L"Nothing to rebuild"); return; } WCHAR newFilePath[MAX_PATH]; WCHAR selectedFilePath[MAX_PATH]; const WCHAR * fileFilter; DWORD_PTR modBase = 0; DWORD_PTR entrypoint = EditOEPAddress.GetValue(); if (ProcessAccessHelp::selectedModule) { modBase = ProcessAccessHelp::selectedModule->modBaseAddr; fileFilter = filterDll; } else { modBase = ProcessAccessHelp::targetImageBase; fileFilter = filterExe; } getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if (showFileDialog(selectedFilePath, false, NULL, fileFilter, NULL, stringBuffer)) { wcscpy_s(newFilePath, selectedFilePath); const WCHAR * extension = 0; WCHAR* dot = wcsrchr(newFilePath, L'.'); if (dot) { *dot = L'\0'; extension = selectedFilePath + (dot - newFilePath); //wcsrchr(selectedFilePath, L'.'); } wcscat_s(newFilePath, L"_SCY"); if(extension) { wcscat_s(newFilePath, extension); } ImportRebuilder importRebuild(selectedFilePath); if (Scylla::config[IAT_FIX_AND_OEP_FIX].isTrue()) { importRebuild.setEntryPointRva((DWORD)(entrypoint - modBase)); } if (Scylla::config[OriginalFirstThunk_SUPPORT].isTrue()) { importRebuild.enableOFTSupport(); } if (Scylla::config[SCAN_DIRECT_IMPORTS].isTrue() && Scylla::config[FIX_DIRECT_IMPORTS_UNIVERSAL].isTrue()) { if (iatReferenceScan.numberOfFoundDirectImports() > 0) { importRebuild.iatReferenceScan = &iatReferenceScan; importRebuild.BuildDirectImportsJumpTable = true; } } if (Scylla::config[CREATE_NEW_IAT_IN_SECTION].isTrue()) { importRebuild.iatReferenceScan = &iatReferenceScan; DWORD_PTR addressIAT = EditIATAddress.GetValue(); DWORD sizeIAT = EditIATSize.GetValue(); importRebuild.enableNewIatInSection(addressIAT, sizeIAT); } if (importRebuild.rebuildImportTable(newFilePath, importsHandling.moduleList)) { Scylla::windowLog.log(L"Import Rebuild success %s", newFilePath); } else { Scylla::windowLog.log(L"Import Rebuild failed %s", selectedFilePath); MessageBox(L"Import Rebuild failed", L"Failure", MB_ICONERROR); } } } void MainGui::enableDialogControls(BOOL value) { BOOL valButton = value ? TRUE : FALSE; GetDlgItem(IDC_BTN_PICKDLL).EnableWindow(valButton); GetDlgItem(IDC_BTN_DUMP).EnableWindow(valButton); GetDlgItem(IDC_BTN_FIXDUMP).EnableWindow(valButton); GetDlgItem(IDC_BTN_IATAUTOSEARCH).EnableWindow(valButton); GetDlgItem(IDC_BTN_GETIMPORTS).EnableWindow(valButton); GetDlgItem(IDC_BTN_SUSPECTIMPORTS).EnableWindow(valButton); GetDlgItem(IDC_BTN_INVALIDIMPORTS).EnableWindow(valButton); GetDlgItem(IDC_BTN_CLEARIMPORTS).EnableWindow(valButton); CMenuHandle menu = GetMenu(); UINT valMenu = value ? MF_ENABLED : MF_GRAYED; menu.EnableMenuItem(ID_FILE_DUMP, valMenu); menu.EnableMenuItem(ID_FILE_DUMPMEMORY, valMenu); menu.EnableMenuItem(ID_FILE_DUMPSECTION, valMenu); menu.EnableMenuItem(ID_FILE_FIXDUMP, valMenu); menu.EnableMenuItem(ID_IMPORTS_INVALIDATESELECTED, valMenu); menu.EnableMenuItem(ID_IMPORTS_CUTSELECTED, valMenu); menu.EnableMenuItem(ID_IMPORTS_SAVETREE, valMenu); menu.EnableMenuItem(ID_IMPORTS_LOADTREE, valMenu); menu.EnableMenuItem(ID_MISC_DLLINJECTION, valMenu); menu.EnableMenuItem(ID_MISC_DISASSEMBLER, valMenu); menu.GetSubMenu(MenuImportsOffsetTrace).EnableMenuItem(MenuImportsTraceOffsetScylla, MF_BYPOSITION | valMenu); menu.GetSubMenu(MenuImportsOffsetTrace).EnableMenuItem(MenuImportsTraceOffsetImpRec, MF_BYPOSITION | valMenu); //not yet implemented GetDlgItem(IDC_BTN_AUTOTRACE).EnableWindow(FALSE); menu.EnableMenuItem(ID_TRACE_AUTOTRACE, MF_GRAYED); } CTreeItem MainGui::findTreeItem(CPoint pt, bool screenCoordinates) { if(screenCoordinates) { TreeImports.ScreenToClient(&pt); } UINT flags; CTreeItem over = TreeImports.HitTest(pt, &flags); if(over) { if(!(flags & TVHT_ONITEM)) { over.m_hTreeItem = NULL; } } return over; } void MainGui::showAboutDialog() { AboutGui dlgAbout; dlgAbout.DoModal(); } void MainGui::showDonateDialog() { DonateGui dlgDonate; dlgDonate.DoModal(); } void MainGui::dllInjectActionHandler() { if(!selectedProcess) return; WCHAR selectedFilePath[MAX_PATH]; HMODULE hMod = 0; DllInjection dllInjection; getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if (showFileDialog(selectedFilePath, false, NULL, filterDll, NULL, stringBuffer)) { hMod = dllInjection.dllInjection(ProcessAccessHelp::hProcess, selectedFilePath); if (hMod && Scylla::config[DLL_INJECTION_AUTO_UNLOAD].isTrue()) { if (!dllInjection.unloadDllInProcess(ProcessAccessHelp::hProcess, hMod)) { Scylla::windowLog.log(L"DLL unloading failed, target %s", selectedFilePath); } } if (hMod) { Scylla::windowLog.log(L"DLL Injection was successful, target %s", selectedFilePath); } else { Scylla::windowLog.log(L"DLL Injection failed, target %s", selectedFilePath); } } } void MainGui::disassemblerActionHandler() { DWORD_PTR oep = EditOEPAddress.GetValue(); DisassemblerGui disGuiDlg(oep, &apiReader); disGuiDlg.DoModal(); } void MainGui::optionsActionHandler() { OptionsGui dlgOptions; dlgOptions.DoModal(); } void MainGui::clearImportsActionHandler() { importsHandling.clearAllImports(); updateStatusBar(); } void MainGui::pluginActionHandler( int menuItem ) { if(!selectedProcess) return; DllInjectionPlugin dllInjectionPlugin; std::vector &scyllaPluginList = Scylla::plugins.getScyllaPluginList(); std::vector &imprecPluginList = Scylla::plugins.getImprecPluginList(); menuItem -= PLUGIN_MENU_BASE_ID; dllInjectionPlugin.hProcess = ProcessAccessHelp::hProcess; dllInjectionPlugin.apiReader = &apiReader; if (menuItem < (int)scyllaPluginList.size()) { //scylla plugin dllInjectionPlugin.injectPlugin(scyllaPluginList[menuItem], importsHandling.moduleList,selectedProcess->imageBase, selectedProcess->imageSize); } else { #ifndef _WIN64 menuItem -= (int)scyllaPluginList.size(); //imprec plugin dllInjectionPlugin.injectImprecPlugin(imprecPluginList[menuItem], importsHandling.moduleList,selectedProcess->imageBase, selectedProcess->imageSize); #endif } importsHandling.scanAndFixModuleList(); importsHandling.displayAllImports(); updateStatusBar(); } bool MainGui::getCurrentModulePath(WCHAR * buffer, size_t bufferSize) { if(!selectedProcess) return false; if(ProcessAccessHelp::selectedModule) { wcscpy_s(buffer, bufferSize, ProcessAccessHelp::selectedModule->fullPath); } else { wcscpy_s(buffer, bufferSize, selectedProcess->fullPath); } WCHAR * slash = wcsrchr(buffer, L'\\'); if(slash) { *(slash+1) = L'\0'; } return true; } void MainGui::checkSuspendProcess() { if (Scylla::config[SUSPEND_PROCESS_FOR_DUMPING].isTrue()) { if (!ProcessAccessHelp::suspendProcess()) { Scylla::windowLog.log(L"Error: Cannot suspend process."); } else { isProcessSuspended = true; Scylla::windowLog.log(L"Suspending process successful, please resume manually."); } } } void MainGui::setDialogIATAddressAndSize( DWORD_PTR addressIAT, DWORD sizeIAT ) { EditIATAddress.SetValue(addressIAT); EditIATSize.SetValue(sizeIAT); swprintf_s(stringBuffer, L"IAT found:\r\n\r\nStart: " PRINTF_DWORD_PTR_FULL L"\r\nSize: 0x%04X (%d) ", addressIAT, sizeIAT, sizeIAT); MessageBox(stringBuffer, L"IAT found", MB_ICONINFORMATION); } bool MainGui::isIATOutsidePeImage( DWORD_PTR addressIAT ) { DWORD_PTR minAdd = 0, maxAdd = 0; if(ProcessAccessHelp::selectedModule) { minAdd = ProcessAccessHelp::selectedModule->modBaseAddr; maxAdd = minAdd + ProcessAccessHelp::selectedModule->modBaseSize; } else { minAdd = selectedProcess->imageBase; maxAdd = minAdd + selectedProcess->imageSize; } if (addressIAT > minAdd && addressIAT < maxAdd) { return false; //inside pe image } else { return true; //outside pe image, requires rebasing iat } } bool MainGui::getCurrentDefaultDumpFilename( WCHAR * buffer, size_t bufferSize ) { if(!selectedProcess) return false; WCHAR * fullPath; if(ProcessAccessHelp::selectedModule) { fullPath = ProcessAccessHelp::selectedModule->fullPath; } else { fullPath = selectedProcess->fullPath; } WCHAR * temp = wcsrchr(fullPath, L'\\'); if(temp) { temp++; wcscpy_s(buffer, bufferSize, temp); temp = wcsrchr(buffer, L'.'); if (temp) { *temp = 0; if(ProcessAccessHelp::selectedModule) { wcscat_s(buffer, bufferSize, L"_dump.dll"); } else { wcscat_s(buffer, bufferSize, L"_dump.exe"); } } return true; } return false; } diff --git a/Scylla/PeParser.cpp b/Scylla/PeParser.cpp index da6b58e..be2b98e 100644 --- a/Scylla/PeParser.cpp +++ b/Scylla/PeParser.cpp @@ -1,1273 +1,1282 @@ #include "PeParser.h" #include "ProcessAccessHelp.h" #include #include #pragma comment(lib, "Imagehlp.lib") PeParser::PeParser() { initClass(); } PeParser::PeParser(const WCHAR * file, bool readSectionHeaders) { initClass(); filename = file; if (filename) { readPeHeaderFromFile(readSectionHeaders); if (readSectionHeaders) { if (isValidPeFile()) { getSectionHeaders(); } } } } PeParser::PeParser(const DWORD_PTR moduleBase, bool readSectionHeaders) { initClass(); moduleBaseAddress = moduleBase; if (moduleBaseAddress) { readPeHeaderFromProcess(readSectionHeaders); if (readSectionHeaders) { if (isValidPeFile()) { getSectionHeaders(); } } } } PeParser::~PeParser() { if (headerMemory) { delete [] headerMemory; } if (fileMemory) { delete [] fileMemory; } for (size_t i = 0; i < listPeSection.size(); i++) { if (listPeSection[i].data) { delete [] listPeSection[i].data; } } listPeSection.clear(); } void PeParser::initClass() { fileMemory = 0; headerMemory = 0; pDosHeader = 0; pDosStub = 0; dosStubSize = 0; pNTHeader32 = 0; pNTHeader64 = 0; overlayData = 0; overlaySize = 0; filename = 0; fileSize = 0; moduleBaseAddress = 0; hFile = INVALID_HANDLE_VALUE; } bool PeParser::isPE64() { if (isValidPeFile()) { return (pNTHeader32->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC); } else { return false; } } bool PeParser::isPE32() { if (isValidPeFile()) { return (pNTHeader32->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC); } else { return false; } } bool PeParser::isTargetFileSamePeFormat() { #ifdef _WIN64 return isPE64(); #else return isPE32(); #endif } bool PeParser::isValidPeFile() { bool retValue = false; if (pDosHeader) { if (pDosHeader->e_magic == IMAGE_DOS_SIGNATURE) { if (pNTHeader32) { if (pNTHeader32->Signature == IMAGE_NT_SIGNATURE) { retValue = true; } } } } return retValue; } bool PeParser::hasDirectory(const int directoryIndex) { if (isPE32()) { return (pNTHeader32->OptionalHeader.DataDirectory[directoryIndex].VirtualAddress != 0); } else if (isPE64()) { return (pNTHeader64->OptionalHeader.DataDirectory[directoryIndex].VirtualAddress != 0); } else { return false; } } bool PeParser::hasExportDirectory() { return hasDirectory(IMAGE_DIRECTORY_ENTRY_EXPORT); } bool PeParser::hasTLSDirectory() { return hasDirectory(IMAGE_DIRECTORY_ENTRY_TLS); } bool PeParser::hasRelocationDirectory() { return hasDirectory(IMAGE_DIRECTORY_ENTRY_BASERELOC); } DWORD PeParser::getEntryPoint() { if (isPE32()) { return pNTHeader32->OptionalHeader.AddressOfEntryPoint; } else if (isPE64()) { return pNTHeader64->OptionalHeader.AddressOfEntryPoint; } else { return 0; } } bool PeParser::readPeHeaderFromProcess(bool readSectionHeaders) { bool retValue = false; DWORD correctSize = 0; DWORD readSize = getInitialHeaderReadSize(readSectionHeaders); headerMemory = new BYTE[readSize]; if (ProcessAccessHelp::readMemoryPartlyFromProcess(moduleBaseAddress, readSize, headerMemory)) { retValue = true; getDosAndNtHeader(headerMemory, (LONG)readSize); if (isValidPeFile()) { correctSize = calcCorrectPeHeaderSize(readSectionHeaders); if (readSize < correctSize) { readSize = correctSize; delete [] headerMemory; headerMemory = new BYTE[readSize]; if (ProcessAccessHelp::readMemoryPartlyFromProcess(moduleBaseAddress, readSize, headerMemory)) { getDosAndNtHeader(headerMemory, (LONG)readSize); } } } } return retValue; } bool PeParser::readPeHeaderFromFile(bool readSectionHeaders) { bool retValue = false; DWORD correctSize = 0; DWORD numberOfBytesRead = 0; DWORD readSize = getInitialHeaderReadSize(readSectionHeaders); headerMemory = new BYTE[readSize]; if (openFileHandle()) { fileSize = (DWORD)ProcessAccessHelp::getFileSize(hFile); if (ReadFile(hFile, headerMemory, readSize, &numberOfBytesRead, 0)) { retValue = true; getDosAndNtHeader(headerMemory, (LONG)readSize); if (isValidPeFile()) { correctSize = calcCorrectPeHeaderSize(readSectionHeaders); if (readSize < correctSize) { readSize = correctSize; if (fileSize > 0) { if (fileSize < correctSize) { readSize = fileSize; } } delete [] headerMemory; headerMemory = new BYTE[readSize]; SetFilePointer(hFile, 0, 0, FILE_BEGIN); if (ReadFile(hFile, headerMemory, readSize, &numberOfBytesRead, 0)) { getDosAndNtHeader(headerMemory, (LONG)readSize); } } } } closeFileHandle(); } return retValue; } bool PeParser::readPeSectionsFromProcess() { bool retValue = true; DWORD_PTR readOffset = 0; listPeSection.reserve(getNumberOfSections()); for (WORD i = 0; i < getNumberOfSections(); i++) { readOffset = listPeSection[i].sectionHeader.VirtualAddress + moduleBaseAddress; listPeSection[i].normalSize = listPeSection[i].sectionHeader.Misc.VirtualSize; if (!readSectionFromProcess(readOffset, listPeSection[i])) { retValue = false; } } return retValue; } bool PeParser::readPeSectionsFromFile() { bool retValue = true; DWORD readOffset = 0; listPeSection.reserve(getNumberOfSections()); if (openFileHandle()) { for (WORD i = 0; i < getNumberOfSections(); i++) { readOffset = listPeSection[i].sectionHeader.PointerToRawData; listPeSection[i].normalSize = listPeSection[i].sectionHeader.SizeOfRawData; if (!readSectionFromFile(readOffset, listPeSection[i])) { retValue = false; } } closeFileHandle(); } else { retValue = false; } return retValue; } bool PeParser::getSectionHeaders() { PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNTHeader32); PeFileSection peFileSection; listPeSection.clear(); listPeSection.reserve(getNumberOfSections()); for (WORD i = 0; i < getNumberOfSections(); i++) { memcpy_s(&peFileSection.sectionHeader, sizeof(IMAGE_SECTION_HEADER), pSection, sizeof(IMAGE_SECTION_HEADER)); listPeSection.push_back(peFileSection); pSection++; } return true; } bool PeParser::getSectionNameUnicode(const int sectionIndex, WCHAR * output, const int outputLen) { CHAR sectionNameA[IMAGE_SIZEOF_SHORT_NAME + 1] = {0}; output[0] = 0; memcpy(sectionNameA, listPeSection[sectionIndex].sectionHeader.Name, IMAGE_SIZEOF_SHORT_NAME); //not null terminated return (swprintf_s(output, outputLen, L"%S", sectionNameA) != -1); } WORD PeParser::getNumberOfSections() { return pNTHeader32->FileHeader.NumberOfSections; } void PeParser::setNumberOfSections(WORD numberOfSections) { pNTHeader32->FileHeader.NumberOfSections = numberOfSections; } std::vector & PeParser::getSectionHeaderList() { return listPeSection; } void PeParser::getDosAndNtHeader(BYTE * memory, LONG size) { pDosHeader = (PIMAGE_DOS_HEADER)memory; pNTHeader32 = 0; pNTHeader64 = 0; dosStubSize = 0; pDosStub = 0; if (pDosHeader->e_lfanew > 0 && pDosHeader->e_lfanew < size) //malformed PE { pNTHeader32 = (PIMAGE_NT_HEADERS32)((DWORD_PTR)pDosHeader + pDosHeader->e_lfanew); pNTHeader64 = (PIMAGE_NT_HEADERS64)((DWORD_PTR)pDosHeader + pDosHeader->e_lfanew); if (pDosHeader->e_lfanew > sizeof(IMAGE_DOS_HEADER)) { dosStubSize = pDosHeader->e_lfanew - sizeof(IMAGE_DOS_HEADER); pDosStub = (BYTE *)((DWORD_PTR)pDosHeader + sizeof(IMAGE_DOS_HEADER)); } else if (pDosHeader->e_lfanew < sizeof(IMAGE_DOS_HEADER)) { //Overlapped Headers, e.g. Spack (by Bagie) pDosHeader->e_lfanew = sizeof(IMAGE_DOS_HEADER); } } } DWORD PeParser::calcCorrectPeHeaderSize(bool readSectionHeaders) { DWORD correctSize = pDosHeader->e_lfanew + 50; //extra buffer if (readSectionHeaders) { correctSize += getNumberOfSections() * sizeof(IMAGE_SECTION_HEADER); } if (isPE32()) { correctSize += sizeof(IMAGE_NT_HEADERS32); } else if(isPE64()) { correctSize += sizeof(IMAGE_NT_HEADERS64); } else { correctSize = 0; //not a valid PE } return correctSize; } DWORD PeParser::getInitialHeaderReadSize(bool readSectionHeaders) { DWORD readSize = sizeof(IMAGE_DOS_HEADER) + 0x300 + sizeof(IMAGE_NT_HEADERS64); //if (readSectionHeaders) //{ // readSize += (10 * sizeof(IMAGE_SECTION_HEADER)); //} return readSize; } DWORD PeParser::getSectionHeaderBasedFileSize() { DWORD lastRawOffset = 0, lastRawSize = 0; //this is needed if the sections aren't sorted by their RawOffset (e.g. Petite) for (WORD i = 0; i < getNumberOfSections(); i++) { if (listPeSection[i].sectionHeader.PointerToRawData > lastRawOffset) { lastRawOffset = listPeSection[i].sectionHeader.PointerToRawData; lastRawSize = listPeSection[i].sectionHeader.SizeOfRawData; } } return (lastRawSize + lastRawOffset); } DWORD PeParser::getSectionHeaderBasedSizeOfImage() { DWORD lastVirtualOffset = 0, lastVirtualSize = 0; //this is needed if the sections aren't sorted by their RawOffset (e.g. Petite) for (WORD i = 0; i < getNumberOfSections(); i++) { if (listPeSection[i].sectionHeader.VirtualAddress > lastVirtualOffset) { lastVirtualOffset = listPeSection[i].sectionHeader.VirtualAddress; lastVirtualSize = listPeSection[i].sectionHeader.Misc.VirtualSize; } } return (lastVirtualSize + lastVirtualOffset); } bool PeParser::openFileHandle() { if (hFile == INVALID_HANDLE_VALUE) { if (filename) { hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); } else { hFile = INVALID_HANDLE_VALUE; } } return (hFile != INVALID_HANDLE_VALUE); } bool PeParser::openWriteFileHandle( const WCHAR * newFile ) { if (newFile) { hFile = CreateFile(newFile, GENERIC_WRITE, FILE_SHARE_WRITE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); } else { hFile = INVALID_HANDLE_VALUE; } return (hFile != INVALID_HANDLE_VALUE); } void PeParser::closeFileHandle() { if (hFile != INVALID_HANDLE_VALUE) { CloseHandle(hFile); hFile = INVALID_HANDLE_VALUE; } } bool PeParser::readSectionFromProcess(const DWORD_PTR readOffset, PeFileSection & peFileSection) { return readSectionFrom(readOffset, peFileSection, true); //process } bool PeParser::readSectionFromFile(const DWORD readOffset, PeFileSection & peFileSection) { return readSectionFrom(readOffset, peFileSection, false); //file } bool PeParser::readSectionFrom(const DWORD_PTR readOffset, PeFileSection & peFileSection, const bool isProcess) { const DWORD maxReadSize = 100; DWORD currentReadSize; BYTE data[maxReadSize]; bool retValue = true; DWORD valuesFound = 0; DWORD readSize = 0; DWORD_PTR currentOffset = 0; peFileSection.data = 0; peFileSection.dataSize = 0; readSize = peFileSection.normalSize; if (!readOffset || !readSize) { return true; //section without data is valid } if (readSize <= maxReadSize) { peFileSection.dataSize = readSize; peFileSection.normalSize = readSize; if (isProcess) { return readPeSectionFromProcess(readOffset, peFileSection); } else { return readPeSectionFromFile((DWORD)readOffset, peFileSection); } } currentReadSize = readSize % maxReadSize; //alignment % if (!currentReadSize) { currentReadSize = maxReadSize; } currentOffset = readOffset + readSize - currentReadSize; while(currentOffset >= readOffset) //start from the end { ZeroMemory(data, currentReadSize); if (isProcess) { retValue = ProcessAccessHelp::readMemoryPartlyFromProcess(currentOffset, currentReadSize, data); } else { retValue = ProcessAccessHelp::readMemoryFromFile(hFile, (LONG)currentOffset, currentReadSize, data); } if (!retValue) { break; } valuesFound = isMemoryNotNull(data, currentReadSize); if (valuesFound) { //found some real code currentOffset += valuesFound; if (readOffset < currentOffset) { //real size peFileSection.dataSize = (DWORD)(currentOffset - readOffset); //some safety space because of something like this at the end of a section: //FF25 C0604000 JMP DWORD PTR DS:[<&KERNEL32.RtlUnwind>] peFileSection.dataSize += sizeof(DWORD); if (peFileSection.normalSize < peFileSection.dataSize) { peFileSection.dataSize = peFileSection.normalSize; } } break; } currentReadSize = maxReadSize; currentOffset -= currentReadSize; } if (peFileSection.dataSize) { if (isProcess) { retValue = readPeSectionFromProcess(readOffset, peFileSection); } else { retValue = readPeSectionFromFile((DWORD)readOffset, peFileSection); } } return retValue; } DWORD PeParser::isMemoryNotNull( BYTE * data, int dataSize ) { for (int i = (dataSize - 1); i >= 0; i--) { if (data[i] != 0) { return i + 1; } } return 0; } bool PeParser::savePeFileToDisk( const WCHAR * newFile ) { bool retValue = true; DWORD dwFileOffset = 0, dwWriteSize = 0; if (getNumberOfSections() != listPeSection.size()) { return false; } if (openWriteFileHandle(newFile)) { //Dos header dwWriteSize = sizeof(IMAGE_DOS_HEADER); if (!ProcessAccessHelp::writeMemoryToFile(hFile, dwFileOffset, dwWriteSize, pDosHeader)) { retValue = false; } dwFileOffset += dwWriteSize; if (dosStubSize && pDosStub) { //Dos Stub dwWriteSize = dosStubSize; if (!ProcessAccessHelp::writeMemoryToFile(hFile, dwFileOffset, dwWriteSize, pDosStub)) { retValue = false; } dwFileOffset += dwWriteSize; } //Pe Header if (isPE32()) { dwWriteSize = sizeof(IMAGE_NT_HEADERS32); } else { dwWriteSize = sizeof(IMAGE_NT_HEADERS64); } if (!ProcessAccessHelp::writeMemoryToFile(hFile, dwFileOffset, dwWriteSize, pNTHeader32)) { retValue = false; } dwFileOffset += dwWriteSize; //section headers dwWriteSize = sizeof(IMAGE_SECTION_HEADER); for (WORD i = 0; i < getNumberOfSections(); i++) { if (!ProcessAccessHelp::writeMemoryToFile(hFile, dwFileOffset, dwWriteSize, &listPeSection[i].sectionHeader)) { retValue = false; break; } dwFileOffset += dwWriteSize; } for (WORD i = 0; i < getNumberOfSections(); i++) { if (!listPeSection[i].sectionHeader.PointerToRawData) continue; if (listPeSection[i].sectionHeader.PointerToRawData > dwFileOffset) { dwWriteSize = listPeSection[i].sectionHeader.PointerToRawData - dwFileOffset; //padding if (!writeZeroMemoryToFile(hFile, dwFileOffset, dwWriteSize)) { retValue = false; break; } dwFileOffset += dwWriteSize; } dwWriteSize = listPeSection[i].dataSize; if (dwWriteSize) { if (!ProcessAccessHelp::writeMemoryToFile(hFile, listPeSection[i].sectionHeader.PointerToRawData, dwWriteSize, listPeSection[i].data)) { retValue = false; break; } dwFileOffset += dwWriteSize; if (listPeSection[i].dataSize < listPeSection[i].sectionHeader.SizeOfRawData) //padding { dwWriteSize = listPeSection[i].sectionHeader.SizeOfRawData - listPeSection[i].dataSize; if (!writeZeroMemoryToFile(hFile, dwFileOffset, dwWriteSize)) { retValue = false; break; } dwFileOffset += dwWriteSize; } } } //add overlay? if (overlaySize && overlayData) { dwWriteSize = overlaySize; if (!ProcessAccessHelp::writeMemoryToFile(hFile, dwFileOffset, dwWriteSize, overlayData)) { retValue = false; } dwFileOffset += dwWriteSize; } SetEndOfFile(hFile); closeFileHandle(); } return retValue; } bool PeParser::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); } return retValue; } void PeParser::removeDosStub() { if (pDosHeader) { dosStubSize = 0; pDosStub = 0; //must not delete [] pDosHeader->e_lfanew = sizeof(IMAGE_DOS_HEADER); } } bool PeParser::readPeSectionFromFile(DWORD readOffset, PeFileSection & peFileSection) { DWORD bytesRead = 0; peFileSection.data = new BYTE[peFileSection.dataSize]; SetFilePointer(hFile, readOffset, 0, FILE_BEGIN); return (ReadFile(hFile, peFileSection.data, peFileSection.dataSize, &bytesRead, 0) != FALSE); } bool PeParser::readPeSectionFromProcess(DWORD_PTR readOffset, PeFileSection & peFileSection) { peFileSection.data = new BYTE[peFileSection.dataSize]; return ProcessAccessHelp::readMemoryPartlyFromProcess(readOffset, peFileSection.dataSize, peFileSection.data); } DWORD PeParser::alignValue(DWORD badValue, DWORD alignTo) { return (((badValue + alignTo - 1) / alignTo) * alignTo); } bool PeParser::addNewLastSection(const CHAR * sectionName, DWORD sectionSize, BYTE * sectionData) { size_t nameLength = strlen(sectionName); DWORD fileAlignment = 0, sectionAlignment = 0; PeFileSection peFileSection; if (nameLength > IMAGE_SIZEOF_SHORT_NAME) { return false; } if (isPE32()) { fileAlignment = pNTHeader32->OptionalHeader.FileAlignment; sectionAlignment = pNTHeader32->OptionalHeader.SectionAlignment; } else { fileAlignment = pNTHeader64->OptionalHeader.FileAlignment; sectionAlignment = pNTHeader64->OptionalHeader.SectionAlignment; } memcpy_s(peFileSection.sectionHeader.Name, IMAGE_SIZEOF_SHORT_NAME, sectionName, nameLength); //last section doesn't need SizeOfRawData alignment peFileSection.sectionHeader.SizeOfRawData = sectionSize; //alignValue(sectionSize, fileAlignment); peFileSection.sectionHeader.Misc.VirtualSize = alignValue(sectionSize, sectionAlignment); peFileSection.sectionHeader.PointerToRawData = alignValue(getSectionHeaderBasedFileSize(), fileAlignment); peFileSection.sectionHeader.VirtualAddress = alignValue(getSectionHeaderBasedSizeOfImage(), sectionAlignment); peFileSection.sectionHeader.Characteristics = IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE|IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA; peFileSection.normalSize = peFileSection.sectionHeader.SizeOfRawData; peFileSection.dataSize = peFileSection.sectionHeader.SizeOfRawData; if (sectionData == 0) { peFileSection.data = new BYTE[peFileSection.sectionHeader.SizeOfRawData]; ZeroMemory(peFileSection.data , peFileSection.sectionHeader.SizeOfRawData); } else { peFileSection.data = sectionData; } listPeSection.push_back(peFileSection); setNumberOfSections(getNumberOfSections() + 1); return true; } DWORD_PTR PeParser::getStandardImagebase() { if (isPE32()) { return pNTHeader32->OptionalHeader.ImageBase; } else { return pNTHeader64->OptionalHeader.ImageBase; } } int PeParser::convertRVAToOffsetVectorIndex(DWORD_PTR dwRVA) { for (WORD i = 0; i < getNumberOfSections(); i++) { if ((listPeSection[i].sectionHeader.VirtualAddress <= dwRVA) && ((listPeSection[i].sectionHeader.VirtualAddress + listPeSection[i].sectionHeader.Misc.VirtualSize) > dwRVA)) { return i; } } return -1; } DWORD_PTR PeParser::convertRVAToOffsetVector(DWORD_PTR dwRVA) { for (WORD i = 0; i < getNumberOfSections(); i++) { if ((listPeSection[i].sectionHeader.VirtualAddress <= dwRVA) && ((listPeSection[i].sectionHeader.VirtualAddress + listPeSection[i].sectionHeader.Misc.VirtualSize) > dwRVA)) { return ((dwRVA - listPeSection[i].sectionHeader.VirtualAddress) + listPeSection[i].sectionHeader.PointerToRawData); } } return 0; } DWORD_PTR PeParser::convertRVAToOffsetRelative(DWORD_PTR dwRVA) { for (WORD i = 0; i < getNumberOfSections(); i++) { if ((listPeSection[i].sectionHeader.VirtualAddress <= dwRVA) && ((listPeSection[i].sectionHeader.VirtualAddress + listPeSection[i].sectionHeader.Misc.VirtualSize) > dwRVA)) { return (dwRVA - listPeSection[i].sectionHeader.VirtualAddress); } } return 0; } DWORD_PTR PeParser::convertOffsetToRVAVector(DWORD_PTR dwOffset) { for (WORD i = 0; i < getNumberOfSections(); i++) { if ((listPeSection[i].sectionHeader.PointerToRawData <= dwOffset) && ((listPeSection[i].sectionHeader.PointerToRawData + listPeSection[i].sectionHeader.SizeOfRawData) > dwOffset)) { return ((dwOffset - listPeSection[i].sectionHeader.PointerToRawData) + listPeSection[i].sectionHeader.VirtualAddress); } } return 0; } void PeParser::fixPeHeader() { DWORD dwSize = pDosHeader->e_lfanew + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER); if (isPE32()) { //delete bound import directories pNTHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0; pNTHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0; //max 16, zeroing possible garbage values for (DWORD i = pNTHeader32->OptionalHeader.NumberOfRvaAndSizes; i < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; i++) { pNTHeader32->OptionalHeader.DataDirectory[i].Size = 0; pNTHeader32->OptionalHeader.DataDirectory[i].VirtualAddress = 0; } pNTHeader32->OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES; pNTHeader32->FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER32); pNTHeader32->OptionalHeader.SizeOfImage = getSectionHeaderBasedSizeOfImage(); if (moduleBaseAddress) { pNTHeader32->OptionalHeader.ImageBase = (DWORD)moduleBaseAddress; } pNTHeader32->OptionalHeader.SizeOfHeaders = alignValue(dwSize + pNTHeader32->FileHeader.SizeOfOptionalHeader + (getNumberOfSections() * sizeof(IMAGE_SECTION_HEADER)), pNTHeader32->OptionalHeader.FileAlignment); } else { //delete bound import directories pNTHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0; pNTHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0; //max 16, zeroing possible garbage values for (DWORD i = pNTHeader64->OptionalHeader.NumberOfRvaAndSizes; i < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; i++) { pNTHeader64->OptionalHeader.DataDirectory[i].Size = 0; pNTHeader64->OptionalHeader.DataDirectory[i].VirtualAddress = 0; } pNTHeader64->OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES; pNTHeader64->FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER64); pNTHeader64->OptionalHeader.SizeOfImage = getSectionHeaderBasedSizeOfImage(); if (moduleBaseAddress) { pNTHeader64->OptionalHeader.ImageBase = moduleBaseAddress; } pNTHeader64->OptionalHeader.SizeOfHeaders = alignValue(dwSize + pNTHeader64->FileHeader.SizeOfOptionalHeader + (getNumberOfSections() * sizeof(IMAGE_SECTION_HEADER)), pNTHeader64->OptionalHeader.FileAlignment); } removeIatDirectory(); } void PeParser::removeIatDirectory() { DWORD searchAddress = 0; if (isPE32()) { searchAddress = pNTHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress; pNTHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = 0; pNTHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = 0; } else { searchAddress = pNTHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress; pNTHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = 0; pNTHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = 0; } if (searchAddress) { for (WORD i = 0; i < getNumberOfSections(); i++) { if ((listPeSection[i].sectionHeader.VirtualAddress <= searchAddress) && ((listPeSection[i].sectionHeader.VirtualAddress + listPeSection[i].sectionHeader.Misc.VirtualSize) > searchAddress)) { //section must be read and writable listPeSection[i].sectionHeader.Characteristics |= IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE; } } } } void PeParser::setDefaultFileAlignment() { if (isPE32()) { pNTHeader32->OptionalHeader.FileAlignment = FileAlignmentConstant; } else { pNTHeader64->OptionalHeader.FileAlignment = FileAlignmentConstant; } } bool PeFileSectionSortByPointerToRawData(const PeFileSection& d1, const PeFileSection& d2) { return d1.sectionHeader.PointerToRawData < d2.sectionHeader.PointerToRawData; } bool PeFileSectionSortByVirtualAddress(const PeFileSection& d1, const PeFileSection& d2) { return d1.sectionHeader.VirtualAddress < d2.sectionHeader.VirtualAddress; } void PeParser::alignAllSectionHeaders() { DWORD sectionAlignment = 0; DWORD fileAlignment = 0; DWORD newFileSize = 0; if (isPE32()) { sectionAlignment = pNTHeader32->OptionalHeader.SectionAlignment; fileAlignment = pNTHeader32->OptionalHeader.FileAlignment; } else { sectionAlignment = pNTHeader64->OptionalHeader.SectionAlignment; fileAlignment = pNTHeader64->OptionalHeader.FileAlignment; } std::sort(listPeSection.begin(), listPeSection.end(), PeFileSectionSortByPointerToRawData); //sort by PointerToRawData ascending newFileSize = pDosHeader->e_lfanew + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + pNTHeader32->FileHeader.SizeOfOptionalHeader + (getNumberOfSections() * sizeof(IMAGE_SECTION_HEADER)); for (WORD i = 0; i < getNumberOfSections(); i++) { listPeSection[i].sectionHeader.VirtualAddress = alignValue(listPeSection[i].sectionHeader.VirtualAddress, sectionAlignment); listPeSection[i].sectionHeader.Misc.VirtualSize = alignValue(listPeSection[i].sectionHeader.Misc.VirtualSize, sectionAlignment); listPeSection[i].sectionHeader.PointerToRawData = alignValue(newFileSize, fileAlignment); listPeSection[i].sectionHeader.SizeOfRawData = alignValue(listPeSection[i].dataSize, fileAlignment); newFileSize = listPeSection[i].sectionHeader.PointerToRawData + listPeSection[i].sectionHeader.SizeOfRawData; } std::sort(listPeSection.begin(), listPeSection.end(), PeFileSectionSortByVirtualAddress); //sort by VirtualAddress ascending } bool PeParser::dumpProcess(DWORD_PTR modBase, DWORD_PTR entryPoint, const WCHAR * dumpFilePath) { moduleBaseAddress = modBase; if (readPeSectionsFromProcess()) { setDefaultFileAlignment(); setEntryPointVa(entryPoint); alignAllSectionHeaders(); fixPeHeader(); getFileOverlay(); return savePeFileToDisk(dumpFilePath); } return false; } bool PeParser::dumpProcess(DWORD_PTR modBase, DWORD_PTR entryPoint, const WCHAR * dumpFilePath, std::vector & sectionList) { if (listPeSection.size() == sectionList.size()) { for (int i = (getNumberOfSections() - 1); i >= 0; i--) { if (!sectionList[i].isDumped) { listPeSection.erase(listPeSection.begin() + i); setNumberOfSections(getNumberOfSections() - 1); } else { listPeSection[i].sectionHeader.Misc.VirtualSize = sectionList[i].virtualSize; listPeSection[i].sectionHeader.SizeOfRawData = sectionList[i].rawSize; listPeSection[i].sectionHeader.Characteristics = sectionList[i].characteristics; } } } return dumpProcess(modBase, entryPoint, dumpFilePath); } void PeParser::setEntryPointVa(DWORD_PTR entryPoint) { DWORD entryPointRva = (DWORD)(entryPoint - moduleBaseAddress); setEntryPointRva(entryPointRva); } void PeParser::setEntryPointRva(DWORD entryPoint) { if (isPE32()) { pNTHeader32->OptionalHeader.AddressOfEntryPoint = entryPoint; } else if (isPE64()) { pNTHeader64->OptionalHeader.AddressOfEntryPoint = entryPoint; } } bool PeParser::getFileOverlay() { DWORD numberOfBytesRead; bool retValue = false; if (!hasOverlayData()) { return false; } if (openFileHandle()) { DWORD overlayOffset = getSectionHeaderBasedFileSize(); DWORD fileSize = (DWORD)ProcessAccessHelp::getFileSize(hFile); overlaySize = fileSize - overlayOffset; overlayData = new BYTE[overlaySize]; SetFilePointer(hFile, overlayOffset, 0, FILE_BEGIN); if (ReadFile(hFile, overlayData, overlaySize, &numberOfBytesRead, 0)) { retValue = true; } closeFileHandle(); } return retValue; } bool PeParser::hasOverlayData() { if (!filename) return false; if (isValidPeFile()) { DWORD fileSize = (DWORD)ProcessAccessHelp::getFileSize(filename); return (fileSize > getSectionHeaderBasedFileSize()); } else { return false; } } bool PeParser::updatePeHeaderChecksum(const WCHAR * targetFile, DWORD fileSize) { PIMAGE_NT_HEADERS32 pNTHeader32 = 0; PIMAGE_NT_HEADERS64 pNTHeader64 = 0; DWORD headerSum = 0; DWORD checkSum = 0; bool retValue = false; if (!fileSize) return retValue; HANDLE hFileToMap = CreateFile(targetFile, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if(hFileToMap != INVALID_HANDLE_VALUE) { HANDLE hMappedFile = CreateFileMapping(hFileToMap, 0, PAGE_READWRITE, 0, 0, 0); if(hMappedFile) { if (GetLastError() != ERROR_ALREADY_EXISTS) { LPVOID addrMappedDll = MapViewOfFile(hMappedFile, FILE_MAP_ALL_ACCESS, 0, 0, 0); if (addrMappedDll) { pNTHeader32 = (PIMAGE_NT_HEADERS32)CheckSumMappedFile(addrMappedDll, fileSize, &headerSum, &checkSum); if (pNTHeader32) { if (pNTHeader32->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) { pNTHeader64 = (PIMAGE_NT_HEADERS64)pNTHeader32; pNTHeader64->OptionalHeader.CheckSum = checkSum; } else { pNTHeader32->OptionalHeader.CheckSum = checkSum; } retValue = true; } UnmapViewOfFile(addrMappedDll); } } CloseHandle(hMappedFile); } CloseHandle(hFileToMap); } return retValue; } BYTE * PeParser::getSectionMemoryByIndex(int index) { return listPeSection[index].data; } DWORD PeParser::getSectionMemorySizeByIndex(int index) { return listPeSection[index].dataSize; } DWORD PeParser::getSectionAddressRVAByIndex( int index ) { return listPeSection[index].sectionHeader.VirtualAddress; } + +PIMAGE_NT_HEADERS PeParser::getCurrentNtHeader() +{ +#ifdef _WIN64 + return pNTHeader64; +#else + return pNTHeader32; +#endif +} \ No newline at end of file diff --git a/Scylla/PeParser.h b/Scylla/PeParser.h index 19328a3..a1e1f9b 100644 --- a/Scylla/PeParser.h +++ b/Scylla/PeParser.h @@ -1,142 +1,144 @@ #pragma once #include #include #include "DumpSectionGui.h" class PeFileSection { public: IMAGE_SECTION_HEADER sectionHeader; BYTE * data; DWORD dataSize; DWORD normalSize; PeFileSection() { ZeroMemory(§ionHeader, sizeof(IMAGE_SECTION_HEADER)); data = 0; dataSize = 0; normalSize = 0; } }; class PeParser { public: PeParser(const WCHAR * file, bool readSectionHeaders = true); PeParser(const DWORD_PTR moduleBase, bool readSectionHeaders = true); ~PeParser(); bool isValidPeFile(); bool isPE64(); bool isPE32(); bool isTargetFileSamePeFormat(); WORD getNumberOfSections(); std::vector & getSectionHeaderList(); bool hasExportDirectory(); bool hasTLSDirectory(); bool hasRelocationDirectory(); bool hasOverlayData(); DWORD getEntryPoint(); bool getSectionNameUnicode(const int sectionIndex, WCHAR * output, const int outputLen); DWORD getSectionHeaderBasedFileSize(); DWORD getSectionHeaderBasedSizeOfImage(); bool readPeSectionsFromProcess(); bool readPeSectionsFromFile(); bool savePeFileToDisk(const WCHAR * newFile); void removeDosStub(); void alignAllSectionHeaders(); void fixPeHeader(); void setDefaultFileAlignment(); bool dumpProcess(DWORD_PTR modBase, DWORD_PTR entryPoint, const WCHAR * dumpFilePath); bool dumpProcess(DWORD_PTR modBase, DWORD_PTR entryPoint, const WCHAR * dumpFilePath, std::vector & sectionList); void setEntryPointVa(DWORD_PTR entryPoint); void setEntryPointRva(DWORD entryPoint); static bool updatePeHeaderChecksum(const WCHAR * targetFile, DWORD fileSize); BYTE * getSectionMemoryByIndex(int index); DWORD getSectionMemorySizeByIndex(int index); int convertRVAToOffsetVectorIndex(DWORD_PTR dwRVA); DWORD_PTR convertOffsetToRVAVector(DWORD_PTR dwOffset); DWORD_PTR convertRVAToOffsetVector(DWORD_PTR dwRVA); DWORD_PTR convertRVAToOffsetRelative(DWORD_PTR dwRVA); DWORD getSectionAddressRVAByIndex( int index ); + + PIMAGE_NT_HEADERS getCurrentNtHeader(); protected: PeParser(); static const DWORD FileAlignmentConstant = 0x200; const WCHAR * filename; DWORD_PTR moduleBaseAddress; /************************************************************************/ /* PE FILE */ /* */ /* IMAGE_DOS_HEADER 64 0x40 */ /* IMAGE_NT_HEADERS32 248 0xF8 */ /* IMAGE_NT_HEADERS64 264 0x108 */ /* IMAGE_SECTION_HEADER 40 0x28 */ /************************************************************************/ PIMAGE_DOS_HEADER pDosHeader; BYTE * pDosStub; //between dos header and section header DWORD dosStubSize; PIMAGE_NT_HEADERS32 pNTHeader32; PIMAGE_NT_HEADERS64 pNTHeader64; std::vector listPeSection; BYTE * overlayData; DWORD overlaySize; /************************************************************************/ BYTE * fileMemory; BYTE * headerMemory; HANDLE hFile; DWORD fileSize; bool readPeHeaderFromFile(bool readSectionHeaders); bool readPeHeaderFromProcess(bool readSectionHeaders); bool hasDirectory(const int directoryIndex); bool getSectionHeaders(); void getDosAndNtHeader(BYTE * memory, LONG size); DWORD calcCorrectPeHeaderSize( bool readSectionHeaders ); DWORD getInitialHeaderReadSize( bool readSectionHeaders ); bool openFileHandle(); void closeFileHandle(); void initClass(); DWORD isMemoryNotNull( BYTE * data, int dataSize ); bool openWriteFileHandle( const WCHAR * newFile ); bool writeZeroMemoryToFile(HANDLE hFile, DWORD fileOffset, DWORD size); bool readPeSectionFromFile( DWORD readOffset, PeFileSection & peFileSection ); bool readPeSectionFromProcess( DWORD_PTR readOffset, PeFileSection & peFileSection ); bool readSectionFromProcess(const DWORD_PTR readOffset, PeFileSection & peFileSection ); bool readSectionFromFile(const DWORD readOffset, PeFileSection & peFileSection ); bool readSectionFrom(const DWORD_PTR readOffset, PeFileSection & peFileSection, const bool isProcess); DWORD_PTR getStandardImagebase(); bool addNewLastSection(const CHAR * sectionName, DWORD sectionSize, BYTE * sectionData); DWORD alignValue(DWORD badValue, DWORD alignTo); void setNumberOfSections(WORD numberOfSections); void removeIatDirectory(); bool getFileOverlay(); };