diff --git a/Scylla/ApiReader.cpp b/Scylla/ApiReader.cpp index b504d4f..836c9ac 100644 --- a/Scylla/ApiReader.cpp +++ b/Scylla/ApiReader.cpp @@ -1,1325 +1,1325 @@ #include "ApiReader.h" #include "Scylla.h" #include "Architecture.h" #include "SystemInformation.h" #include "StringConversion.h" -std::unordered_map ApiReader::apiList; //api look up table +stdext::hash_map 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) { *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) { - std::unordered_map::iterator it1, it2; + stdext::hash_map::iterator it1, it2; size_t c = 0; size_t countDuplicates = apiList.count(virtualAddress); int countHighPriority = 0; ApiInfo *apiFound = 0; if (countDuplicates == 0) { Scylla::windowLog.log(L"getApiByVirtualAddress :: No Api found " PRINTF_DWORD_PTR_FULL, virtualAddress); return 0; } else if (countDuplicates == 1) { //API is 100% correct *isSuspect = false; it1 = apiList.find(virtualAddress); // Find first match. return (ApiInfo *)((*it1).second); } else { it1 = apiList.find(virtualAddress); // Find first match. //any high priority with a name apiFound = getScoredApi(it1,countDuplicates,true,false,false,true,false,false,false,false); if (apiFound) return apiFound; *isSuspect = true; //high priority with a name and ansi/unicode name apiFound = getScoredApi(it1,countDuplicates,true,true,false,true,false,false,false,false); if (apiFound) return apiFound; //priority 2 with no underline in name apiFound = getScoredApi(it1,countDuplicates,true,false,true,false,false,false,true,false); if (apiFound) return apiFound; //priority 1 with a name apiFound = getScoredApi(it1,countDuplicates,true,false,false,false,false,true,false,false); if (apiFound) return apiFound; //With a name apiFound = getScoredApi(it1,countDuplicates,true,false,false,false,false,false,false,false); if (apiFound) return apiFound; //any with priority, name, ansi/unicode apiFound = getScoredApi(it1,countDuplicates,true,true,false,true,false,false,false,true); if (apiFound) return apiFound; //any with priority apiFound = getScoredApi(it1,countDuplicates,false,false,false,true,false,false,false,true); if (apiFound) return apiFound; //has prio 0 and name apiFound = getScoredApi(it1,countDuplicates,false,false,false,false,true,false,false,true); if (apiFound) return apiFound; } //is never reached Scylla::windowLog.log(L"getApiByVirtualAddress :: There is a api resolving bug, VA: " PRINTF_DWORD_PTR_FULL, virtualAddress); for (size_t c = 0; c < countDuplicates; c++, it1++) { apiFound = (ApiInfo *)((*it1).second); Scylla::windowLog.log(L"-> Possible API: %S ord: %d ", apiFound->name, apiFound->ordinal); } return (ApiInfo *) 1; } /*ApiInfo * ApiReader::getApiByVirtualAddress(DWORD_PTR virtualAddress, bool * isSuspect) { std::unordered_map::iterator it1, it2; size_t c = 0; size_t countDuplicates = apiList.count(virtualAddress); int countHighPriority = 0; ApiInfo *apiFound = 0; if (countDuplicates == 0) { Scylla::windowLog.log(L"getApiByVirtualAddress :: No Api found " PRINTF_DWORD_PTR_FULL, virtualAddress); return 0; } else if (countDuplicates == 1) { //API is 100% correct *isSuspect = false; it1 = apiList.find(virtualAddress); // Find first match. return (ApiInfo *)((*it1).second); } else { it1 = apiList.find(virtualAddress); // Find first match. it2 = it1; for (c = 0; c < countDuplicates; c++, it1++) { apiFound = (ApiInfo *)((*it1).second); if (apiFound->module->priority >= 1) //1 == high priority { countHighPriority++; } } it1 = it2; This is flawed: It chooses api(prio:1, name:no) over api(prio:0, name:yes) (e.g. SHLWAPI.PathCombineW vs SHELL32.#25) Maybe there should be a check higher up in the code, to see if this API is surrounded by APIs of a DLL and pick the duplicate from that DLL if (countHighPriority == 0) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"getApiByVirtualAddress :: countHighPriority == 0 " PRINTF_DWORD_PTR_FULL, virtualAddress); #endif *isSuspect = true; return (ApiInfo *)((*it1).second); } else if (countHighPriority == 1) // what about kernel32, it has priority 2 { //API is 100% correct if countHighPriority == 1 and name export *isSuspect = false; for (c = 0; c < countDuplicates; c++, it1++) { apiFound = (ApiInfo *)((*it1).second); if (apiFound->module->priority >= 1 && apiFound->name[0] != 0x00) //1 == high priority { return apiFound; } } } //else // fall through for case api1(priority:1, name:false) <> api2(priority:0, name:true) { //API not 100% correct #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"getApiByVirtualAddress :: countHighPriority == %d " PRINTF_DWORD_PTR_FULL, countHighPriority, virtualAddress); #endif *isSuspect = true; for (c = 0; c < countDuplicates; c++, it1++) { apiFound = (ApiInfo *)((*it1).second); Scylla::windowLog.log(L"%s - %s %X %X\n",apiFound->name, apiFound->module->getFilename(), apiFound->rva, apiFound->ordinal); } it1 = it2; for (c = 0; c < countDuplicates; c++, it1++) { apiFound = (ApiInfo *)((*it1).second); //prefer APIs with a name if (apiFound->module->priority >= 1 && apiFound->name[0] != 0x00) //1 == high priority { //prefer ANSI/UNICODE APIs if (strrchr(apiFound->name, 'W') || strrchr(apiFound->name, 'A')) { return apiFound; } } } it1 = it2; for (c = 0; c < countDuplicates; c++, it1++) { apiFound = (ApiInfo *)((*it1).second); //prefer APIs with a name if (apiFound->module->priority == 2 && !strrchr(apiFound->name, '_')) //1 == high priority { return apiFound; } } it1 = it2; for (c = 0; c < countDuplicates; c++, it1++) { apiFound = (ApiInfo *)((*it1).second); if (apiFound->module->priority == 1 && apiFound->name[0] != 0x00) //1 == high priority { return apiFound; } } it1 = it2; for (c = 0; c < countDuplicates; c++, it1++) { apiFound = (ApiInfo *)((*it1).second); if (apiFound->module->priority == 1) //1 == high priority { return apiFound; } } } } //is never reached Scylla::windowLog.log(L"getApiByVirtualAddress :: There is a big bug"); return (ApiInfo *) 1; }*/ -ApiInfo * ApiReader::getScoredApi(std::unordered_map::iterator it1,size_t countDuplicates, bool hasName, bool hasUnicodeAnsiName, bool hasNoUnderlineInName, bool hasPrioDll,bool hasPrio0Dll,bool hasPrio1Dll, bool hasPrio2Dll, bool firstWin ) +ApiInfo * ApiReader::getScoredApi(stdext::hash_map::iterator it1,size_t countDuplicates, bool hasName, bool hasUnicodeAnsiName, bool hasNoUnderlineInName, bool hasPrioDll,bool hasPrio0Dll,bool hasPrio1Dll, bool hasPrio2Dll, bool firstWin ) { 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 ( std::unordered_map::iterator it = apiList.begin(); it != apiList.end(); ++it ) + 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/ApiReader.h b/Scylla/ApiReader.h index 81e4bea..ac66656 100644 --- a/Scylla/ApiReader.h +++ b/Scylla/ApiReader.h @@ -1,74 +1,74 @@ #pragma once #include #include -#include +#include #include "ProcessAccessHelp.h" #include "Thunks.h" typedef std::pair API_Pair; class ApiReader : public ProcessAccessHelp { public: - static std::unordered_map apiList; //api look up table + static stdext::hash_map 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, WORD ordinal, DWORD_PTR va, DWORD_PTR rva, bool isForwarded, ModuleInfo *moduleInfo); void addApiWithoutName(WORD ordinal, DWORD_PTR va, DWORD_PTR rva,bool isForwarded, ModuleInfo *moduleInfo); inline bool isApiForwarded(DWORD_PTR rva, PIMAGE_NT_HEADERS pNtHeader); void handleForwardedApi(DWORD_PTR vaStringPointer,char *functionNameParent,DWORD_PTR rvaParent, WORD ordinalParent, ModuleInfo *moduleParent); void parseModule(ModuleInfo *module); void parseModuleWithProcess(ModuleInfo * module); void parseExportTable(ModuleInfo *module, PIMAGE_NT_HEADERS pNtHeader, PIMAGE_EXPORT_DIRECTORY pExportDir, DWORD_PTR deltaAddress); ModuleInfo * findModuleByName(WCHAR *name); void findApiByModuleAndOrdinal(ModuleInfo * module, WORD ordinal, DWORD_PTR * vaApi, DWORD_PTR * rvaApi); void findApiByModuleAndName(ModuleInfo * module, char * searchFunctionName, DWORD_PTR * vaApi, DWORD_PTR * rvaApi); void findApiByModule(ModuleInfo * module, char * searchFunctionName, WORD ordinal, DWORD_PTR * vaApi, DWORD_PTR * rvaApi); bool isModuleLoadedInOwnProcess( ModuleInfo * module ); void parseModuleWithOwnProcess( ModuleInfo * module ); bool isPeAndExportTableValid(PIMAGE_NT_HEADERS pNtHeader); void findApiInProcess( ModuleInfo * module, char * searchFunctionName, WORD ordinal, DWORD_PTR * vaApi, DWORD_PTR * rvaApi ); bool findApiInExportTable(ModuleInfo *module, PIMAGE_EXPORT_DIRECTORY pExportDir, DWORD_PTR deltaAddress, char * searchFunctionName, WORD ordinal, DWORD_PTR * vaApi, DWORD_PTR * rvaApi); BYTE * getHeaderFromProcess(ModuleInfo * module); BYTE * getExportTableFromProcess(ModuleInfo * module, PIMAGE_NT_HEADERS pNtHeader); void setModulePriority(ModuleInfo * module); void setMinMaxApiAddress(DWORD_PTR virtualAddress); void parseModuleWithMapping(ModuleInfo *moduleInfo); //not used void addFoundApiToModuleList(DWORD_PTR iatAddress, ApiInfo * apiFound, bool isNewModule, bool isSuspect); bool addModuleToModuleList(const WCHAR * moduleName, DWORD_PTR firstThunk); bool addFunctionToModuleList(ApiInfo * apiFound, DWORD_PTR va, DWORD_PTR rva, WORD ordinal, bool valid, bool suspect); bool addNotFoundApiToModuleList(DWORD_PTR iatAddressVA, DWORD_PTR apiAddress); void addUnknownModuleToModuleList(DWORD_PTR firstThunk); bool isApiBlacklisted( const char * functionName ); bool isWinSxSModule( ModuleInfo * module ); - ApiInfo * getScoredApi(std::unordered_map::iterator it1,size_t countDuplicates, bool hasName, bool hasUnicodeAnsiName, bool hasNoUnderlineInName, bool hasPrioDll,bool hasPrio0Dll,bool hasPrio1Dll, bool hasPrio2Dll, bool firstWin ); + ApiInfo * getScoredApi(stdext::hash_map::iterator it1,size_t countDuplicates, bool hasName, bool hasUnicodeAnsiName, bool hasNoUnderlineInName, bool hasPrioDll,bool hasPrio0Dll,bool hasPrio1Dll, bool hasPrio2Dll, bool firstWin ); }; diff --git a/Scylla/DumpMemoryGui.cpp b/Scylla/DumpMemoryGui.cpp new file mode 100644 index 0000000..a15443e --- /dev/null +++ b/Scylla/DumpMemoryGui.cpp @@ -0,0 +1,540 @@ +#include "DumpMemoryGui.h" + +#include "definitions.h" +#include "ProcessAccessHelp.h" +#include + +WCHAR DumpMemoryGui::protectionString[100]; +const WCHAR DumpMemoryGui::MemoryUnknown[] = L"UNKNOWN"; +const WCHAR * DumpMemoryGui::MemoryStateValues[] = {L"COMMIT",L"FREE",L"RESERVE"}; +const WCHAR * DumpMemoryGui::MemoryTypeValues[] = {L"IMAGE",L"MAPPED",L"PRIVATE", L"NONE"}; +const WCHAR * DumpMemoryGui::MemoryProtectionValues[] = {L"EXECUTE",L"EXECUTE_READ",L"EXECUTE_READWRITE",L"EXECUTE_WRITECOPY",L"NOACCESS",L"READONLY",L"READWRITE",L"WRITECOPY",L"GUARD",L"NOCACHE",L"WRITECOMBINE"}; + + +DumpMemoryGui::DumpMemoryGui() +{ + dumpedMemory = 0; + dumpedMemorySize = 0; +} +DumpMemoryGui::~DumpMemoryGui() +{ + if (dumpedMemory) + { + delete [] dumpedMemory; + } +} +BOOL DumpMemoryGui::OnInitDialog(CWindow wndFocus, LPARAM lInitParam) +{ + DoDataExchange(); // attach controls + DlgResize_Init(true, true); + + addColumnsToMemoryList(ListMemorySelect); + displayMemoryList(ListMemorySelect); + + EditMemoryAddress.SetValue(ProcessAccessHelp::targetImageBase); + EditMemorySize.SetValue((DWORD)ProcessAccessHelp::targetSizeOfImage); + + CenterWindow(); + return TRUE; +} + +void DumpMemoryGui::addColumnsToMemoryList(CListViewCtrl& list) +{ + list.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT); + + list.InsertColumn(COL_ADDRESS, L"Address", LVCFMT_CENTER); + list.InsertColumn(COL_SIZE, L"Size", LVCFMT_CENTER); + list.InsertColumn(COL_FILENAME, L"File", LVCFMT_LEFT); + list.InsertColumn(COL_PESECTION, L"PE Section", LVCFMT_LEFT); + + list.InsertColumn(COL_TYPE, L"Type", LVCFMT_CENTER); + list.InsertColumn(COL_PROTECTION, L"Protection", LVCFMT_CENTER); + list.InsertColumn(COL_STATE, L"State", LVCFMT_CENTER); +} + +void DumpMemoryGui::displayMemoryList(CListViewCtrl& list) +{ + int count = 0; + WCHAR temp[20]; + list.DeleteAllItems(); + + + getMemoryList(); + + std::vector::const_iterator iter; + + for( iter = memoryList.begin(); iter != memoryList.end(); iter++ , count++) + { + swprintf_s(temp, TEXT(PRINTF_DWORD_PTR_FULL), iter->address); + list.InsertItem(count,temp); + + swprintf_s(temp, L"%08X", iter->size); + list.SetItemText(count, COL_SIZE, temp); + + list.SetItemText(count, COL_FILENAME, iter->filename); + list.SetItemText(count, COL_PESECTION, iter->peSection); + + list.SetItemText(count, COL_TYPE, getMemoryTypeString(iter->type)); + list.SetItemText(count, COL_PROTECTION, getMemoryProtectionString(iter->protect)); + list.SetItemText(count, COL_STATE, getMemoryStateString(iter->state)); + list.SetItemData(count, (DWORD_PTR)&(*iter)); + } + + list.SetColumnWidth(COL_ADDRESS, LVSCW_AUTOSIZE_USEHEADER); + list.SetColumnWidth(COL_SIZE, LVSCW_AUTOSIZE_USEHEADER); + list.SetColumnWidth(COL_FILENAME, LVSCW_AUTOSIZE_USEHEADER); + list.SetColumnWidth(COL_PESECTION, LVSCW_AUTOSIZE_USEHEADER); + list.SetColumnWidth(COL_TYPE, LVSCW_AUTOSIZE_USEHEADER); + list.SetColumnWidth(COL_PROTECTION, LVSCW_AUTOSIZE_USEHEADER); + list.SetColumnWidth(COL_STATE, LVSCW_AUTOSIZE_USEHEADER); +} + +const WCHAR * DumpMemoryGui::getMemoryTypeString(DWORD value) +{ + switch(value) + { + case 0: + return MemoryTypeValues[TYPE_NONE]; + case MEM_IMAGE: + return MemoryTypeValues[TYPE_IMAGE]; + case MEM_MAPPED: + return MemoryTypeValues[TYPE_MAPPED]; + case MEM_PRIVATE: + return MemoryTypeValues[TYPE_PRIVATE]; + default: + return MemoryUnknown; + } +} +const WCHAR * DumpMemoryGui::getMemoryStateString(DWORD value) +{ + switch(value) + { + case MEM_COMMIT: + return MemoryStateValues[STATE_COMMIT]; + case MEM_FREE: + return MemoryStateValues[STATE_FREE]; + case MEM_RESERVE: + return MemoryStateValues[STATE_RESERVE]; + default: + return MemoryUnknown; + } +} + +WCHAR * DumpMemoryGui::getMemoryProtectionString(DWORD value) +{ + protectionString[0] = 0; + + if (value & PAGE_GUARD) + { + wcscpy_s(protectionString,_countof(protectionString), MemoryProtectionValues[PROT_GUARD]); + wcscat_s(protectionString,_countof(protectionString), L" | "); + value ^= PAGE_GUARD; + } + if (value & PAGE_NOCACHE) + { + wcscpy_s(protectionString,_countof(protectionString), MemoryProtectionValues[PROT_NOCACHE]); + wcscat_s(protectionString,_countof(protectionString), L" | "); + value ^= PAGE_NOCACHE; + } + if (value & PAGE_WRITECOMBINE) + { + wcscpy_s(protectionString,_countof(protectionString), MemoryProtectionValues[PROT_WRITECOMBINE]); + wcscat_s(protectionString,_countof(protectionString), L" | "); + value ^= PAGE_WRITECOMBINE; + } + + switch(value) + { + case 0: + { + wcscat_s(protectionString,_countof(protectionString), MemoryProtectionValues[PROT_NOACCESS]); + break; + } + case PAGE_EXECUTE: + { + wcscat_s(protectionString,_countof(protectionString), MemoryProtectionValues[PROT_EXECUTE]); + break; + } + case PAGE_EXECUTE_READ: + { + wcscat_s(protectionString,_countof(protectionString), MemoryProtectionValues[PROT_EXECUTE_READ]); + break; + } + case PAGE_EXECUTE_READWRITE: + { + wcscat_s(protectionString,_countof(protectionString), MemoryProtectionValues[PROT_EXECUTE_READWRITE]); + break; + } + case PAGE_EXECUTE_WRITECOPY: + { + wcscat_s(protectionString,_countof(protectionString), MemoryProtectionValues[PROT_EXECUTE_WRITECOPY]); + break; + } + case PAGE_NOACCESS: + { + wcscat_s(protectionString,_countof(protectionString), MemoryProtectionValues[PROT_NOACCESS]); + break; + } + case PAGE_READONLY: + { + wcscat_s(protectionString,_countof(protectionString), MemoryProtectionValues[PROT_READONLY]); + break; + } + case PAGE_READWRITE: + { + wcscat_s(protectionString,_countof(protectionString), MemoryProtectionValues[PROT_READWRITE]); + break; + } + case PAGE_WRITECOPY: + { + wcscat_s(protectionString,_countof(protectionString), MemoryProtectionValues[PROT_WRITECOPY]); + break; + } + default: + { + wcscat_s(protectionString,_countof(protectionString), MemoryUnknown); + } + } + + return protectionString; +} + + +LRESULT DumpMemoryGui::OnListMemoryColumnClicked(NMHDR* pnmh) +{ + NMLISTVIEW* list = (NMLISTVIEW*)pnmh; + int column = list->iSubItem; + + if(column == prevColumn) + { + ascending = !ascending; + } + else + { + prevColumn = column; + ascending = true; + } + + // lo-byte: column, hi-byte: sort-order + ListMemorySelect.SortItems(&listviewCompareFunc, MAKEWORD(column, ascending)); + + return 0; +} +LRESULT DumpMemoryGui::OnListMemoryClick(NMHDR* pnmh) +{ + int index = ListMemorySelect.GetSelectionMark(); + if (index != -1) + { + selectedMemory = (Memory *)ListMemorySelect.GetItemData(index); + if (selectedMemory) + { + updateAddressAndSize(selectedMemory); + } + + } + return 0; +} +void DumpMemoryGui::OnOK(UINT uNotifyCode, int nID, CWindow wndCtl) +{ + + if (EditMemoryAddress.GetValue() == 0 || EditMemorySize.GetValue() == 0) + { + wndCtl.MessageBoxW(L"Textbox is empty!",L"Error",MB_ICONERROR); + } + else + { + if (dumpMemory()) + { + EndDialog(1); + } + else + { + wndCtl.MessageBoxW(L"Read memory from process failed",L"Error",MB_ICONERROR); + } + } +} +void DumpMemoryGui::OnCancel(UINT uNotifyCode, int nID, CWindow wndCtl) +{ + EndDialog(0); +} + +void DumpMemoryGui::updateAddressAndSize( Memory * selectedMemory ) +{ + EditMemoryAddress.SetValue(selectedMemory->address); + EditMemorySize.SetValue(selectedMemory->size); +} + +int DumpMemoryGui::listviewCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) +{ + const Memory * module1 = (Memory *)lParam1; + const Memory * module2 = (Memory *)lParam2; + + int column = LOBYTE(lParamSort); + bool ascending = (HIBYTE(lParamSort) == TRUE); + + int diff = 0; + + switch(column) + { + case COL_ADDRESS: + diff = module1->address < module2->address ? -1 : 1; + break; + case COL_SIZE: + diff = module1->size < module2->size ? -1 : 1; + break; + case COL_FILENAME: + diff = _wcsicmp(module1->filename, module2->filename); + break; + case COL_PESECTION: + diff = _wcsicmp(module1->peSection, module2->peSection); + break; + case COL_TYPE: + diff = module1->type < module2->type ? -1 : 1; + break; + case COL_PROTECTION: + diff = module1->protect < module2->protect ? -1 : 1; + break; + case COL_STATE: + diff = module1->state < module2->state ? -1 : 1; + break; + } + + return ascending ? diff : -diff; +} + +void DumpMemoryGui::getMemoryList() +{ + DWORD count = 0; + DWORD_PTR address = 0; + MEMORY_BASIC_INFORMATION memBasic = {0}; + Memory memory; + HMODULE * hMods = 0; + DWORD cbNeeded = 0; + bool notEnough = true; + WCHAR target[MAX_PATH]; + + count = 100; + hMods = new HMODULE[count]; + + if (memoryList.empty()) + { + memoryList.reserve(20); + } + else + { + memoryList.clear(); + } + + memory.filename[0] = 0; + memory.peSection[0] = 0; + + while(VirtualQueryEx(ProcessAccessHelp::hProcess,(LPCVOID)address,&memBasic,sizeof(memBasic))) + { + memory.address = (DWORD_PTR)memBasic.BaseAddress; + memory.type = memBasic.Type; + memory.state = memBasic.State; + memory.size = (DWORD)memBasic.RegionSize; + memory.protect = memBasic.Protect; + memoryList.push_back(memory); + + address += memBasic.RegionSize; + } + + do + { + if (!EnumProcessModules(ProcessAccessHelp::hProcess, hMods, count * sizeof(HMODULE), &cbNeeded)) + { +#ifdef DEBUG_COMMENTS + Scylla::debugLog.log(L"getMemoryList :: EnumProcessModules failed count %d", count); +#endif + delete [] hMods; + return; + } + + if ( (count * sizeof(HMODULE)) < cbNeeded ) + { + delete [] hMods; + count += 100; + hMods = new HMODULE[count]; + } + else + { + notEnough = false; + } + } while (notEnough); + + for (DWORD i = 0; i < (cbNeeded / sizeof(HMODULE)); i++ ) + { + if (GetModuleFileNameExW(ProcessAccessHelp::hProcess, hMods[i], target, _countof(target))) + { + setModuleName((DWORD_PTR)hMods[i],target); + setAllSectionNames((DWORD_PTR)hMods[i],target); + } + else + { +#ifdef DEBUG_COMMENTS + Scylla::debugLog.log(L"getMemoryList :: GetModuleFileNameExW failed 0x%X", GetLastError()); +#endif + } + } + + delete [] hMods; + + +} + +void DumpMemoryGui::setSectionName(DWORD_PTR sectionAddress, DWORD sectionSize, const WCHAR * sectionName) +{ + bool found = false; + std::vector::const_iterator iter; + + + for( iter = memoryList.begin(); iter != memoryList.end(); iter++) + { + if (!found) + { + if ( (iter->address <= sectionAddress) && (sectionAddress < (iter->address + iter->size)) ) + { + if (wcslen(iter->peSection) == 0) + { + wcscpy_s((WCHAR *)iter->peSection, IMAGE_SIZEOF_SHORT_NAME + 1, sectionName); + } + else + { + wcscat_s((WCHAR *)iter->peSection, IMAGE_SIZEOF_SHORT_NAME *4,L"|"); + wcscat_s((WCHAR *)iter->peSection, IMAGE_SIZEOF_SHORT_NAME *4,sectionName); + } + + found = true; + } + } + else + { + if ((sectionSize+sectionAddress) < iter->address) + { + break; + } + if (wcslen(iter->peSection) == 0) + { + wcscpy_s((WCHAR *)iter->peSection, IMAGE_SIZEOF_SHORT_NAME + 1, sectionName); + } + else + { + wcscat_s((WCHAR *)iter->peSection, IMAGE_SIZEOF_SHORT_NAME *4,L"|"); + wcscat_s((WCHAR *)iter->peSection, IMAGE_SIZEOF_SHORT_NAME *4,sectionName); + } + } + + } +} + +void DumpMemoryGui::setModuleName(DWORD_PTR moduleBase, const WCHAR * moduleName) +{ + bool found = false; + std::vector::const_iterator iter; + + //get filename + const WCHAR* slash = wcsrchr(moduleName, L'\\'); + if(slash) + { + moduleName = slash+1; + } + + + for( iter = memoryList.begin(); iter != memoryList.end(); iter++) + { + if (iter->address == moduleBase) + { + found = true; + } + + if (found) + { + if (iter->type == MEM_IMAGE) + { + wcscpy_s((WCHAR *)iter->filename, MAX_PATH, moduleName); + } + else + { + break; + } + } + } +} + +void DumpMemoryGui::setAllSectionNames( DWORD_PTR moduleBase, WCHAR * moduleName ) +{ + WORD numSections = 0; + PIMAGE_DOS_HEADER pDos = 0; + PIMAGE_NT_HEADERS pNT = 0; + PIMAGE_SECTION_HEADER pSec = 0; + DWORD size = sizeof(IMAGE_DOS_HEADER) + sizeof(IMAGE_NT_HEADERS) + 200; + DWORD correctSize = 0; + WCHAR sectionNameW[IMAGE_SIZEOF_SHORT_NAME + 1] = {0}; + CHAR sectionNameA[IMAGE_SIZEOF_SHORT_NAME + 1] = {0}; + + BYTE * buffer = new BYTE[size]; + + if (ProcessAccessHelp::readMemoryFromProcess(moduleBase,size,buffer)) + { + pDos = (PIMAGE_DOS_HEADER)buffer; + + if (pDos->e_magic == IMAGE_DOS_SIGNATURE) + { + pNT = (PIMAGE_NT_HEADERS)((DWORD_PTR)pDos + pDos->e_lfanew); + if (pNT->Signature == IMAGE_NT_SIGNATURE) + { + numSections = pNT->FileHeader.NumberOfSections; + correctSize = (numSections*sizeof(IMAGE_SECTION_HEADER)) + sizeof(IMAGE_NT_HEADERS) + pDos->e_lfanew; + + if (size < correctSize) + { + size = correctSize; + delete [] buffer; + buffer = new BYTE[size]; + if (!ProcessAccessHelp::readMemoryFromProcess(moduleBase,size,buffer)) + { + delete [] buffer; + return; + } + + pDos = (PIMAGE_DOS_HEADER)buffer; + pNT = (PIMAGE_NT_HEADERS)((DWORD_PTR)pDos + pDos->e_lfanew); + } + + pSec = IMAGE_FIRST_SECTION(pNT); + + for (WORD i = 0; i < numSections; i++) + { + memcpy(sectionNameA,pSec->Name,8); + swprintf_s(sectionNameW,_countof(sectionNameW),L"%S",sectionNameA); + + setSectionName(moduleBase + pSec->VirtualAddress, pSec->Misc.VirtualSize,sectionNameW); + pSec++; + } + + } + } + } + + delete [] buffer; +} + +bool DumpMemoryGui::dumpMemory() +{ + DWORD_PTR address = EditMemoryAddress.GetValue(); + dumpedMemorySize = EditMemorySize.GetValue(); + + swprintf_s(dumpFilename,_countof(dumpFilename),TEXT("MEM_")TEXT(PRINTF_DWORD_PTR_FULL)TEXT("_")TEXT("%08X"),address,dumpedMemorySize); + + dumpedMemory = new BYTE[dumpedMemorySize]; + + if (dumpedMemory) + { + return ProcessAccessHelp::readMemoryFromProcess(address,dumpedMemorySize,dumpedMemory); + } + else + { + return false; + } +} diff --git a/Scylla/DumpMemoryGui.h b/Scylla/DumpMemoryGui.h new file mode 100644 index 0000000..5c24147 --- /dev/null +++ b/Scylla/DumpMemoryGui.h @@ -0,0 +1,159 @@ +#pragma once + +#include +#include "resource.h" + +// WTL +#include // base ATL classes +#include // base WTL classes +#include // ATL GUI classes +#include // WTL window frame helpers +#include // WTL utility classes +#include // WTL enhanced msg map macros +#include // WTL controls +#include // WTL dialog data exchange + +#include +#include "hexedit.h" + +class Memory +{ +public: + DWORD_PTR address; + DWORD size; + WCHAR filename[MAX_PATH]; + WCHAR peSection[IMAGE_SIZEOF_SHORT_NAME *4]; + DWORD state; + DWORD protect; + DWORD type; +}; + +class DumpMemoryGui : public CDialogImpl, public CWinDataExchange, public CDialogResize +{ +public: + enum { IDD = IDD_DLG_DUMPMEMORY }; + + BEGIN_DDX_MAP(DumpMemoryGui) + DDX_CONTROL_HANDLE(IDC_LIST_DUMPMEMORY, ListMemorySelect) + DDX_CONTROL(IDC_EDIT_DUMPADDRESS, EditMemoryAddress) + DDX_CONTROL(IDC_EDIT_DUMPSIZE, EditMemorySize) + END_DDX_MAP() + + BEGIN_MSG_MAP(DumpMemoryGui) + MSG_WM_INITDIALOG(OnInitDialog) + + NOTIFY_HANDLER_EX(IDC_LIST_DUMPMEMORY, LVN_COLUMNCLICK, OnListMemoryColumnClicked) + NOTIFY_HANDLER_EX(IDC_LIST_DUMPMEMORY, NM_CLICK, OnListMemoryClick) + + COMMAND_ID_HANDLER_EX(IDC_BTN_DUMPMEMORY_OK, OnOK) + COMMAND_ID_HANDLER_EX(IDC_BTN_DUMPMEMORY_CANCEL, OnCancel) + COMMAND_ID_HANDLER_EX(IDCANCEL, OnCancel) + + CHAIN_MSG_MAP(CDialogResize) + END_MSG_MAP() + + BEGIN_DLGRESIZE_MAP(DumpMemoryGui) + DLGRESIZE_CONTROL(IDC_LIST_DUMPMEMORY, DLSZ_SIZE_X | DLSZ_SIZE_Y) + DLGRESIZE_CONTROL(IDC_BTN_DUMPMEMORY_OK, DLSZ_MOVE_X | DLSZ_MOVE_Y) + DLGRESIZE_CONTROL(IDC_BTN_DUMPMEMORY_CANCEL, DLSZ_MOVE_X | DLSZ_MOVE_Y) + DLGRESIZE_CONTROL(IDC_EDIT_DUMPADDRESS, DLSZ_MOVE_Y) + DLGRESIZE_CONTROL(IDC_EDIT_DUMPSIZE, DLSZ_MOVE_Y) + DLGRESIZE_CONTROL(IDC_STATIC_SIZE, DLSZ_MOVE_Y) + DLGRESIZE_CONTROL(IDC_STATIC_ADDRESS, DLSZ_MOVE_Y) + END_DLGRESIZE_MAP() + + DumpMemoryGui(); + ~DumpMemoryGui(); + + BYTE * dumpedMemory; + DWORD dumpedMemorySize; + WCHAR dumpFilename[39]; + +protected: + CListViewCtrl ListMemorySelect; + CHexEdit EditMemoryAddress; + CHexEdit EditMemorySize; + + std::vector memoryList; + Memory * selectedMemory; + + + enum ListColumns { + COL_ADDRESS = 0, + COL_SIZE, + COL_FILENAME, + COL_PESECTION, + COL_TYPE, + COL_PROTECTION, + COL_STATE + }; + + int prevColumn; + bool ascending; + + // Message handlers + + BOOL OnInitDialog(CWindow wndFocus, LPARAM lInitParam); + + LRESULT OnListMemoryColumnClicked(NMHDR* pnmh); + LRESULT OnListMemoryClick(NMHDR* pnmh); + void OnOK(UINT uNotifyCode, int nID, CWindow wndCtl); + void OnCancel(UINT uNotifyCode, int nID, CWindow wndCtl); + + // GUI functions + + void addColumnsToMemoryList(CListViewCtrl& list); + void displayMemoryList(CListViewCtrl& list); + + static int CALLBACK listviewCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort); + +private: + + enum enumMemoryStateValues { + STATE_COMMIT = 0, + STATE_FREE, + STATE_RESERVE + }; + + //"IMAGE",L"MAPPED",L"PRIVATE" + enum enumMemoryTypeValues { + TYPE_IMAGE = 0, + TYPE_MAPPED, + TYPE_PRIVATE, + TYPE_NONE + }; + + //"EXECUTE",L"EXECUTE_READ",L"EXECUTE_READWRITE",L"EXECUTE_WRITECOPY",L"NOACCESS",L"READONLY",L"READWRITE",L"WRITECOPY",L"GUARD",L"NOCACHE",L"WRITECOMBINE" + enum enumMemoryProtectionValues { + PROT_EXECUTE = 0, + PROT_EXECUTE_READ, + PROT_EXECUTE_READWRITE, + PROT_EXECUTE_WRITECOPY, + PROT_NOACCESS, + PROT_READONLY, + PROT_READWRITE, + PROT_WRITECOPY, + PROT_GUARD, + PROT_NOCACHE, + PROT_WRITECOMBINE + }; + + static const WCHAR * MemoryStateValues[]; + static const WCHAR * MemoryTypeValues[]; + static const WCHAR * MemoryProtectionValues[]; + static const WCHAR MemoryUnknown[]; + + static WCHAR protectionString[100]; + + const WCHAR * getMemoryTypeString(DWORD value); + const WCHAR * getMemoryStateString(DWORD value); + WCHAR * getMemoryProtectionString(DWORD value); + void updateAddressAndSize( Memory * selectedMemory ); + void getMemoryList(); + SIZE_T getSizeOfImage(DWORD_PTR moduleBase); + void setModuleName(DWORD_PTR moduleBase, const WCHAR * moduleName); + void setAllSectionNames( DWORD_PTR moduleBase, WCHAR * moduleName ); + + void setSectionName(DWORD_PTR sectionAddress, DWORD sectionSize, const WCHAR * sectionName); + bool dumpMemory(); +}; diff --git a/Scylla/ImportRebuild.cpp b/Scylla/ImportRebuild.cpp index 888f584..8324e26 100644 --- a/Scylla/ImportRebuild.cpp +++ b/Scylla/ImportRebuild.cpp @@ -1,713 +1,713 @@ #include "ImportRebuild.h" #include "Scylla.h" #include "StringConversion.h" //#define DEBUG_COMMENTS ImportRebuild::ImportRebuild() { imageData = NULL; sizeOfFile = 0; pDosStub = NULL; pOverlay = NULL; sizeOfOverlay = 0; pImportDescriptor = NULL; pThunkData = NULL; pImportByName = NULL; numberOfImportDescriptors = 0; sizeOfImportSection = 0; sizeOfApiAndModuleNames = 0; importSectionIndex = 0; } ImportRebuild::~ImportRebuild() { delete [] pDosStub; delete [] imageData; for (size_t i = 0; i < vecSectionData.size(); i++) { delete [] vecSectionData[i]; } delete [] pOverlay; } bool ImportRebuild::splitTargetFile() { PIMAGE_SECTION_HEADER pSecHeader = 0; BYTE * data = 0; DWORD alignment = 0; DosHeader = *(IMAGE_DOS_HEADER*)imageData; if (DosHeader.e_magic != IMAGE_DOS_SIGNATURE) { return false; } NTHeader = *(IMAGE_NT_HEADERS*)(imageData + DosHeader.e_lfanew); if (NTHeader.Signature != IMAGE_NT_SIGNATURE) { return false; } if (DosHeader.e_lfanew > sizeof(IMAGE_DOS_HEADER)) { size_t sizeOfStub = DosHeader.e_lfanew - sizeof(IMAGE_DOS_HEADER); pDosStub = new BYTE[sizeOfStub]; CopyMemory(pDosStub, imageData + sizeof(IMAGE_DOS_HEADER), sizeOfStub); } pSecHeader = IMAGE_FIRST_SECTION((IMAGE_NT_HEADERS*)(imageData + DosHeader.e_lfanew)); for (WORD i = 0; i < NTHeader.FileHeader.NumberOfSections; i++) { const DWORD SECTION_SIZE_MAX = 300000000; DWORD sizeOfSection = pSecHeader->SizeOfRawData; if (sizeOfSection > SECTION_SIZE_MAX) { sizeOfSection = SECTION_SIZE_MAX; } //TODO better use section alignment because it is better? alignment = alignValue(sizeOfSection, NTHeader.OptionalHeader.SectionAlignment); data = new BYTE[alignment]; ZeroMemory(data, alignment); CopyMemory(data, imageData + pSecHeader->PointerToRawData, sizeOfSection); vecSectionData.push_back(data); vecSectionHeaders.push_back(*pSecHeader); pSecHeader++; } if(NTHeader.FileHeader.NumberOfSections > 0) // ?? { const IMAGE_SECTION_HEADER* pLastSec = &(*vecSectionHeaders.rbegin()); DWORD calcSize = pLastSec->PointerToRawData + pLastSec->SizeOfRawData; if (calcSize < sizeOfFile) { sizeOfOverlay = sizeOfFile - calcSize; pOverlay = new BYTE[sizeOfOverlay]; memcpy(pOverlay, imageData + calcSize, sizeOfOverlay); } } delete [] imageData; imageData = 0; return true; } bool ImportRebuild::alignSectionHeaders() { for (WORD i = 0; i < vecSectionHeaders.size(); i++) { vecSectionHeaders[i].VirtualAddress = alignValue(vecSectionHeaders[i].VirtualAddress, NTHeader.OptionalHeader.SectionAlignment); vecSectionHeaders[i].Misc.VirtualSize = alignValue(vecSectionHeaders[i].Misc.VirtualSize, NTHeader.OptionalHeader.SectionAlignment); vecSectionHeaders[i].PointerToRawData = alignValue(vecSectionHeaders[i].PointerToRawData, NTHeader.OptionalHeader.FileAlignment); vecSectionHeaders[i].SizeOfRawData = alignValue(vecSectionHeaders[i].SizeOfRawData, NTHeader.OptionalHeader.FileAlignment); } return true; } bool ImportRebuild::saveNewFile(const WCHAR * filepath) { DWORD fileOffset = 0; DWORD dwWriteSize = 0; size_t i = 0; if (vecSectionHeaders.size() != vecSectionData.size()) { return false; } HANDLE hFile = CreateFile(filepath, GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, 0,CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); if(hFile == INVALID_HANDLE_VALUE) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"saveNewFile :: INVALID_HANDLE_VALUE %u", GetLastError()); #endif return false; } //alignSectionHeaders(); updatePeHeader(); fileOffset = 0; dwWriteSize = sizeof(IMAGE_DOS_HEADER); ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, dwWriteSize, &DosHeader); fileOffset += dwWriteSize; dwWriteSize = DosHeader.e_lfanew - sizeof(IMAGE_DOS_HEADER); ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, dwWriteSize, pDosStub); fileOffset += dwWriteSize; dwWriteSize = sizeof(IMAGE_NT_HEADERS); ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, dwWriteSize, &NTHeader); fileOffset += dwWriteSize; dwWriteSize = sizeof(IMAGE_SECTION_HEADER); for (i = 0; i < vecSectionHeaders.size(); i++) { if (!ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, dwWriteSize, &vecSectionHeaders[i])) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"saveNewFile :: writeMemoryToFile failed offset %X size %X", fileOffset, dwWriteSize); #endif CloseHandle(hFile); return false; } fileOffset += dwWriteSize; } for (i = 0; i < vecSectionHeaders.size(); i++) { dwWriteSize = vecSectionHeaders[i].PointerToRawData - fileOffset; if (dwWriteSize) { if (!writeZeroMemoryToFile(hFile, fileOffset, dwWriteSize)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"saveNewFile :: writeZeroMemoryToFile failed offset %X size %X", fileOffset, dwWriteSize); #endif CloseHandle(hFile); return false; } fileOffset += dwWriteSize; } dwWriteSize = vecSectionHeaders[i].SizeOfRawData; ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, dwWriteSize, vecSectionData[i]); fileOffset += dwWriteSize; } if(pOverlay) { - ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, sizeOfOverlay, pOverlay); - fileOffset += sizeOfOverlay; + ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, (DWORD)sizeOfOverlay, pOverlay); + fileOffset += (DWORD)sizeOfOverlay; } CloseHandle(hFile); return true; } bool ImportRebuild::writeZeroMemoryToFile(HANDLE hFile, DWORD fileOffset, DWORD size) { bool retValue = false; PVOID zeromemory = calloc(size, 1); if (zeromemory) { retValue = ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, size, zeromemory); free(zeromemory); } else { retValue = false; } return retValue; } bool ImportRebuild::addNewSection(char * sectionName, DWORD sectionSize, BYTE * sectionData) { BYTE * newBuffer = 0; IMAGE_SECTION_HEADER pNewSection = {0}; size_t lastSectionIndex = vecSectionHeaders.size() - 1; size_t nameLength = strlen(sectionName); if (nameLength > IMAGE_SIZEOF_SHORT_NAME) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"addNewSection :: sectionname is too long %d", nameLength); #endif return false; } memcpy_s(pNewSection.Name, IMAGE_SIZEOF_SHORT_NAME, sectionName, nameLength); pNewSection.SizeOfRawData = alignValue(sectionSize, NTHeader.OptionalHeader.FileAlignment); pNewSection.Misc.VirtualSize = alignValue(sectionSize, NTHeader.OptionalHeader.SectionAlignment); pNewSection.PointerToRawData = alignValue(vecSectionHeaders[lastSectionIndex].PointerToRawData + vecSectionHeaders[lastSectionIndex].SizeOfRawData, NTHeader.OptionalHeader.FileAlignment); pNewSection.VirtualAddress = alignValue(vecSectionHeaders[lastSectionIndex].VirtualAddress + vecSectionHeaders[lastSectionIndex].Misc.VirtualSize, NTHeader.OptionalHeader.SectionAlignment); pNewSection.Characteristics = IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE|IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA; vecSectionHeaders.push_back(pNewSection); if ( (sectionSize != pNewSection.SizeOfRawData) || (sectionData == 0) ) { newBuffer = new BYTE[pNewSection.SizeOfRawData]; ZeroMemory(newBuffer, pNewSection.SizeOfRawData); if (sectionData) { CopyMemory(newBuffer, sectionData, sectionSize); } } else { newBuffer = sectionData; } vecSectionData.push_back(newBuffer); return true; } bool ImportRebuild::loadTargetFile(const WCHAR * filepath) { HANDLE hTargetFile = INVALID_HANDLE_VALUE; DWORD fileSize = 0; bool retValue = false; hTargetFile = CreateFile(filepath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if(hTargetFile == INVALID_HANDLE_VALUE) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"loadTargetFile :: INVALID_HANDLE_VALUE %u", GetLastError()); #endif return false; } fileSize = (DWORD)ProcessAccessHelp::getFileSize(hTargetFile); if (!fileSize) { CloseHandle(hTargetFile); hTargetFile = 0; return false; } imageData = new BYTE[fileSize]; if (!imageData) { retValue = false; } else { sizeOfFile = fileSize; retValue = ProcessAccessHelp::readMemoryFromFile(hTargetFile, 0, fileSize, imageData); } CloseHandle(hTargetFile); hTargetFile = 0; return retValue; } DWORD ImportRebuild::alignValue(DWORD badValue, DWORD alignTo) { return (((badValue + alignTo - 1) / alignTo) * alignTo); } DWORD ImportRebuild::convertRVAToOffsetVector(DWORD dwRVA) { for (size_t i = 0; i < vecSectionHeaders.size(); i++) { if ((vecSectionHeaders[i].VirtualAddress <= dwRVA) && ((vecSectionHeaders[i].VirtualAddress + vecSectionHeaders[i].Misc.VirtualSize) > dwRVA)) { return ((dwRVA - vecSectionHeaders[i].VirtualAddress) + vecSectionHeaders[i].PointerToRawData); } } return 0; } /* DWORD ImportRebuild::convertRVAToOffset(DWORD dwRVA) { PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(&NTHeader); for (WORD i = 0; i < NTHeader.FileHeader.NumberOfSections; i++) { if ((pSectionHeader->VirtualAddress <= dwRVA) && ((pSectionHeader->VirtualAddress + pSectionHeader->Misc.VirtualSize) > dwRVA)) { return ((dwRVA - pSectionHeader->VirtualAddress) + pSectionHeader->PointerToRawData); } pSectionHeader++; } return 0; } */ DWORD_PTR ImportRebuild::convertOffsetToRVAVector(DWORD dwOffset) { for (size_t i = 0; i < vecSectionHeaders.size(); i++) { if ((vecSectionHeaders[i].PointerToRawData <= dwOffset) && ((vecSectionHeaders[i].PointerToRawData + vecSectionHeaders[i].SizeOfRawData) > dwOffset)) { return ((dwOffset - vecSectionHeaders[i].PointerToRawData) + vecSectionHeaders[i].VirtualAddress); } } return 0; } /* DWORD ImportRebuild::convertOffsetToRVA(DWORD dwOffset) { PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(&NTHeader); for (WORD i = 0; i < NTHeader.FileHeader.NumberOfSections; i++) { if ((pSectionHeader->PointerToRawData <= dwOffset) && ((pSectionHeader->PointerToRawData + pSectionHeader->SizeOfRawData) > dwOffset)) { return ((dwOffset - pSectionHeader->PointerToRawData) + pSectionHeader->VirtualAddress); } pSectionHeader++; } return 0; } */ void ImportRebuild::updatePeHeader() { size_t lastSectionIndex = vecSectionHeaders.size() - 1; NTHeader.FileHeader.NumberOfSections = (WORD)(lastSectionIndex + 1); NTHeader.OptionalHeader.SizeOfImage = vecSectionHeaders[lastSectionIndex].VirtualAddress + vecSectionHeaders[lastSectionIndex].Misc.VirtualSize; NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0; NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0; if (NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress) { for (size_t i = 0; i < vecSectionHeaders.size(); i++) { if ((vecSectionHeaders[i].VirtualAddress <= NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress) && ((vecSectionHeaders[i].VirtualAddress + vecSectionHeaders[i].Misc.VirtualSize) > NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress)) { //section must be read and writeable vecSectionHeaders[i].Characteristics |= IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE; } } NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = 0; NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = 0; } NTHeader.OptionalHeader.NumberOfRvaAndSizes = 0x10; NTHeader.OptionalHeader.SizeOfHeaders = alignValue(DosHeader.e_lfanew + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + NTHeader.FileHeader.SizeOfOptionalHeader + (NTHeader.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER)), NTHeader.OptionalHeader.FileAlignment); } bool ImportRebuild::buildNewImportTable(std::map & moduleList) { createNewImportSection(moduleList); importSectionIndex = vecSectionHeaders.size() - 1; DWORD dwSize = fillImportSection(moduleList); if (!dwSize) { return false; } setFlagToIATSection((*moduleList.begin()).second.firstThunk); NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = vecSectionHeaders[importSectionIndex].VirtualAddress; NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = (DWORD)(numberOfImportDescriptors * sizeof(IMAGE_IMPORT_DESCRIPTOR)); return true; } bool ImportRebuild::createNewImportSection(std::map & moduleList) { char sectionName[9] = {0}; //DWORD sectionSize = calculateMinSize(moduleList); calculateImportSizes(moduleList); if (wcslen(Scylla::config[IAT_SECTION_NAME].getString()) > IMAGE_SIZEOF_SHORT_NAME) { strcpy_s(sectionName, ".SCY"); } else { StringConversion::ToASCII(Scylla::config[IAT_SECTION_NAME].getString(), sectionName, _countof(sectionName)); } return addNewSection(sectionName, (DWORD)sizeOfImportSection, 0); } /*DWORD ImportRebuild::calculateMinSize(std::map & moduleList) { DWORD dwSize = 0; std::map::iterator mapIt; std::map::iterator mapIt2; dwSize = (DWORD)((moduleList.size() + 1) * sizeof(IMAGE_IMPORT_DESCRIPTOR)); //last is zero'ed for ( mapIt = moduleList.begin() ; mapIt != moduleList.end(); mapIt++ ) { //dwSize += (DWORD)((*mapIt).second.thunkList.size() + sizeof(IMAGE_IMPORT_BY_NAME)); dwSize += (DWORD)(wcslen((*mapIt).second.moduleName) + 1); for ( mapIt2 = (*mapIt).second.thunkList.begin() ; mapIt2 != (*mapIt).second.thunkList.end(); mapIt2++ ) { if((*mapIt2).second.name[0] != '\0') { dwSize += sizeof(IMAGE_IMPORT_BY_NAME); dwSize += (DWORD)strlen((*mapIt2).second.name); } } } return dwSize; }*/ BYTE * ImportRebuild::getMemoryPointerFromRVA(DWORD_PTR dwRVA) { DWORD_PTR offset = convertRVAToOffsetVector((DWORD)dwRVA); for (size_t i = 0; i < vecSectionHeaders.size(); i++) { if ((vecSectionHeaders[i].PointerToRawData <= offset) && ((vecSectionHeaders[i].PointerToRawData + vecSectionHeaders[i].SizeOfRawData) > offset)) { return (BYTE *)((DWORD_PTR)vecSectionData[i] + (offset - vecSectionHeaders[i].PointerToRawData)); } } return 0; } DWORD ImportRebuild::fillImportSection( std::map & 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 = vecSectionData[importSectionIndex]; DWORD offset = 0; pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)(sectionData); //skip the IMAGE_IMPORT_DESCRIPTOR offset += (DWORD)(numberOfImportDescriptors * sizeof(IMAGE_IMPORT_DESCRIPTOR)); for ( mapIt = moduleList.begin() ; mapIt != moduleList.end(); mapIt++ ) { importModuleThunk = &((*mapIt).second); stringLength = addImportDescriptor(importModuleThunk, offset); #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"fillImportSection :: importDesc.Name %X", pImportDescriptor->Name); #endif offset += (DWORD)stringLength; //stringLength has null termination char pImportByName = (PIMAGE_IMPORT_BY_NAME)((DWORD_PTR)sectionData + offset); //pThunk = (PIMAGE_THUNK_DATA)(getMemoryPointerFromRVA(importModuleThunk->firstThunk)); lastRVA = importModuleThunk->firstThunk - sizeof(DWORD_PTR); for ( mapIt2 = (*mapIt).second.thunkList.begin() ; mapIt2 != (*mapIt).second.thunkList.end(); mapIt2++ ) { importThunk = &((*mapIt2).second); pThunk = (PIMAGE_THUNK_DATA)(getMemoryPointerFromRVA(importThunk->rva)); //check wrong iat pointer if (!pThunk) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"fillImportSection :: Failed to get pThunk RVA: %X", importThunk->rva); #endif return 0; } if ((lastRVA + sizeof(DWORD_PTR)) != importThunk->rva) { //add additional import desc addSpecialImportDescriptor(importThunk->rva); } lastRVA = importThunk->rva; #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"fillImportSection :: importThunk %X pThunk %X pImportByName %X offset %X", importThunk,pThunk,pImportByName,offset); #endif stringLength = addImportToImportTable(importThunk, pThunk, pImportByName, offset); offset += (DWORD)stringLength; //is 0 bei import by ordinal pImportByName = (PIMAGE_IMPORT_BY_NAME)((DWORD_PTR)pImportByName + stringLength); } pImportDescriptor++; } return offset; } bool ImportRebuild::rebuildImportTable(const WCHAR * targetFilePath, const WCHAR * newFilePath, std::map & moduleList) { bool retValue = false; if (loadTargetFile(targetFilePath)) { splitTargetFile(); retValue = buildNewImportTable(moduleList); if (retValue) { retValue = saveNewFile(newFilePath); } return retValue; } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"rebuildImportTable ::Failed to load target %s", targetFilePath); #endif return false; } } void ImportRebuild::setFlagToIATSection(DWORD_PTR iatAddress) { for (size_t i = 0; i < vecSectionHeaders.size(); i++) { if ((vecSectionHeaders[i].VirtualAddress <= iatAddress) && ((vecSectionHeaders[i].VirtualAddress + vecSectionHeaders[i].Misc.VirtualSize) > iatAddress)) { //section must be read and writeable vecSectionHeaders[i].Characteristics |= IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE; } } } size_t ImportRebuild::addImportToImportTable( ImportThunk * pImport, PIMAGE_THUNK_DATA pThunk, PIMAGE_IMPORT_BY_NAME pImportByName, DWORD sectionOffset) { size_t stringLength = 0; if(pImport->name[0] == '\0') { pThunk->u1.AddressOfData = (IMAGE_ORDINAL(pImport->ordinal) | IMAGE_ORDINAL_FLAG); } else { pImportByName->Hint = pImport->hint; stringLength = strlen(pImport->name) + 1; memcpy(pImportByName->Name, pImport->name, stringLength); pThunk->u1.AddressOfData = convertOffsetToRVAVector(vecSectionHeaders[importSectionIndex].PointerToRawData + sectionOffset); if (!pThunk->u1.AddressOfData) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"addImportToImportTable :: failed to get AddressOfData %X %X", vecSectionHeaders[importSectionIndex].PointerToRawData, sectionOffset); #endif } //next import should be nulled pThunk++; pThunk->u1.AddressOfData = 0; #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"addImportToImportTable :: pThunk->u1.AddressOfData %X %X %X", pThunk->u1.AddressOfData, pThunk, vecSectionHeaders[importSectionIndex].PointerToRawData + sectionOffset); #endif stringLength += sizeof(WORD); } return stringLength; } size_t ImportRebuild::addImportDescriptor(ImportModuleThunk * pImportModule, DWORD sectionOffset) { char dllName[MAX_PATH]; StringConversion::ToASCII(pImportModule->moduleName, dllName, _countof(dllName)); size_t stringLength = strlen(dllName); memcpy((vecSectionData[importSectionIndex] + sectionOffset), dllName, stringLength); //copy module name to section pImportDescriptor->FirstThunk = (DWORD)pImportModule->firstThunk; pImportDescriptor->Name = (DWORD)convertOffsetToRVAVector(vecSectionHeaders[importSectionIndex].PointerToRawData + sectionOffset); return stringLength; } void ImportRebuild::addSpecialImportDescriptor(DWORD_PTR rvaFirstThunk) { PIMAGE_IMPORT_DESCRIPTOR oldID = pImportDescriptor; pImportDescriptor++; pImportDescriptor->FirstThunk = (DWORD)rvaFirstThunk; pImportDescriptor->Name = oldID->Name; } void ImportRebuild::calculateImportSizes(std::map & moduleList) { std::map::iterator mapIt; std::map::iterator mapIt2; DWORD_PTR lastRVA = 0; numberOfImportDescriptors = 0; sizeOfImportSection = 0; sizeOfApiAndModuleNames = 0; numberOfImportDescriptors = moduleList.size() + 1; //last is zero'd for ( mapIt = moduleList.begin() ; mapIt != moduleList.end(); mapIt++ ) { lastRVA = (*mapIt).second.firstThunk - sizeof(DWORD_PTR); sizeOfApiAndModuleNames += (DWORD)(wcslen((*mapIt).second.moduleName) + 1); for ( mapIt2 = (*mapIt).second.thunkList.begin() ; mapIt2 != (*mapIt).second.thunkList.end(); mapIt2++ ) { if ((lastRVA + sizeof(DWORD_PTR)) != (*mapIt2).second.rva) { numberOfImportDescriptors++; //add additional import desc } if((*mapIt2).second.name[0] != '\0') { sizeOfApiAndModuleNames += sizeof(WORD); //Hint from IMAGE_IMPORT_BY_NAME sizeOfApiAndModuleNames += (DWORD)(strlen((*mapIt2).second.name) + 1); } lastRVA = (*mapIt2).second.rva; } } sizeOfImportSection = sizeOfApiAndModuleNames + (numberOfImportDescriptors * sizeof(IMAGE_IMPORT_DESCRIPTOR)); } \ No newline at end of file diff --git a/Scylla/ImportsHandling.cpp b/Scylla/ImportsHandling.cpp index b82511e..dd005e9 100644 --- a/Scylla/ImportsHandling.cpp +++ b/Scylla/ImportsHandling.cpp @@ -1,807 +1,807 @@ #include "ImportsHandling.h" #include "Thunks.h" #include "Architecture.h" #include #include #include "multitree.h" // CMultiSelectTreeViewCtrl #include "resource.h" //#define DEBUG_COMMENTS 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; } } ImportsHandling::ImportsHandling(CMultiSelectTreeViewCtrl& TreeImports) : TreeImports(TreeImports) { hIconCheck.LoadIcon(IDI_ICON_CHECK, 16, 16); hIconWarning.LoadIcon(IDI_ICON_WARNING, 16, 16); hIconError.LoadIcon(IDI_ICON_ERROR, 16, 16); CDCHandle dc = CWindow(::GetDesktopWindow()).GetDC(); int bits = dc.GetDeviceCaps(BITSPIXEL); const UINT FLAGS = bits > 16 ? ILC_COLOR32 : (ILC_COLOR24 | ILC_MASK); TreeIcons.Create(16, 16, FLAGS, 3, 1); TreeIcons.AddIcon(hIconCheck); TreeIcons.AddIcon(hIconWarning); TreeIcons.AddIcon(hIconError); m_thunkCount = m_invalidThunkCount = m_suspectThunkCount = 0; } ImportsHandling::~ImportsHandling() { TreeIcons.Destroy(); } bool ImportsHandling::isModule(CTreeItem item) { return (0 != getModuleThunk(item)); } bool ImportsHandling::isImport(CTreeItem item) { return (0 != getImportThunk(item)); } ImportModuleThunk * ImportsHandling::getModuleThunk(CTreeItem item) { - std::unordered_map::const_iterator it; + stdext::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::unordered_map::const_iterator it; + stdext::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::unordered_map::iterator it; + stdext::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::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) { Scylla::debugLog.log(L"ImportsHandling::addFunction module not found rva " PRINTF_DWORD_PTR_FULL, 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_import; TreeImports.DeleteAllItems(); itemData.clear(); TreeImports.SetImageList(TreeIcons); it_module = moduleList.begin(); while (it_module != moduleList.end()) { ImportModuleThunk &moduleThunk = it_module->second; moduleThunk.key = moduleThunk.firstThunk; // This belongs elsewhere... moduleThunk.hTreeItem = addDllToTreeView(TreeImports, &moduleThunk); it_import = moduleThunk.thunkList.begin(); while (it_import != moduleThunk.thunkList.end()) { ImportThunk &importThunk = it_import->second; importThunk.key = importThunk.rva; // This belongs elsewhere... importThunk.hTreeItem = addApiToTreeView(TreeImports, moduleThunk.hTreeItem, &importThunk); it_import++; } it_module++; } updateCounts(); } void ImportsHandling::clearAllImports() { TreeImports.DeleteAllItems(); itemData.clear(); moduleList.clear(); updateCounts(); } CTreeItem ImportsHandling::addDllToTreeView(CMultiSelectTreeViewCtrl& idTreeView, ImportModuleThunk * moduleThunk) { CTreeItem item = idTreeView.InsertItem(L"", NULL, TVI_ROOT); 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, 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::selectImports(bool invalid, bool suspect) { std::map::iterator it_module; std::map::iterator it_import; TreeImports.SelectAllItems(FALSE); //remove selection 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; if ((invalid && !importThunk.valid) || (suspect && importThunk.suspect)) { TreeImports.SelectItem(importThunk.hTreeItem, TRUE); importThunk.hTreeItem.EnsureVisible(); } it_import++; } it_module++; } } bool ImportsHandling::invalidateImport(CTreeItem item) { ImportThunk * import = getImportThunk(item); if(import) { CTreeItem parent = item.GetParent(); if(!parent.IsNull()) { const ImportModuleThunk * module = getModuleThunk(parent); if(module) { import->invalidate(); updateImportInTreeView(import, import->hTreeItem); updateModuleInTreeView(module, module->hTreeItem); updateCounts(); return true; } } } return false; } bool ImportsHandling::invalidateModule(CTreeItem item) { ImportModuleThunk * module = getModuleThunk(item); if(module) { std::map::iterator it_import; it_import = module->thunkList.begin(); while(it_import != module->thunkList.end()) { ImportThunk * import = &it_import->second; import->invalidate(); updateImportInTreeView(import, import->hTreeItem); it_import++; } updateModuleInTreeView(module, module->hTreeItem); updateCounts(); return true; } return false; } bool ImportsHandling::setImport(CTreeItem item, const WCHAR * moduleName, const CHAR * apiName, WORD ordinal, WORD hint, bool valid, bool suspect) { ImportThunk * import = getImportThunk(item); if(import) { CTreeItem parent = item.GetParent(); if(!parent.IsNull()) { const ImportModuleThunk * module = getModuleThunk(parent); if(module) { wcscpy_s(import->moduleName, moduleName); strcpy_s(import->name, 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; } } } return false; } void ImportsHandling::updateImportInTreeView(const ImportThunk * importThunk, CTreeItem item) { if (importThunk->valid) { WCHAR tempString[300]; if (importThunk->name[0] != 0x00) { swprintf_s(tempString, L"ord: %04X name: %S", importThunk->ordinal, importThunk->name); } else { swprintf_s(tempString, L"ord: %04X", importThunk->ordinal); } swprintf_s(stringBuffer, L" rva: " PRINTF_DWORD_PTR_HALF L" mod: %s %s", importThunk->rva, importThunk->moduleName, tempString); } else { swprintf_s(stringBuffer, L" rva: " PRINTF_DWORD_PTR_HALF L" ptr: " 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, L"%s (%d) FThunk: " 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::cutImport(CTreeItem item) { ImportThunk * import = getImportThunk(item); if(import) { CTreeItem parent = item.GetParent(); if(!parent.IsNull()) { ImportModuleThunk * module = getModuleThunk(parent); if(module) { itemData.erase(item); import->hTreeItem.Delete(); module->thunkList.erase(import->key); import = 0; if (module->thunkList.empty()) { itemData.erase(parent); module->hTreeItem.Delete(); moduleList.erase(module->key); module = 0; } else { if (module->isValid() && module->moduleName[0] == L'?') { //update module name wcscpy_s(module->moduleName, module->thunkList.begin()->second.moduleName); } module->firstThunk = module->thunkList.begin()->second.rva; updateModuleInTreeView(module, module->hTreeItem); } updateCounts(); return true; } } } return false; } bool ImportsHandling::cutModule(CTreeItem item) { ImportModuleThunk * module = getModuleThunk(item); if(module) { CTreeItem child = item.GetChild(); while(!child.IsNull()) { itemData.erase(child); child = child.GetNextSibling(); } itemData.erase(item); module->hTreeItem.Delete(); moduleList.erase(module->key); module = 0; updateCounts(); return true; } return false; } DWORD_PTR ImportsHandling::getApiAddressByNode(CTreeItem item) { const ImportThunk * import = getImportThunk(item); if(import) { return import->apiAddressVA; } return 0; } void ImportsHandling::scanAndFixModuleList() { std::map::iterator it_module; std::map::iterator it_import; 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; if (importThunk.moduleName[0] == 0 || importThunk.moduleName[0] == L'?') { addNotFoundApiToModuleList(&importThunk); } else { if (isNewModule(importThunk.moduleName)) { addModuleToModuleList(importThunk.moduleName, importThunk.rva); } addFunctionToModuleList(&importThunk); } it_import++; } moduleThunk.thunkList.clear(); it_module++; } 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, moduleName); module.key = module.firstThunk; moduleListNew[module.key] = module; return true; } bool ImportsHandling::isNewModule(const WCHAR * moduleName) { std::map::iterator it_module; it_module = moduleListNew.begin(); while (it_module != moduleListNew.end()) { if (!_wcsicmp(it_module->second.moduleName, moduleName)) { return false; } it_module++; } return true; } void ImportsHandling::addUnknownModuleToModuleList(DWORD_PTR firstThunk) { ImportModuleThunk module; module.firstThunk = firstThunk; wcscpy_s(module.moduleName, L"?"); module.key = module.firstThunk; moduleListNew[module.key] = module; } bool ImportsHandling::addNotFoundApiToModuleList(const ImportThunk * apiNotFound) { ImportThunk import; ImportModuleThunk * module = 0; std::map::iterator it_module; DWORD_PTR rva = apiNotFound->rva; if (moduleListNew.size() > 0) { it_module = moduleListNew.begin(); while (it_module != moduleListNew.end()) { if (rva >= it_module->second.firstThunk) { it_module++; if (it_module == moduleListNew.end()) { it_module--; //new unknown module if (it_module->second.moduleName[0] == L'?') { module = &(it_module->second); } else { addUnknownModuleToModuleList(apiNotFound->rva); module = &(moduleListNew.find(rva)->second); } break; } else if (rva < it_module->second.firstThunk) { it_module--; module = &(it_module->second); break; } } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"Error iterator1 != (*moduleThunkList).end()"); #endif break; } } } else { //new unknown module addUnknownModuleToModuleList(apiNotFound->rva); module = &(moduleListNew.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 = apiNotFound->va; import.rva = apiNotFound->rva; import.apiAddressVA = apiNotFound->apiAddressVA; import.ordinal = 0; wcscpy_s(import.moduleName, L"?"); strcpy_s(import.name, "?"); import.key = import.rva; module->thunkList[import.key] = import; return true; } bool ImportsHandling::addFunctionToModuleList(const ImportThunk * apiFound) { ImportThunk import; ImportModuleThunk * module = 0; std::map::iterator it_module; if (moduleListNew.size() > 1) { it_module = moduleListNew.begin(); while (it_module != moduleListNew.end()) { if (apiFound->rva >= it_module->second.firstThunk) { it_module++; if (it_module == moduleListNew.end()) { it_module--; module = &(it_module->second); break; } else if (apiFound->rva < it_module->second.firstThunk) { it_module--; module = &(it_module->second); break; } } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"Error iterator1 != moduleListNew.end()"); #endif break; } } } else { it_module = moduleListNew.begin(); module = &(it_module->second); } if (!module) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"ImportsHandling::addFunction module not found rva " PRINTF_DWORD_PTR_FULL, 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, apiFound->moduleName); strcpy_s(import.name, apiFound->name); import.key = import.rva; module->thunkList[import.key] = import; return true; } void ImportsHandling::expandAllTreeNodes() { changeExpandStateOfTreeNodes(TVE_EXPAND); } void ImportsHandling::collapseAllTreeNodes() { changeExpandStateOfTreeNodes(TVE_COLLAPSE); } void ImportsHandling::changeExpandStateOfTreeNodes(UINT flag) { std::map::iterator it_module; it_module = moduleList.begin(); while (it_module != moduleList.end()) { ImportModuleThunk &moduleThunk = it_module->second; moduleThunk.hTreeItem.Expand(flag); it_module++; } } diff --git a/Scylla/ImportsHandling.h b/Scylla/ImportsHandling.h index c58e188..ef4444d 100644 --- a/Scylla/ImportsHandling.h +++ b/Scylla/ImportsHandling.h @@ -1,112 +1,112 @@ #pragma once #include -#include +#include // WTL #include #include #include // CTreeItem class CMultiSelectTreeViewCtrl; class ImportThunk; class ImportModuleThunk; class ImportsHandling { public: std::map moduleList; std::map moduleListNew; 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 clearAllImports(); void selectImports(bool invalid, bool suspect); bool invalidateImport(CTreeItem item); bool invalidateModule(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); 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::unordered_map itemData; + stdext::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 }; 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); 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); }; diff --git a/Scylla/MainGui.cpp b/Scylla/MainGui.cpp index 79deb91..ce7d222 100644 --- a/Scylla/MainGui.cpp +++ b/Scylla/MainGui.cpp @@ -1,1244 +1,1273 @@ #include "MainGui.h" #include "Architecture.h" //#include "PluginLoader.h" //#include "ConfigurationHolder.h" #include "PeDump.h" #include "PeRebuild.h" #include "DllInjectionPlugin.h" #include "DisassemblerGui.h" #include "PickApiGui.h" //#include "NativeWinApi.h" #include "ImportRebuild.h" #include "SystemInformation.h" #include "Scylla.h" #include "AboutGui.h" #include "OptionsGui.h" #include "TreeImportExport.h" extern CAppModule _Module; // o_O const WCHAR MainGui::filterExe[] = L"Executable (*.exe)\0*.exe\0All files\0*.*\0"; const WCHAR MainGui::filterDll[] = L"Dynamic Link Library (*.dll)\0*.dll\0All files\0*.*\0"; const WCHAR MainGui::filterExeDll[] = L"Executable (*.exe)\0*.exe\0Dynamic Link Library (*.dll)\0*.dll\0All files\0*.*\0"; const WCHAR MainGui::filterTxt[] = L"Text file (*.txt)\0*.txt\0All files\0*.*\0"; const WCHAR MainGui::filterXml[] = L"XML file (*.xml)\0*.xml\0All files\0*.*\0"; +const WCHAR MainGui::filterMem[] = L"MEM file (*.mem)\0*.mem\0All files\0*.*\0"; MainGui::MainGui() : selectedProcess(0), importsHandling(TreeImports), TreeImportsSubclass(this, IDC_TREE_IMPORTS) { /* Logger::getDebugLogFilePath(); ConfigurationHolder::loadConfiguration(); PluginLoader::findAllPlugins(); NativeWinApi::initialize(); SystemInformation::getSystemInformation(); if(ConfigurationHolder::getConfigObject(DEBUG_PRIVILEGE)->isTrue()) { processLister.setDebugPrivileges(); } ProcessAccessHelp::getProcessModules(GetCurrentProcessId(), ProcessAccessHelp::ownModuleList); */ Scylla::init(); hIcon.LoadIcon(IDI_ICON_SCYLLA); hMenuImports.LoadMenu(IDR_MENU_IMPORTS); hMenuLog.LoadMenu(IDR_MENU_LOG); accelerators.LoadAccelerators(IDR_ACCELERATOR_MAIN); hIconCheck.LoadIcon(IDI_ICON_CHECK, 16, 16); hIconWarning.LoadIcon(IDI_ICON_WARNING, 16, 16); hIconError.LoadIcon(IDI_ICON_ERROR, 16, 16); } BOOL MainGui::PreTranslateMessage(MSG* pMsg) { if(accelerators.TranslateAccelerator(m_hWnd, pMsg)) { return TRUE; // handled keyboard shortcuts } else if(IsDialogMessage(pMsg)) { return TRUE; // handled dialog messages } return FALSE; } BOOL MainGui::OnInitDialog(CWindow wndFocus, LPARAM lInitParam) { if (SystemInformation::currenOS == UNKNOWN_OS) { if(IDCANCEL == MessageBox(L"Operating System is not supported\r\nContinue anyway?", L"Scylla", MB_ICONWARNING | MB_OKCANCEL)) { SendMessage(WM_CLOSE); return FALSE; } } // register ourselves to receive PreTranslateMessage CMessageLoop* pLoop = _Module.GetMessageLoop(); pLoop->AddMessageFilter(this); setupStatusBar(); DoDataExchange(); // attach controls DlgResize_Init(true, true); // init CDialogResize Scylla::windowLog.setWindow(ListLog); appendPluginListToMenu(hMenuImports.GetSubMenu(0)); appendPluginListToMenu(CMenuHandle(GetMenu()).GetSubMenu(MenuImportsOffsetTrace)); enableDialogControls(FALSE); setIconAndDialogCaption(); return TRUE; } void MainGui::OnDestroy() { PostQuitMessage(0); } void MainGui::OnSize(UINT nType, CSize size) { StatusBar.SendMessage(WM_SIZE); SetMsgHandled(FALSE); } void MainGui::OnContextMenu(CWindow wnd, CPoint point) { switch(wnd.GetDlgCtrlID()) { case IDC_TREE_IMPORTS: DisplayContextMenuImports(wnd, point); return; case IDC_LIST_LOG: DisplayContextMenuLog(wnd, point); return; } SetMsgHandled(FALSE); } void MainGui::OnCommand(UINT uNotifyCode, int nID, CWindow wndCtl) { // Handle plugin trace menu selection if(uNotifyCode == 0 && !wndCtl.IsWindow()) // make sure it's a menu { if ((nID >= PLUGIN_MENU_BASE_ID) && (nID <= (int)(Scylla::plugins.getScyllaPluginList().size() + Scylla::plugins.getImprecPluginList().size() + PLUGIN_MENU_BASE_ID))) { pluginActionHandler(nID); return; } } SetMsgHandled(FALSE); } LRESULT MainGui::OnTreeImportsDoubleClick(const NMHDR* pnmh) { if(TreeImports.GetCount() < 1) return 0; // Get item under cursor CTreeItem over = findTreeItem(CPoint(GetMessagePos()), true); if(over && importsHandling.isImport(over)) { pickApiActionHandler(over); } return 0; } LRESULT MainGui::OnTreeImportsKeyDown(const NMHDR* pnmh) { const NMTVKEYDOWN * tkd = (NMTVKEYDOWN *)pnmh; switch(tkd->wVKey) { case VK_RETURN: { CTreeItem selected = TreeImports.GetFocusItem(); if(!selected.IsNull() && importsHandling.isImport(selected)) { pickApiActionHandler(selected); } } return 1; case VK_DELETE: deleteSelectedImportsActionHandler(); return 1; } SetMsgHandled(FALSE); return 0; } UINT MainGui::OnTreeImportsSubclassGetDlgCode(const MSG * lpMsg) { if(lpMsg) { switch(lpMsg->wParam) { case VK_RETURN: return DLGC_WANTMESSAGE; } } SetMsgHandled(FALSE); return 0; } void MainGui::OnTreeImportsSubclassChar(UINT nChar, UINT nRepCnt, UINT nFlags) { switch(nChar) { case VK_RETURN: break; default: SetMsgHandled(FALSE); break; } } void MainGui::OnProcessListDrop(UINT uNotifyCode, int nID, CWindow wndCtl) { fillProcessListComboBox(ComboProcessList); } void MainGui::OnProcessListSelected(UINT uNotifyCode, int nID, CWindow wndCtl) { processSelectedActionHandler(ComboProcessList.GetCurSel()); } void MainGui::OnPickDLL(UINT uNotifyCode, int nID, CWindow wndCtl) { pickDllActionHandler(); } void MainGui::OnOptions(UINT uNotifyCode, int nID, CWindow wndCtl) { optionsActionHandler(); } void MainGui::OnDump(UINT uNotifyCode, int nID, CWindow wndCtl) { dumpActionHandler(); } +void MainGui::OnDumpMemory(UINT uNotifyCode, int nID, CWindow wndCtl) +{ + dumpMemoryActionHandler(); +} + void MainGui::OnFixDump(UINT uNotifyCode, int nID, CWindow wndCtl) { dumpFixActionHandler(); } void MainGui::OnPERebuild(UINT uNotifyCode, int nID, CWindow wndCtl) { peRebuildActionHandler(); } void MainGui::OnDLLInject(UINT uNotifyCode, int nID, CWindow wndCtl) { dllInjectActionHandler(); } void MainGui::OnIATAutoSearch(UINT uNotifyCode, int nID, CWindow wndCtl) { iatAutosearchActionHandler(); } void MainGui::OnGetImports(UINT uNotifyCode, int nID, CWindow wndCtl) { getImportsActionHandler(); } void MainGui::OnInvalidImports(UINT uNotifyCode, int nID, CWindow wndCtl) { showInvalidImportsActionHandler(); } void MainGui::OnSuspectImports(UINT uNotifyCode, int nID, CWindow wndCtl) { showSuspectImportsActionHandler(); } void MainGui::OnClearImports(UINT uNotifyCode, int nID, CWindow wndCtl) { clearImportsActionHandler(); } void MainGui::OnInvalidateSelected(UINT uNotifyCode, int nID, CWindow wndCtl) { invalidateSelectedImportsActionHandler(); } void MainGui::OnCutSelected(UINT uNotifyCode, int nID, CWindow wndCtl) { deleteSelectedImportsActionHandler(); } void MainGui::OnSaveTree(UINT uNotifyCode, int nID, CWindow wndCtl) { saveTreeActionHandler(); } void MainGui::OnLoadTree(UINT uNotifyCode, int nID, CWindow wndCtl) { loadTreeActionHandler(); } void MainGui::OnAutotrace(UINT uNotifyCode, int nID, CWindow wndCtl) { // TODO } void MainGui::OnExit(UINT uNotifyCode, int nID, CWindow wndCtl) { DestroyWindow(); } void MainGui::OnAbout(UINT uNotifyCode, int nID, CWindow wndCtl) { showAboutDialog(); } void MainGui::setupStatusBar() { StatusBar.Create(m_hWnd, NULL, L"", WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_TOOLTIPS, NULL, IDC_STATUS_BAR); CRect rcMain, rcStatus; GetClientRect(&rcMain); StatusBar.GetWindowRect(&rcStatus); const int PARTS = 4; int widths[PARTS]; widths[PART_COUNT] = rcMain.Width() / 5; widths[PART_INVALID] = widths[PART_COUNT] + rcMain.Width() / 5; widths[PART_IMAGEBASE] = widths[PART_INVALID] + rcMain.Width() / 3; widths[PART_MODULE] = -1; StatusBar.SetParts(PARTS, widths); ResizeClient(rcMain.Width(), rcMain.Height() + rcStatus.Height(), FALSE); } void MainGui::updateStatusBar() { // Rewrite ImportsHandling so we get these easily unsigned int totalImports = importsHandling.thunkCount(); unsigned int invalidImports = importsHandling.invalidThunkCount(); // \t = center, \t\t = right-align swprintf_s(stringBuffer, L"\tImports: %u", totalImports); StatusBar.SetText(PART_COUNT, stringBuffer); if(invalidImports > 0) { StatusBar.SetIcon(PART_INVALID, hIconError); } else { StatusBar.SetIcon(PART_INVALID, hIconCheck); } swprintf_s(stringBuffer, L"\tInvalid: %u", invalidImports); StatusBar.SetText(PART_INVALID, stringBuffer); if(selectedProcess) { DWORD_PTR imageBase = 0; const WCHAR * fileName = 0; if(ProcessAccessHelp::selectedModule) { imageBase = ProcessAccessHelp::selectedModule->modBaseAddr; fileName = ProcessAccessHelp::selectedModule->getFilename(); } else { imageBase = selectedProcess->imageBase; fileName = selectedProcess->filename; } swprintf_s(stringBuffer, L"\tImagebase: " PRINTF_DWORD_PTR_FULL, imageBase); StatusBar.SetText(PART_IMAGEBASE, stringBuffer); StatusBar.SetText(PART_MODULE, fileName); StatusBar.SetTipText(PART_MODULE, fileName); } else { StatusBar.SetText(PART_IMAGEBASE, L""); StatusBar.SetText(PART_MODULE, L""); } } bool MainGui::showFileDialog(WCHAR * selectedFile, bool save, const WCHAR * defFileName, const WCHAR * filter, const WCHAR * defExtension, const WCHAR * directory) { OPENFILENAME ofn = {0}; // WTL doesn't support new explorer styles on Vista and up // This is because it uses a custom hook, we could remove it or derive // from CFileDialog but this solution is easier and allows more control anyway (e.g. initial dir) if(defFileName) { wcscpy_s(selectedFile, MAX_PATH, defFileName); } else { selectedFile[0] = L'\0'; } ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = m_hWnd; ofn.lpstrFilter = filter; ofn.lpstrDefExt = defExtension; // only first 3 chars are used, no dots! ofn.lpstrFile = selectedFile; ofn.lpstrInitialDir = directory; ofn.nMaxFile = MAX_PATH; ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY; /* *OFN_EXPLORER is automatically used, it only has to be specified *if using a custom hook *OFN_LONGNAMES is automatically used by explorer-style dialogs */ if(save) ofn.Flags |= OFN_OVERWRITEPROMPT; else ofn.Flags |= OFN_FILEMUSTEXIST; if(save) return 0 != GetSaveFileName(&ofn); else return 0 != GetOpenFileName(&ofn); } void MainGui::setIconAndDialogCaption() { SetIcon(hIcon, TRUE); SetIcon(hIcon, FALSE); SetWindowText(APPNAME L" " ARCHITECTURE L" " APPVERSION); } void MainGui::pickDllActionHandler() { if(!selectedProcess) return; PickDllGui dlgPickDll(ProcessAccessHelp::moduleList); if(dlgPickDll.DoModal()) { //get selected module ProcessAccessHelp::selectedModule = dlgPickDll.getSelectedModule(); ProcessAccessHelp::targetImageBase = ProcessAccessHelp::selectedModule->modBaseAddr; Scylla::windowLog.log(L"->>> Module %s selected.", ProcessAccessHelp::selectedModule->getFilename()); Scylla::windowLog.log(L"Imagebase: " PRINTF_DWORD_PTR_FULL L" Size: %08X", ProcessAccessHelp::selectedModule->modBaseAddr, ProcessAccessHelp::selectedModule->modBaseSize); } else { ProcessAccessHelp::selectedModule = 0; } updateStatusBar(); } void MainGui::pickApiActionHandler(CTreeItem item) { if(!importsHandling.isImport(item)) return; // TODO: new node when user picked an API from another DLL? PickApiGui dlgPickApi(ProcessAccessHelp::moduleList); if(dlgPickApi.DoModal()) { const ApiInfo* api = dlgPickApi.getSelectedApi(); if(api && api->module) { importsHandling.setImport(item, api->module->getFilename(), api->name, api->ordinal, api->hint, true, api->isForwarded); } } updateStatusBar(); } void MainGui::startDisassemblerGui(CTreeItem selectedTreeNode) { if(!selectedProcess) return; DWORD_PTR address = importsHandling.getApiAddressByNode(selectedTreeNode); if (address) { BYTE test; if(!ProcessAccessHelp::readMemoryFromProcess(address, sizeof(test), &test)) { swprintf_s(stringBuffer, L"Can't read memory at " PRINTF_DWORD_PTR_FULL, address); MessageBox(stringBuffer, L"Failure", MB_ICONERROR); } else { DisassemblerGui dlgDisassembler(address); dlgDisassembler.DoModal(); } } } void MainGui::processSelectedActionHandler(int index) { std::vector& processList = Scylla::processLister.getProcessList(); Process &process = processList.at(index); selectedProcess = 0; clearImportsActionHandler(); Scylla::windowLog.log(L"Analyzing %s", process.fullPath); if (ProcessAccessHelp::hProcess != 0) { ProcessAccessHelp::closeProcessHandle(); apiReader.clearAll(); } if (!ProcessAccessHelp::openProcessHandle(process.PID)) { enableDialogControls(FALSE); Scylla::windowLog.log(L"Error: Cannot open process handle."); updateStatusBar(); return; } ProcessAccessHelp::getProcessModules(process.PID, ProcessAccessHelp::moduleList); apiReader.readApisFromModuleList(); Scylla::windowLog.log(L"Loading modules done."); //TODO improve ProcessAccessHelp::selectedModule = 0; ProcessAccessHelp::targetSizeOfImage = process.imageSize; ProcessAccessHelp::targetImageBase = process.imageBase; ProcessAccessHelp::getSizeOfImageCurrentProcess(); process.imageSize = (DWORD)ProcessAccessHelp::targetSizeOfImage; Scylla::windowLog.log(L"Imagebase: " PRINTF_DWORD_PTR_FULL L" Size: %08X", process.imageBase, process.imageSize); process.entryPoint = ProcessAccessHelp::getEntryPointFromFile(process.fullPath); EditOEPAddress.SetValue(process.entryPoint + process.imageBase); selectedProcess = &process; enableDialogControls(TRUE); updateStatusBar(); } void MainGui::fillProcessListComboBox(CComboBox& hCombo) { hCombo.ResetContent(); std::vector& processList = Scylla::processLister.getProcessListSnapshot(); for (size_t i = 0; i < processList.size(); i++) { swprintf_s(stringBuffer, L"0x%04X - %s - %s", processList[i].PID, processList[i].filename, processList[i].fullPath); hCombo.AddString(stringBuffer); } } /* void MainGui::addTextToOutputLog(const WCHAR * text) { if (m_hWnd) { ListLog.SetCurSel(ListLog.AddString(text)); } } */ void MainGui::clearOutputLog() { if (m_hWnd) { ListLog.ResetContent(); } } bool MainGui::saveLogToFile(const WCHAR * file) { const BYTE BOM[] = {0xFF, 0xFE}; // UTF-16 little-endian const WCHAR newLine[] = L"\r\n"; bool success = true; HANDLE hFile = CreateFile(file, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); if(hFile != INVALID_HANDLE_VALUE) { ProcessAccessHelp::writeMemoryToFileEnd(hFile, sizeof(BOM), BOM); WCHAR * buffer = 0; size_t bufsize = 0; for(int i = 0; i < ListLog.GetCount(); i++) { size_t size = ListLog.GetTextLen(i); size += _countof(newLine)-1; if(size+1 > bufsize) { bufsize = size+1; delete[] buffer; try { buffer = new WCHAR[bufsize]; } catch(std::bad_alloc&) { buffer = 0; success = false; break; } } ListLog.GetText(i, buffer); wcscat_s(buffer, bufsize, newLine); ProcessAccessHelp::writeMemoryToFileEnd(hFile, (DWORD)(size * sizeof(WCHAR)), buffer); } delete[] buffer; CloseHandle(hFile); } return success; } void MainGui::showInvalidImportsActionHandler() { importsHandling.selectImports(true, false); GotoDlgCtrl(TreeImports); } void MainGui::showSuspectImportsActionHandler() { importsHandling.selectImports(false, true); GotoDlgCtrl(TreeImports); } void MainGui::deleteSelectedImportsActionHandler() { CTreeItem selected = TreeImports.GetFirstSelectedItem(); while(!selected.IsNull()) { if(importsHandling.isModule(selected)) { importsHandling.cutModule(selected); } else { importsHandling.cutImport(selected); } selected = TreeImports.GetNextSelectedItem(selected); } updateStatusBar(); } void MainGui::invalidateSelectedImportsActionHandler() { CTreeItem selected = TreeImports.GetFirstSelectedItem(); while(!selected.IsNull()) { if(importsHandling.isImport(selected)) { importsHandling.invalidateImport(selected); } selected = TreeImports.GetNextSelectedItem(selected); } updateStatusBar(); } void MainGui::loadTreeActionHandler() { if(!selectedProcess) return; WCHAR selectedFilePath[MAX_PATH]; getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if(showFileDialog(selectedFilePath, false, NULL, filterXml, NULL, stringBuffer)) { TreeImportExport treeIO(selectedFilePath); DWORD_PTR addrOEP = 0; DWORD_PTR addrIAT = 0; DWORD sizeIAT = 0; if(!treeIO.importTreeList(importsHandling.moduleList, &addrOEP, &addrIAT, &sizeIAT)) { Scylla::windowLog.log(L"Loading tree file failed %s", selectedFilePath); MessageBox(L"Loading tree file failed.", L"Failure", MB_ICONERROR); } else { EditOEPAddress.SetValue(addrOEP); EditIATAddress.SetValue(addrIAT); EditIATSize.SetValue(sizeIAT); importsHandling.displayAllImports(); updateStatusBar(); Scylla::windowLog.log(L"Loaded tree file %s", selectedFilePath); Scylla::windowLog.log(L"-> OEP: " PRINTF_DWORD_PTR_FULL, addrOEP); Scylla::windowLog.log(L"-> IAT: " PRINTF_DWORD_PTR_FULL L" Size: " PRINTF_DWORD_PTR, addrIAT, sizeIAT); } } } void MainGui::saveTreeActionHandler() { if(!selectedProcess) return; WCHAR selectedFilePath[MAX_PATH]; getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if(showFileDialog(selectedFilePath, true, NULL, filterXml, L"xml", stringBuffer)) { TreeImportExport treeIO(selectedFilePath); DWORD_PTR addrOEP = EditOEPAddress.GetValue(); DWORD_PTR addrIAT = EditIATAddress.GetValue(); DWORD sizeIAT = EditIATSize.GetValue(); if(!treeIO.exportTreeList(importsHandling.moduleList, selectedProcess, addrOEP, addrIAT, sizeIAT)) { Scylla::windowLog.log(L"Saving tree file failed %s", selectedFilePath); MessageBox(L"Saving tree file failed.", L"Failure", MB_ICONERROR); } else { Scylla::windowLog.log(L"Saved tree file %s", selectedFilePath); } } } void MainGui::iatAutosearchActionHandler() { DWORD_PTR searchAddress = 0; DWORD_PTR addressIAT = 0; DWORD sizeIAT = 0; IATSearch iatSearch; if(!selectedProcess) return; if(EditOEPAddress.GetWindowTextLength() > 0) { searchAddress = EditOEPAddress.GetValue(); if (searchAddress) { if (iatSearch.searchImportAddressTableInProcess(searchAddress, &addressIAT, &sizeIAT)) { Scylla::windowLog.log(L"IAT found at VA " PRINTF_DWORD_PTR_FULL L" RVA " PRINTF_DWORD_PTR_FULL L" Size 0x%04X (%d)", addressIAT, addressIAT - ProcessAccessHelp::targetImageBase, sizeIAT, sizeIAT); EditIATAddress.SetValue(addressIAT); EditIATSize.SetValue(sizeIAT); swprintf_s(stringBuffer, L"IAT found:\r\n\r\nStart: " PRINTF_DWORD_PTR_FULL L"\r\nSize: 0x%04X (%d) ", addressIAT, sizeIAT, sizeIAT); MessageBox(stringBuffer, L"IAT found", MB_ICONINFORMATION); } else { Scylla::windowLog.log(L"IAT not found at OEP " PRINTF_DWORD_PTR_FULL L"!", searchAddress); } } } } void MainGui::getImportsActionHandler() { if(!selectedProcess) return; DWORD_PTR addressIAT = EditIATAddress.GetValue(); DWORD sizeIAT = EditIATSize.GetValue(); if (addressIAT && sizeIAT) { apiReader.readAndParseIAT(addressIAT, sizeIAT, importsHandling.moduleList); importsHandling.displayAllImports(); updateStatusBar(); } } void MainGui::SetupImportsMenuItems(CTreeItem item) { bool isItem, isImport = false; isItem = !item.IsNull(); if(isItem) { isImport = importsHandling.isImport(item); } CMenuHandle hSub = hMenuImports.GetSubMenu(0); UINT itemOnly = isItem ? MF_ENABLED : MF_GRAYED; UINT importOnly = isImport ? MF_ENABLED : MF_GRAYED; hSub.EnableMenuItem(ID__INVALIDATE, itemOnly); hSub.EnableMenuItem(ID__DISASSEMBLE, importOnly); hSub.EnableMenuItem(ID__CUTTHUNK, importOnly); hSub.EnableMenuItem(ID__DELETETREENODE, itemOnly); } void MainGui::DisplayContextMenuImports(CWindow hwnd, CPoint pt) { if(TreeImports.GetCount() < 1) return; CTreeItem over, parent; if(pt.x == -1 && pt.y == -1) // invoked by keyboard { CRect pos; over = TreeImports.GetFocusItem(); if(over) { over.EnsureVisible(); over.GetRect(&pos, TRUE); TreeImports.ClientToScreen(&pos); } else { TreeImports.GetWindowRect(&pos); } pt = pos.TopLeft(); } else { // Get item under cursor over = findTreeItem(pt, true); } SetupImportsMenuItems(over); CMenuHandle hSub = hMenuImports.GetSubMenu(0); BOOL menuItem = hSub.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD, pt.x, pt.y, hwnd); if (menuItem) { if ((menuItem >= PLUGIN_MENU_BASE_ID) && (menuItem <= (int)(Scylla::plugins.getScyllaPluginList().size() + Scylla::plugins.getImprecPluginList().size() + PLUGIN_MENU_BASE_ID))) { //wsprintf(stringBuffer, L"%d %s\n",menuItem,pluginList[menuItem - PLUGIN_MENU_BASE_ID].pluginName); //MessageBox(stringBuffer, L"plugin selection"); pluginActionHandler(menuItem); return; } switch (menuItem) { case ID__INVALIDATE: if(importsHandling.isModule(over)) importsHandling.invalidateModule(over); else importsHandling.invalidateImport(over); break; case ID__DISASSEMBLE: startDisassemblerGui(over); break; case ID__EXPANDALLNODES: importsHandling.expandAllTreeNodes(); break; case ID__COLLAPSEALLNODES: importsHandling.collapseAllTreeNodes(); break; case ID__CUTTHUNK: importsHandling.cutImport(over); break; case ID__DELETETREENODE: importsHandling.cutModule(importsHandling.isImport(over) ? over.GetParent() : over); break; } } updateStatusBar(); } void MainGui::DisplayContextMenuLog(CWindow hwnd, CPoint pt) { if(pt.x == -1 && pt.y == -1) // invoked by keyboard { CRect pos; ListLog.GetWindowRect(&pos); pt = pos.TopLeft(); } CMenuHandle hSub = hMenuLog.GetSubMenu(0); BOOL menuItem = hSub.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD, pt.x, pt.y, hwnd); if (menuItem) { switch (menuItem) { case ID__SAVE: WCHAR selectedFilePath[MAX_PATH]; getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if(showFileDialog(selectedFilePath, true, NULL, filterTxt, L"txt", stringBuffer)) { saveLogToFile(selectedFilePath); } break; case ID__CLEAR: clearOutputLog(); break; } } } void MainGui::appendPluginListToMenu(CMenuHandle hMenu) { std::vector &scyllaPluginList = Scylla::plugins.getScyllaPluginList(); std::vector &imprecPluginList = Scylla::plugins.getImprecPluginList(); if (scyllaPluginList.size() > 0) { CMenuHandle newMenu; newMenu.CreatePopupMenu(); for (size_t i = 0; i < scyllaPluginList.size(); i++) { newMenu.AppendMenu(MF_STRING, i + PLUGIN_MENU_BASE_ID, scyllaPluginList[i].pluginName); } hMenu.AppendMenu(MF_MENUBARBREAK); hMenu.AppendMenu(MF_POPUP, newMenu, L"Scylla Plugins"); } if (imprecPluginList.size() > 0) { CMenuHandle newMenu; newMenu.CreatePopupMenu(); for (size_t i = 0; i < imprecPluginList.size(); i++) { newMenu.AppendMenu(MF_STRING, scyllaPluginList.size() + i + PLUGIN_MENU_BASE_ID, imprecPluginList[i].pluginName); } hMenu.AppendMenu(MF_MENUBARBREAK); hMenu.AppendMenu(MF_POPUP, newMenu, L"ImpREC Plugins"); } } +void MainGui::dumpMemoryActionHandler() +{ + WCHAR selectedFilePath[MAX_PATH]; + DumpMemoryGui dlgDumpMemory; + + if(dlgDumpMemory.DoModal()) + { + getCurrentModulePath(stringBuffer, _countof(stringBuffer)); + if(showFileDialog(selectedFilePath, true, dlgDumpMemory.dumpFilename, filterMem, L"mem", stringBuffer)) + { + if (ProcessAccessHelp::writeMemoryToNewFile(selectedFilePath,dlgDumpMemory.dumpedMemorySize,dlgDumpMemory.dumpedMemory)) + { + Scylla::windowLog.log(L"Memory dump saved %s", selectedFilePath); + } + else + { + Scylla::windowLog.log(L"Error! Cannot write memory dump to disk"); + } + } + } +} + void MainGui::dumpActionHandler() { if(!selectedProcess) return; WCHAR selectedFilePath[MAX_PATH]; const WCHAR * fileFilter; const WCHAR * defExtension; PeDump peDump; if (ProcessAccessHelp::selectedModule) { fileFilter = filterDll; defExtension = L"dll"; } else { fileFilter = filterExe; defExtension = L"exe"; } getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if(showFileDialog(selectedFilePath, true, NULL, fileFilter, defExtension, stringBuffer)) { if (ProcessAccessHelp::selectedModule) { //dump DLL peDump.imageBase = ProcessAccessHelp::selectedModule->modBaseAddr; peDump.sizeOfImage = ProcessAccessHelp::selectedModule->modBaseSize; //get it from gui peDump.entryPoint = EditOEPAddress.GetValue(); wcscpy_s(peDump.fullpath, ProcessAccessHelp::selectedModule->fullPath); } else { peDump.imageBase = ProcessAccessHelp::targetImageBase; peDump.sizeOfImage = (DWORD)ProcessAccessHelp::targetSizeOfImage; //get it from gui peDump.entryPoint = EditOEPAddress.GetValue(); wcscpy_s(peDump.fullpath, selectedProcess->fullPath); } peDump.useHeaderFromDisk = Scylla::config[USE_PE_HEADER_FROM_DISK].isTrue(); if (peDump.dumpCompleteProcessToDisk(selectedFilePath)) { Scylla::windowLog.log(L"Dump success %s", selectedFilePath); } else { Scylla::windowLog.log(L"Error: Cannot dump image."); MessageBox(L"Cannot dump image.", L"Failure", MB_ICONERROR); } } } void MainGui::peRebuildActionHandler() { DWORD newSize = 0; WCHAR selectedFilePath[MAX_PATH]; PeRebuild peRebuild; getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if(showFileDialog(selectedFilePath, false, NULL, filterExeDll, NULL, stringBuffer)) { if (Scylla::config[CREATE_BACKUP].isTrue()) { if (!ProcessAccessHelp::createBackupFile(selectedFilePath)) { Scylla::windowLog.log(L"Creating backup file failed %s", selectedFilePath); } } LONGLONG fileSize = ProcessAccessHelp::getFileSize(selectedFilePath); LPVOID mapped = peRebuild.createFileMappingViewFull(selectedFilePath); newSize = peRebuild.realignPE(mapped, (DWORD)fileSize); peRebuild.closeAllMappingHandles(); if (newSize < 10) { Scylla::windowLog.log(L"Rebuild failed %s", selectedFilePath); MessageBox(L"Rebuild failed.", L"Failure", MB_ICONERROR); } else { peRebuild.truncateFile(selectedFilePath, newSize); Scylla::windowLog.log(L"Rebuild success %s", selectedFilePath); Scylla::windowLog.log(L"-> Old file size 0x%08X new file size 0x%08X (%d %%)", (DWORD)fileSize, newSize, (DWORD)((newSize * 100) / (DWORD)fileSize) ); } } } void MainGui::dumpFixActionHandler() { if(!selectedProcess) return; if (TreeImports.GetCount() < 2) { Scylla::windowLog.log(L"Nothing to rebuild"); return; } WCHAR newFilePath[MAX_PATH]; WCHAR selectedFilePath[MAX_PATH]; const WCHAR * fileFilter; if (ProcessAccessHelp::selectedModule) { fileFilter = filterDll; } else { fileFilter = filterExe; } getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if (showFileDialog(selectedFilePath, false, NULL, fileFilter, NULL, stringBuffer)) { wcscpy_s(newFilePath, selectedFilePath); const WCHAR * extension = 0; WCHAR* dot = wcsrchr(newFilePath, L'.'); if (dot) { *dot = L'\0'; extension = selectedFilePath + (dot - newFilePath); //wcsrchr(selectedFilePath, L'.'); } wcscat_s(newFilePath, L"_SCY"); if(extension) { wcscat_s(newFilePath, extension); } ImportRebuild importRebuild; if (importRebuild.rebuildImportTable(selectedFilePath,newFilePath,importsHandling.moduleList)) { Scylla::windowLog.log(L"Import Rebuild success %s", newFilePath); } else { Scylla::windowLog.log(L"Import Rebuild failed %s", selectedFilePath); MessageBox(L"Import Rebuild failed", L"Failure", MB_ICONERROR); } } } void MainGui::enableDialogControls(BOOL value) { BOOL valButton = value ? TRUE : FALSE; GetDlgItem(IDC_BTN_PICKDLL).EnableWindow(valButton); GetDlgItem(IDC_BTN_DUMP).EnableWindow(valButton); GetDlgItem(IDC_BTN_FIXDUMP).EnableWindow(valButton); GetDlgItem(IDC_BTN_IATAUTOSEARCH).EnableWindow(valButton); GetDlgItem(IDC_BTN_GETIMPORTS).EnableWindow(valButton); GetDlgItem(IDC_BTN_SUSPECTIMPORTS).EnableWindow(valButton); GetDlgItem(IDC_BTN_INVALIDIMPORTS).EnableWindow(valButton); GetDlgItem(IDC_BTN_CLEARIMPORTS).EnableWindow(valButton); CMenuHandle menu = GetMenu(); UINT valMenu = value ? MF_ENABLED : MF_GRAYED; menu.EnableMenuItem(ID_FILE_DUMP, valMenu); + menu.EnableMenuItem(ID_FILE_DUMPMEMORY, valMenu); menu.EnableMenuItem(ID_FILE_FIXDUMP, valMenu); menu.EnableMenuItem(ID_IMPORTS_INVALIDATESELECTED, valMenu); menu.EnableMenuItem(ID_IMPORTS_CUTSELECTED, valMenu); menu.EnableMenuItem(ID_IMPORTS_SAVETREE, valMenu); menu.EnableMenuItem(ID_IMPORTS_LOADTREE, valMenu); menu.EnableMenuItem(ID_MISC_DLLINJECTION, valMenu); menu.GetSubMenu(MenuImportsOffsetTrace).EnableMenuItem(MenuImportsTraceOffsetScylla, MF_BYPOSITION | valMenu); menu.GetSubMenu(MenuImportsOffsetTrace).EnableMenuItem(MenuImportsTraceOffsetImpRec, MF_BYPOSITION | valMenu); //not yet implemented GetDlgItem(IDC_BTN_AUTOTRACE).EnableWindow(FALSE); menu.EnableMenuItem(ID_TRACE_AUTOTRACE, MF_GRAYED); } CTreeItem MainGui::findTreeItem(CPoint pt, bool screenCoordinates) { if(screenCoordinates) { TreeImports.ScreenToClient(&pt); } UINT flags; CTreeItem over = TreeImports.HitTest(pt, &flags); if(over) { if(!(flags & TVHT_ONITEM)) { over.m_hTreeItem = NULL; } } return over; } void MainGui::showAboutDialog() { AboutGui dlgAbout; dlgAbout.DoModal(); } void MainGui::dllInjectActionHandler() { if(!selectedProcess) return; WCHAR selectedFilePath[MAX_PATH]; HMODULE hMod = 0; DllInjection dllInjection; getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if (showFileDialog(selectedFilePath, false, NULL, filterDll, NULL, stringBuffer)) { hMod = dllInjection.dllInjection(ProcessAccessHelp::hProcess, selectedFilePath); if (hMod && Scylla::config[DLL_INJECTION_AUTO_UNLOAD].isTrue()) { if (!dllInjection.unloadDllInProcess(ProcessAccessHelp::hProcess, hMod)) { Scylla::windowLog.log(L"DLL unloading failed, target %s", selectedFilePath); } } if (hMod) { Scylla::windowLog.log(L"DLL Injection was successful, target %s", selectedFilePath); } else { Scylla::windowLog.log(L"DLL Injection failed, target %s", selectedFilePath); } } } void MainGui::optionsActionHandler() { OptionsGui dlgOptions; dlgOptions.DoModal(); } void MainGui::clearImportsActionHandler() { importsHandling.clearAllImports(); updateStatusBar(); } void MainGui::pluginActionHandler( int menuItem ) { if(!selectedProcess) return; DllInjectionPlugin dllInjectionPlugin; std::vector &scyllaPluginList = Scylla::plugins.getScyllaPluginList(); std::vector &imprecPluginList = Scylla::plugins.getImprecPluginList(); menuItem -= PLUGIN_MENU_BASE_ID; dllInjectionPlugin.hProcess = ProcessAccessHelp::hProcess; dllInjectionPlugin.apiReader = &apiReader; if (menuItem < (int)scyllaPluginList.size()) { //scylla plugin dllInjectionPlugin.injectPlugin(scyllaPluginList[menuItem], importsHandling.moduleList,selectedProcess->imageBase, selectedProcess->imageSize); } else { #ifndef _WIN64 menuItem -= (int)scyllaPluginList.size(); //imprec plugin dllInjectionPlugin.injectImprecPlugin(imprecPluginList[menuItem], importsHandling.moduleList,selectedProcess->imageBase, selectedProcess->imageSize); #endif } importsHandling.scanAndFixModuleList(); importsHandling.displayAllImports(); updateStatusBar(); } bool MainGui::getCurrentModulePath(WCHAR * buffer, size_t bufferSize) { if(!selectedProcess) return false; if(ProcessAccessHelp::selectedModule) { wcscpy_s(buffer, bufferSize, ProcessAccessHelp::selectedModule->fullPath); } else { wcscpy_s(buffer, bufferSize, selectedProcess->fullPath); } WCHAR * slash = wcsrchr(buffer, L'\\'); if(slash) { *(slash+1) = L'\0'; } return true; } diff --git a/Scylla/MainGui.h b/Scylla/MainGui.h index 62d8d2d..9e397e3 100644 --- a/Scylla/MainGui.h +++ b/Scylla/MainGui.h @@ -1,295 +1,300 @@ #pragma once #include #include "resource.h" // WTL #include // base ATL classes #include // base WTL classes #include // ATL GUI classes #include // WTL window frame helpers #include // WTL utility classes #include // WTL enhanced msg map macros #include // WTL controls #include // WTL dialog data exchange #include "multitree.h" #include "hexedit.h" #include "Logger.h" #include "ProcessLister.h" #include "IATSearch.h" #include "PickDllGui.h" +#include "DumpMemoryGui.h" #include "ImportsHandling.h" class MainGui : public CDialogImpl, public CWinDataExchange, public CDialogResize, public CMessageFilter { public: enum { IDD = IDD_DLG_MAIN }; // Dialog Data eXchange, attaches/subclasses child controls to wrappers // DDX_CONTROL : subclass // DDX_CONTROL_HANDLE : attach BEGIN_DDX_MAP(MainGui) DDX_CONTROL(IDC_TREE_IMPORTS, TreeImportsSubclass) // needed for message reflection DDX_CONTROL(IDC_TREE_IMPORTS, TreeImports) DDX_CONTROL_HANDLE(IDC_CBO_PROCESSLIST, ComboProcessList) DDX_CONTROL_HANDLE(IDC_LIST_LOG, ListLog) DDX_CONTROL(IDC_EDIT_OEPADDRESS, EditOEPAddress) DDX_CONTROL(IDC_EDIT_IATADDRESS, EditIATAddress) DDX_CONTROL(IDC_EDIT_IATSIZE, EditIATSize) END_DDX_MAP() // Our message map // Messages are passed from top to bottom // The first handler that doesn't call SetMsgHandled(FALSE) aborts the chain // If none signals the message as handled, it will be passed to mixins (CHAIN_MSG_MAP) // or ultimately passed to DefWindowProc BEGIN_MSG_MAP_EX(MainGui) MSG_WM_INITDIALOG(OnInitDialog) MSG_WM_DESTROY(OnDestroy) MSG_WM_SIZE(OnSize) MSG_WM_CONTEXTMENU(OnContextMenu) MSG_WM_COMMAND(OnCommand) NOTIFY_HANDLER_EX(IDC_TREE_IMPORTS, NM_DBLCLK, OnTreeImportsDoubleClick) NOTIFY_HANDLER_EX(IDC_TREE_IMPORTS, TVN_KEYDOWN, OnTreeImportsKeyDown) COMMAND_HANDLER_EX(IDC_CBO_PROCESSLIST, CBN_DROPDOWN, OnProcessListDrop) COMMAND_HANDLER_EX(IDC_CBO_PROCESSLIST, CBN_SELENDOK, OnProcessListSelected) COMMAND_ID_HANDLER_EX(IDC_BTN_PICKDLL, OnPickDLL) COMMAND_ID_HANDLER_EX(IDC_BTN_OPTIONS, OnOptions) COMMAND_ID_HANDLER_EX(IDC_BTN_DUMP, OnDump) COMMAND_ID_HANDLER_EX(IDC_BTN_FIXDUMP, OnFixDump) COMMAND_ID_HANDLER_EX(IDC_BTN_PEREBUILD, OnPERebuild) COMMAND_ID_HANDLER_EX(IDC_BTN_IATAUTOSEARCH, OnIATAutoSearch) COMMAND_ID_HANDLER_EX(IDC_BTN_GETIMPORTS, OnGetImports) COMMAND_ID_HANDLER_EX(IDC_BTN_INVALIDIMPORTS, OnInvalidImports) COMMAND_ID_HANDLER_EX(IDC_BTN_SUSPECTIMPORTS, OnSuspectImports) COMMAND_ID_HANDLER_EX(IDC_BTN_CLEARIMPORTS, OnClearImports) COMMAND_ID_HANDLER_EX(ID_FILE_DUMP, OnDump) + COMMAND_ID_HANDLER_EX(ID_FILE_DUMPMEMORY, OnDumpMemory) COMMAND_ID_HANDLER_EX(ID_FILE_PEREBUILD, OnPERebuild) COMMAND_ID_HANDLER_EX(ID_FILE_FIXDUMP, OnFixDump) COMMAND_ID_HANDLER_EX(ID_FILE_EXIT, OnExit) COMMAND_ID_HANDLER_EX(ID_IMPORTS_SHOWINVALID, OnInvalidImports) COMMAND_ID_HANDLER_EX(ID_IMPORTS_SHOWSUSPECT, OnSuspectImports) COMMAND_ID_HANDLER_EX(ID_IMPORTS_INVALIDATESELECTED, OnInvalidateSelected) COMMAND_ID_HANDLER_EX(ID_IMPORTS_CUTSELECTED, OnCutSelected) COMMAND_ID_HANDLER_EX(ID_IMPORTS_CLEARIMPORTS, OnClearImports) COMMAND_ID_HANDLER_EX(ID_IMPORTS_SAVETREE, OnSaveTree) COMMAND_ID_HANDLER_EX(ID_IMPORTS_LOADTREE, OnLoadTree) COMMAND_ID_HANDLER_EX(ID_TRACE_AUTOTRACE, OnAutotrace) COMMAND_ID_HANDLER_EX(ID_MISC_DLLINJECTION, OnDLLInject) COMMAND_ID_HANDLER_EX(ID_MISC_OPTIONS, OnOptions) COMMAND_ID_HANDLER_EX(ID_HELP_ABOUT, OnAbout) COMMAND_ID_HANDLER_EX(IDCANCEL, OnExit) REFLECT_NOTIFY_ID(IDC_TREE_IMPORTS) // pass WM_NOTIFY to child control CHAIN_MSG_MAP(CDialogResize) // Message map for subclassed treeview // CContainedWindow forwards all messages to this map ALT_MSG_MAP(IDC_TREE_IMPORTS) MSG_WM_GETDLGCODE(OnTreeImportsSubclassGetDlgCode) MSG_WM_CHAR(OnTreeImportsSubclassChar) END_MSG_MAP() // Dialog resize 'table' // States if child controls move or resize or center in a specific direction // when the parent dialog is resized BEGIN_DLGRESIZE_MAP(MainGui) DLGRESIZE_CONTROL(IDC_GROUP_ATTACH, DLSZ_SIZE_X) DLGRESIZE_CONTROL(IDC_CBO_PROCESSLIST, DLSZ_SIZE_X) DLGRESIZE_CONTROL(IDC_BTN_PICKDLL, DLSZ_MOVE_X) DLGRESIZE_CONTROL(IDC_GROUP_IMPORTS, DLSZ_SIZE_X | DLSZ_SIZE_Y) DLGRESIZE_CONTROL(IDC_TREE_IMPORTS, DLSZ_SIZE_X | DLSZ_SIZE_Y) DLGRESIZE_CONTROL(IDC_BTN_INVALIDIMPORTS, DLSZ_MOVE_Y) DLGRESIZE_CONTROL(IDC_BTN_SUSPECTIMPORTS, DLSZ_MOVE_Y) DLGRESIZE_CONTROL(IDC_BTN_CLEARIMPORTS, DLSZ_MOVE_X | DLSZ_MOVE_Y) DLGRESIZE_CONTROL(IDC_GROUP_IATINFO, DLSZ_MOVE_Y) DLGRESIZE_CONTROL(IDC_STATIC_OEPADDRESS, DLSZ_MOVE_Y) DLGRESIZE_CONTROL(IDC_STATIC_IATADDRESS, DLSZ_MOVE_Y) DLGRESIZE_CONTROL(IDC_STATIC_IATSIZE, DLSZ_MOVE_Y) DLGRESIZE_CONTROL(IDC_EDIT_OEPADDRESS, DLSZ_MOVE_Y) DLGRESIZE_CONTROL(IDC_EDIT_IATADDRESS, DLSZ_MOVE_Y) DLGRESIZE_CONTROL(IDC_EDIT_IATSIZE, DLSZ_MOVE_Y) DLGRESIZE_CONTROL(IDC_BTN_IATAUTOSEARCH, DLSZ_MOVE_Y) DLGRESIZE_CONTROL(IDC_BTN_GETIMPORTS, DLSZ_MOVE_Y) DLGRESIZE_CONTROL(IDC_GROUP_ACTIONS, DLSZ_MOVE_Y) DLGRESIZE_CONTROL(IDC_BTN_AUTOTRACE, DLSZ_MOVE_Y) DLGRESIZE_CONTROL(IDC_GROUP_DUMP, DLSZ_MOVE_Y) DLGRESIZE_CONTROL(IDC_BTN_DUMP, DLSZ_MOVE_Y) DLGRESIZE_CONTROL(IDC_BTN_PEREBUILD, DLSZ_MOVE_Y) DLGRESIZE_CONTROL(IDC_BTN_FIXDUMP, DLSZ_MOVE_Y) DLGRESIZE_CONTROL(IDC_GROUP_LOG, DLSZ_MOVE_Y | DLSZ_SIZE_X) DLGRESIZE_CONTROL(IDC_LIST_LOG, DLSZ_MOVE_Y | DLSZ_SIZE_X) END_DLGRESIZE_MAP() MainGui(); //void addTextToOutputLog(const WCHAR * text); //CWindow getLogListboxHandle() const { return ListLog; } protected: // Variables WCHAR stringBuffer[600]; ImportsHandling importsHandling; //ProcessAccessHelp processAccessHelp; ApiReader apiReader; Process * selectedProcess; // File selection filters static const WCHAR filterExe[]; static const WCHAR filterDll[]; static const WCHAR filterExeDll[]; static const WCHAR filterTxt[]; static const WCHAR filterXml[]; + static const WCHAR filterMem[]; // Controls CMultiSelectTreeViewCtrl TreeImports; CComboBox ComboProcessList; CHexEdit EditOEPAddress; CHexEdit EditIATAddress; CHexEdit EditIATSize; CListBox ListLog; CStatusBarCtrl StatusBar; enum StatusParts { PART_COUNT = 0, PART_INVALID, PART_IMAGEBASE, PART_MODULE }; CContainedWindow TreeImportsSubclass; // Handles CIcon hIcon; CMenu hMenuImports; CMenu hMenuLog; CAccelerator accelerators; CIcon hIconCheck; CIcon hIconWarning; CIcon hIconError; static const int MenuImportsOffsetTrace = 2; static const int MenuImportsTraceOffsetScylla = 2; static const int MenuImportsTraceOffsetImpRec = 4; static const int PLUGIN_MENU_BASE_ID = 0x10; protected: virtual BOOL PreTranslateMessage(MSG* pMsg); // Message handlers BOOL OnInitDialog(CWindow wndFocus, LPARAM lInitParam); void OnDestroy(); void OnSize(UINT nType, CSize size); void OnContextMenu(CWindow wnd, CPoint point); void OnCommand(UINT uNotifyCode, int nID, CWindow wndCtl); // WM_NOTIFY handlers LRESULT OnTreeImportsDoubleClick(const NMHDR* pnmh); LRESULT OnTreeImportsKeyDown(const NMHDR* pnmh); // Forwarded messages from subclassed treeview UINT OnTreeImportsSubclassGetDlgCode(const MSG * lpMsg); void OnTreeImportsSubclassChar(UINT nChar, UINT nRepCnt, UINT nFlags); // WM_COMMAND handlers void OnProcessListDrop(UINT uNotifyCode, int nID, CWindow wndCtl); void OnProcessListSelected(UINT uNotifyCode, int nID, CWindow wndCtl); void OnPickDLL(UINT uNotifyCode, int nID, CWindow wndCtl); void OnOptions(UINT uNotifyCode, int nID, CWindow wndCtl); void OnDump(UINT uNotifyCode, int nID, CWindow wndCtl); + void OnDumpMemory(UINT uNotifyCode, int nID, CWindow wndCtl); void OnFixDump(UINT uNotifyCode, int nID, CWindow wndCtl); void OnPERebuild(UINT uNotifyCode, int nID, CWindow wndCtl); void OnDLLInject(UINT uNotifyCode, int nID, CWindow wndCtl); void OnIATAutoSearch(UINT uNotifyCode, int nID, CWindow wndCtl); void OnGetImports(UINT uNotifyCode, int nID, CWindow wndCtl); void OnInvalidImports(UINT uNotifyCode, int nID, CWindow wndCtl); void OnSuspectImports(UINT uNotifyCode, int nID, CWindow wndCtl); void OnClearImports(UINT uNotifyCode, int nID, CWindow wndCtl); void OnInvalidateSelected(UINT uNotifyCode, int nID, CWindow wndCtl); void OnCutSelected(UINT uNotifyCode, int nID, CWindow wndCtl); void OnSaveTree(UINT uNotifyCode, int nID, CWindow wndCtl); void OnLoadTree(UINT uNotifyCode, int nID, CWindow wndCtl); void OnAutotrace(UINT uNotifyCode, int nID, CWindow wndCtl); void OnExit(UINT uNotifyCode, int nID, CWindow wndCtl); void OnAbout(UINT uNotifyCode, int nID, CWindow wndCtl); // GUI functions bool showFileDialog(WCHAR * selectedFile, bool save, const WCHAR * defFileName, const WCHAR * filter = NULL, const WCHAR * defExtension = NULL, const WCHAR * directory = NULL); void setupStatusBar(); void updateStatusBar(); void fillProcessListComboBox(CComboBox& hCombo); void setIconAndDialogCaption(); void enableDialogControls(BOOL value); CTreeItem findTreeItem(CPoint pt, bool screenCoordinates); // Actions void pickDllActionHandler(); void pickApiActionHandler(CTreeItem item); void processSelectedActionHandler(int index); void showInvalidImportsActionHandler(); void showSuspectImportsActionHandler(); void deleteSelectedImportsActionHandler(); void invalidateSelectedImportsActionHandler(); void loadTreeActionHandler(); void saveTreeActionHandler(); void iatAutosearchActionHandler(); void getImportsActionHandler(); void dumpActionHandler(); + void dumpMemoryActionHandler(); void peRebuildActionHandler(); void startDisassemblerGui(CTreeItem selectedTreeNode); void dumpFixActionHandler(); void showAboutDialog(); void dllInjectActionHandler(); void optionsActionHandler(); void clearImportsActionHandler(); void pluginActionHandler(int menuItem); // Popup menu functions void SetupImportsMenuItems(CTreeItem item); void appendPluginListToMenu(CMenuHandle hMenuTrackPopup); void DisplayContextMenuImports(CWindow, CPoint); void DisplayContextMenuLog(CWindow, CPoint); // Log void clearOutputLog(); bool saveLogToFile(const WCHAR * file); // Misc bool getCurrentModulePath(WCHAR * buffer, size_t bufferSize); }; diff --git a/Scylla/MainGui.rc b/Scylla/MainGui.rc index d12db6c..91abd3c 100644 Binary files a/Scylla/MainGui.rc and b/Scylla/MainGui.rc differ diff --git a/Scylla/NativeWinApi.h b/Scylla/NativeWinApi.h index 262f776..d356994 100644 --- a/Scylla/NativeWinApi.h +++ b/Scylla/NativeWinApi.h @@ -1,261 +1,261 @@ #pragma once #include #define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) #define STATUS_SUCCESS ((NTSTATUS)0x00000000L) #define DUPLICATE_SAME_ATTRIBUTES 0x00000004 #define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0) typedef enum _SYSTEM_INFORMATION_CLASS { SystemBasicInformation, SystemProcessorInformation, SystemPerformanceInformation, SystemTimeOfDayInformation, SystemPathInformation, SystemProcessInformation, SystemCallCountInformation, SystemDeviceInformation, SystemProcessorPerformanceInformation, SystemFlagsInformation, SystemCallTimeInformation, SystemModuleInformation, SystemLocksInformation, SystemStackTraceInformation, SystemPagedPoolInformation, SystemNonPagedPoolInformation, SystemHandleInformation, SystemObjectInformation, SystemPageFileInformation, SystemVdmInstemulInformation, SystemVdmBopInformation, SystemFileCacheInformation, SystemPoolTagInformation, SystemInterruptInformation, SystemDpcBehaviorInformation, SystemFullMemoryInformation, SystemLoadGdiDriverInformation, SystemUnloadGdiDriverInformation, SystemTimeAdjustmentInformation, SystemSummaryMemoryInformation, SystemNextEventIdInformation, SystemEventIdsInformation, SystemCrashDumpInformation, SystemExceptionInformation, SystemCrashDumpStateInformation, SystemKernelDebuggerInformation, SystemContextSwitchInformation, SystemRegistryQuotaInformation, SystemExtendServiceTableInformation, SystemPrioritySeperation, SystemPlugPlayBusInformation, SystemDockInformation, SystemPowerInformation2, SystemProcessorSpeedInformation, SystemCurrentTimeZoneInformation, SystemLookasideInformation } SYSTEM_INFORMATION_CLASS; typedef struct _IO_STATUS_BLOCK { union { NTSTATUS Status; PVOID Pointer; }; ULONG_PTR Information; } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; typedef struct _FILE_NAME_INFORMATION { // Information Classes 9 and 21 ULONG FileNameLength; WCHAR FileName[1]; } FILE_NAME_INFORMATION; typedef enum _FILE_INFORMATION_CLASS { FileNameInformation=9, } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; typedef struct _UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer; } UNICODE_STRING, *PUNICODE_STRING; typedef struct _CLIENT_ID{ HANDLE UniqueProcess; HANDLE UniqueThread; } CLIENT_ID, *PCLIENT_ID; #define InitializeObjectAttributes(p,n,a,r,s) \ { \ (p)->Length = sizeof(OBJECT_ATTRIBUTES); \ (p)->ObjectName = n; \ (p)->Attributes = a; \ (p)->RootDirectory = r; \ (p)->SecurityDescriptor = s; \ (p)->SecurityQualityOfService = NULL; \ } typedef struct _OBJECT_ATTRIBUTES { ULONG Length; PVOID RootDirectory; PUNICODE_STRING ObjectName; ULONG Attributes; PVOID SecurityDescriptor; PVOID SecurityQualityOfService; } OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES; typedef enum _OBJECT_INFORMATION_CLASS { ObjectBasicInformation, ObjectNameInformation, ObjectTypeInformation, ObjectAllInformation, ObjectDataInformation } OBJECT_INFORMATION_CLASS, *POBJECT_INFORMATION_CLASS; typedef enum _THREADINFOCLASS { ThreadBasicInformation, ThreadTimes, ThreadPriority, ThreadBasePriority, ThreadAffinityMask, ThreadImpersonationToken, ThreadDescriptorTableEntry, ThreadEnableAlignmentFaultFixup, ThreadEventPair_Reusable, ThreadQuerySetWin32StartAddress, ThreadZeroTlsCell, ThreadPerformanceCount, ThreadAmILastThread, ThreadIdealProcessor, ThreadPriorityBoost, ThreadSetTlsArrayAddress, ThreadIsIoPending, ThreadHideFromDebugger, ThreadBreakOnTermination, MaxThreadInfoClass } THREADINFOCLASS; typedef enum _PROCESSINFOCLASS { ProcessBasicInformation, ProcessQuotaLimits, ProcessIoCounters, ProcessVmCounters, ProcessTimes, ProcessBasePriority, ProcessRaisePriority, ProcessDebugPort, ProcessExceptionPort, ProcessAccessToken, ProcessLdtInformation, ProcessLdtSize, ProcessDefaultHardErrorMode, ProcessIoPortHandlers, ProcessPooledUsageAndLimits, ProcessWorkingSetWatch, ProcessUserModeIOPL, ProcessEnableAlignmentFaultFixup, ProcessPriorityClass, ProcessWx86Information, ProcessHandleCount, ProcessAffinityMask, ProcessPriorityBoost, ProcessDeviceMap, ProcessSessionInformation, ProcessForegroundInformation, ProcessWow64Information, ProcessImageFileName, ProcessLUIDDeviceMapsEnabled, ProcessBreakOnTermination, ProcessDebugObjectHandle, ProcessDebugFlags, ProcessHandleTracing, ProcessIoPriority, ProcessExecuteFlags, ProcessResourceManagement, ProcessCookie, ProcessImageInformation, MaxProcessInfoClass } PROCESSINFOCLASS; typedef struct _PEB_LDR_DATA { BYTE Reserved1[8]; PVOID Reserved2[3]; LIST_ENTRY InMemoryOrderModuleList; } PEB_LDR_DATA, *PPEB_LDR_DATA; typedef struct _RTL_USER_PROCESS_PARAMETERS { BYTE Reserved1[16]; PVOID Reserved2[10]; UNICODE_STRING ImagePathName; UNICODE_STRING CommandLine; } RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS; typedef struct _PEB { BYTE Reserved1[2]; BYTE BeingDebugged; BYTE Reserved2[1]; PVOID Reserved3[2]; PPEB_LDR_DATA Ldr; PRTL_USER_PROCESS_PARAMETERS ProcessParameters; BYTE Reserved4[104]; PVOID Reserved5[52]; PVOID PostProcessInitRoutine; BYTE Reserved6[128]; PVOID Reserved7[1]; ULONG SessionId; } PEB, *PPEB; typedef struct _PROCESS_BASIC_INFORMATION { PVOID Reserved1; PPEB PebBaseAddress; PVOID Reserved2[2]; ULONG_PTR UniqueProcessId; PVOID Reserved3; } PROCESS_BASIC_INFORMATION; typedef NTSTATUS (WINAPI *def_NtTerminateProcess)(HANDLE ProcessHandle, NTSTATUS ExitStatus); typedef NTSTATUS (WINAPI *def_NtQueryObject)(HANDLE Handle,OBJECT_INFORMATION_CLASS ObjectInformationClass,PVOID ObjectInformation,ULONG ObjectInformationLength,PULONG ReturnLength); typedef NTSTATUS (WINAPI *def_NtDuplicateObject)(HANDLE SourceProcessHandle, HANDLE SourceHandle, HANDLE TargetProcessHandle, PHANDLE TargetHandle, ACCESS_MASK DesiredAccess, BOOLEAN InheritHandle, ULONG Options ); typedef NTSTATUS (WINAPI *def_NtQueryInformationFile)(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass); -typedef ULONG (WINAPI *def_NtQueryInformationThread)(HANDLE ThreadHandle,THREADINFOCLASS ThreadInformationClass,PVOID ThreadInformation,ULONG ThreadInformationLength,PULONG ReturnLength); +typedef NTSTATUS (WINAPI *def_NtQueryInformationThread)(HANDLE ThreadHandle,THREADINFOCLASS ThreadInformationClass,PVOID ThreadInformation,ULONG ThreadInformationLength,PULONG ReturnLength); typedef NTSTATUS (WINAPI *def_NtQueryInformationProcess)(HANDLE ProcessHandle,PROCESSINFOCLASS ProcessInformationClass,PVOID ProcessInformation,ULONG ProcessInformationLength,PULONG ReturnLength); typedef NTSTATUS (WINAPI *def_NtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS SystemInformationClass,PVOID SystemInformation,ULONG SystemInformationLength, PULONG ReturnLength); typedef NTSTATUS (WINAPI *def_NtOpenProcess)(PHANDLE ProcessHandle, ACCESS_MASK AccessMask, PVOID ObjectAttributes, PCLIENT_ID ClientId ); typedef NTSTATUS (WINAPI *def_NtOpenThread)(PHANDLE ThreadHandle,ACCESS_MASK DesiredAccess,POBJECT_ATTRIBUTES ObjectAttributes,PCLIENT_ID ClientId); typedef NTSTATUS (WINAPI *def_NtResumeThread)(HANDLE ThreadHandle, PULONG SuspendCount); typedef NTSTATUS (WINAPI *def_NtSetInformationThread)(HANDLE ThreadHandle,THREADINFOCLASS ThreadInformationClass,PVOID ThreadInformation,ULONG ThreadInformationLength); typedef NTSTATUS (WINAPI *def_NtCreateThreadEx)(PHANDLE hThread,ACCESS_MASK DesiredAccess,LPVOID ObjectAttributes,HANDLE ProcessHandle,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter,BOOL CreateSuspended,ULONG StackZeroBits,LPVOID SizeOfStackCommit,LPVOID SizeOfStackReserve,LPVOID lpBytesBuffer); typedef ULONG (WINAPI *def_RtlNtStatusToDosError)(NTSTATUS Status); class NativeWinApi { public: static def_NtCreateThreadEx NtCreateThreadEx; static def_NtDuplicateObject NtDuplicateObject; static def_NtOpenProcess NtOpenProcess; static def_NtOpenThread NtOpenThread; static def_NtQueryObject NtQueryObject; static def_NtQueryInformationFile NtQueryInformationFile; static def_NtQueryInformationProcess NtQueryInformationProcess; static def_NtQueryInformationThread NtQueryInformationThread; static def_NtQuerySystemInformation NtQuerySystemInformation; static def_NtResumeThread NtResumeThread; static def_NtSetInformationThread NtSetInformationThread; static def_NtTerminateProcess NtTerminateProcess; static def_RtlNtStatusToDosError RtlNtStatusToDosError; static void initialize(); static PPEB getCurrentProcessEnvironmentBlock(); static PPEB getProcessEnvironmentBlockAddress(HANDLE processHandle); }; diff --git a/Scylla/PickDllGui.cpp b/Scylla/PickDllGui.cpp index dcf1516..75616c3 100644 --- a/Scylla/PickDllGui.cpp +++ b/Scylla/PickDllGui.cpp @@ -1,145 +1,144 @@ #include "PickDllGui.h" +#include "definitions.h" + PickDllGui::PickDllGui(std::vector &moduleList) : moduleList(moduleList) { selectedModule = 0; prevColumn = -1; ascending = true; } BOOL PickDllGui::OnInitDialog(CWindow wndFocus, LPARAM lInitParam) { DoDataExchange(); // attach controls DlgResize_Init(true, true); addColumnsToModuleList(ListDLLSelect); displayModuleList(ListDLLSelect); CenterWindow(); return TRUE; } LRESULT PickDllGui::OnListDllColumnClicked(NMHDR* pnmh) { NMLISTVIEW* list = (NMLISTVIEW*)pnmh; int column = list->iSubItem; if(column == prevColumn) { ascending = !ascending; } else { prevColumn = column; ascending = true; } // lo-byte: column, hi-byte: sort-order ListDLLSelect.SortItems(&listviewCompareFunc, MAKEWORD(column, ascending)); return 0; } LRESULT PickDllGui::OnListDllDoubleClick(NMHDR* pnmh) { NMITEMACTIVATE* ia = (NMITEMACTIVATE*)pnmh; LVHITTESTINFO hti; hti.pt = ia->ptAction; int clicked = ListDLLSelect.HitTest(&hti); if(clicked != -1) { selectedModule = (ModuleInfo *)ListDLLSelect.GetItemData(clicked); EndDialog(1); } return 0; } void PickDllGui::OnOK(UINT uNotifyCode, int nID, CWindow wndCtl) { int index = ListDLLSelect.GetSelectionMark(); if (index != -1) { selectedModule = (ModuleInfo *)ListDLLSelect.GetItemData(index); EndDialog(1); } } void PickDllGui::OnCancel(UINT uNotifyCode, int nID, CWindow wndCtl) { EndDialog(0); } void PickDllGui::addColumnsToModuleList(CListViewCtrl& list) { list.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT); list.InsertColumn(COL_NAME, L"Name", LVCFMT_LEFT); list.InsertColumn(COL_IMAGEBASE, L"ImageBase", LVCFMT_CENTER); list.InsertColumn(COL_IMAGESIZE, L"ImageSize", LVCFMT_CENTER); list.InsertColumn(COL_PATH, L"Path", LVCFMT_LEFT); } void PickDllGui::displayModuleList(CListViewCtrl& list) { WCHAR temp[20]; list.DeleteAllItems(); std::vector::const_iterator iter; int count = 0; for( iter = moduleList.begin(); iter != moduleList.end(); iter++ , count++) { list.InsertItem(count, iter->getFilename()); -#ifdef _WIN64 - swprintf_s(temp, L"%016I64X", iter->modBaseAddr); -#else - swprintf_s(temp, L"%08X", iter->modBaseAddr); -#endif + swprintf_s(temp, TEXT(PRINTF_DWORD_PTR_FULL), iter->modBaseAddr); + list.SetItemText(count, COL_IMAGEBASE, temp); swprintf_s(temp, L"%08X",iter->modBaseSize); list.SetItemText(count, COL_IMAGESIZE, temp); list.SetItemText(count, COL_PATH, iter->fullPath); list.SetItemData(count, (DWORD_PTR)&(*iter)); } list.SetColumnWidth(COL_NAME, LVSCW_AUTOSIZE_USEHEADER); list.SetColumnWidth(COL_IMAGEBASE, LVSCW_AUTOSIZE_USEHEADER); list.SetColumnWidth(COL_IMAGESIZE, LVSCW_AUTOSIZE_USEHEADER); list.SetColumnWidth(COL_PATH, LVSCW_AUTOSIZE_USEHEADER); } // lParamSort - lo-byte: column, hi-byte: sort-order int PickDllGui::listviewCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { const ModuleInfo * module1 = (ModuleInfo *)lParam1; const ModuleInfo * module2 = (ModuleInfo *)lParam2; int column = LOBYTE(lParamSort); bool ascending = (HIBYTE(lParamSort) == TRUE); int diff = 0; switch(column) { case COL_NAME: diff = _wcsicmp(module1->getFilename(), module2->getFilename()); break; case COL_IMAGEBASE: diff = module1->modBaseAddr < module2->modBaseAddr ? -1 : 1; break; case COL_IMAGESIZE: diff = module1->modBaseSize < module2->modBaseSize ? -1 : 1; break; case COL_PATH: diff = _wcsicmp(module1->fullPath, module2->fullPath); break; } return ascending ? diff : -diff; } diff --git a/Scylla/ProcessAccessHelp.cpp b/Scylla/ProcessAccessHelp.cpp index 6f191a4..00ca738 100644 --- a/Scylla/ProcessAccessHelp.cpp +++ b/Scylla/ProcessAccessHelp.cpp @@ -1,715 +1,729 @@ #include "ProcessAccessHelp.h" #include "Scylla.h" #include "NativeWinApi.h" HANDLE ProcessAccessHelp::hProcess = 0; ModuleInfo * ProcessAccessHelp::selectedModule; DWORD_PTR ProcessAccessHelp::targetImageBase = 0; DWORD_PTR ProcessAccessHelp::targetSizeOfImage = 0; DWORD_PTR ProcessAccessHelp::maxValidAddress = 0; std::vector ProcessAccessHelp::moduleList; //target process module list std::vector ProcessAccessHelp::ownModuleList; //own module list _DInst ProcessAccessHelp::decomposerResult[MAX_INSTRUCTIONS]; unsigned int ProcessAccessHelp::decomposerInstructionsCount = 0; _CodeInfo ProcessAccessHelp::decomposerCi = {0}; _DecodedInst ProcessAccessHelp::decodedInstructions[MAX_INSTRUCTIONS]; unsigned int ProcessAccessHelp::decodedInstructionsCount = 0; BYTE ProcessAccessHelp::fileHeaderFromDisk[PE_HEADER_BYTES_COUNT]; //#define DEBUG_COMMENTS bool ProcessAccessHelp::openProcessHandle(DWORD dwPID) { if (dwPID > 0) { if (hProcess) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"openProcessHandle :: There is already a process handle, HANDLE %X", hProcess); #endif return false; } else { //hProcess = OpenProcess(PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_QUERY_INFORMATION|PROCESS_VM_READ|PROCESS_VM_WRITE, 0, dwPID); //if (!NT_SUCCESS(NativeWinApi::NtOpenProcess(&hProcess,PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_QUERY_INFORMATION|PROCESS_VM_READ|PROCESS_VM_WRITE,&ObjectAttributes, &cid))) hProcess = NativeOpenProcess(PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_QUERY_INFORMATION|PROCESS_VM_READ|PROCESS_VM_WRITE, dwPID); if (hProcess) { return true; } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"openProcessHandle :: Failed to open handle, PID %X", dwPID); #endif return false; } } } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"openProcessHandle :: Wrong PID, PID %X", dwPID); #endif return false; } } HANDLE ProcessAccessHelp::NativeOpenProcess(DWORD dwDesiredAccess, DWORD dwProcessId) { HANDLE hProcess = 0; CLIENT_ID cid = {0}; OBJECT_ATTRIBUTES ObjectAttributes; NTSTATUS ntStatus = 0; InitializeObjectAttributes(&ObjectAttributes, 0, 0, 0, 0); cid.UniqueProcess = (HANDLE)dwProcessId; ntStatus = NativeWinApi::NtOpenProcess(&hProcess,dwDesiredAccess,&ObjectAttributes, &cid); if (NT_SUCCESS(ntStatus)) { return hProcess; } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"NativeOpenProcess :: Failed to open handle, PID %X Error 0x%X", dwProcessId, NativeWinApi::RtlNtStatusToDosError(ntStatus)); #endif return 0; } } void ProcessAccessHelp::closeProcessHandle() { CloseHandle(hProcess); hProcess = 0; moduleList.clear(); targetImageBase = 0; selectedModule = 0; } bool ProcessAccessHelp::readMemoryFromProcess(DWORD_PTR address, SIZE_T size, LPVOID dataBuffer) { SIZE_T lpNumberOfBytesRead = 0; DWORD dwProtect = 0; bool returnValue = false; if (!hProcess) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"readMemoryFromProcess :: hProcess == NULL"); #endif return returnValue; } if (!ReadProcessMemory(hProcess, (LPVOID)address, dataBuffer, size, &lpNumberOfBytesRead)) { if (!VirtualProtectEx(hProcess, (LPVOID)address, size, PAGE_READWRITE, &dwProtect)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"readMemoryFromProcess :: Error VirtualProtectEx %X %X err: %u", address,size, GetLastError()); #endif returnValue = false; } else { if (!ReadProcessMemory(hProcess, (LPVOID)address, dataBuffer, size, &lpNumberOfBytesRead)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"readMemoryFromProcess :: Error ReadProcessMemory %X %X err: %u", address, size, GetLastError()); #endif returnValue = false; } else { returnValue = true; } VirtualProtectEx(hProcess, (LPVOID)address, size, dwProtect, &dwProtect); } } else { returnValue = true; } if (returnValue) { if (size != lpNumberOfBytesRead) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"readMemoryFromProcess :: Error ReadProcessMemory read %d bytes requested %d bytes", lpNumberOfBytesRead, size); #endif returnValue = false; } else { returnValue = true; } } return returnValue; } bool ProcessAccessHelp::decomposeMemory(BYTE * dataBuffer, SIZE_T bufferSize, DWORD_PTR startAddress) { ZeroMemory(&decomposerCi, sizeof(_CodeInfo)); decomposerCi.code = dataBuffer; decomposerCi.codeLen = (int)bufferSize; decomposerCi.dt = dt; decomposerCi.codeOffset = startAddress; decomposerInstructionsCount = 0; if (distorm_decompose(&decomposerCi, decomposerResult, sizeof(decomposerResult)/sizeof(decomposerResult[0]), &decomposerInstructionsCount) == DECRES_INPUTERR) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"decomposeMemory :: distorm_decompose == DECRES_INPUTERR"); #endif return false; } else { return true; } } bool ProcessAccessHelp::disassembleMemory(BYTE * dataBuffer, SIZE_T bufferSize, DWORD_PTR startOffset) { // Holds the result of the decoding. _DecodeResult res; // next is used for instruction's offset synchronization. // decodedInstructionsCount holds the count of filled instructions' array by the decoder. decodedInstructionsCount = 0; _OffsetType offset = startOffset; res = distorm_decode(offset, dataBuffer, (int)bufferSize, dt, decodedInstructions, MAX_INSTRUCTIONS, &decodedInstructionsCount); /* for (unsigned int i = 0; i < decodedInstructionsCount; i++) { #ifdef SUPPORT_64BIT_OFFSET printf("%0*I64x (%02d) %-24s %s%s%s\n", dt != Decode64Bits ? 8 : 16, decodedInstructions[i].offset, decodedInstructions[i].size, (char*)decodedInstructions[i].instructionHex.p, (char*)decodedInstructions[i].mnemonic.p, decodedInstructions[i].operands.length != 0 ? " " : "", (char*)decodedInstructions[i].operands.p); #else printf("%08x (%02d) %-24s %s%s%s\n", decodedInstructions[i].offset, decodedInstructions[i].size, (char*)decodedInstructions[i].instructionHex.p, (char*)decodedInstructions[i].mnemonic.p, decodedInstructions[i].operands.length != 0 ? " " : "", (char*)decodedInstructions[i].operands.p); #endif }*/ if (res == DECRES_INPUTERR) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"disassembleMemory :: res == DECRES_INPUTERR"); #endif return false; } else if (res == DECRES_SUCCESS) { //printf("disassembleMemory :: res == DECRES_SUCCESS\n"); return true; } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"disassembleMemory :: res == %d", res); #endif return false; } } DWORD_PTR ProcessAccessHelp::findPattern(DWORD_PTR startOffset, DWORD size, BYTE * pattern, const char * mask) { DWORD pos = 0; size_t searchLen = strlen(mask) - 1; for(DWORD_PTR retAddress = startOffset; retAddress < startOffset + size; retAddress++) { if( *(BYTE*)retAddress == pattern[pos] || mask[pos] == '?' ) { if(mask[pos+1] == 0x00) { return (retAddress - searchLen); } pos++; } else { pos = 0; } } return 0; } bool ProcessAccessHelp::readHeaderFromCurrentFile(const WCHAR * filePath) { return readHeaderFromFile(fileHeaderFromDisk, sizeof(fileHeaderFromDisk), filePath); } LONGLONG ProcessAccessHelp::getFileSize(const WCHAR * filePath) { LONGLONG fileSize = 0; HANDLE hFile = CreateFile(filePath, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); if (hFile != INVALID_HANDLE_VALUE) { fileSize = getFileSize(hFile); CloseHandle(hFile); hFile = 0; } return fileSize; } LONGLONG ProcessAccessHelp::getFileSize(HANDLE hFile) { LARGE_INTEGER lpFileSize = {0}; if ((hFile != INVALID_HANDLE_VALUE) && (hFile != 0)) { if (!GetFileSizeEx(hFile, &lpFileSize)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"ProcessAccessHelp::getFileSize :: GetFileSizeEx failed %u", GetLastError()); #endif return 0; } else { return lpFileSize.QuadPart; } } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"ProcessAccessHelp::getFileSize hFile invalid"); #endif return 0; } } bool ProcessAccessHelp::readMemoryFromFile(HANDLE hFile, LONG offset, DWORD size, LPVOID dataBuffer) { DWORD lpNumberOfBytesRead = 0; DWORD retValue = 0; DWORD dwError = 0; if ((hFile != INVALID_HANDLE_VALUE) && (hFile != 0)) { retValue = SetFilePointer(hFile, offset, NULL, FILE_BEGIN); dwError = GetLastError(); if ((retValue == INVALID_SET_FILE_POINTER) && (dwError != NO_ERROR)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"readMemoryFromFile :: SetFilePointer failed error %u", dwError); #endif return false; } else { if (ReadFile(hFile, dataBuffer, size, &lpNumberOfBytesRead, 0)) { return true; } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"readMemoryFromFile :: ReadFile failed - size %d - error %u", size, GetLastError()); #endif return false; } } } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"readMemoryFromFile :: hFile invalid"); #endif return false; } } +bool ProcessAccessHelp::writeMemoryToNewFile(const WCHAR * file,DWORD size, LPCVOID dataBuffer) +{ + HANDLE hFile = CreateFile(file, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0); + + if (hFile != INVALID_HANDLE_VALUE) + { + return writeMemoryToFile(hFile,0,size,dataBuffer); + } + else + { + return false; + } +} + bool ProcessAccessHelp::writeMemoryToFile(HANDLE hFile, LONG offset, DWORD size, LPCVOID dataBuffer) { DWORD lpNumberOfBytesWritten = 0; DWORD retValue = 0; DWORD dwError = 0; if ((hFile != INVALID_HANDLE_VALUE) && (hFile != 0)) { retValue = SetFilePointer(hFile, offset, NULL, FILE_BEGIN); dwError = GetLastError(); if ((retValue == INVALID_SET_FILE_POINTER) && (dwError != NO_ERROR)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"writeMemoryToFile :: SetFilePointer failed error %u", dwError); #endif return false; } else { if (WriteFile(hFile, dataBuffer, size, &lpNumberOfBytesWritten, 0)) { return true; } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"writeMemoryToFile :: WriteFile failed - size %d - error %u", size, GetLastError()); #endif return false; } } } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"writeMemoryToFile :: hFile invalid"); #endif return false; } } bool ProcessAccessHelp::writeMemoryToFileEnd(HANDLE hFile, DWORD size, LPCVOID dataBuffer) { DWORD lpNumberOfBytesWritten = 0; DWORD retValue = 0; if ((hFile != INVALID_HANDLE_VALUE) && (hFile != 0)) { SetFilePointer(hFile, 0, 0, FILE_END); if (WriteFile(hFile, dataBuffer, size, &lpNumberOfBytesWritten, 0)) { return true; } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"writeMemoryToFileEnd :: WriteFile failed - size %d - error %u", size, GetLastError()); #endif return false; } } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"writeMemoryToFileEnd :: hFile invalid"); #endif return false; } } bool ProcessAccessHelp::readHeaderFromFile(BYTE * buffer, DWORD bufferSize, const WCHAR * filePath) { DWORD lpNumberOfBytesRead = 0; LONGLONG fileSize = 0; DWORD dwSize = 0; bool returnValue = 0; HANDLE hFile = CreateFile(filePath, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); if( hFile == INVALID_HANDLE_VALUE ) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"readHeaderFromFile :: INVALID_HANDLE_VALUE %u", GetLastError()); #endif returnValue = false; } else { fileSize = getFileSize(hFile); if (fileSize > 0) { if (fileSize > bufferSize) { dwSize = bufferSize; } else { dwSize = (DWORD)(fileSize - 1); } returnValue = readMemoryFromFile(hFile, 0, dwSize, buffer); } CloseHandle(hFile); } return returnValue; } LPVOID ProcessAccessHelp::createFileMappingViewRead(const WCHAR * filePath) { return createFileMappingView(filePath, GENERIC_READ, PAGE_READONLY | SEC_IMAGE, FILE_MAP_READ); } LPVOID ProcessAccessHelp::createFileMappingViewFull(const WCHAR * filePath) { return createFileMappingView(filePath, GENERIC_ALL, PAGE_EXECUTE_READWRITE, FILE_MAP_ALL_ACCESS); } LPVOID ProcessAccessHelp::createFileMappingView(const WCHAR * filePath, DWORD accessFile, DWORD flProtect, DWORD accessMap) { HANDLE hFile = CreateFile(filePath, accessFile, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); if( hFile == INVALID_HANDLE_VALUE ) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"createFileMappingView :: INVALID_HANDLE_VALUE %u", GetLastError()); #endif return NULL; } HANDLE hMappedFile = CreateFileMapping(hFile, NULL, flProtect, 0, 0, NULL); CloseHandle(hFile); if( hMappedFile == NULL ) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"createFileMappingView :: hMappedFile == NULL"); #endif return NULL; } if (GetLastError() == ERROR_ALREADY_EXISTS) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"createFileMappingView :: GetLastError() == ERROR_ALREADY_EXISTS); #endif return NULL; } LPVOID addrMappedDll = MapViewOfFile(hMappedFile, accessMap, 0, 0, 0); if( addrMappedDll == NULL ) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"createFileMappingView :: addrMappedDll == NULL"); #endif CloseHandle(hMappedFile); return NULL; } CloseHandle(hMappedFile); return addrMappedDll; } DWORD ProcessAccessHelp::getProcessByName(const WCHAR * processName) { DWORD dwPID = 0; HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); PROCESSENTRY32W pe32; pe32.dwSize = sizeof(PROCESSENTRY32W); if( !Process32FirstW( hProcessSnap, &pe32 ) ) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"getProcessByName :: Error getting first Process"); #endif CloseHandle( hProcessSnap ); return 0; } do { if(!_wcsicmp(pe32.szExeFile, processName)) { dwPID = pe32.th32ProcessID; break; } } while(Process32NextW(hProcessSnap, &pe32)); CloseHandle(hProcessSnap); return dwPID; } bool ProcessAccessHelp::getProcessModules(DWORD dwPID, std::vector &moduleList) { HANDLE hModuleSnap = INVALID_HANDLE_VALUE; MODULEENTRY32 me32; ModuleInfo module; // Take a snapshot of all modules in the specified process. hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, dwPID ); if( hModuleSnap == INVALID_HANDLE_VALUE ) { return false; } // Set the size of the structure before using it. me32.dwSize = sizeof( MODULEENTRY32 ); // Retrieve information about the first module, // and exit if unsuccessful if( !Module32First( hModuleSnap, &me32 ) ) { CloseHandle( hModuleSnap ); return false; } // Now walk the module list of the process, // and display information about each module //the first is always the .exe if (!Module32Next(hModuleSnap, &me32)) { CloseHandle( hModuleSnap ); return false; } moduleList.reserve(20); do { //printf(L"\n MODULE NAME: %s", me32.szModule); module.modBaseAddr = (DWORD_PTR)me32.modBaseAddr; module.modBaseSize = me32.modBaseSize; module.isAlreadyParsed = false; module.parsing = false; wcscpy_s(module.fullPath, me32.szExePath); moduleList.push_back(module); } while(Module32Next(hModuleSnap, &me32)); CloseHandle( hModuleSnap ); return true; } bool ProcessAccessHelp::getMemoryRegionFromAddress(DWORD_PTR address, DWORD_PTR * memoryRegionBase, SIZE_T * memoryRegionSize) { MEMORY_BASIC_INFORMATION memBasic; if (VirtualQueryEx(hProcess,(LPCVOID)address,&memBasic,sizeof(MEMORY_BASIC_INFORMATION)) != sizeof(MEMORY_BASIC_INFORMATION)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"getMemoryRegionFromAddress :: VirtualQueryEx error %u", GetLastError()); #endif return false; } else { *memoryRegionBase = (DWORD_PTR)memBasic.BaseAddress; *memoryRegionSize = memBasic.RegionSize; return true; } } bool ProcessAccessHelp::getSizeOfImageCurrentProcess() { DWORD_PTR newSizeOfImage = getSizeOfImageProcess(ProcessAccessHelp::hProcess, ProcessAccessHelp::targetImageBase); if (newSizeOfImage != 0) { ProcessAccessHelp::targetSizeOfImage = newSizeOfImage; return true; } else { return false; } } SIZE_T ProcessAccessHelp::getSizeOfImageProcess(HANDLE processHandle, DWORD_PTR moduleBase) { SIZE_T sizeOfImage = 0; MEMORY_BASIC_INFORMATION lpBuffer = {0}; SIZE_T dwLength = sizeof(MEMORY_BASIC_INFORMATION); do { moduleBase = (DWORD_PTR)((SIZE_T)moduleBase + lpBuffer.RegionSize); sizeOfImage += lpBuffer.RegionSize; //printf("Query 0x"PRINTF_DWORD_PTR_FULL" size 0x%08X\n",moduleBase,sizeOfImage); if (!VirtualQueryEx(processHandle, (LPCVOID)moduleBase, &lpBuffer, dwLength)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"getSizeOfImageProcess :: VirtualQuery failed %X", GetLastError()); #endif lpBuffer.Type = 0; sizeOfImage = 0; } /*else { printf("\nAllocationBase %X\n",lpBuffer.AllocationBase); printf("AllocationProtect %X\n",lpBuffer.AllocationProtect); printf("BaseAddress %X\n",lpBuffer.BaseAddress); printf("Protect %X\n",lpBuffer.Protect); printf("RegionSize %X\n",lpBuffer.RegionSize); printf("State %X\n",lpBuffer.State); printf("Type %X\n",lpBuffer.Type); }*/ } while (lpBuffer.Type == MEM_IMAGE); //printf("Real sizeOfImage %X\n",sizeOfImage); return sizeOfImage; } DWORD ProcessAccessHelp::getEntryPointFromFile(const WCHAR * filePath) { PIMAGE_NT_HEADERS pNtHeader = 0; PIMAGE_DOS_HEADER pDosHeader = 0; readHeaderFromCurrentFile(filePath); pDosHeader = (PIMAGE_DOS_HEADER)fileHeaderFromDisk; if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) { return 0; } pNtHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)fileHeaderFromDisk + (DWORD_PTR)(pDosHeader->e_lfanew)); if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) { return 0; } return pNtHeader->OptionalHeader.AddressOfEntryPoint; } bool ProcessAccessHelp::createBackupFile(const WCHAR * filePath) { size_t fileNameLength = wcslen(filePath) + 5; //.bak + null BOOL retValue = 0; WCHAR * backupFile = new WCHAR[fileNameLength]; wcscpy_s(backupFile, fileNameLength, filePath); wcscat_s(backupFile, fileNameLength, L".bak"); retValue = CopyFile(filePath, backupFile, FALSE); if (!retValue) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"createBackupFile :: CopyFile failed with error 0x%X", GetLastError()); #endif } delete [] backupFile; return retValue != 0; } diff --git a/Scylla/ProcessAccessHelp.h b/Scylla/ProcessAccessHelp.h index a219673..5b49e29 100644 --- a/Scylla/ProcessAccessHelp.h +++ b/Scylla/ProcessAccessHelp.h @@ -1,206 +1,212 @@ #pragma once #include #include #include /************************************************************************/ /* distorm */ /************************************************************************/ #include // The number of the array of instructions the decoder function will use to return the disassembled instructions. // Play with this value for performance... #define MAX_INSTRUCTIONS (200) /************************************************************************/ class ApiInfo; class ModuleInfo { public: WCHAR fullPath[MAX_PATH]; DWORD_PTR modBaseAddr; DWORD modBaseSize; bool isAlreadyParsed; bool parsing; /* for iat rebuilding with duplicate entries: ntdll = low priority kernelbase = low priority SHLWAPI = low priority kernel32 = high priority priority = 1 -> normal/high priority priority = 0 -> low priority */ int priority; std::vector apiList; ModuleInfo() { modBaseAddr = 0; modBaseSize = 0; priority = 1; isAlreadyParsed = false; parsing = false; } const WCHAR * getFilename() const { const WCHAR* slash = wcsrchr(fullPath, L'\\'); if(slash) { return slash+1; } return fullPath; } }; class ApiInfo { public: char name[MAX_PATH]; WORD hint; DWORD_PTR va; DWORD_PTR rva; WORD ordinal; bool isForwarded; ModuleInfo * module; }; class ProcessAccessHelp { public: static HANDLE hProcess; //OpenProcess handle to target process static DWORD_PTR targetImageBase; static DWORD_PTR targetSizeOfImage; static DWORD_PTR maxValidAddress; static ModuleInfo * selectedModule; static std::vector moduleList; //target process module list static std::vector ownModuleList; //own module list static const size_t PE_HEADER_BYTES_COUNT = 2000; static BYTE fileHeaderFromDisk[PE_HEADER_BYTES_COUNT]; //for decomposer static _DInst decomposerResult[MAX_INSTRUCTIONS]; static unsigned int decomposerInstructionsCount; static _CodeInfo decomposerCi; //distorm :: Decoded instruction information. static _DecodedInst decodedInstructions[MAX_INSTRUCTIONS]; static unsigned int decodedInstructionsCount; #ifdef _WIN64 static const _DecodeType dt = Decode64Bits; #else static const _DecodeType dt = Decode32Bits; #endif /* * Open a new process handle */ static bool openProcessHandle(DWORD dwPID); static HANDLE NativeOpenProcess(DWORD dwDesiredAccess, DWORD dwProcessId); static void closeProcessHandle(); /* * Get all modules from a process */ static bool getProcessModules(DWORD dwPID, std::vector &moduleList); /* * file mapping view with different access level */ static LPVOID createFileMappingViewRead(const WCHAR * filePath); static LPVOID createFileMappingViewFull(const WCHAR * filePath); /* * Create a file mapping view of a file */ static LPVOID createFileMappingView(const WCHAR * filePath, DWORD accessFile, DWORD flProtect, DWORD accessMap); /* * Read memory from target process */ static bool readMemoryFromProcess(DWORD_PTR address, SIZE_T size, LPVOID dataBuffer); /* * Read memory from file */ static bool readMemoryFromFile(HANDLE hFile, LONG offset, DWORD size, LPVOID dataBuffer); /* * Write memory to file */ static bool writeMemoryToFile(HANDLE hFile, LONG offset, DWORD size, LPCVOID dataBuffer); + + /* + * Write memory to new file + */ + static bool writeMemoryToNewFile(const WCHAR * file,DWORD size, LPCVOID dataBuffer); + /* * Write memory to file end */ static bool writeMemoryToFileEnd(HANDLE hFile, DWORD size, LPCVOID dataBuffer); /* * Disassemble Memory */ static bool disassembleMemory(BYTE * dataBuffer, SIZE_T bufferSize, DWORD_PTR startOffset); static bool decomposeMemory(BYTE * dataBuffer, SIZE_T bufferSize, DWORD_PTR startAddress); /* * Search for pattern */ static DWORD_PTR findPattern(DWORD_PTR startOffset, DWORD size, BYTE * pattern, const char * mask); /* * Get process ID by process name */ static DWORD getProcessByName(const WCHAR * processName); /* * Get memory region from address */ static bool getMemoryRegionFromAddress(DWORD_PTR address, DWORD_PTR * memoryRegionBase, SIZE_T * memoryRegionSize); /* * Read PE Header from file */ static bool readHeaderFromFile(BYTE * buffer, DWORD bufferSize, const WCHAR * filePath); static bool readHeaderFromCurrentFile(const WCHAR * filePath); /* * Get real sizeOfImage value */ static SIZE_T getSizeOfImageProcess(HANDLE processHandle, DWORD_PTR moduleBase); /* * Get real sizeOfImage value current process */ static bool getSizeOfImageCurrentProcess(); static LONGLONG getFileSize(HANDLE hFile); static LONGLONG getFileSize(const WCHAR * filePath); static DWORD getEntryPointFromFile(const WCHAR * filePath); static bool createBackupFile(const WCHAR * filePath); }; diff --git a/Scylla/ProcessLister.cpp b/Scylla/ProcessLister.cpp index b078316..c793ae1 100644 --- a/Scylla/ProcessLister.cpp +++ b/Scylla/ProcessLister.cpp @@ -1,364 +1,372 @@ #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 } void ProcessLister::initDeviceNameList() { TCHAR shortName[3] = {0}; TCHAR longName[MAX_PATH] = {0}; HardDisk hardDisk; shortName[1] = L':'; for ( WCHAR shortD = L'a'; shortD < L'z'; shortD++ ) { shortName[0] = shortD; if (QueryDosDeviceW( shortName, longName, MAX_PATH ) > 0) { hardDisk.shortName[0] = towupper(shortD); hardDisk.shortName[1] = L':'; hardDisk.shortName[2] = 0; hardDisk.longNameLength = wcslen(longName); wcscpy_s(hardDisk.longName, longName); deviceNameList.push_back(hardDisk); } } } //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; //hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, NULL, process->PID); hProcess = ProcessAccessHelp::NativeOpenProcess(PROCESS_QUERY_INFORMATION, process->PID); if(!hProcess) { //missing rights return false; } if (GetProcessImageFileName(hProcess, processPath, _countof(processPath)) > 0) { CloseHandle(hProcess); if (!resolveDeviceLongNameToShort(processPath, process->fullPath)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"getAbsoluteFilePath :: resolveDeviceLongNameToShort failed with path %s", processPath); #endif } return true; } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"getAbsoluteFilePath :: GetProcessImageFileName failed %u", GetLastError()); #endif CloseHandle(hProcess); return false; } } std::vector& ProcessLister::getProcessListSnapshot() { HANDLE hProcessSnap; ProcessType processType; PROCESSENTRY32 pe32; HANDLE hModuleSnap = INVALID_HANDLE_VALUE; MODULEENTRY32 me32 = {0}; Process process; - processList.reserve(34); 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); - //get module informations - //getAllModuleInformation(); + + //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);*/ } bool ProcessLister::resolveDeviceLongNameToShort( WCHAR * sourcePath, WCHAR * targetPath ) { for (unsigned int i = 0; i < deviceNameList.size(); i++) { if (!_wcsnicmp(deviceNameList[i].longName, sourcePath, deviceNameList[i].longNameLength)) { wcscpy_s(targetPath, MAX_PATH,deviceNameList[i].shortName); wcscat_s(targetPath, MAX_PATH, sourcePath + deviceNameList[i].longNameLength); return true; } } return false; } diff --git a/Scylla/Scylla.h b/Scylla/Scylla.h index 84ed093..bf02bc6 100644 --- a/Scylla/Scylla.h +++ b/Scylla/Scylla.h @@ -1,31 +1,31 @@ #pragma once #include "ConfigurationHolder.h" #include "PluginLoader.h" #include "ProcessLister.h" #include "Logger.h" #define APPNAME_S "Scylla" -#define APPVERSION_S "v0.5a" +#define APPVERSION_S "v0.6 Beta" #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[]; }; diff --git a/Scylla/Scylla.vcxproj.user b/Scylla/Scylla.vcxproj.user deleted file mode 100644 index ace9a86..0000000 --- a/Scylla/Scylla.vcxproj.user +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/Scylla/resource.h b/Scylla/resource.h index 7dfe8fd..2420cac 100644 Binary files a/Scylla/resource.h and b/Scylla/resource.h differ