diff --git a/Scylla/ApiReader.cpp b/Scylla/ApiReader.cpp index 036a7bb..2794fb9 100644 --- a/Scylla/ApiReader.cpp +++ b/Scylla/ApiReader.cpp @@ -1,1184 +1,1183 @@ #include "ApiReader.h" #include "Scylla.h" #include "Architecture.h" #include "SystemInformation.h" #include "StringConversion.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 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(!readMemoryFromProcess(module->modBaseAddr + pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress, readSize, bufferExportTable)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"getExportTableFromProcess :: Error reading export table from process"); #endif delete[] bufferExportTable; return 0; } else { return bufferExportTable; } } else { return 0; } } void ApiReader::parseModuleWithProcess(ModuleInfo * module) { PIMAGE_NT_HEADERS pNtHeader = 0; PIMAGE_DOS_HEADER pDosHeader = 0; BYTE *bufferHeader = 0; BYTE *bufferExportTable = 0; bufferHeader = getHeaderFromProcess(module); if (bufferHeader == 0) return; pDosHeader = (PIMAGE_DOS_HEADER)bufferHeader; pNtHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)bufferHeader + (DWORD_PTR)(pDosHeader->e_lfanew)); if (isPeAndExportTableValid(pNtHeader)) { bufferExportTable = getExportTableFromProcess(module, pNtHeader); if(bufferExportTable) { parseExportTable(module,pNtHeader,(PIMAGE_EXPORT_DIRECTORY)bufferExportTable, (DWORD_PTR)bufferExportTable - pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); delete[] bufferExportTable; } } delete[] bufferHeader; } void ApiReader::parseExportTable(ModuleInfo *module, PIMAGE_NT_HEADERS pNtHeader, PIMAGE_EXPORT_DIRECTORY pExportDir, DWORD_PTR deltaAddress) { DWORD *addressOfFunctionsArray = 0,*addressOfNamesArray = 0; WORD *addressOfNameOrdinalsArray = 0; char *functionName = 0; DWORD_PTR RVA = 0, VA = 0; WORD ordinal = 0; WORD i = 0, j = 0; bool withoutName; addressOfFunctionsArray = (DWORD *)((DWORD_PTR)pExportDir->AddressOfFunctions + deltaAddress); addressOfNamesArray = (DWORD *)((DWORD_PTR)pExportDir->AddressOfNames + deltaAddress); addressOfNameOrdinalsArray = (WORD *)((DWORD_PTR)pExportDir->AddressOfNameOrdinals + deltaAddress); #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"parseExportTable :: module %s NumberOfNames %X", module->fullPath, pExportDir->NumberOfNames); #endif for (i = 0; i < pExportDir->NumberOfNames; i++) { functionName = (char*)(addressOfNamesArray[i] + deltaAddress); ordinal = (WORD)(addressOfNameOrdinalsArray[i] + pExportDir->Base); RVA = addressOfFunctionsArray[addressOfNameOrdinalsArray[i]]; VA = addressOfFunctionsArray[addressOfNameOrdinalsArray[i]] + module->modBaseAddr; #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"parseExportTable :: api %S ordinal %d imagebase " PRINTF_DWORD_PTR_FULL L" RVA " PRINTF_DWORD_PTR_FULL L" VA " PRINTF_DWORD_PTR_FULL, functionName, ordinal, module->modBaseAddr, RVA, VA); #endif if (!isApiBlacklisted(functionName)) { if (!isApiForwarded(RVA,pNtHeader)) { addApi(functionName, i, ordinal,VA,RVA,false,module); } else { //printf("Forwarded: %s\n",functionName); handleForwardedApi(RVA + deltaAddress,functionName,RVA,ordinal,module); } } } /*Exports without name*/ if (pExportDir->NumberOfNames != pExportDir->NumberOfFunctions) { for (i = 0; i < pExportDir->NumberOfFunctions; i++) { withoutName = true; for (j = 0; j < pExportDir->NumberOfNames; j++) { if(addressOfNameOrdinalsArray[j] == i) { withoutName = false; break; } } if (withoutName && addressOfFunctionsArray[i] != 0) { ordinal = (WORD)(i+pExportDir->Base); RVA = addressOfFunctionsArray[i]; VA = (addressOfFunctionsArray[i] + module->modBaseAddr); if (!isApiForwarded(RVA,pNtHeader)) { addApiWithoutName(ordinal,VA,RVA,false,module); } else { handleForwardedApi(RVA + deltaAddress,0,RVA,ordinal,module); } } } } } void ApiReader::findApiByModuleAndOrdinal(ModuleInfo * module, WORD ordinal, DWORD_PTR * vaApi, DWORD_PTR * rvaApi) { findApiByModule(module,0,ordinal,vaApi,rvaApi); } void ApiReader::findApiByModuleAndName(ModuleInfo * module, char * searchFunctionName, DWORD_PTR * vaApi, DWORD_PTR * rvaApi) { findApiByModule(module,searchFunctionName,0,vaApi,rvaApi); } void ApiReader::findApiByModule(ModuleInfo * module, char * searchFunctionName, WORD ordinal, DWORD_PTR * vaApi, DWORD_PTR * rvaApi) { if (isModuleLoadedInOwnProcess(module)) { HMODULE hModule = GetModuleHandle(module->getFilename()); if (hModule) { - if (ordinal) - { - *vaApi = (DWORD_PTR)GetProcAddress(hModule, (LPCSTR)ordinal); - } - else - { - *vaApi = (DWORD_PTR)GetProcAddress(hModule, searchFunctionName); - } - - if (vaApi) { + 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 { 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) { Scylla::windowLog.log(L"getApiByVirtualAddress :: No Api found " PRINTF_DWORD_PTR_FULL, virtualAddress); return 0; } else if (countDuplicates == 1) { //API is 100% correct *isSuspect = false; it1 = apiList.find(virtualAddress); // Find first match. return (ApiInfo *)((*it1).second); } else { it1 = apiList.find(virtualAddress); // Find first match. //any high priority with a name apiFound = getScoredApi(it1,countDuplicates,true,false,false,true,false,false,false,false); if (apiFound) return apiFound; *isSuspect = true; //high priority with a name and ansi/unicode name apiFound = getScoredApi(it1,countDuplicates,true,true,false,true,false,false,false,false); if (apiFound) return apiFound; //priority 2 with no underline in name apiFound = getScoredApi(it1,countDuplicates,true,false,true,false,false,false,true,false); if (apiFound) return apiFound; //priority 1 with a name apiFound = getScoredApi(it1,countDuplicates,true,false,false,false,false,true,false,false); if (apiFound) return apiFound; //With a name apiFound = getScoredApi(it1,countDuplicates,true,false,false,false,false,false,false,false); if (apiFound) return apiFound; //any with priority, name, ansi/unicode apiFound = getScoredApi(it1,countDuplicates,true,true,false,true,false,false,false,true); if (apiFound) return apiFound; //any with priority apiFound = getScoredApi(it1,countDuplicates,false,false,false,true,false,false,false,true); if (apiFound) return apiFound; //has prio 0 and name apiFound = getScoredApi(it1,countDuplicates,false,false,false,false,true,false,false,true); if (apiFound) return apiFound; } //is never reached Scylla::windowLog.log(L"getApiByVirtualAddress :: There is a api resolving bug, VA: " PRINTF_DWORD_PTR_FULL, virtualAddress); for (size_t c = 0; c < countDuplicates; c++, it1++) { apiFound = (ApiInfo *)((*it1).second); Scylla::windowLog.log(L"-> Possible API: %S ord: %d ", apiFound->name, apiFound->ordinal); } return (ApiInfo *) 1; } ApiInfo * ApiReader::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); bool foundModuleBreak = false; for (SIZE_T i = 0; i < sizeIAT; i++) { //Scylla::windowLog.log(L"%08X %08X %d von %d", addressIAT + (DWORD_PTR)&pIATAddress[i] - (DWORD_PTR)iatBuffer, pIATAddress[i],i,sizeIAT); if (pIATAddress[i] == 0 || pIATAddress[i] == -1) { /*if (pIATAddress[i+1] != 0) { printf("parseIAT :: Module break\n"); }*/ /*else { printf("parseIAT :: IAT finished\n"); break; }*/ foundModuleBreak = true; } else if ( (pIATAddress[i] > minApiAddress) && (pIATAddress[i] < maxApiAddress) ) { apiFound = getApiByVirtualAddress(pIATAddress[i], &isSuspect); if (apiFound == (ApiInfo *)1) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"apiFound == (ApiInfo *)1 -> " PRINTF_DWORD_PTR_FULL, pIATAddress[i]); #endif } else if (apiFound) { countApiFound++; #ifdef DEBUG_COMMENTS Scylla::debugLog.log(PRINTF_DWORD_PTR_FULL L" %s %d %s", apiFound->va, apiFound->module->getFilename(), apiFound->ordinal, apiFound->name); #endif if (module != apiFound->module) { module = apiFound->module; addFoundApiToModuleList(addressIAT + (DWORD_PTR)&pIATAddress[i] - (DWORD_PTR)iatBuffer, apiFound, true, isSuspect); } else { addFoundApiToModuleList(addressIAT + (DWORD_PTR)&pIATAddress[i] - (DWORD_PTR)iatBuffer, apiFound, false, isSuspect); } } else { countApiNotFound++; addNotFoundApiToModuleList(addressIAT + (DWORD_PTR)&pIATAddress[i] - (DWORD_PTR)iatBuffer, pIATAddress[i]); //printf("parseIAT :: API not found %08X\n", pIATAddress[i]); } } else { //printf("parseIAT :: API not found %08X\n", pIATAddress[i]); countApiNotFound++; addNotFoundApiToModuleList(addressIAT + (DWORD_PTR)&pIATAddress[i] - (DWORD_PTR)iatBuffer, pIATAddress[i]); } } Scylla::windowLog.log(L"IAT parsing finished, found %d valid APIs, missed %d APIs", countApiFound, countApiNotFound); } void ApiReader::addFoundApiToModuleList(DWORD_PTR iatAddressVA, ApiInfo * apiFound, bool isNewModule, bool isSuspect) { if (isNewModule) { addModuleToModuleList(apiFound->module->getFilename(), iatAddressVA - targetImageBase); } addFunctionToModuleList(apiFound, iatAddressVA, iatAddressVA - targetImageBase, apiFound->ordinal, true, isSuspect); } bool ApiReader::addModuleToModuleList(const WCHAR * moduleName, DWORD_PTR firstThunk) { ImportModuleThunk module; module.firstThunk = firstThunk; wcscpy_s(module.moduleName, 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; } } diff --git a/Scylla/ImportRebuilder.cpp b/Scylla/ImportRebuilder.cpp index 588225c..8ebe9d5 100644 --- a/Scylla/ImportRebuilder.cpp +++ b/Scylla/ImportRebuilder.cpp @@ -1,366 +1,366 @@ #include "ImportRebuilder.h" #include "Scylla.h" #include "StringConversion.h" //#define DEBUG_COMMENTS bool ImportRebuilder::rebuildImportTable(const WCHAR * newFilePath, std::map & moduleList) { bool retValue = false; if (isValidPeFile()) { if (readPeSectionsFromFile()) { setDefaultFileAlignment(); retValue = buildNewImportTable(moduleList); if (retValue) { alignAllSectionHeaders(); fixPeHeader(); retValue = savePeFileToDisk(newFilePath); } } } return retValue; } bool ImportRebuilder::buildNewImportTable(std::map & moduleList) { createNewImportSection(moduleList); importSectionIndex = listPeSection.size() - 1; DWORD dwSize = fillImportSection(moduleList); if (!dwSize) { return false; } setFlagToIATSection((*moduleList.begin()).second.firstThunk); DWORD vaImportAddress = listPeSection[importSectionIndex].sectionHeader.VirtualAddress; if (useOFT) { //OFT array is at the beginning of the import section vaImportAddress += (DWORD)sizeOfOFTArray; } if (isPE32()) { pNTHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = vaImportAddress; pNTHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = (DWORD)(numberOfImportDescriptors * sizeof(IMAGE_IMPORT_DESCRIPTOR)); } else { pNTHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = vaImportAddress; pNTHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = (DWORD)(numberOfImportDescriptors * sizeof(IMAGE_IMPORT_DESCRIPTOR)); } return true; } bool ImportRebuilder::createNewImportSection(std::map & moduleList) { char sectionName[IMAGE_SIZEOF_SHORT_NAME + 1] = {0}; const WCHAR * sectionNameW = Scylla::config[IAT_SECTION_NAME].getString(); calculateImportSizes(moduleList); if (wcslen(sectionNameW) > IMAGE_SIZEOF_SHORT_NAME) { strcpy_s(sectionName, ".SCY"); } else { StringConversion::ToASCII(sectionNameW, sectionName, _countof(sectionName)); } return addNewLastSection(sectionName, (DWORD)sizeOfImportSection, 0); } void ImportRebuilder::setFlagToIATSection(DWORD_PTR iatAddress) { for (size_t i = 0; i < listPeSection.size(); i++) { if ((listPeSection[i].sectionHeader.VirtualAddress <= iatAddress) && ((listPeSection[i].sectionHeader.VirtualAddress + listPeSection[i].sectionHeader.Misc.VirtualSize) > iatAddress)) { //section must be read and writeable listPeSection[i].sectionHeader.Characteristics |= IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE; } } } DWORD ImportRebuilder::fillImportSection(std::map & moduleList) { std::map::iterator mapIt; std::map::iterator mapIt2; PIMAGE_IMPORT_DESCRIPTOR pImportDesc = 0; PIMAGE_IMPORT_BY_NAME pImportByName = 0; PIMAGE_THUNK_DATA pThunk = 0; ImportModuleThunk * importModuleThunk = 0; ImportThunk * importThunk = 0; size_t stringLength = 0; DWORD_PTR lastRVA = 0; BYTE * sectionData = listPeSection[importSectionIndex].data; DWORD offset; DWORD offsetOFTArray = 0; if (useOFT) { //OFT Array is always at the beginning of the import section offset = (DWORD)sizeOfOFTArray; //size includes null termination } else { offset = 0; } pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD_PTR)sectionData + offset); //skip the IMAGE_IMPORT_DESCRIPTOR offset += (DWORD)(numberOfImportDescriptors * sizeof(IMAGE_IMPORT_DESCRIPTOR)); for ( mapIt = moduleList.begin() ; mapIt != moduleList.end(); mapIt++ ) { importModuleThunk = &((*mapIt).second); stringLength = addImportDescriptor(importModuleThunk, offset, offsetOFTArray); #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"fillImportSection :: importDesc.Name %X", pImportDescriptor->Name); #endif offset += (DWORD)stringLength; //stringLength has null termination char pImportByName = (PIMAGE_IMPORT_BY_NAME)((DWORD_PTR)sectionData + offset); //pThunk = (PIMAGE_THUNK_DATA)(getMemoryPointerFromRVA(importModuleThunk->firstThunk)); lastRVA = importModuleThunk->firstThunk - sizeof(DWORD_PTR); for ( mapIt2 = (*mapIt).second.thunkList.begin() ; mapIt2 != (*mapIt).second.thunkList.end(); mapIt2++ ) { importThunk = &((*mapIt2).second); if (useOFT) { //OFT Array is always at the beginning of the import section pThunk = (PIMAGE_THUNK_DATA)((DWORD_PTR)sectionData + offsetOFTArray); offsetOFTArray += sizeof(DWORD_PTR); //increase OFT array index } else { pThunk = (PIMAGE_THUNK_DATA)(getMemoryPointerFromRVA(importThunk->rva)); } //check wrong iat pointer if (!pThunk) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"fillImportSection :: Failed to get pThunk RVA: %X", importThunk->rva); #endif return 0; } if ((lastRVA + sizeof(DWORD_PTR)) != importThunk->rva) { //add additional import desc addSpecialImportDescriptor(importThunk->rva, offsetOFTArray); if (useOFT) { pThunk = (PIMAGE_THUNK_DATA)((DWORD_PTR)sectionData + offsetOFTArray); offsetOFTArray += sizeof(DWORD_PTR); //increase OFT array index, next module } } lastRVA = importThunk->rva; #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"fillImportSection :: importThunk %X pThunk %X pImportByName %X offset %X", importThunk,pThunk,pImportByName,offset); #endif stringLength = addImportToImportTable(importThunk, pThunk, pImportByName, offset); offset += (DWORD)stringLength; //is 0 bei import by ordinal pImportByName = (PIMAGE_IMPORT_BY_NAME)((DWORD_PTR)pImportByName + stringLength); } offsetOFTArray += sizeof(DWORD_PTR); //increase OFT array index, next module pImportDescriptor++; } return offset; } size_t ImportRebuilder::addImportDescriptor(ImportModuleThunk * pImportModule, DWORD sectionOffset, DWORD sectionOffsetOFTArray) { char dllName[MAX_PATH]; StringConversion::ToASCII(pImportModule->moduleName, dllName, _countof(dllName)); size_t stringLength = strlen(dllName) + 1; /* Warning: stringLength MUST include null termination char */ memcpy((listPeSection[importSectionIndex].data + sectionOffset), dllName, stringLength); //copy module name to section pImportDescriptor->FirstThunk = (DWORD)pImportModule->firstThunk; pImportDescriptor->Name = (DWORD)convertOffsetToRVAVector(listPeSection[importSectionIndex].sectionHeader.PointerToRawData + sectionOffset); if (useOFT) { pImportDescriptor->OriginalFirstThunk = (DWORD)convertOffsetToRVAVector(listPeSection[importSectionIndex].sectionHeader.PointerToRawData + sectionOffsetOFTArray); } return stringLength; } void ImportRebuilder::addSpecialImportDescriptor(DWORD_PTR rvaFirstThunk, DWORD sectionOffsetOFTArray) { PIMAGE_IMPORT_DESCRIPTOR oldID = pImportDescriptor; pImportDescriptor++; pImportDescriptor->FirstThunk = (DWORD)rvaFirstThunk; pImportDescriptor->Name = oldID->Name; if (useOFT) { pImportDescriptor->OriginalFirstThunk = (DWORD)convertOffsetToRVAVector(listPeSection[importSectionIndex].sectionHeader.PointerToRawData + sectionOffsetOFTArray); } } void ImportRebuilder::calculateImportSizes(std::map & moduleList) { std::map::iterator mapIt; std::map::iterator mapIt2; DWORD_PTR lastRVA = 0; - numberOfImportDescriptors = 0; + sizeOfImportSection = 0; sizeOfApiAndModuleNames = 0; sizeOfOFTArray = 0; numberOfImportDescriptors = moduleList.size() + 1; //last is zero'd for ( mapIt = moduleList.begin() ; mapIt != moduleList.end(); mapIt++ ) { lastRVA = (*mapIt).second.firstThunk - sizeof(DWORD_PTR); sizeOfApiAndModuleNames += (DWORD)(wcslen((*mapIt).second.moduleName) + 1); for ( mapIt2 = (*mapIt).second.thunkList.begin() ; mapIt2 != (*mapIt).second.thunkList.end(); mapIt2++ ) { if ((lastRVA + sizeof(DWORD_PTR)) != (*mapIt2).second.rva) { numberOfImportDescriptors++; //add additional import desc sizeOfOFTArray += sizeof(DWORD_PTR) + sizeof(DWORD_PTR); } if((*mapIt2).second.name[0] != '\0') { sizeOfApiAndModuleNames += sizeof(WORD); //Hint from IMAGE_IMPORT_BY_NAME sizeOfApiAndModuleNames += (DWORD)(strlen((*mapIt2).second.name) + 1); } //OriginalFirstThunk Array in Import Section: value sizeOfOFTArray += sizeof(DWORD_PTR); lastRVA = (*mapIt2).second.rva; } //OriginalFirstThunk Array in Import Section: NULL termination sizeOfOFTArray += sizeof(DWORD_PTR); } sizeOfImportSection = sizeOfOFTArray + sizeOfApiAndModuleNames + (numberOfImportDescriptors * sizeof(IMAGE_IMPORT_DESCRIPTOR)); } size_t ImportRebuilder::addImportToImportTable( ImportThunk * pImport, PIMAGE_THUNK_DATA pThunk, PIMAGE_IMPORT_BY_NAME pImportByName, DWORD sectionOffset) { size_t stringLength = 0; if(pImport->name[0] == '\0') { pThunk->u1.AddressOfData = (IMAGE_ORDINAL(pImport->ordinal) | IMAGE_ORDINAL_FLAG); } else { pImportByName->Hint = pImport->hint; stringLength = strlen(pImport->name) + 1; memcpy(pImportByName->Name, pImport->name, stringLength); pThunk->u1.AddressOfData = convertOffsetToRVAVector(listPeSection[importSectionIndex].sectionHeader.PointerToRawData + sectionOffset); if (!pThunk->u1.AddressOfData) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"addImportToImportTable :: failed to get AddressOfData %X %X", listPeSection[importSectionIndex].sectionHeader.PointerToRawData, sectionOffset); #endif } //next import should be nulled pThunk++; pThunk->u1.AddressOfData = 0; #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"addImportToImportTable :: pThunk->u1.AddressOfData %X %X %X", pThunk->u1.AddressOfData, pThunk, listPeSection[importSectionIndex].sectionHeader.PointerToRawData + sectionOffset); #endif stringLength += sizeof(WORD); } return stringLength; } BYTE * ImportRebuilder::getMemoryPointerFromRVA(DWORD_PTR dwRVA) { int peSectionIndex = convertRVAToOffsetVectorIndex(dwRVA); if (peSectionIndex == -1) { return 0; } DWORD rvaPointer = ((DWORD)dwRVA - listPeSection[peSectionIndex].sectionHeader.VirtualAddress); DWORD minSectionSize = rvaPointer + (sizeof(DWORD_PTR) * 2); //add space for 1 IAT address if (listPeSection[peSectionIndex].data == 0 || listPeSection[peSectionIndex].dataSize == 0) { listPeSection[peSectionIndex].dataSize = minSectionSize; listPeSection[peSectionIndex].normalSize = minSectionSize; listPeSection[peSectionIndex].data = new BYTE[listPeSection[peSectionIndex].dataSize]; listPeSection[peSectionIndex].sectionHeader.SizeOfRawData = listPeSection[peSectionIndex].dataSize; } else if(listPeSection[peSectionIndex].dataSize < minSectionSize) { BYTE * temp = new BYTE[minSectionSize]; memcpy(temp, listPeSection[peSectionIndex].data, listPeSection[peSectionIndex].dataSize); delete [] listPeSection[peSectionIndex].data; listPeSection[peSectionIndex].data = temp; listPeSection[peSectionIndex].dataSize = minSectionSize; listPeSection[peSectionIndex].normalSize = minSectionSize; listPeSection[peSectionIndex].sectionHeader.SizeOfRawData = listPeSection[peSectionIndex].dataSize; } return (BYTE *)((DWORD_PTR)listPeSection[peSectionIndex].data + rvaPointer); } void ImportRebuilder::enableOFTSupport() { useOFT = true; } diff --git a/Scylla/PeParser.cpp b/Scylla/PeParser.cpp index 8a22411..ca700ed 100644 --- a/Scylla/PeParser.cpp +++ b/Scylla/PeParser.cpp @@ -1,1223 +1,1223 @@ #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) + 200 + sizeof(IMAGE_NT_HEADERS64); + DWORD readSize = sizeof(IMAGE_DOS_HEADER) + 0x300 + sizeof(IMAGE_NT_HEADERS64); - if (readSectionHeaders) - { - readSize += (10 * sizeof(IMAGE_SECTION_HEADER)); - } + //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); } 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; } 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::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; } diff --git a/Scylla/ProcessLister.cpp b/Scylla/ProcessLister.cpp index 1bb5c13..3a5f30e 100644 --- a/Scylla/ProcessLister.cpp +++ b/Scylla/ProcessLister.cpp @@ -1,331 +1,344 @@ #include "ProcessLister.h" #include "SystemInformation.h" #include "Logger.h" #include "ProcessAccessHelp.h" #include //#define DEBUG_COMMENTS def_IsWow64Process ProcessLister::_IsWow64Process = 0; std::vector& ProcessLister::getProcessList() { return processList; } bool ProcessLister::isWindows64() { #ifdef _WIN64 //compiled 64bit application return true; #else //32bit exe, check wow64 BOOL bIsWow64 = FALSE; //not available in all windows operating systems //Minimum supported client: Windows Vista, Windows XP with SP2 //Minimum supported server: Windows Server 2008, Windows Server 2003 with SP1 if (_IsWow64Process) { _IsWow64Process(GetCurrentProcess(), &bIsWow64); if (bIsWow64 == TRUE) { return true; } else { return false; } } else { return false; } #endif } //only needed in windows xp DWORD ProcessLister::setDebugPrivileges() { DWORD err = 0; HANDLE hToken = 0; TOKEN_PRIVILEGES Debug_Privileges = {0}; if(!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &Debug_Privileges.Privileges[0].Luid)) { return GetLastError(); } if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) { err = GetLastError(); if(hToken) CloseHandle(hToken); return err; } Debug_Privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; Debug_Privileges.PrivilegeCount = 1; AdjustTokenPrivileges(hToken, false, &Debug_Privileges, 0, NULL, NULL); CloseHandle(hToken); return GetLastError(); } /************************************************************************/ /* Check if a process is 32 or 64bit */ /************************************************************************/ ProcessType ProcessLister::checkIsProcess64(DWORD dwPID) { HANDLE hProcess; BOOL bIsWow64 = FALSE; if (dwPID == 0) { //unknown return PROCESS_UNKNOWN; } //hProcess = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, NULL, dwPID); hProcess = ProcessAccessHelp::NativeOpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, dwPID); if(!hProcess) { //missing rights return PROCESS_MISSING_RIGHTS; } if (!isWindows64()) { //32bit win can only run 32bit process CloseHandle(hProcess); return PROCESS_32; } _IsWow64Process(hProcess, &bIsWow64); CloseHandle(hProcess); if (bIsWow64 == FALSE) { //process not running under wow return PROCESS_64; } else { //process running under wow -> 32bit return PROCESS_32; } } bool ProcessLister::getAbsoluteFilePath(Process * process) { WCHAR processPath[MAX_PATH]; HANDLE hProcess; + bool retVal = false; //hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, NULL, process->PID); - hProcess = ProcessAccessHelp::NativeOpenProcess(PROCESS_QUERY_INFORMATION, process->PID); + hProcess = ProcessAccessHelp::NativeOpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, process->PID); + + wcscpy_s(process->fullPath, L"Unknown path"); if(!hProcess) { //missing rights return false; } - if (GetProcessImageFileName(hProcess, processPath, _countof(processPath)) > 0) + if (GetProcessImageFileNameW(hProcess, processPath, _countof(processPath)) > 0) { - CloseHandle(hProcess); - if (!deviceNameResolver->resolveDeviceLongNameToShort(processPath, process->fullPath)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"getAbsoluteFilePath :: resolveDeviceLongNameToShort failed with path %s", processPath); #endif + //some virtual volumes + if (GetModuleFileNameExW(hProcess, 0, process->fullPath, _countof(process->fullPath)) != 0) + { + retVal = true; + } + } + else + { + retVal = true; } - return true; } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"getAbsoluteFilePath :: GetProcessImageFileName failed %u", GetLastError()); #endif - CloseHandle(hProcess); - return false; + if (GetModuleFileNameExW(hProcess, 0, process->fullPath, _countof(process->fullPath)) != 0) + { + retVal = true; + } } + CloseHandle(hProcess); + return retVal; } std::vector& ProcessLister::getProcessListSnapshot() { HANDLE hProcessSnap; ProcessType processType; PROCESSENTRY32 pe32; HANDLE hModuleSnap = INVALID_HANDLE_VALUE; MODULEENTRY32 me32 = {0}; Process process; if (!processList.empty()) { //clear elements, but keep reversed memory processList.clear(); } else { //first time, reserve memory processList.reserve(34); } hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if(hProcessSnap == INVALID_HANDLE_VALUE) { return processList; } pe32.dwSize = sizeof(PROCESSENTRY32); if(!Process32First(hProcessSnap, &pe32)) { CloseHandle(hProcessSnap); return processList; } do { //filter process list if (pe32.th32ProcessID > 4) { processType = checkIsProcess64(pe32.th32ProcessID); if (processType != PROCESS_MISSING_RIGHTS) { #ifdef _WIN64 if (processType == PROCESS_64) #else if (processType == PROCESS_32) #endif { process.PID = pe32.th32ProcessID; hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, process.PID); if(hModuleSnap != INVALID_HANDLE_VALUE) { me32.dwSize = sizeof(MODULEENTRY32); Module32First(hModuleSnap, &me32); process.imageBase = (DWORD_PTR)me32.hModule; process.imageSize = me32.modBaseSize; CloseHandle(hModuleSnap); } wcscpy_s(process.filename, pe32.szExeFile); getAbsoluteFilePath(&process); processList.push_back(process); } } } } while(Process32Next(hProcessSnap, &pe32)); CloseHandle(hProcessSnap); //reverse process list std::reverse(processList.begin(), processList.end()); return processList; } void ProcessLister::getAllModuleInformation() { /*for (std::size_t i = 0; i < processList.size(); i++) { getModuleInformationByProcess(&processList[i]); }*/ } void ProcessLister::getModuleInformationByProcess(Process *process) { /* MODULEENTRY32 me32 = {0}; HANDLE hModuleSnap = INVALID_HANDLE_VALUE; char temp[111]; if (process->PID == 0) { MessageBox(0, "PID == NULL","ProcessLister::getModuleInformationByProcess", MB_OK|MB_ICONWARNING); return; } #ifdef _WIN64 if (!process->is64BitProcess) { //MessageBox(hWndDlg, "I'm a x64 process and you're trying to access a 32-bit process!","displayModuleList", MB_OK); return; } #else if (process->is64BitProcess) { //MessageBox(hWndDlg, "I'm a 32-bit process and you're trying to access a x64 process!","displayModuleList", MB_OK); return; } #endif hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, process->PID); if(hModuleSnap == INVALID_HANDLE_VALUE) { sprintf_s(temp, "GetLastError %d",GetLastError()); MessageBox(0, temp,"ProcessLister::getModuleInformationByProcess", MB_OK|MB_ICONWARNING); return; } me32.dwSize = sizeof(MODULEENTRY32); if(!Module32First(hModuleSnap, &me32)) { MessageBox(0, "Module32First error","ProcessLister::getModuleInformationByProcess", MB_OK|MB_ICONWARNING); CloseHandle(hModuleSnap); return; } do { ModuleInfo moduleInfo; if (!_strnicmp(me32.szExePath,"\\Systemroot",11)) { char * path = (char *)malloc(MAX_PATH); sprintf_s(path"%s\\%s",getenv("SystemRoot"),(me32.szExePath + 12)); strcpy_s(moduleInfo.fullPath,MAX_PATH, path); free(path); } else if(!_strnicmp(me32.szExePath,"\\??\\",4)) { strcpy_s(moduleInfo.fullPath,MAX_PATH, (me32.szExePath + 4)); } else { strcpy_s(moduleInfo.fullPath,MAX_PATH,me32.szExePath); } moduleInfo.hModule = (DWORD_PTR)me32.hModule; moduleInfo.modBaseSize = me32.modBaseSize; moduleInfo.modBaseAddr = (DWORD_PTR)me32.modBaseAddr; process->moduleList[moduleInfo.hModule] = moduleInfo; } while(Module32Next(hModuleSnap, &me32)); CloseHandle(hModuleSnap);*/ } diff --git a/Scylla/Scylla.h b/Scylla/Scylla.h index 1cb85ab..41e74f8 100644 --- a/Scylla/Scylla.h +++ b/Scylla/Scylla.h @@ -1,32 +1,32 @@ #pragma once #include "ConfigurationHolder.h" #include "PluginLoader.h" #include "ProcessLister.h" #include "Logger.h" #define APPNAME_S "Scylla" -#define APPVERSION_S "v0.9" -#define APPVERSIONDWORD 0x00009000 +#define APPVERSION_S "v0.9.1" +#define APPVERSIONDWORD 0x00009100 #define APPNAME TEXT(APPNAME_S) #define APPVERSION TEXT(APPVERSION_S) class Scylla { public: static void init(); static ConfigurationHolder config; static PluginLoader plugins; static ProcessLister processLister; static FileLog debugLog; static ListboxLog windowLog; private: static const WCHAR DEBUG_LOG_FILENAME[]; };