diff --git a/Scylla/ApiReader.cpp b/Scylla/ApiReader.cpp index aeff6fe..f07ed76 100644 --- a/Scylla/ApiReader.cpp +++ b/Scylla/ApiReader.cpp @@ -1,1116 +1,1117 @@ #include "ApiReader.h" #include "Logger.h" #include "definitions.h" #include "SystemInformation.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; } Logger::printfDialog(TEXT("Module parsing: %s"),moduleList[i].fullPath); if (!moduleList[i].isAlreadyParsed) { parseModule(&moduleList[i]); } } #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("Address Min ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT(" Max ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT("\nimagebase ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT(" maxValidAddress ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT("\r\n"),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, DWORD_PTR ordinalParent, ModuleInfo *moduleParent) +void ApiReader::handleForwardedApi(DWORD_PTR vaStringPointer,char * functionNameParent, DWORD_PTR rvaParent, WORD ordinalParent, ModuleInfo *moduleParent) { size_t dllNameLength = 0; - DWORD_PTR ordinal = 0; + WORD ordinal = 0; ModuleInfo *module = 0; DWORD_PTR vaApi = 0; DWORD_PTR rvaApi = 0; char dllName[100] = {0}; WCHAR dllNameW[100] = {0}; char *fordwardedString = (char *)vaStringPointer; char *searchFunctionName = strchr(fordwardedString, '.'); if (!searchFunctionName) return; dllNameLength = searchFunctionName - fordwardedString; if (dllNameLength >= 99) { return; } else { strncpy_s(dllName,sizeof(dllName),fordwardedString,dllNameLength); } searchFunctionName++; //Windows 7 if (!strncmp(dllName,"api-ms-win-", 11)) { /* Info: http://www.nirsoft.net/articles/windows_7_kernel_architecture_changes.html */ FARPROC addy = GetProcAddress(GetModuleHandleA(dllName), searchFunctionName); if (addy != 0) { addApi(functionNameParent,0, ordinalParent, (DWORD_PTR)addy, (DWORD_PTR)addy - (DWORD_PTR)GetModuleHandleA(dllName), true, moduleParent); } return; } strcat_s(dllName,sizeof(dllName),".dll"); size_t convertedChars = 0; mbstowcs_s(&convertedChars, dllNameW, strlen(dllName) + 1, dllName, _TRUNCATE); 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 = atoi(searchFunctionName); + ordinal = (WORD)atoi(searchFunctionName); findApiByModuleAndOrdinal(module, ordinal, &vaApi, &rvaApi); } else { findApiByModuleAndName(module, searchFunctionName, &vaApi, &rvaApi); } if (rvaApi == 0) { #ifdef DEBUG_COMMENTS Logger::debugLog(L"handleForwardedApi :: Api not found, this is really BAD! %S\r\n",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(DWORD_PTR ordinal, DWORD_PTR va, DWORD_PTR rva,bool isForwarded, ModuleInfo *moduleInfo) +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, DWORD_PTR ordinal, DWORD_PTR va, DWORD_PTR rva, bool isForwarded, ModuleInfo *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) < MAX_PATH)) { strcpy_s(apiInfo->name, MAX_PATH, 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 Logger::debugLog(L"getHeaderFromProcess :: Error reading header\r\n"); #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 Logger::debugLog(L"Something is wrong with the PE Header here Export table size %d\r\n",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 Logger::debugLog(L"getExportTableFromProcess :: Error reading export table from process\r\n"); #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, ordinal = 0; - DWORD i = 0, j = 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 Logger::debugLog(L"parseExportTable :: module %s NumberOfNames %X\r\n",module->fullPath,pExportDir->NumberOfNames); #endif for (i = 0; i < pExportDir->NumberOfNames; i++) { functionName = (char*)(addressOfNamesArray[i] + deltaAddress); - ordinal = (addressOfNameOrdinalsArray[i] + pExportDir->Base); + ordinal = (WORD)(addressOfNameOrdinalsArray[i] + pExportDir->Base); RVA = addressOfFunctionsArray[addressOfNameOrdinalsArray[i]]; VA = addressOfFunctionsArray[addressOfNameOrdinalsArray[i]] + module->modBaseAddr; #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("parseExportTable :: api %S ")TEXT(" ordinal %d imagebase ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT(" RVA ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT(" VA ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT("\r\n"),functionName,ordinal,module->modBaseAddr,RVA,VA); #endif if (!isApiBlacklisted(functionName)) { if (!isApiForwarded(RVA,pNtHeader)) { - addApi(functionName, (WORD)i, ordinal,VA,RVA,false,module); + 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 = (i+pExportDir->Base); + 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, DWORD_PTR ordinal, DWORD_PTR * vaApi, DWORD_PTR * rvaApi) +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, DWORD_PTR ordinal, DWORD_PTR * vaApi, DWORD_PTR * rvaApi) +void ApiReader::findApiByModule(ModuleInfo * module, char * searchFunctionName, WORD ordinal, DWORD_PTR * vaApi, DWORD_PTR * rvaApi) { if (isModuleLoadedInOwnProcess(module)) { HMODULE hModule = GetModuleHandle(module->getFilename()); if (hModule) { if (ordinal) { *vaApi = (DWORD_PTR)GetProcAddress(hModule, (LPCSTR)ordinal); } else { *vaApi = (DWORD_PTR)GetProcAddress(hModule, searchFunctionName); } if (vaApi) { *rvaApi = (*vaApi) - (DWORD_PTR)hModule; *vaApi = (*rvaApi) + module->modBaseAddr; } else { #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("findApiByModule :: vaApi == NULL, should never happen %S\r\n"),searchFunctionName); #endif } } else { #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("findApiByModule :: hModule == NULL, should never happen %s\r\n"),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 Logger::debugLog(TEXT("parseModuleWithOwnProcess :: hModule is NULL\r\n")); #endif } } bool ApiReader::isPeAndExportTableValid(PIMAGE_NT_HEADERS pNtHeader) { if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) { Logger::printfDialog(TEXT("-> 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)) { Logger::printfDialog(TEXT("-> No export table.")); return false; } else { return true; } } -void ApiReader::findApiInProcess(ModuleInfo * module, char * searchFunctionName, DWORD_PTR ordinal, DWORD_PTR * vaApi, DWORD_PTR * rvaApi) +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, DWORD_PTR ordinal, DWORD_PTR * vaApi, DWORD_PTR * rvaApi) +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(); if (!_wcsicmp(moduleFileName, TEXT("kernelbase.dll"))) { module->priority = 0; } else if (!_wcsicmp(moduleFileName, TEXT("ntdll.dll"))) { module->priority = 0; } else if (!_wcsicmp(moduleFileName, TEXT("shlwapi.dll"))) { module->priority = 0; } else if (!_wcsicmp(moduleFileName, TEXT("ShimEng.dll"))) { module->priority = 0; } else if (!_wcsicmp(moduleFileName, TEXT("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) { Logger::printfDialog(TEXT("getApiByVirtualAddress :: No Api found ")TEXT(PRINTF_DWORD_PTR_FULL),virtualAddress); return 0; } else if (countDuplicates == 1) { //API is 100% correct *isSuspect = false; it1 = apiList.find(virtualAddress); // Find first match. return (ApiInfo *)((*it1).second); } else { it1 = apiList.find(virtualAddress); // Find first match. it2 = it1; for (c = 0; c < countDuplicates; c++, it1++) { apiFound = (ApiInfo *)((*it1).second); if (apiFound->module->priority >= 1) //1 == high priority { countHighPriority++; } } it1 = it2; /* This is flawed: It chooses api(prio:1, name:no) over api(prio:0, name:yes) (e.g. SHLWAPI.PathCombineW vs SHELL32.#25) Maybe there should be a check higher up in the code, to see if this API is surrounded by APIs of a DLL and pick the duplicate from that DLL */ if (countHighPriority == 0) { #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("getApiByVirtualAddress :: countHighPriority == 0 ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT("\r\n"),virtualAddress); #endif *isSuspect = true; return (ApiInfo *)((*it1).second); } else if (countHighPriority == 1) // what about kernel32, it has priority 2 { //API is 100% correct if countHighPriority == 1 and name export *isSuspect = false; for (c = 0; c < countDuplicates; c++, it1++) { apiFound = (ApiInfo *)((*it1).second); if (apiFound->module->priority >= 1 && apiFound->name[0] != 0x00) //1 == high priority { return apiFound; } } } //else // fall through for case api1(priority:1, name:false) <> api2(priority:0, name:true) { //API not 100% correct #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("getApiByVirtualAddress :: countHighPriority == %d ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT("\r\n"),countHighPriority,virtualAddress); #endif *isSuspect = true; /*for (c = 0; c < countDuplicates; c++, it1++) { apiFound = (ApiInfo *)((*it1).second); Logger::printfDialog("%s - %s %X %X\n",apiFound->name,apiFound->module->getFilename(),apiFound->rva, apiFound->ordinal); } it1 = it2;*/ for (c = 0; c < countDuplicates; c++, it1++) { apiFound = (ApiInfo *)((*it1).second); //prefer APIs with a name if (apiFound->module->priority >= 1 && apiFound->name[0] != 0x00) //1 == high priority { //prefer ANSI/UNICODE APIs if (strrchr(apiFound->name,TEXT('W')) || strrchr(apiFound->name,TEXT('A'))) { return apiFound; } } } it1 = it2; for (c = 0; c < countDuplicates; c++, it1++) { apiFound = (ApiInfo *)((*it1).second); //prefer APIs with a name if (apiFound->module->priority == 2 && !strrchr(apiFound->name,TEXT('_'))) //1 == high priority { return apiFound; } } it1 = it2; for (c = 0; c < countDuplicates; c++, it1++) { apiFound = (ApiInfo *)((*it1).second); if (apiFound->module->priority == 1 && apiFound->name[0] != 0x00) //1 == high priority { return apiFound; } } it1 = it2; for (c = 0; c < countDuplicates; c++, it1++) { apiFound = (ApiInfo *)((*it1).second); if (apiFound->module->priority == 1) //1 == high priority { return apiFound; } } } } //is never reached Logger::printfDialog(TEXT("getApiByVirtualAddress :: There is a big bug")); return (ApiInfo *) 1; } 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 Logger::debugLog(TEXT("ApiReader::readAndParseIAT :: error reading iat ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT("\r\n"),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++) { //Logger::printfDialog("%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 Logger::debugLog(TEXT("apiFound == (ApiInfo *)1 -> ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT("\r\n"),pIATAddress[i]); #endif } else if (apiFound) { countApiFound++; #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("")TEXT(PRINTF_DWORD_PTR_FULL)TEXT(" %s %d %s\r\n"),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]); } } Logger::printfDialog(TEXT("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, MAX_PATH, moduleName); (*moduleThunkList).insert(std::pair(firstThunk,module)); return true; } void ApiReader::addUnknownModuleToModuleList(DWORD_PTR firstThunk) { ImportModuleThunk module; module.firstThunk = firstThunk; wcscpy_s(module.moduleName, MAX_PATH, TEXT("?")); (*moduleThunkList).insert(std::pair(firstThunk,module)); } -bool ApiReader::addFunctionToModuleList(ApiInfo * apiFound, DWORD_PTR va, DWORD_PTR rva, DWORD_PTR ordinal, bool valid, bool suspect) +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 Logger::debugLog(TEXT("Error iterator1 != (*moduleThunkList).end()\r\n")); #endif break; } } } else { iterator1 = (*moduleThunkList).begin(); module = &(iterator1->second); } if (!module) { #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("ImportsHandling::addFunction module not found rva ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT("\r\n"),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, MAX_PATH, apiFound->module->getFilename()); strcpy_s(import.name, MAX_PATH, apiFound->name); module->thunkList.insert(std::pair(import.rva, import)); return true; } void ApiReader::clearAll() { minApiAddress = -1; maxApiAddress = 0; for ( stdext::hash_multimap::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 Logger::debugLog(TEXT("Error iterator1 != (*moduleThunkList).end()\r\n")); #endif break; } } } else { //new unknown module addUnknownModuleToModuleList(rva); module = &((*moduleThunkList).find(rva)->second); } if (!module) { #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("ImportsHandling::addFunction module not found rva ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT("\r\n"),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, MAX_PATH, TEXT("?")); strcpy_s(import.name, MAX_PATH, "?"); 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, TEXT("\\WinSxS\\"))) { return true; } else if (wcsstr(module->fullPath, TEXT("\\winsxs\\"))) { return true; } else { return false; } } diff --git a/Scylla/ApiReader.h b/Scylla/ApiReader.h index de09da2..36f86a2 100644 --- a/Scylla/ApiReader.h +++ b/Scylla/ApiReader.h @@ -1,70 +1,70 @@ #pragma once #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 clearAll(); private: void parseIAT(DWORD_PTR addressIAT, BYTE * iatBuffer, SIZE_T size); - void addApi(char *functionName, WORD hint, DWORD_PTR ordinal, DWORD_PTR va, DWORD_PTR rva, bool isForwarded, ModuleInfo *moduleInfo); - void addApiWithoutName(DWORD_PTR ordinal, DWORD_PTR va, DWORD_PTR rva,bool isForwarded, ModuleInfo *moduleInfo); + 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, DWORD_PTR ordinalParent, ModuleInfo *moduleParent); + 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, DWORD_PTR ordinal, DWORD_PTR * vaApi, DWORD_PTR * rvaApi); + 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, DWORD_PTR ordinal, 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, DWORD_PTR ordinal, DWORD_PTR * vaApi, DWORD_PTR * rvaApi ); - bool findApiInExportTable(ModuleInfo *module, PIMAGE_EXPORT_DIRECTORY pExportDir, DWORD_PTR deltaAddress, char * searchFunctionName, DWORD_PTR ordinal, DWORD_PTR * vaApi, DWORD_PTR * rvaApi); + void findApiInProcess( ModuleInfo * module, char * searchFunctionName, WORD ordinal, DWORD_PTR * vaApi, DWORD_PTR * rvaApi ); + bool findApiInExportTable(ModuleInfo *module, PIMAGE_EXPORT_DIRECTORY pExportDir, DWORD_PTR deltaAddress, char * searchFunctionName, WORD ordinal, DWORD_PTR * vaApi, DWORD_PTR * rvaApi); BYTE * getHeaderFromProcess(ModuleInfo * module); BYTE * getExportTableFromProcess(ModuleInfo * module, PIMAGE_NT_HEADERS pNtHeader); void setModulePriority(ModuleInfo * module); void setMinMaxApiAddress(DWORD_PTR virtualAddress); void parseModuleWithMapping(ModuleInfo *moduleInfo); //not used void addFoundApiToModuleList(DWORD_PTR iatAddress, ApiInfo * apiFound, bool isNewModule, bool isSuspect); bool addModuleToModuleList(const WCHAR * moduleName, DWORD_PTR firstThunk); - bool addFunctionToModuleList(ApiInfo * apiFound, DWORD_PTR va, DWORD_PTR rva, DWORD_PTR ordinal, bool valid, bool suspect); + 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 ); }; \ No newline at end of file diff --git a/Scylla/ImportsHandling.cpp b/Scylla/ImportsHandling.cpp index d9b4744..ea8ca46 100644 --- a/Scylla/ImportsHandling.cpp +++ b/Scylla/ImportsHandling.cpp @@ -1,788 +1,771 @@ #include "ImportsHandling.h" #include "Thunks.h" #include "definitions.h" #include #include #include "multitree.h" // CMultiSelectTreeViewCtrl #include "resource.h" //#define DEBUG_COMMENTS -ImportsHandling::ImportsHandling(CMultiSelectTreeViewCtrl& TreeImports) : TreeImports(TreeImports) -{ - hIconCheck.LoadIcon(IDI_ICON_CHECK); - hIconWarning.LoadIcon(IDI_ICON_WARNING); - hIconError.LoadIcon(IDI_ICON_ERROR); - - TreeIcons.Create(16, 16, ILC_COLOR32, 3, 1); - TreeIcons.AddIcon(hIconCheck); - TreeIcons.AddIcon(hIconWarning); - TreeIcons.AddIcon(hIconError); -} - -ImportsHandling::~ImportsHandling() -{ - TreeIcons.Destroy(); +void ImportThunk::invalidate() +{ + ordinal = 0; + hint = 0; + valid = false; + suspect = false; + moduleName[0] = 0; + name[0] = 0; } bool ImportModuleThunk::isValid() const { std::map::const_iterator iterator = thunkList.begin(); while (iterator != thunkList.end()) { if (iterator->second.valid == false) { return false; } iterator++; } return true; } DWORD_PTR ImportModuleThunk::getFirstThunk() const { if (thunkList.size() > 0) { const std::map::const_iterator iterator = thunkList.begin(); return iterator->first; } else { return 0; } } -/*bool ImportsHandling::addModule(WCHAR * moduleName, DWORD_PTR firstThunk) +ImportsHandling::ImportsHandling(CMultiSelectTreeViewCtrl& TreeImports) : TreeImports(TreeImports) { - ImportModuleThunk module; + hIconCheck.LoadIcon(IDI_ICON_CHECK, 16, 16); + hIconWarning.LoadIcon(IDI_ICON_WARNING, 16, 16); + hIconError.LoadIcon(IDI_ICON_ERROR, 16, 16); - module.firstThunk = firstThunk; - wcscpy_s(module.moduleName, MAX_PATH, moduleName); + TreeIcons.Create(16, 16, ILC_COLOR32, 3, 1); + TreeIcons.AddIcon(hIconCheck); + TreeIcons.AddIcon(hIconWarning); + TreeIcons.AddIcon(hIconError); +} - moduleList.insert(std::pair(firstThunk,module)); +ImportsHandling::~ImportsHandling() +{ + TreeIcons.Destroy(); +} - return true; -}*/ +bool ImportsHandling::isModule(CTreeItem item) +{ + return (0 != getModuleThunk(item)); +} + +bool ImportsHandling::isImport(CTreeItem item) +{ + return (0 != getImportThunk(item)); +} + +ImportModuleThunk * ImportsHandling::getModuleThunk(CTreeItem item) +{ + std::hash_map::const_iterator it; + it = itemData.find(item); + if(it != itemData.end()) + { + const TreeItemData * data = &it->second; + if(data->isModule) + { + return data->module; + } + } + return NULL; +} + +ImportThunk * ImportsHandling::getImportThunk(CTreeItem item) +{ + std::hash_map::const_iterator it; + TreeItemData * data = getItemData(item); + if(data && !data->isModule) + { + return data->import; + } + return NULL; +} + +void ImportsHandling::setItemData(CTreeItem item, const TreeItemData& data) +{ + itemData[item] = data; +} + +ImportsHandling::TreeItemData * ImportsHandling::getItemData(CTreeItem item) +{ + std::hash_map::iterator it; + it = itemData.find(item); + if(it != itemData.end()) + { + return &it->second; + } + return NULL; +} + +void ImportsHandling::updateCounts() +{ + std::map::iterator it_module; + std::map::iterator it_import; + + m_thunkCount = m_invalidThunkCount = m_suspectThunkCount = 0; + + it_module = moduleList.begin(); + while (it_module != moduleList.end()) + { + ImportModuleThunk &moduleThunk = it_module->second; + + it_import = moduleThunk.thunkList.begin(); + while (it_import != moduleThunk.thunkList.end()) + { + ImportThunk &importThunk = it_import->second; + + m_thunkCount++; + if(!importThunk.valid) + m_invalidThunkCount++; + else if(importThunk.suspect) + m_suspectThunkCount++; + + it_import++; + } + + it_module++; + } +} -/*bool ImportsHandling::addFunction(WCHAR * moduleName, char * name, DWORD_PTR va, DWORD_PTR rva, DWORD_PTR ordinal, bool valid, bool suspect) +/*bool ImportsHandling::addImport(const WCHAR * moduleName, const CHAR * name, DWORD_PTR va, DWORD_PTR rva, WORD ordinal, bool valid, bool suspect) { ImportThunk import; ImportModuleThunk * module = 0; std::map::iterator iterator1; if (moduleList.size() > 1) { iterator1 = moduleList.begin(); while (iterator1 != moduleList.end()) { if (rva >= iterator1->second.firstThunk) { iterator1++; if (iterator1 == moduleList.end()) { iterator1--; module = &(iterator1->second); break; } else if (rva < iterator1->second.firstThunk) { iterator1--; module = &(iterator1->second); break; } } } } else { iterator1 = moduleList.begin(); module = &(iterator1->second); } if (!module) { Logger::debugLog(TEXT("ImportsHandling::addFunction module not found rva ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT(""),rva); return false; } //TODO import.suspect = true; import.valid = false; import.va = va; import.rva = rva; import.ordinal = ordinal; wcscpy_s(import.moduleName, MAX_PATH, moduleName); strcpy_s(import.name, MAX_PATH, name); module->thunkList.insert(std::pair(import.rva, import)); return true; -}*/ +} +*/ + +/* +bool ImportsHandling::addModule(const WCHAR * moduleName, DWORD_PTR firstThunk) +{ + ImportModuleThunk module; + + module.firstThunk = firstThunk; + wcscpy_s(module.moduleName, MAX_PATH, moduleName); + + moduleList.insert(std::pair(firstThunk,module)); + + return true; +} +*/ void ImportsHandling::displayAllImports() { std::map::iterator it_module; - std::map::iterator it_thunk; - ImportModuleThunk * moduleThunk; - ImportThunk * importThunk; - CTreeItem module; - CTreeItem apiFunction; + std::map::iterator it_import; TreeImports.DeleteAllItems(); + itemData.clear(); TreeImports.SetImageList(TreeIcons); - it_module = moduleList.begin(); + it_module = moduleList.begin(); + while (it_module != moduleList.end()) + { + ImportModuleThunk &moduleThunk = it_module->second; - while (it_module != moduleList.end()) - { - moduleThunk = &(it_module->second); + moduleThunk.hTreeItem = addDllToTreeView(TreeImports, &moduleThunk); - module = addDllToTreeView(TreeImports,moduleThunk); - - moduleThunk->hTreeItem = module; + it_import = moduleThunk.thunkList.begin(); + while (it_import != moduleThunk.thunkList.end()) + { + ImportThunk &importThunk = it_import->second; - it_thunk = moduleThunk->thunkList.begin(); + importThunk.hTreeItem = addApiToTreeView(TreeImports, moduleThunk.hTreeItem, &importThunk); - while (it_thunk != moduleThunk->thunkList.end()) - { - importThunk = &(it_thunk->second); - apiFunction = addApiToTreeView(TreeImports,module,importThunk); - importThunk->hTreeItem = apiFunction; - it_thunk++; - } + it_import++; + } + + it_module++; + } + + updateCounts(); +} - it_module++; - } +void ImportsHandling::clearAllImports() +{ + TreeImports.DeleteAllItems(); + itemData.clear(); + moduleList.clear(); + updateCounts(); } -CTreeItem ImportsHandling::addDllToTreeView(CMultiSelectTreeViewCtrl& idTreeView, const ImportModuleThunk * importThunk) +CTreeItem ImportsHandling::addDllToTreeView(CMultiSelectTreeViewCtrl& idTreeView, ImportModuleThunk * moduleThunk) { CTreeItem item = idTreeView.InsertItem(L"", NULL, TVI_ROOT); - updateModuleInTreeView(importThunk, item); + + item.SetData(itemData.size()); + + TreeItemData data; + data.isModule = true; + data.module = moduleThunk; + + setItemData(item, data); + + updateModuleInTreeView(moduleThunk, item); return item; } -CTreeItem ImportsHandling::addApiToTreeView(CMultiSelectTreeViewCtrl& idTreeView, CTreeItem parentDll, const ImportThunk * importThunk) +CTreeItem ImportsHandling::addApiToTreeView(CMultiSelectTreeViewCtrl& idTreeView, CTreeItem parentDll, ImportThunk * importThunk) { CTreeItem item = idTreeView.InsertItem(L"", parentDll, TVI_LAST); + + item.SetData(itemData.size()); + + TreeItemData data; + data.isModule = false; + data.import = importThunk; + + setItemData(item, data); + updateImportInTreeView(importThunk, item); return item; } -void ImportsHandling::showImports(bool invalid, bool suspect) +void ImportsHandling::selectImports(bool invalid, bool suspect) { - std::map::iterator iterator1; - std::map::iterator iterator2; - ImportModuleThunk * moduleThunk; - ImportThunk * importThunk; + std::map::iterator it_module; + std::map::iterator it_import; - TreeImports.SetFocus(); // should be GotoDlgCtrl... TreeImports.SelectAllItems(FALSE); //remove selection - iterator1 = moduleList.begin(); - - while (iterator1 != moduleList.end()) + it_module = moduleList.begin(); + while (it_module != moduleList.end()) { - moduleThunk = &(iterator1->second); + ImportModuleThunk &moduleThunk = it_module->second; - iterator2 = moduleThunk->thunkList.begin(); - - while (iterator2 != moduleThunk->thunkList.end()) + it_import = moduleThunk.thunkList.begin(); + while (it_import != moduleThunk.thunkList.end()) { - importThunk = &(iterator2->second); + ImportThunk &importThunk = it_import->second; - if (invalid && !importThunk->valid) - { - selectItem(importThunk->hTreeItem); - setFocus(TreeImports, importThunk->hTreeItem); - } - else if (suspect && importThunk->suspect) - { - selectItem(importThunk->hTreeItem); - setFocus(TreeImports, importThunk->hTreeItem); - } - else + if ((invalid && !importThunk.valid) || (suspect && importThunk.suspect)) { - unselectItem(importThunk->hTreeItem); + TreeImports.SelectItem(importThunk.hTreeItem, TRUE); + importThunk.hTreeItem.EnsureVisible(); } - iterator2++; + it_import++; } - iterator1++; + it_module++; } } -bool ImportsHandling::isItemSelected(CTreeItem hItem) -{ - const UINT state = TVIS_SELECTED; - return ((hItem.GetState(state) & state) == state); -} - -void ImportsHandling::unselectItem(CTreeItem htItem) -{ - selectItem(htItem, false); -} - -bool ImportsHandling::selectItem(CTreeItem hItem, bool select) -{ - const UINT state = TVIS_SELECTED; - return FALSE != hItem.SetState((select ? state : 0), state); -} - -void ImportsHandling::setFocus(CMultiSelectTreeViewCtrl& hwndTV, CTreeItem htItem) +bool ImportsHandling::invalidateImport(CTreeItem item) { - // the current focus - CTreeItem htFocus = hwndTV.GetFirstSelectedItem(); - - if ( htItem ) + ImportThunk * import = getImportThunk(item); + if(import) { - // set the focus - if ( htItem != htFocus ) + CTreeItem parent = item.GetParent(); + if(!parent.IsNull()) { - // remember the selection state of the item - bool wasSelected = isItemSelected(htItem); - - if ( htFocus && isItemSelected(htFocus) ) + const ImportModuleThunk * module = getModuleThunk(parent); + if(module) { - // prevent the tree from unselecting the old focus which it - // would do by default (TreeView_SelectItem unselects the - // focused item) - hwndTV.SelectAllItems(FALSE); - selectItem(htFocus); - } + import->invalidate(); - hwndTV.SelectItem(htItem, FALSE); + updateImportInTreeView(import, import->hTreeItem); + updateModuleInTreeView(module, module->hTreeItem); - if ( !wasSelected ) - { - // need to clear the selection which TreeView_SelectItem() gave - // us - unselectItem(htItem); - } - //else: was selected, still selected - ok - } - //else: nothing to do, focus already there - } - else - { - if ( htFocus ) - { - bool wasFocusSelected = isItemSelected(htFocus); - - // just clear the focus - hwndTV.SelectItem(NULL, FALSE); - - if ( wasFocusSelected ) - { - // restore the selection state - selectItem(htFocus); + updateCounts(); + return true; } } - //else: nothing to do, no focus already } + return false; } -bool ImportsHandling::invalidateFunction(CTreeItem selectedTreeNode) +bool ImportsHandling::setImport(CTreeItem item, const WCHAR * moduleName, const CHAR * apiName, WORD ordinal, WORD hint, bool valid, bool suspect) { - std::map::iterator iterator1; - std::map::iterator iterator2; - ImportModuleThunk * moduleThunk; - ImportThunk * importThunk; - - - iterator1 = moduleList.begin(); - - while (iterator1 != moduleList.end()) + ImportThunk * import = getImportThunk(item); + if(import) { - moduleThunk = &(iterator1->second); - - iterator2 = moduleThunk->thunkList.begin(); - - while (iterator2 != moduleThunk->thunkList.end()) + CTreeItem parent = item.GetParent(); + if(!parent.IsNull()) { - importThunk = &(iterator2->second); - - if (importThunk->hTreeItem == selectedTreeNode) + const ImportModuleThunk * module = getModuleThunk(parent); + if(module) { - importThunk->ordinal = 0; - importThunk->hint = 0; - importThunk->valid = false; - importThunk->suspect = false; - importThunk->moduleName[0] = 0; - importThunk->name[0] = 0; - - updateImportInTreeView(importThunk, importThunk->hTreeItem); - updateModuleInTreeView(moduleThunk, moduleThunk->hTreeItem); + wcscpy_s(import->moduleName, MAX_PATH, moduleName); + strcpy_s(import->name, MAX_PATH, apiName); + import->ordinal = ordinal; + //import->apiAddressVA = api->va; //?? + import->hint = hint; + import->valid = valid; + import->suspect = suspect; + + updateImportInTreeView(import, item); + updateModuleInTreeView(module, module->hTreeItem); + + updateCounts(); return true; } - - iterator2++; } - - iterator1++; } - return false; } void ImportsHandling::updateImportInTreeView(const ImportThunk * importThunk, CTreeItem item) { if (importThunk->valid) { WCHAR tempString[300]; if (importThunk->name[0] != 0x00) { swprintf_s(tempString, _countof(tempString),TEXT("ord: %04X name: %S"),importThunk->ordinal,importThunk->name); } else { swprintf_s(tempString, _countof(tempString),TEXT("ord: %04X"),importThunk->ordinal); } swprintf_s(stringBuffer, _countof(stringBuffer),TEXT(" rva: ")TEXT(PRINTF_DWORD_PTR_HALF)TEXT(" mod: %s %s"),importThunk->rva,importThunk->moduleName,tempString); } else { swprintf_s(stringBuffer, _countof(stringBuffer),TEXT(" rva: ")TEXT(PRINTF_DWORD_PTR_HALF)TEXT(" ptr: ")TEXT(PRINTF_DWORD_PTR_FULL),importThunk->rva,importThunk->apiAddressVA); } item.SetText(stringBuffer); Icon icon = getAppropiateIcon(importThunk); item.SetImage(icon, icon); } void ImportsHandling::updateModuleInTreeView(const ImportModuleThunk * importThunk, CTreeItem item) { swprintf_s(stringBuffer, _countof(stringBuffer),TEXT("%s (%d) FThunk: ")TEXT(PRINTF_DWORD_PTR_HALF),importThunk->moduleName,importThunk->thunkList.size(), importThunk->firstThunk); item.SetText(stringBuffer); Icon icon = getAppropiateIcon(importThunk->isValid()); item.SetImage(icon, icon); } ImportsHandling::Icon ImportsHandling::getAppropiateIcon(const ImportThunk * importThunk) { if(importThunk->valid) { if(importThunk->suspect) { return iconWarning; } else { return iconCheck; } } else { return iconError; } } ImportsHandling::Icon ImportsHandling::getAppropiateIcon(bool valid) { if(valid) { return iconCheck; } else { return iconError; } } -bool ImportsHandling::cutThunk(CTreeItem selectedTreeNode) +bool ImportsHandling::cutImport(CTreeItem item) { - std::map::iterator iterator1; - std::map::iterator iterator2; - ImportModuleThunk * moduleThunk; - ImportThunk * importThunk; - - iterator1 = moduleList.begin(); - - while (iterator1 != moduleList.end()) + ImportThunk * import = getImportThunk(item); + if(import) { - moduleThunk = &(iterator1->second); - - iterator2 = moduleThunk->thunkList.begin(); - - while (iterator2 != moduleThunk->thunkList.end()) + CTreeItem parent = item.GetParent(); + if(!parent.IsNull()) { - importThunk = &(iterator2->second); - - if (importThunk->hTreeItem == selectedTreeNode) + ImportModuleThunk * module = getModuleThunk(parent); + if(module) { - importThunk->hTreeItem.Delete(); - moduleThunk->thunkList.erase(iterator2); + itemData.erase(item); + import->hTreeItem.Delete(); + module->thunkList.erase(import->rva); + import = 0; - if (moduleThunk->thunkList.empty()) + if (module->thunkList.empty()) { - moduleThunk->hTreeItem.Delete(); - moduleList.erase(iterator1); + itemData.erase(parent); + module->hTreeItem.Delete(); + moduleList.erase(module->firstThunk); + module = 0; } else { - updateModuleInTreeView(moduleThunk, moduleThunk->hTreeItem); + updateModuleInTreeView(module, module->hTreeItem); } + + updateCounts(); return true; } - - iterator2++; } - - iterator1++; } - return false; } -bool ImportsHandling::deleteTreeNode(CTreeItem selectedTreeNode) +bool ImportsHandling::cutModule(CTreeItem item) { - std::map::iterator iterator1; - std::map::iterator iterator2; - ImportModuleThunk * moduleThunk; - ImportThunk * importThunk; - - iterator1 = moduleList.begin(); - - while (iterator1 != moduleList.end()) + ImportModuleThunk * module = getModuleThunk(item); + if(module) { - moduleThunk = &(iterator1->second); - - if (moduleThunk->hTreeItem == selectedTreeNode) + CTreeItem child = item.GetChild(); + while(!child.IsNull()) { - moduleThunk->hTreeItem.Delete(); - - moduleThunk->thunkList.clear(); - moduleList.erase(iterator1); - return true; + itemData.erase(child); + child = child.GetNextSibling(); } - else - { - iterator2 = moduleThunk->thunkList.begin(); - - while (iterator2 != moduleThunk->thunkList.end()) - { - importThunk = &(iterator2->second); - - if (importThunk->hTreeItem == selectedTreeNode) - { - moduleThunk->hTreeItem.Delete(); - moduleThunk->thunkList.clear(); - moduleList.erase(iterator1); - return true; - } - - iterator2++; - } - } - - iterator1++; + itemData.erase(item); + module->hTreeItem.Delete(); + moduleList.erase(module->firstThunk); + module = 0; + updateCounts(); + return true; } - return false; } -DWORD_PTR ImportsHandling::getApiAddressByNode(CTreeItem selectedTreeNode) +DWORD_PTR ImportsHandling::getApiAddressByNode(CTreeItem item) { - std::map::iterator iterator1; - std::map::iterator iterator2; - ImportModuleThunk * moduleThunk; - ImportThunk * importThunk; - - iterator1 = moduleList.begin(); - - while (iterator1 != moduleList.end()) + const ImportThunk * import = getImportThunk(item); + if(import) { - moduleThunk = &(iterator1->second); - - iterator2 = moduleThunk->thunkList.begin(); - - while (iterator2 != moduleThunk->thunkList.end()) - { - importThunk = &(iterator2->second); - - if (importThunk->hTreeItem == selectedTreeNode) - { - return importThunk->apiAddressVA; - } - - iterator2++; - } - - iterator1++; + return import->apiAddressVA; } return 0; } - void ImportsHandling::scanAndFixModuleList() { std::map::iterator iterator1; std::map::iterator iterator2; ImportModuleThunk * moduleThunk; ImportThunk * importThunk; iterator1 = moduleList.begin(); while (iterator1 != moduleList.end()) { moduleThunk = &(iterator1->second); iterator2 = moduleThunk->thunkList.begin(); while (iterator2 != moduleThunk->thunkList.end()) { importThunk = &(iterator2->second); if (importThunk->moduleName[0] == 0 || importThunk->moduleName[0] == L'?') { addNotFoundApiToModuleList(importThunk); } else { if (isNewModule(importThunk->moduleName)) { addModuleToModuleList(importThunk->moduleName, importThunk->rva); } addFunctionToModuleList(importThunk); } iterator2++; } moduleThunk->thunkList.clear(); iterator1++; } moduleList = moduleListNew; moduleListNew.clear(); } bool ImportsHandling::findNewModules(std::map & thunkList) { throw std::exception("The method or operation is not implemented."); } bool ImportsHandling::addModuleToModuleList(const WCHAR * moduleName, DWORD_PTR firstThunk) { ImportModuleThunk module; module.firstThunk = firstThunk; wcscpy_s(module.moduleName, MAX_PATH, moduleName); moduleListNew.insert(std::pair(firstThunk,module)); return true; } bool ImportsHandling::isNewModule(const WCHAR * moduleName) { - std::map::iterator iterator1; - - iterator1 = moduleListNew.begin(); + std::map::iterator it_module; - while (iterator1 != moduleListNew.end()) + it_module = moduleListNew.begin(); + while (it_module != moduleListNew.end()) { - if (!_wcsicmp(iterator1->second.moduleName, moduleName)) + if (!_wcsicmp(it_module->second.moduleName, moduleName)) { return false; } - iterator1++; + it_module++; } return true; } void ImportsHandling::addUnknownModuleToModuleList(DWORD_PTR firstThunk) { ImportModuleThunk module; module.firstThunk = firstThunk; wcscpy_s(module.moduleName, MAX_PATH, L"?"); moduleListNew.insert(std::pair(firstThunk,module)); } bool ImportsHandling::addNotFoundApiToModuleList(const ImportThunk * apiNotFound) { ImportThunk import; ImportModuleThunk * module = 0; - std::map::iterator iterator1; + std::map::iterator it_module; DWORD_PTR rva = apiNotFound->rva; if (moduleListNew.size() > 0) { - iterator1 = moduleListNew.begin(); - while (iterator1 != moduleListNew.end()) + it_module = moduleListNew.begin(); + while (it_module != moduleListNew.end()) { - if (rva >= iterator1->second.firstThunk) + if (rva >= it_module->second.firstThunk) { - iterator1++; - if (iterator1 == moduleListNew.end()) + it_module++; + if (it_module == moduleListNew.end()) { - iterator1--; + it_module--; //new unknown module - if (iterator1->second.moduleName[0] == L'?') + if (it_module->second.moduleName[0] == L'?') { - module = &(iterator1->second); + module = &(it_module->second); } else { addUnknownModuleToModuleList(apiNotFound->rva); module = &(moduleListNew.find(rva)->second); } break; } - else if (rva < iterator1->second.firstThunk) + else if (rva < it_module->second.firstThunk) { - iterator1--; - module = &(iterator1->second); + it_module--; + module = &(it_module->second); break; } } else { #ifdef DEBUG_COMMENTS Logger::debugLog("Error iterator1 != (*moduleThunkList).end()\r\n"); #endif break; } } } else { //new unknown module addUnknownModuleToModuleList(apiNotFound->rva); module = &(moduleListNew.find(rva)->second); } if (!module) { #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("ImportsHandling::addFunction module not found rva ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT("\r\n"),rva); #endif return false; } import.suspect = true; import.valid = false; import.va = apiNotFound->va; import.rva = apiNotFound->rva; import.apiAddressVA = apiNotFound->apiAddressVA; import.ordinal = 0; wcscpy_s(import.moduleName, MAX_PATH, L"?"); strcpy_s(import.name, MAX_PATH, "?"); module->thunkList.insert(std::pair(import.rva, import)); return true; } bool ImportsHandling::addFunctionToModuleList(const ImportThunk * apiFound) { ImportThunk import; ImportModuleThunk * module = 0; - std::map::iterator iterator1; + std::map::iterator it_module; if (moduleListNew.size() > 1) { - iterator1 = moduleListNew.begin(); - while (iterator1 != moduleListNew.end()) + it_module = moduleListNew.begin(); + while (it_module != moduleListNew.end()) { - if (apiFound->rva >= iterator1->second.firstThunk) + if (apiFound->rva >= it_module->second.firstThunk) { - iterator1++; - if (iterator1 == moduleListNew.end()) + it_module++; + if (it_module == moduleListNew.end()) { - iterator1--; - module = &(iterator1->second); + it_module--; + module = &(it_module->second); break; } - else if (apiFound->rva < iterator1->second.firstThunk) + else if (apiFound->rva < it_module->second.firstThunk) { - iterator1--; - module = &(iterator1->second); + it_module--; + module = &(it_module->second); break; } } else { #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("Error iterator1 != moduleListNew.end()\r\n")); #endif break; } } } else { - iterator1 = moduleListNew.begin(); - module = &(iterator1->second); + it_module = moduleListNew.begin(); + module = &(it_module->second); } if (!module) { #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("ImportsHandling::addFunction module not found rva ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT("\r\n"),apiFound->rva); #endif return false; } import.suspect = apiFound->suspect; import.valid = apiFound->valid; import.va = apiFound->va; import.rva = apiFound->rva; import.apiAddressVA = apiFound->apiAddressVA; import.ordinal = apiFound->ordinal; import.hint = apiFound->hint; wcscpy_s(import.moduleName, MAX_PATH, apiFound->moduleName); strcpy_s(import.name, MAX_PATH, apiFound->name); module->thunkList.insert(std::pair(import.rva, import)); return true; } void ImportsHandling::expandAllTreeNodes() { changeExpandStateOfTreeNodes(TVE_EXPAND); } void ImportsHandling::collapseAllTreeNodes() { changeExpandStateOfTreeNodes(TVE_COLLAPSE); } void ImportsHandling::changeExpandStateOfTreeNodes(UINT flag) { - std::map::iterator iterator1; - ImportModuleThunk * moduleThunk; - - iterator1 = moduleList.begin(); + std::map::iterator it_module; - while (iterator1 != moduleList.end()) + it_module = moduleList.begin(); + while (it_module != moduleList.end()) { - moduleThunk = &(iterator1->second); + ImportModuleThunk &moduleThunk = it_module->second; - moduleThunk->hTreeItem.Expand(flag); + moduleThunk.hTreeItem.Expand(flag); - iterator1++; + it_module++; } } diff --git a/Scylla/ImportsHandling.h b/Scylla/ImportsHandling.h index 8950ddc..7de87aa 100644 --- a/Scylla/ImportsHandling.h +++ b/Scylla/ImportsHandling.h @@ -1,77 +1,111 @@ #pragma once #include +#include // WTL #include #include #include // CTreeItem class CMultiSelectTreeViewCtrl; class ImportThunk; class ImportModuleThunk; class ImportsHandling { public: std::map moduleList; std::map moduleListNew; - //bool addFunction(WCHAR * moduleName, char * name, DWORD_PTR va, DWORD_PTR rva, DWORD_PTR ordinal, bool valid, bool suspect); - //bool addModule(WCHAR * moduleName, DWORD_PTR firstThunk); - ImportsHandling(CMultiSelectTreeViewCtrl& TreeImports); ~ImportsHandling(); + unsigned int thunkCount() const { return m_thunkCount; } + unsigned int invalidThunkCount() const { return m_invalidThunkCount; } + unsigned int suspectThunkCount() const { return m_suspectThunkCount; } + + bool isModule(CTreeItem item); + bool isImport(CTreeItem item); + + ImportModuleThunk * getModuleThunk(CTreeItem item); + ImportThunk * getImportThunk(CTreeItem item); + void displayAllImports(); - void showImports(bool invalid, bool suspect); - bool invalidateFunction(CTreeItem selectedTreeNode); - bool cutThunk(CTreeItem selectedTreeNode); - bool deleteTreeNode(CTreeItem selectedTreeNode); + void clearAllImports(); + void selectImports(bool invalid, bool suspect); + + bool invalidateImport(CTreeItem item); + bool setImport(CTreeItem item, const WCHAR * moduleName, const CHAR * apiName, WORD ordinal = 0, WORD hint = 0, bool valid = true, bool suspect = false); + bool cutImport(CTreeItem item); + bool cutModule(CTreeItem item); + //bool addImport(const WCHAR * moduleName, const CHAR * name, DWORD_PTR va, DWORD_PTR rva, WORD ordinal = 0, bool valid = true, bool suspect = false); + //bool addModule(const WCHAR * moduleName, DWORD_PTR firstThunk); - void updateImportInTreeView(const ImportThunk * importThunk, CTreeItem item); - void updateModuleInTreeView(const ImportModuleThunk * importThunk, CTreeItem item); DWORD_PTR getApiAddressByNode(CTreeItem selectedTreeNode); void scanAndFixModuleList(); void expandAllTreeNodes(); void collapseAllTreeNodes(); private: DWORD numberOfFunctions; + unsigned int m_thunkCount; + unsigned int m_invalidThunkCount; + unsigned int m_suspectThunkCount; + + struct TreeItemData + { + bool isModule; + union + { + ImportModuleThunk * module; + ImportThunk * import; + }; + }; + + std::hash_map itemData; + + void setItemData(CTreeItem item, const TreeItemData& data); + TreeItemData * getItemData(CTreeItem item); + WCHAR stringBuffer[600]; CMultiSelectTreeViewCtrl& TreeImports; CImageList TreeIcons; CIcon hIconCheck; CIcon hIconWarning; CIcon hIconError; // They have to be added to the image list in that order! enum Icon { iconCheck = 0, iconWarning, iconError }; - CTreeItem addDllToTreeView(CMultiSelectTreeViewCtrl& idTreeView, const ImportModuleThunk * importThunk); - CTreeItem addApiToTreeView(CMultiSelectTreeViewCtrl& idTreeView, CTreeItem parentDll, const ImportThunk * importThunk); + void updateCounts(); + + CTreeItem addDllToTreeView(CMultiSelectTreeViewCtrl& idTreeView, ImportModuleThunk * moduleThunk); + CTreeItem addApiToTreeView(CMultiSelectTreeViewCtrl& idTreeView, CTreeItem parentDll, ImportThunk * importThunk); + + void updateImportInTreeView(const ImportThunk * importThunk, CTreeItem item); + void updateModuleInTreeView(const ImportModuleThunk * importThunk, CTreeItem item); - bool isItemSelected(CTreeItem hItem); - void unselectItem(CTreeItem htItem); - bool selectItem(CTreeItem hItem, bool select = true); - void setFocus(CMultiSelectTreeViewCtrl& hwndTV, CTreeItem htItem); + //bool isItemSelected(CTreeItem hItem); + //void unselectItem(CTreeItem htItem); + //bool selectItem(CTreeItem hItem, bool select = true); bool findNewModules(std::map & thunkList); Icon getAppropiateIcon(const ImportThunk * importThunk); Icon getAppropiateIcon(bool valid); bool addModuleToModuleList(const WCHAR * moduleName, DWORD_PTR firstThunk); void addUnknownModuleToModuleList(DWORD_PTR firstThunk); bool addNotFoundApiToModuleList(const ImportThunk * apiNotFound); bool addFunctionToModuleList(const ImportThunk * apiFound); bool isNewModule(const WCHAR * moduleName); void changeExpandStateOfTreeNodes(UINT flag); };