diff --git a/README.txt b/README.txt index 3b9f975..308c009 100644 --- a/README.txt +++ b/README.txt @@ -1,54 +1,54 @@ Scylla - x64/x86 Imports Reconstruction ****************************************************************** ImpREC, CHimpREC, Imports Fixer... this are all great tools to rebuild an import table, but they all have some major disadvantages, so I decided to create my own tool for this job. Scylla's key benefits are: - x64 and x86 support - full unicode support (probably some russian or chinese will like this :-) ) - written in C/C++ - plugin support - works great with Windows 7 This tool was designed to be used with Windows 7 x64, so it is recommend to use this operating system. But it may work with XP and Vista, too. -Sour code is licensed under GNU GENERAL PUBLIC LICENSE v3.0 +Source code is licensed under GNU GENERAL PUBLIC LICENSE v3.0 ****************************************************************** Known Bugs ****************************************************************** - Only Windows XP x64: Windows XP x64 has some API bugs. 100% correct imports reconstruction is impossible. If you still want to use XP x64, here are some hints: * EncodePointer/DecodePointer exported by kernel32.dll have both the same VA. Scylla, CHimpREC and other tools cannot know which API is correct. You need to fix this manually. Your fixed dump will probably run fine on XP but crash on Vista/7. ****************************************************************** Changelog ****************************************************************** Version 0.2: - improved process detection - added some options - new options dialog - improved source code diff --git a/Scylla/ApiReader.cpp b/Scylla/ApiReader.cpp index 7586b48..4739fe9 100644 --- a/Scylla/ApiReader.cpp +++ b/Scylla/ApiReader.cpp @@ -1,1103 +1,1107 @@ #include "ApiReader.h" #include "Logger.h" #include "definitions.h" #include "SystemInformation.h" stdext::hash_multimap ApiReader::apiList; //api look up table std::map * ApiReader::moduleThunkList; //store found apis DWORD_PTR ApiReader::minApiAddress = 0xFFFFFFFF; DWORD_PTR ApiReader::maxApiAddress = 0; //#define DEBUG_COMMENTS void ApiReader::readApisFromModuleList() { for (unsigned int i = 0; i < moduleList.size();i++) { setModulePriority(&moduleList[i]); if (moduleList[i].modBaseAddr + moduleList[i].modBaseSize > maxValidAddress) { maxValidAddress = moduleList[i].modBaseAddr + moduleList[i].modBaseSize; } Logger::printfDialog(TEXT("Module parsing: %s"),moduleList[i].fullPath); if (!moduleList[i].isAlreadyParsed) { parseModule(&moduleList[i]); } } #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("Address Min ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT(" Max ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT("\nimagebase ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT(" maxValidAddress ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT("\r\n"),minApiAddress,maxApiAddress,targetImageBase,maxValidAddress); #endif } void ApiReader::parseModule(ModuleInfo *module) { module->parsing = true; if (isWinSxSModule(module)) { parseModuleWithMapping(module); } else if (isModuleLoadedInOwnProcess(module)) { parseModuleWithOwnProcess(module); } else { parseModuleWithProcess(module); } module->isAlreadyParsed = true; } void ApiReader::parseModuleWithMapping(ModuleInfo *moduleInfo) { LPVOID fileMapping = 0; PIMAGE_NT_HEADERS pNtHeader = 0; PIMAGE_DOS_HEADER pDosHeader = 0; fileMapping = createFileMappingViewRead(moduleInfo->fullPath); if (fileMapping == 0) return; pDosHeader = (PIMAGE_DOS_HEADER)fileMapping; pNtHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)fileMapping + (DWORD_PTR)(pDosHeader->e_lfanew)); if (isPeAndExportTableValid(pNtHeader)) { parseExportTable(moduleInfo, pNtHeader, (PIMAGE_EXPORT_DIRECTORY)((DWORD_PTR)fileMapping + pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress), (DWORD_PTR)fileMapping); } UnmapViewOfFile(fileMapping); } inline bool ApiReader::isApiForwarded(DWORD_PTR rva, PIMAGE_NT_HEADERS pNtHeader) { if ((rva > pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress) && (rva < (pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size))) { return true; } else { return false; } } void ApiReader::handleForwardedApi(DWORD_PTR vaStringPointer,char * functionNameParent, DWORD_PTR rvaParent, DWORD_PTR ordinalParent, ModuleInfo *moduleParent) { size_t dllNameLength = 0; DWORD_PTR ordinal = 0; ModuleInfo *module = 0; DWORD_PTR vaApi = 0; DWORD_PTR rvaApi = 0; char dllName[100] = {0}; WCHAR dllNameW[100] = {0}; char *fordwardedString = (char *)vaStringPointer; char *searchFunctionName = strchr(fordwardedString, '.'); if (!searchFunctionName) return; dllNameLength = searchFunctionName - fordwardedString; if (dllNameLength >= 99) { return; } else { strncpy_s(dllName,sizeof(dllName),fordwardedString,dllNameLength); } searchFunctionName++; //Windows 7 if (!strncmp(dllName,"api-ms-win-", 11)) { /* Info: http://www.nirsoft.net/articles/windows_7_kernel_architecture_changes.html */ FARPROC addy = GetProcAddress(GetModuleHandleA(dllName), searchFunctionName); if (addy != 0) { addApi(functionNameParent,0, ordinalParent, (DWORD_PTR)addy, (DWORD_PTR)addy - (DWORD_PTR)GetModuleHandleA(dllName), true, moduleParent); } return; } strcat_s(dllName,sizeof(dllName),".dll"); size_t convertedChars = 0; mbstowcs_s(&convertedChars, dllNameW, strlen(dllName) + 1, dllName, _TRUNCATE); if (!_wcsicmp(dllNameW, moduleParent->getFilename())) { module = moduleParent; } else { module = findModuleByName(dllNameW); } if (module != 0) // module == 0 -> can be ignored { /*if ((module->isAlreadyParsed == false) && (module != moduleParent)) { //do API extract if (module->parsing == true) { //some stupid circle dependency printf("stupid circle dependency %s\n",module->getFilename()); } else { parseModule(module); } }*/ if (strchr(searchFunctionName,'#')) { //forwarding by ordinal searchFunctionName++; ordinal = atoi(searchFunctionName); findApiByModuleAndOrdinal(module, ordinal, &vaApi, &rvaApi); } else { findApiByModuleAndName(module, searchFunctionName, &vaApi, &rvaApi); } if (rvaApi == 0) { #ifdef DEBUG_COMMENTS Logger::debugLog(L"handleForwardedApi :: Api not found, this is really BAD! %S\r\n",fordwardedString); #endif } else { addApi(functionNameParent,0, ordinalParent, vaApi, rvaApi, true, moduleParent); } } } ModuleInfo * ApiReader::findModuleByName(WCHAR *name) { for (unsigned int i = 0; i < moduleList.size(); i++) { if (!_wcsicmp(moduleList[i].getFilename(), name)) { return &moduleList[i]; } } return 0; } void ApiReader::addApiWithoutName(DWORD_PTR ordinal, DWORD_PTR va, DWORD_PTR rva,bool isForwarded, ModuleInfo *moduleInfo) { addApi(0, 0, ordinal, va, rva, isForwarded, moduleInfo); } void ApiReader::addApi(char *functionName, WORD hint, DWORD_PTR ordinal, DWORD_PTR va, DWORD_PTR rva, bool isForwarded, ModuleInfo *moduleInfo) { ApiInfo *apiInfo = new ApiInfo(); if ((functionName != 0) && (strlen(functionName) < MAX_PATH)) { strcpy_s(apiInfo->name, MAX_PATH, functionName); } else { apiInfo->name[0] = 0x00; } apiInfo->ordinal = ordinal; apiInfo->isForwarded = isForwarded; apiInfo->module = moduleInfo; apiInfo->rva = rva; apiInfo->va = va; apiInfo->hint = hint; setMinMaxApiAddress(va); moduleInfo->apiList.push_back(apiInfo); apiList.insert(API_Pair(va, apiInfo)); } BYTE * ApiReader::getHeaderFromProcess(ModuleInfo * module) { BYTE *bufferHeader = 0; DWORD readSize = 0; if (module->modBaseSize < PE_HEADER_BYTES_COUNT) { readSize = module->modBaseSize; } else { readSize = PE_HEADER_BYTES_COUNT; } bufferHeader = new BYTE[readSize]; if(!readMemoryFromProcess(module->modBaseAddr, readSize, bufferHeader)) { #ifdef DEBUG_COMMENTS Logger::debugLog(L"getHeaderFromProcess :: Error reading header\r\n"); #endif delete[] bufferHeader; return 0; } else { return bufferHeader; } } BYTE * ApiReader::getExportTableFromProcess(ModuleInfo * module, PIMAGE_NT_HEADERS pNtHeader) { DWORD readSize = 0; BYTE *bufferExportTable = 0; readSize = pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size; if (readSize < (sizeof(IMAGE_EXPORT_DIRECTORY) + 8)) { //Something is wrong with the PE Header #ifdef DEBUG_COMMENTS Logger::debugLog(L"Something is wrong with the PE Header here Export table size %d\r\n",readSize); #endif readSize = sizeof(IMAGE_EXPORT_DIRECTORY) + 100; } if (readSize) { bufferExportTable = new BYTE[readSize]; if(!readMemoryFromProcess(module->modBaseAddr + pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress, readSize, bufferExportTable)) { #ifdef DEBUG_COMMENTS Logger::debugLog(L"getExportTableFromProcess :: Error reading export table from process\r\n"); #endif delete[] bufferExportTable; return 0; } else { return bufferExportTable; } } else { return 0; } } void ApiReader::parseModuleWithProcess(ModuleInfo * module) { PIMAGE_NT_HEADERS pNtHeader = 0; PIMAGE_DOS_HEADER pDosHeader = 0; BYTE *bufferHeader = 0; BYTE *bufferExportTable = 0; bufferHeader = getHeaderFromProcess(module); if (bufferHeader == 0) return; pDosHeader = (PIMAGE_DOS_HEADER)bufferHeader; pNtHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)bufferHeader + (DWORD_PTR)(pDosHeader->e_lfanew)); if (isPeAndExportTableValid(pNtHeader)) { bufferExportTable = getExportTableFromProcess(module, pNtHeader); if(bufferExportTable) { parseExportTable(module,pNtHeader,(PIMAGE_EXPORT_DIRECTORY)bufferExportTable, (DWORD_PTR)bufferExportTable - pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); delete[] bufferExportTable; } } delete[] bufferHeader; } void ApiReader::parseExportTable(ModuleInfo *module, PIMAGE_NT_HEADERS pNtHeader, PIMAGE_EXPORT_DIRECTORY pExportDir, DWORD_PTR deltaAddress) { DWORD *addressOfFunctionsArray = 0,*addressOfNamesArray = 0; WORD *addressOfNameOrdinalsArray = 0; char *functionName = 0; DWORD_PTR RVA = 0, VA = 0, ordinal = 0; DWORD i = 0, j = 0; bool withoutName; addressOfFunctionsArray = (DWORD *)((DWORD_PTR)pExportDir->AddressOfFunctions + deltaAddress); addressOfNamesArray = (DWORD *)((DWORD_PTR)pExportDir->AddressOfNames + deltaAddress); addressOfNameOrdinalsArray = (WORD *)((DWORD_PTR)pExportDir->AddressOfNameOrdinals + deltaAddress); #ifdef DEBUG_COMMENTS Logger::debugLog(L"parseExportTable :: module %s NumberOfNames %X\r\n",module->fullPath,pExportDir->NumberOfNames); #endif for (i = 0; i < pExportDir->NumberOfNames; i++) { functionName = (char*)(addressOfNamesArray[i] + deltaAddress); ordinal = (addressOfNameOrdinalsArray[i] + pExportDir->Base); RVA = addressOfFunctionsArray[addressOfNameOrdinalsArray[i]]; VA = addressOfFunctionsArray[addressOfNameOrdinalsArray[i]] + module->modBaseAddr; #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("parseExportTable :: api %S ")TEXT(" ordinal %d imagebase ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT(" RVA ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT(" VA ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT("\r\n"),functionName,ordinal,module->modBaseAddr,RVA,VA); #endif if (!isApiBlacklisted(functionName)) { if (!isApiForwarded(RVA,pNtHeader)) { addApi(functionName, (WORD)i, ordinal,VA,RVA,false,module); } else { //printf("Forwarded: %s\n",functionName); handleForwardedApi(RVA + deltaAddress,functionName,RVA,ordinal,module); } } } /*Exports without name*/ if (pExportDir->NumberOfNames != pExportDir->NumberOfFunctions) { for (i = 0; i < pExportDir->NumberOfFunctions; i++) { withoutName = true; for (j = 0; j < pExportDir->NumberOfNames; j++) { if(addressOfNameOrdinalsArray[j] == i) { withoutName = false; break; } } if (withoutName && addressOfFunctionsArray[i] != 0) { ordinal = (i+pExportDir->Base); RVA = addressOfFunctionsArray[i]; VA = (addressOfFunctionsArray[i] + module->modBaseAddr); if (!isApiForwarded(RVA,pNtHeader)) { addApiWithoutName(ordinal,VA,RVA,false,module); } else { handleForwardedApi(RVA + deltaAddress,0,RVA,ordinal,module); } } } } } void ApiReader::findApiByModuleAndOrdinal(ModuleInfo * module, DWORD_PTR ordinal, DWORD_PTR * vaApi, DWORD_PTR * rvaApi) { findApiByModule(module,0,ordinal,vaApi,rvaApi); } void ApiReader::findApiByModuleAndName(ModuleInfo * module, char * searchFunctionName, DWORD_PTR * vaApi, DWORD_PTR * rvaApi) { findApiByModule(module,searchFunctionName,0,vaApi,rvaApi); } void ApiReader::findApiByModule(ModuleInfo * module, char * searchFunctionName, DWORD_PTR ordinal, DWORD_PTR * vaApi, DWORD_PTR * rvaApi) { if (isModuleLoadedInOwnProcess(module)) { HMODULE hModule = GetModuleHandle(module->getFilename()); if (hModule) { if (ordinal) { *vaApi = (DWORD_PTR)GetProcAddress(hModule, (LPCSTR)ordinal); } else { *vaApi = (DWORD_PTR)GetProcAddress(hModule, searchFunctionName); } if (vaApi) { *rvaApi = (*vaApi) - (DWORD_PTR)hModule; *vaApi = (*rvaApi) + module->modBaseAddr; } else { #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("findApiByModule :: vaApi == NULL, should never happen %S\r\n"),searchFunctionName); #endif } } else { #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("findApiByModule :: hModule == NULL, should never happen %s\r\n"),module->getFilename()); #endif } } else { //search api in extern process findApiInProcess(module,searchFunctionName,ordinal,vaApi,rvaApi); } } bool ApiReader::isModuleLoadedInOwnProcess(ModuleInfo * module) { for (unsigned int i = 0; i < ownModuleList.size(); i++) { if (!_wcsicmp(module->fullPath, ownModuleList[i].fullPath)) { //printf("isModuleLoadedInOwnProcess :: %s %s\n",module->fullPath,ownModuleList[i].fullPath); return true; } } return false; } void ApiReader::parseModuleWithOwnProcess( ModuleInfo * module ) { PIMAGE_NT_HEADERS pNtHeader = 0; PIMAGE_DOS_HEADER pDosHeader = 0; HMODULE hModule = GetModuleHandle(module->getFilename()); if (hModule) { pDosHeader = (PIMAGE_DOS_HEADER)hModule; pNtHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)hModule + (DWORD_PTR)(pDosHeader->e_lfanew)); if (isPeAndExportTableValid(pNtHeader)) { parseExportTable(module, pNtHeader, (PIMAGE_EXPORT_DIRECTORY)((DWORD_PTR)hModule + pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress), (DWORD_PTR)hModule); } } else { #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("parseModuleWithOwnProcess :: hModule is NULL\r\n")); #endif } } bool ApiReader::isPeAndExportTableValid(PIMAGE_NT_HEADERS pNtHeader) { if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) { Logger::printfDialog(TEXT("-> IMAGE_NT_SIGNATURE doesn't match.")); return false; } else if ((pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress == 0) || (pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size == 0)) { Logger::printfDialog(TEXT("-> No export table.")); return false; } else { return true; } } void ApiReader::findApiInProcess(ModuleInfo * module, char * searchFunctionName, DWORD_PTR ordinal, DWORD_PTR * vaApi, DWORD_PTR * rvaApi) { PIMAGE_NT_HEADERS pNtHeader = 0; PIMAGE_DOS_HEADER pDosHeader = 0; BYTE *bufferHeader = 0; BYTE *bufferExportTable = 0; bufferHeader = getHeaderFromProcess(module); if (bufferHeader == 0) return; pDosHeader = (PIMAGE_DOS_HEADER)bufferHeader; pNtHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)bufferHeader + (DWORD_PTR)(pDosHeader->e_lfanew)); if (isPeAndExportTableValid(pNtHeader)) { bufferExportTable = getExportTableFromProcess(module, pNtHeader); if(bufferExportTable) { findApiInExportTable(module,(PIMAGE_EXPORT_DIRECTORY)bufferExportTable, (DWORD_PTR)bufferExportTable - pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress,searchFunctionName,ordinal,vaApi,rvaApi); delete[] bufferExportTable; } } delete[] bufferHeader; } bool ApiReader::findApiInExportTable(ModuleInfo *module, PIMAGE_EXPORT_DIRECTORY pExportDir, DWORD_PTR deltaAddress, char * searchFunctionName, DWORD_PTR ordinal, DWORD_PTR * vaApi, DWORD_PTR * rvaApi) { 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) { WCHAR *moduleFileName = module->getFilename(); if (!_wcsicmp(moduleFileName, TEXT("kernelbase.dll"))) { module->priority = 0; } else if (!_wcsicmp(moduleFileName, TEXT("ntdll.dll"))) { module->priority = 0; } else if (!_wcsicmp(moduleFileName, TEXT("shlwapi.dll"))) { module->priority = 0; } + else if (!_wcsicmp(moduleFileName, TEXT("ShimEng.dll"))) + { + module->priority = 0; + } else if (!_wcsicmp(moduleFileName, TEXT("kernel32.dll"))) { module->priority = 2; } else { module->priority = 1; } } bool ApiReader::isApiAddressValid(DWORD_PTR virtualAddress) { return apiList.count(virtualAddress) > 0; } ApiInfo * ApiReader::getApiByVirtualAddress(DWORD_PTR virtualAddress, bool * isSuspect) { stdext::hash_multimap::iterator it1, it2; size_t c = 0; size_t countDuplicates = apiList.count(virtualAddress); int countHighPriority = 0; ApiInfo *apiFound = 0; if (countDuplicates == 0) { Logger::printfDialog(TEXT("getApiByVirtualAddress :: No Api found ")TEXT(PRINTF_DWORD_PTR_FULL),virtualAddress); return 0; } else if (countDuplicates == 1) { //API is 100% correct *isSuspect = false; it1 = apiList.find(virtualAddress); // Find first match. return (ApiInfo *)((*it1).second); } else { it1 = apiList.find(virtualAddress); // Find first match. it2 = it1; for (c = 0; c < countDuplicates; c++, it1++) { apiFound = (ApiInfo *)((*it1).second); if (apiFound->module->priority >= 1) //1 == high priority { countHighPriority++; } } it1 = it2; if (countHighPriority == 0) { #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("getApiByVirtualAddress :: countHighPriority == 0 ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT("\r\n"),virtualAddress); #endif *isSuspect = true; return (ApiInfo *)((*it1).second); } else if (countHighPriority == 1) { - //API is 100% correct if countHighPriority == 1 + //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) //1 == high priority + if (apiFound->module->priority >= 1 && apiFound->name[0] != 0x00) //1 == high priority { return apiFound; } } } else { //API not 100% correct #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("getApiByVirtualAddress :: countHighPriority == %d ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT("\r\n"),countHighPriority,virtualAddress); #endif *isSuspect = true; /*for (c = 0; c < countDuplicates; c++, it1++) { apiFound = (ApiInfo *)((*it1).second); Logger::printfDialog("%s - %s %X %X\n",apiFound->name,apiFound->module->getFilename(),apiFound->rva, apiFound->ordinal); } it1 = it2;*/ for (c = 0; c < countDuplicates; c++, it1++) { apiFound = (ApiInfo *)((*it1).second); //prefer APIs with a name if (apiFound->module->priority >= 1 && apiFound->name[0] != 0x00) //1 == high priority { //prefer ANSI/UNICODE APIs if (strrchr(apiFound->name,TEXT('W')) || strrchr(apiFound->name,TEXT('A'))) { return apiFound; } } } it1 = it2; for (c = 0; c < countDuplicates; c++, it1++) { apiFound = (ApiInfo *)((*it1).second); //prefer APIs with a name if (apiFound->module->priority == 2 && !strrchr(apiFound->name,TEXT('_'))) //1 == high priority { return apiFound; } } it1 = it2; for (c = 0; c < countDuplicates; c++, it1++) { apiFound = (ApiInfo *)((*it1).second); if (apiFound->module->priority == 1 && apiFound->name[0] != 0x00) //1 == high priority { return apiFound; } } it1 = it2; for (c = 0; c < countDuplicates; c++, it1++) { apiFound = (ApiInfo *)((*it1).second); if (apiFound->module->priority == 1) //1 == high priority { return apiFound; } } } } //is never reached Logger::printfDialog(TEXT("getApiByVirtualAddress :: There is a big bug\n")); return (ApiInfo *) 1; } void ApiReader::setMinMaxApiAddress(DWORD_PTR virtualAddress) { if (virtualAddress < minApiAddress) { minApiAddress = virtualAddress - 1; } if (virtualAddress > maxApiAddress) { maxApiAddress = virtualAddress + 1; } } void ApiReader::readAndParseIAT(DWORD_PTR addressIAT, DWORD sizeIAT, std::map &moduleListNew) { moduleThunkList = &moduleListNew; BYTE *dataIat = new BYTE[sizeIAT]; if (readMemoryFromProcess(addressIAT,sizeIAT,dataIat)) { parseIAT(addressIAT,dataIat,sizeIAT); } else { #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("ApiReader::readAndParseIAT :: error reading iat ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT("\r\n"),addressIAT); #endif } delete[] dataIat; } void ApiReader::parseIAT(DWORD_PTR addressIAT, BYTE * iatBuffer, SIZE_T size) { ApiInfo *apiFound = 0; ModuleInfo *module = 0; bool isSuspect = false; int countApiFound = 0, countApiNotFound = 0; DWORD_PTR * pIATAddress = (DWORD_PTR *)iatBuffer; SIZE_T sizeIAT = size / sizeof(DWORD_PTR); bool foundModuleBreak = false; for (SIZE_T i = 0; i < sizeIAT; i++) { //Logger::printfDialog("%08X %08X %d von %d",addressIAT + (DWORD_PTR)&pIATAddress[i] - (DWORD_PTR)iatBuffer,pIATAddress[i],i,sizeIAT); if (pIATAddress[i] == 0 || pIATAddress[i] == -1) { /*if (pIATAddress[i+1] != 0) { printf("parseIAT :: Module break\n"); }*/ /*else { printf("parseIAT :: IAT finished\n"); break; }*/ foundModuleBreak = true; } else if ( (pIATAddress[i] > minApiAddress) && (pIATAddress[i] < maxApiAddress) ) { apiFound = getApiByVirtualAddress(pIATAddress[i], &isSuspect); if (apiFound == (ApiInfo *)1) { #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("apiFound == (ApiInfo *)1 -> ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT("\r\n"),pIATAddress[i]); #endif } else if (apiFound) { countApiFound++; #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("")TEXT(PRINTF_DWORD_PTR_FULL)TEXT(" %s %d %s\r\n"),apiFound->va, apiFound->module->getFilename(), apiFound->ordinal,apiFound->name); #endif if (module != apiFound->module) { module = apiFound->module; addFoundApiToModuleList(addressIAT + (DWORD_PTR)&pIATAddress[i] - (DWORD_PTR)iatBuffer, apiFound, true, isSuspect); } else { addFoundApiToModuleList(addressIAT + (DWORD_PTR)&pIATAddress[i] - (DWORD_PTR)iatBuffer, apiFound, false, isSuspect); } } else { countApiNotFound++; addNotFoundApiToModuleList(addressIAT + (DWORD_PTR)&pIATAddress[i] - (DWORD_PTR)iatBuffer, pIATAddress[i]); //printf("parseIAT :: API not found %08X\n", pIATAddress[i]); } } else { //printf("parseIAT :: API not found %08X\n", pIATAddress[i]); countApiNotFound++; addNotFoundApiToModuleList(addressIAT + (DWORD_PTR)&pIATAddress[i] - (DWORD_PTR)iatBuffer, pIATAddress[i]); } } Logger::printfDialog(TEXT("IAT parsing finished, found %d valid APIs, missed %d APIs"),countApiFound,countApiNotFound); } void ApiReader::addFoundApiToModuleList(DWORD_PTR iatAddressVA, ApiInfo * apiFound, bool isNewModule, bool isSuspect) { if (isNewModule) { addModuleToModuleList(apiFound->module->getFilename(), iatAddressVA - targetImageBase); } addFunctionToModuleList(apiFound, iatAddressVA, iatAddressVA - targetImageBase, apiFound->ordinal, true, isSuspect); } bool ApiReader::addModuleToModuleList(const WCHAR * moduleName, DWORD_PTR firstThunk) { ImportModuleThunk module; module.firstThunk = firstThunk; wcscpy_s(module.moduleName, MAX_PATH, moduleName); (*moduleThunkList).insert(std::pair(firstThunk,module)); return true; } void ApiReader::addUnknownModuleToModuleList(DWORD_PTR firstThunk) { ImportModuleThunk module; module.firstThunk = firstThunk; wcscpy_s(module.moduleName, MAX_PATH, TEXT("?")); (*moduleThunkList).insert(std::pair(firstThunk,module)); } bool ApiReader::addFunctionToModuleList(ApiInfo * apiFound, DWORD_PTR va, DWORD_PTR rva, DWORD_PTR ordinal, bool valid, bool suspect) { ImportThunk import; ImportModuleThunk * module = 0; std::map::iterator iterator1; if ((*moduleThunkList).size() > 1) { iterator1 = (*moduleThunkList).begin(); while (iterator1 != (*moduleThunkList).end()) { if (rva >= iterator1->second.firstThunk) { iterator1++; if (iterator1 == (*moduleThunkList).end()) { iterator1--; module = &(iterator1->second); break; } else if (rva < iterator1->second.firstThunk) { iterator1--; module = &(iterator1->second); break; } } else { #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("Error iterator1 != (*moduleThunkList).end()\r\n")); #endif break; } } } else { iterator1 = (*moduleThunkList).begin(); module = &(iterator1->second); } if (!module) { #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("ImportsHandling::addFunction module not found rva ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT("\r\n"),rva); #endif return false; } import.suspect = suspect; import.valid = valid; import.va = va; import.rva = rva; import.apiAddressVA = apiFound->va; import.ordinal = ordinal; import.hint = (WORD)apiFound->hint; wcscpy_s(import.moduleName, MAX_PATH, apiFound->module->getFilename()); strcpy_s(import.name, MAX_PATH, apiFound->name); module->thunkList.insert(std::pair(import.rva, import)); return true; } void ApiReader::clearAll() { minApiAddress = -1; maxApiAddress = 0; for ( stdext::hash_multimap::iterator it = apiList.begin(); it != apiList.end(); ++it ) { delete it->second; } apiList.clear(); if (moduleThunkList != 0) { (*moduleThunkList).clear(); } } bool ApiReader::addNotFoundApiToModuleList(DWORD_PTR iatAddressVA, DWORD_PTR apiAddress) { ImportThunk import; ImportModuleThunk * module = 0; std::map::iterator iterator1; DWORD_PTR rva = iatAddressVA - targetImageBase; if ((*moduleThunkList).size() > 0) { iterator1 = (*moduleThunkList).begin(); while (iterator1 != (*moduleThunkList).end()) { if (rva >= iterator1->second.firstThunk) { iterator1++; if (iterator1 == (*moduleThunkList).end()) { iterator1--; //new unknown module if (iterator1->second.moduleName[0] == L'?') { module = &(iterator1->second); } else { addUnknownModuleToModuleList(rva); module = &((*moduleThunkList).find(rva)->second); } break; } else if (rva < iterator1->second.firstThunk) { iterator1--; module = &(iterator1->second); break; } } else { #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("Error iterator1 != (*moduleThunkList).end()\r\n")); #endif break; } } } else { //new unknown module addUnknownModuleToModuleList(rva); module = &((*moduleThunkList).find(rva)->second); } if (!module) { #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("ImportsHandling::addFunction module not found rva ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT("\r\n"),rva); #endif return false; } import.suspect = true; import.valid = false; import.va = iatAddressVA; import.rva = rva; import.apiAddressVA = apiAddress; import.ordinal = 0; wcscpy_s(import.moduleName, MAX_PATH, TEXT("?")); strcpy_s(import.name, MAX_PATH, "?"); module->thunkList.insert(std::pair(import.rva, import)); return true; } bool ApiReader::isApiBlacklisted( const char * functionName ) { if (SystemInformation::currenOS < WIN_VISTA_32) { if (!strcmp(functionName, "RestoreLastError")) { return true; } else { return false; } } else { return false; } /*#ifdef _WIN64 else if (SystemInformation::currenOS == WIN_XP_64 && !strcmp(functionName, "DecodePointer")) { return true; } #endif*/ } bool ApiReader::isWinSxSModule( ModuleInfo * module ) { if (wcsstr(module->fullPath, TEXT("\\WinSxS\\"))) { return true; } else if (wcsstr(module->fullPath, TEXT("\\winsxs\\"))) { return true; } else { return false; } } diff --git a/Scylla/DllInjectionPlugin.cpp b/Scylla/DllInjectionPlugin.cpp index 097a81a..e74751e 100644 --- a/Scylla/DllInjectionPlugin.cpp +++ b/Scylla/DllInjectionPlugin.cpp @@ -1,264 +1,303 @@ #include "DllInjectionPlugin.h" #include "Logger.h" const WCHAR * DllInjectionPlugin::FILE_MAPPING_NAME = L"ScyllaPluginExchange"; HANDLE DllInjectionPlugin::hProcess = 0; //#define DEBUG_COMMENTS void DllInjectionPlugin::injectPlugin(Plugin & plugin, std::map & moduleList, DWORD_PTR imageBase, DWORD_PTR imageSize) { PSCYLLA_EXCHANGE scyllaExchange = 0; PUNRESOLVED_IMPORT unresImp = 0; BYTE * dataBuffer = 0; DWORD_PTR numberOfUnresolvedImports = getNumberOfUnresolvedImports(moduleList); if (numberOfUnresolvedImports == 0) { Logger::printfDialog(L"No unresolved Imports"); return; } if (!createFileMapping((DWORD)(sizeof(SCYLLA_EXCHANGE) + sizeof(UNRESOLVED_IMPORT) + (sizeof(UNRESOLVED_IMPORT) * numberOfUnresolvedImports)))) { #ifdef DEBUG_COMMENTS Logger::debugLog(L"injectPlugin :: createFileMapping %X failed\r\n",sizeof(SCYLLA_EXCHANGE) + sizeof(UNRESOLVED_IMPORT) + (sizeof(UNRESOLVED_IMPORT) * numberOfUnresolvedImports)); #endif return; } scyllaExchange = (PSCYLLA_EXCHANGE)lpViewOfFile; scyllaExchange->status = 0xFF; scyllaExchange->imageBase = imageBase; scyllaExchange->imageSize = imageSize; scyllaExchange->numberOfUnresolvedImports = numberOfUnresolvedImports; scyllaExchange->offsetUnresolvedImportsArray = sizeof(SCYLLA_EXCHANGE); unresImp = (PUNRESOLVED_IMPORT)((DWORD_PTR)lpViewOfFile + sizeof(SCYLLA_EXCHANGE)); addUnresolvedImports(unresImp, moduleList); UnmapViewOfFile(lpViewOfFile); lpViewOfFile = 0; HMODULE hDll = dllInjection(hProcess, plugin.fullpath); if (hDll) { Logger::printfDialog(L"Plugin injection was successful"); if (!unloadDllInProcess(hProcess,hDll)) { Logger::printfDialog(L"Plugin unloading failed"); } lpViewOfFile = MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0); if (lpViewOfFile) { scyllaExchange = (PSCYLLA_EXCHANGE)lpViewOfFile; handlePluginResults(scyllaExchange, moduleList); } } else { Logger::printfDialog(L"Plugin injection failed"); } closeAllHandles(); } +void DllInjectionPlugin::injectImprecPlugin(Plugin & plugin, std::map & moduleList, DWORD_PTR imageBase, DWORD_PTR imageSize) +{ + Plugin newPlugin; + size_t mapSize = (wcslen(plugin.fullpath) + 1) * sizeof(WCHAR); + + HANDLE hImprecMap = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE|SEC_COMMIT, 0, (DWORD)mapSize, TEXT(PLUGIN_IMPREC_EXCHANGE_DLL_PATH)); + + if (hImprecMap == NULL) + { +#ifdef DEBUG_COMMENTS + Logger::debugLog("injectImprecPlugin :: CreateFileMapping failed 0x%X\r\n",GetLastError()); +#endif + return; + } + + LPVOID lpImprecViewOfFile = MapViewOfFile(hImprecMap, FILE_MAP_ALL_ACCESS, 0, 0, 0); + + if (lpImprecViewOfFile == NULL) + { +#ifdef DEBUG_COMMENTS + Logger::debugLog("injectImprecPlugin :: MapViewOfFile failed 0x%X\r\n",GetLastError()); +#endif + CloseHandle(hImprecMap); + return; + } + + CopyMemory(lpImprecViewOfFile,plugin.fullpath, mapSize); + + UnmapViewOfFile(lpImprecViewOfFile); + + newPlugin.fileSize = plugin.fileSize; + wcscpy_s(newPlugin.pluginName, plugin.pluginName); + wcscpy_s(newPlugin.fullpath, PluginLoader::imprecWrapperDllPath); + + injectPlugin(newPlugin,moduleList,imageBase,imageSize); + + CloseHandle(hImprecMap); +} + bool DllInjectionPlugin::createFileMapping(DWORD mappingSize) { hMapFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE|SEC_COMMIT, 0, mappingSize, FILE_MAPPING_NAME); if (hMapFile == NULL) { #ifdef DEBUG_COMMENTS Logger::debugLog("createFileMapping :: CreateFileMapping failed 0x%X\r\n",GetLastError()); #endif return false; } lpViewOfFile = MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0); if (lpViewOfFile == NULL) { #ifdef DEBUG_COMMENTS Logger::debugLog("createFileMapping :: MapViewOfFile failed 0x%X\r\n",GetLastError()); #endif CloseHandle(hMapFile); hMapFile = 0; return false; } else { return true; } } void DllInjectionPlugin::closeAllHandles() { if (lpViewOfFile) { UnmapViewOfFile(lpViewOfFile); lpViewOfFile = 0; } if (hMapFile) { CloseHandle(hMapFile); hMapFile = 0; } } DWORD_PTR DllInjectionPlugin::getNumberOfUnresolvedImports( std::map & moduleList ) { std::map::iterator iterator1; std::map::iterator iterator2; ImportModuleThunk * moduleThunk = 0; ImportThunk * importThunk = 0; DWORD_PTR dwNumber = 0; iterator1 = moduleList.begin(); while (iterator1 != moduleList.end()) { moduleThunk = &(iterator1->second); iterator2 = moduleThunk->thunkList.begin(); while (iterator2 != moduleThunk->thunkList.end()) { importThunk = &(iterator2->second); if (importThunk->valid == false) { dwNumber++; } iterator2++; } iterator1++; } return dwNumber; } void DllInjectionPlugin::addUnresolvedImports( PUNRESOLVED_IMPORT firstUnresImp, std::map & moduleList ) { std::map::iterator iterator1; std::map::iterator iterator2; ImportModuleThunk * moduleThunk = 0; ImportThunk * importThunk = 0; iterator1 = moduleList.begin(); while (iterator1 != moduleList.end()) { moduleThunk = &(iterator1->second); iterator2 = moduleThunk->thunkList.begin(); while (iterator2 != moduleThunk->thunkList.end()) { importThunk = &(iterator2->second); if (importThunk->valid == false) { firstUnresImp->InvalidApiAddress = importThunk->apiAddressVA; firstUnresImp->ImportTableAddressPointer = importThunk->va; firstUnresImp++; } iterator2++; } iterator1++; } firstUnresImp->InvalidApiAddress = 0; firstUnresImp->ImportTableAddressPointer = 0; } void DllInjectionPlugin::handlePluginResults( PSCYLLA_EXCHANGE scyllaExchange, std::map & moduleList ) { PUNRESOLVED_IMPORT unresImp = (PUNRESOLVED_IMPORT)((DWORD_PTR)scyllaExchange + scyllaExchange->offsetUnresolvedImportsArray);; switch (scyllaExchange->status) { case SCYLLA_STATUS_SUCCESS: Logger::printfDialog(L"Plugin was successful"); updateImportsWithPluginResult(unresImp, moduleList); break; case SCYLLA_STATUS_UNKNOWN_ERROR: Logger::printfDialog(L"Plugin reported Unknown Error"); break; case SCYLLA_STATUS_UNSUPPORTED_PROTECTION: Logger::printfDialog(L"Plugin detected unknown protection"); updateImportsWithPluginResult(unresImp, moduleList); break; case SCYLLA_STATUS_IMPORT_RESOLVING_FAILED: Logger::printfDialog(L"Plugin import resolving failed"); updateImportsWithPluginResult(unresImp, moduleList); break; case SCYLLA_STATUS_MAPPING_FAILED: Logger::printfDialog(L"Plugin file mapping failed"); break; default: Logger::printfDialog(L"Plugin failed without reason"); } } void DllInjectionPlugin::updateImportsWithPluginResult( PUNRESOLVED_IMPORT firstUnresImp, std::map & moduleList ) { std::map::iterator iterator1; std::map::iterator iterator2; ImportModuleThunk * moduleThunk = 0; ImportThunk * importThunk = 0; ApiInfo * apiInfo = 0; bool isSuspect = 0; iterator1 = moduleList.begin(); while (iterator1 != moduleList.end()) { moduleThunk = &(iterator1->second); iterator2 = moduleThunk->thunkList.begin(); while (iterator2 != moduleThunk->thunkList.end()) { importThunk = &(iterator2->second); if (importThunk->valid == false) { if (apiReader->isApiAddressValid(firstUnresImp->InvalidApiAddress)) { apiInfo = apiReader->getApiByVirtualAddress(firstUnresImp->InvalidApiAddress,&isSuspect); importThunk->suspect = isSuspect; importThunk->valid = true; importThunk->apiAddressVA = firstUnresImp->InvalidApiAddress; importThunk->hint = (WORD)apiInfo->hint; importThunk->ordinal = apiInfo->ordinal; strcpy_s(importThunk->name, MAX_PATH,apiInfo->name); wcscpy_s(importThunk->moduleName, MAX_PATH, apiInfo->module->getFilename()); if (moduleThunk->moduleName[0] == TEXT('?')) { wcscpy_s(moduleThunk->moduleName, MAX_PATH, apiInfo->module->getFilename()); } } firstUnresImp++; } iterator2++; } iterator1++; } } diff --git a/Scylla/DllInjectionPlugin.h b/Scylla/DllInjectionPlugin.h index 9f8fb14..1f22613 100644 --- a/Scylla/DllInjectionPlugin.h +++ b/Scylla/DllInjectionPlugin.h @@ -1,61 +1,65 @@ #include "DllInjection.h" #include "PluginLoader.h" #include "Thunks.h" #include "ApiReader.h" + +#define PLUGIN_IMPREC_EXCHANGE_DLL_PATH "ScyllaImprecPluginExchangePath" + #define SCYLLA_STATUS_SUCCESS 0 #define SCYLLA_STATUS_UNKNOWN_ERROR 1 #define SCYLLA_STATUS_UNSUPPORTED_PROTECTION 2 #define SCYLLA_STATUS_IMPORT_RESOLVING_FAILED 3 #define SCYLLA_STATUS_MAPPING_FAILED 0xFF /* Important note: * * If you write a plugin for the x86 (32-Bit) edition: DWORD_PTR address has 32 bit (4 byte) * If you write a plugin for the x64 (64-Bit) edition: DWORD_PTR address has 64 bit (8 byte) */ typedef struct _UNRESOLVED_IMPORT { // Scylla Plugin exchange format DWORD_PTR ImportTableAddressPointer; //in VA, address in IAT which points to an invalid api address DWORD_PTR InvalidApiAddress; //in VA, invalid api address that needs to be resolved } UNRESOLVED_IMPORT, *PUNRESOLVED_IMPORT; typedef struct _SCYLLA_EXCHANGE { BYTE status; //return a status, default 0xFF DWORD_PTR imageBase; //image base DWORD_PTR imageSize; //size of the image DWORD_PTR numberOfUnresolvedImports; //number of unresolved imports in this structure BYTE offsetUnresolvedImportsArray; } SCYLLA_EXCHANGE, *PSCYLLA_EXCHANGE; class DllInjectionPlugin : public DllInjection { public: static const WCHAR * FILE_MAPPING_NAME; static HANDLE hProcess; ApiReader * apiReader; HANDLE hMapFile; LPVOID lpViewOfFile; DllInjectionPlugin() { hMapFile = 0; lpViewOfFile = 0; apiReader = 0; } ~DllInjectionPlugin() { closeAllHandles(); } void injectPlugin(Plugin & plugin, std::map & moduleList, DWORD_PTR imageBase, DWORD_PTR imageSize); + void injectImprecPlugin(Plugin & plugin, std::map & moduleList, DWORD_PTR imageBase, DWORD_PTR imageSize); private: bool createFileMapping(DWORD mappingSize); void closeAllHandles(); DWORD_PTR getNumberOfUnresolvedImports( std::map & moduleList ); void addUnresolvedImports( PUNRESOLVED_IMPORT firstUnresImp, std::map & moduleList ); void handlePluginResults( PSCYLLA_EXCHANGE scyllaExchange, std::map & moduleList ); void updateImportsWithPluginResult( PUNRESOLVED_IMPORT firstUnresImp, std::map & moduleList ); }; \ No newline at end of file diff --git a/Scylla/ImportsHandling.cpp b/Scylla/ImportsHandling.cpp index c94a798..246c871 100644 --- a/Scylla/ImportsHandling.cpp +++ b/Scylla/ImportsHandling.cpp @@ -1,825 +1,825 @@ #include "ImportsHandling.h" #include "definitions.h" //#define DEBUG_COMMENTS bool ImportModuleThunk::isValid() { std::map::iterator iterator = thunkList.begin(); while (iterator != thunkList.end()) { if (iterator->second.valid == false) { return false; } iterator++; } return true; } DWORD_PTR ImportModuleThunk::getFirstThunk() { if (thunkList.size() > 0) { std::map::iterator iterator = thunkList.begin(); return iterator->first; } else { return 0; } } /*bool ImportsHandling::addModule(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; }*/ /*bool ImportsHandling::addFunction(WCHAR * moduleName, char * name, DWORD_PTR va, DWORD_PTR rva, DWORD_PTR ordinal, bool valid, bool suspect) { ImportThunk import; ImportModuleThunk * module = 0; std::map::iterator iterator1; if (moduleList.size() > 1) { iterator1 = moduleList.begin(); while (iterator1 != moduleList.end()) { if (rva >= iterator1->second.firstThunk) { iterator1++; if (iterator1 == moduleList.end()) { iterator1--; module = &(iterator1->second); break; } else if (rva < iterator1->second.firstThunk) { iterator1--; module = &(iterator1->second); break; } } } } else { iterator1 = moduleList.begin(); module = &(iterator1->second); } if (!module) { Logger::debugLog(TEXT("ImportsHandling::addFunction module not found rva ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT(""),rva); return false; } //TODO import.suspect = true; import.valid = false; import.va = va; import.rva = rva; import.ordinal = ordinal; wcscpy_s(import.moduleName, MAX_PATH, moduleName); strcpy_s(import.name, MAX_PATH, name); module->thunkList.insert(std::pair(import.rva, import)); return true; }*/ void ImportsHandling::displayAllImports() { std::map::iterator iterator1; std::map::iterator iterator2; ImportModuleThunk * moduleThunk; ImportThunk * importThunk; HTREEITEM module; HTREEITEM apiFunction; HWND idTreeView = GetDlgItem(hWndMainDlg, IDC_TREE_IMPORTS); TreeView_DeleteAllItems(idTreeView); iterator1 = moduleList.begin(); while (iterator1 != moduleList.end()) { moduleThunk = &(iterator1->second); module = addDllToTreeView(idTreeView,moduleThunk->moduleName,moduleThunk->firstThunk,moduleThunk->thunkList.size(),moduleThunk->isValid()); moduleThunk->hTreeItem = module; iterator2 = moduleThunk->thunkList.begin(); while (iterator2 != moduleThunk->thunkList.end()) { importThunk = &(iterator2->second); apiFunction = addApiToTreeView(idTreeView,module,importThunk); importThunk->hTreeItem = apiFunction; iterator2++; } iterator1++; } } HTREEITEM ImportsHandling::addDllToTreeView(HWND idTreeView, const WCHAR * dllName, DWORD_PTR firstThunk, size_t numberOfFunctions, bool valid) { WCHAR validString[4]; if (valid) { wcscpy_s(validString,_countof(validString),TEXT("YES")); } else { wcscpy_s(validString,_countof(validString),TEXT("NO")); } swprintf_s(stringBuffer, _countof(stringBuffer),TEXT("%s FThunk: ")TEXT(PRINTF_DWORD_PTR_HALF)TEXT(" NbThunk: %02X (dec: %02d) valid: %s"),dllName,firstThunk,numberOfFunctions,numberOfFunctions,validString); tvInsert.hParent = NULL; tvInsert.hInsertAfter = TVI_ROOT; tvInsert.item.mask = TVIF_TEXT|TVIF_IMAGE|TVIF_SELECTEDIMAGE; tvInsert.item.pszText = stringBuffer; return TreeView_InsertItem(idTreeView, &tvInsert); } HTREEITEM ImportsHandling::addApiToTreeView(HWND idTreeView, HTREEITEM parentDll, ImportThunk * importThunk) { if (importThunk->ordinal != 0) { if (importThunk->name[0] != 0x00) { swprintf_s(tempString, _countof(tempString),TEXT("ord: %04X name: %S"),importThunk->ordinal,importThunk->name); } else { swprintf_s(tempString, _countof(tempString),TEXT("ord: %04X"),importThunk->ordinal); } swprintf_s(stringBuffer, _countof(stringBuffer),TEXT("va: ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT(" rva: ")TEXT(PRINTF_DWORD_PTR_HALF)TEXT(" mod: %s %s"),importThunk->va,importThunk->rva,importThunk->moduleName,tempString); } else { - swprintf_s(stringBuffer, _countof(stringBuffer),TEXT("va: ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT(" rva: ")TEXT(PRINTF_DWORD_PTR_HALF)TEXT(" prt: ")TEXT(PRINTF_DWORD_PTR_HALF)TEXT(""),importThunk->va,importThunk->rva,importThunk->apiAddressVA); + swprintf_s(stringBuffer, _countof(stringBuffer),TEXT("va: ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT(" rva: ")TEXT(PRINTF_DWORD_PTR_HALF)TEXT(" ptr: ")TEXT(PRINTF_DWORD_PTR_HALF)TEXT(""),importThunk->va,importThunk->rva,importThunk->apiAddressVA); } tvInsert.hParent = parentDll; tvInsert.hInsertAfter = TVI_LAST; tvInsert.item.mask = TVIF_TEXT|TVIF_IMAGE|TVIF_SELECTEDIMAGE; tvInsert.item.pszText = stringBuffer; return TreeView_InsertItem(idTreeView, &tvInsert); } void ImportsHandling::showImports(bool invalid, bool suspect) { std::map::iterator iterator1; std::map::iterator iterator2; ImportModuleThunk * moduleThunk; ImportThunk * importThunk; HWND idTreeView = GetDlgItem(hWndMainDlg, IDC_TREE_IMPORTS); SetFocus(idTreeView); TreeView_SelectItem(idTreeView,0); //remove selection iterator1 = moduleList.begin(); while (iterator1 != moduleList.end()) { moduleThunk = &(iterator1->second); iterator2 = moduleThunk->thunkList.begin(); while (iterator2 != moduleThunk->thunkList.end()) { importThunk = &(iterator2->second); if (invalid && !importThunk->valid) { selectItem(idTreeView, importThunk->hTreeItem); setFocus(idTreeView,importThunk->hTreeItem); } else if (suspect && importThunk->suspect) { selectItem(idTreeView, importThunk->hTreeItem); setFocus(idTreeView,importThunk->hTreeItem); } else { unselectItem(idTreeView, importThunk->hTreeItem); } iterator2++; } iterator1++; } } bool ImportsHandling::isItemSelected(HWND hwndTV, HTREEITEM hItem) { TV_ITEM tvi; tvi.mask = TVIF_STATE | TVIF_HANDLE; tvi.stateMask = TVIS_SELECTED; tvi.hItem = hItem; TreeView_GetItem(hwndTV, &tvi); return (tvi.state & TVIS_SELECTED) != 0; } void ImportsHandling::unselectItem(HWND hwndTV, HTREEITEM htItem) { selectItem(hwndTV, htItem, false); } bool ImportsHandling::selectItem(HWND hwndTV, HTREEITEM hItem, bool select) { TV_ITEM tvi; tvi.mask = TVIF_STATE | TVIF_HANDLE; tvi.stateMask = TVIS_SELECTED; tvi.state = select ? TVIS_SELECTED : 0; tvi.hItem = hItem; if ( TreeView_SetItem(hwndTV, &tvi) == -1 ) { return false; } return true; } void ImportsHandling::setFocus(HWND hwndTV, HTREEITEM htItem) { // the current focus HTREEITEM htFocus = (HTREEITEM)TreeView_GetSelection(hwndTV); if ( htItem ) { // set the focus if ( htItem != htFocus ) { // remember the selection state of the item bool wasSelected = isItemSelected(hwndTV, htItem); if ( htFocus && isItemSelected(hwndTV, htFocus) ) { // prevent the tree from unselecting the old focus which it // would do by default (TreeView_SelectItem unselects the // focused item) TreeView_SelectItem(hwndTV, 0); selectItem(hwndTV, htFocus); } TreeView_SelectItem(hwndTV, htItem); if ( !wasSelected ) { // need to clear the selection which TreeView_SelectItem() gave // us unselectItem(hwndTV, htItem); } //else: was selected, still selected - ok } //else: nothing to do, focus already there } else { if ( htFocus ) { bool wasFocusSelected = isItemSelected(hwndTV, htFocus); // just clear the focus TreeView_SelectItem(hwndTV, 0); if ( wasFocusSelected ) { // restore the selection state selectItem(hwndTV, htFocus); } } //else: nothing to do, no focus already } } bool ImportsHandling::invalidateFunction( HTREEITEM selectedTreeNode ) { std::map::iterator iterator1; std::map::iterator iterator2; ImportModuleThunk * moduleThunk; ImportThunk * importThunk; TV_ITEM tvi = {0}; iterator1 = moduleList.begin(); while (iterator1 != moduleList.end()) { moduleThunk = &(iterator1->second); iterator2 = moduleThunk->thunkList.begin(); while (iterator2 != moduleThunk->thunkList.end()) { importThunk = &(iterator2->second); if (importThunk->hTreeItem == selectedTreeNode) { importThunk->ordinal = 0; importThunk->hint = 0; importThunk->valid = false; importThunk->suspect = false; importThunk->moduleName[0] = 0; importThunk->name[0] = 0; updateImportInTreeView(importThunk); updateModuleInTreeView(moduleThunk); return true; } iterator2++; } iterator1++; } return false; } void ImportsHandling::updateImportInTreeView(ImportThunk * importThunk) { TV_ITEM tvi = {0}; HWND treeControl = GetDlgItem(hWndMainDlg,IDC_TREE_IMPORTS); if (importThunk->ordinal != 0) { if (importThunk->name[0] != 0x00) { swprintf_s(tempString, _countof(tempString),TEXT("ord: %04X name: %S"),importThunk->ordinal,importThunk->name); } else { swprintf_s(tempString, _countof(tempString),TEXT("ord: %04X"),importThunk->ordinal); } swprintf_s(stringBuffer, _countof(stringBuffer),TEXT("va: ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT(" rva: ")TEXT(PRINTF_DWORD_PTR_HALF)TEXT(" mod: %s %s"),importThunk->va,importThunk->rva,importThunk->moduleName,tempString); } else { swprintf_s(stringBuffer, _countof(stringBuffer),TEXT("va: ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT(" rva: ")TEXT(PRINTF_DWORD_PTR_HALF)TEXT(" prt: ")TEXT(PRINTF_DWORD_PTR_HALF)TEXT(""),importThunk->va,importThunk->rva,importThunk->apiAddressVA); } tvi.pszText = stringBuffer; tvi.cchTextMax = 260; tvi.hItem = importThunk->hTreeItem; tvi.mask = TVIF_TEXT; TreeView_SetItem(treeControl,&tvi); } void ImportsHandling::updateModuleInTreeView(ImportModuleThunk * importThunk) { TV_ITEM tvi = {0}; HWND treeControl = GetDlgItem(hWndMainDlg,IDC_TREE_IMPORTS); WCHAR validString[4]; if (importThunk->isValid()) { wcscpy_s(validString,_countof(validString),TEXT("YES")); } else { wcscpy_s(validString,_countof(validString),TEXT("NO")); } swprintf_s(stringBuffer, _countof(stringBuffer),TEXT("%s FThunk: ")TEXT(PRINTF_DWORD_PTR_HALF)TEXT(" NbThunk: %02X (dec: %02d) valid: %s"),importThunk->moduleName,importThunk->firstThunk,importThunk->thunkList.size(),importThunk->thunkList.size(),validString); tvi.pszText = stringBuffer; tvi.cchTextMax = 260; tvi.hItem = importThunk->hTreeItem; tvi.mask = TVIF_TEXT; TreeView_SetItem(treeControl,&tvi); } bool ImportsHandling::cutThunk( HTREEITEM selectedTreeNode ) { std::map::iterator iterator1; std::map::iterator iterator2; ImportModuleThunk * moduleThunk; ImportThunk * importThunk; TV_ITEM tvi = {0}; HWND treeControl = GetDlgItem(hWndMainDlg,IDC_TREE_IMPORTS); iterator1 = moduleList.begin(); while (iterator1 != moduleList.end()) { moduleThunk = &(iterator1->second); iterator2 = moduleThunk->thunkList.begin(); while (iterator2 != moduleThunk->thunkList.end()) { importThunk = &(iterator2->second); if (importThunk->hTreeItem == selectedTreeNode) { TreeView_DeleteItem(treeControl,importThunk->hTreeItem); moduleThunk->thunkList.erase(iterator2); if (moduleThunk->thunkList.empty()) { TreeView_DeleteItem(treeControl,moduleThunk->hTreeItem); moduleList.erase(iterator1); } else { updateModuleInTreeView(moduleThunk); } return true; } iterator2++; } iterator1++; } return false; } bool ImportsHandling::deleteTreeNode( HTREEITEM selectedTreeNode ) { std::map::iterator iterator1; std::map::iterator iterator2; ImportModuleThunk * moduleThunk; ImportThunk * importThunk; TV_ITEM tvi = {0}; HWND treeControl = GetDlgItem(hWndMainDlg,IDC_TREE_IMPORTS); iterator1 = moduleList.begin(); while (iterator1 != moduleList.end()) { moduleThunk = &(iterator1->second); if (moduleThunk->hTreeItem == selectedTreeNode) { TreeView_DeleteItem(treeControl,moduleThunk->hTreeItem); moduleThunk->thunkList.clear(); moduleList.erase(iterator1); return true; } else { iterator2 = moduleThunk->thunkList.begin(); while (iterator2 != moduleThunk->thunkList.end()) { importThunk = &(iterator2->second); if (importThunk->hTreeItem == selectedTreeNode) { TreeView_DeleteItem(treeControl,moduleThunk->hTreeItem); moduleThunk->thunkList.clear(); moduleList.erase(iterator1); return true; } iterator2++; } } iterator1++; } return false; } DWORD_PTR ImportsHandling::getApiAddressByNode( HTREEITEM selectedTreeNode ) { std::map::iterator iterator1; std::map::iterator iterator2; ImportModuleThunk * moduleThunk; ImportThunk * importThunk; iterator1 = moduleList.begin(); while (iterator1 != moduleList.end()) { moduleThunk = &(iterator1->second); iterator2 = moduleThunk->thunkList.begin(); while (iterator2 != moduleThunk->thunkList.end()) { importThunk = &(iterator2->second); if (importThunk->hTreeItem == selectedTreeNode) { return importThunk->apiAddressVA; } iterator2++; } iterator1++; } return 0; } void ImportsHandling::scanAndFixModuleList() { std::map::iterator iterator1; std::map::iterator iterator2; ImportModuleThunk * moduleThunk; ImportThunk * importThunk; iterator1 = moduleList.begin(); while (iterator1 != moduleList.end()) { moduleThunk = &(iterator1->second); iterator2 = moduleThunk->thunkList.begin(); while (iterator2 != moduleThunk->thunkList.end()) { importThunk = &(iterator2->second); if (importThunk->moduleName[0] == 0 || importThunk->moduleName[0] == L'?') { addNotFoundApiToModuleList(importThunk); } else { if (isNewModule(importThunk->moduleName)) { addModuleToModuleList(importThunk->moduleName, importThunk->rva); } addFunctionToModuleList(importThunk); } iterator2++; } moduleThunk->thunkList.clear(); iterator1++; } moduleList.clear(); moduleList.insert(moduleListNew.begin(), moduleListNew.end()); moduleListNew.clear(); } bool ImportsHandling::findNewModules( std::map & thunkList ) { throw std::exception("The method or operation is not implemented."); } bool ImportsHandling::addModuleToModuleList(const WCHAR * moduleName, DWORD_PTR firstThunk) { ImportModuleThunk module; module.firstThunk = firstThunk; wcscpy_s(module.moduleName, MAX_PATH, moduleName); moduleListNew.insert(std::pair(firstThunk,module)); return true; } bool ImportsHandling::isNewModule(const WCHAR * moduleName) { std::map::iterator iterator1; iterator1 = moduleListNew.begin(); while (iterator1 != moduleListNew.end()) { if (!_wcsicmp(iterator1->second.moduleName, moduleName)) { return false; } iterator1++; } return true; } void ImportsHandling::addUnknownModuleToModuleList(DWORD_PTR firstThunk) { ImportModuleThunk module; module.firstThunk = firstThunk; wcscpy_s(module.moduleName, MAX_PATH, TEXT("?")); moduleListNew.insert(std::pair(firstThunk,module)); } bool ImportsHandling::addNotFoundApiToModuleList(ImportThunk * apiNotFound) { ImportThunk import; ImportModuleThunk * module = 0; std::map::iterator iterator1; DWORD_PTR rva = apiNotFound->rva; if (moduleListNew.size() > 0) { iterator1 = moduleListNew.begin(); while (iterator1 != moduleListNew.end()) { if (rva >= iterator1->second.firstThunk) { iterator1++; if (iterator1 == moduleListNew.end()) { iterator1--; //new unknown module if (iterator1->second.moduleName[0] == L'?') { module = &(iterator1->second); } else { addUnknownModuleToModuleList(apiNotFound->rva); module = &(moduleListNew.find(rva)->second); } break; } else if (rva < iterator1->second.firstThunk) { iterator1--; module = &(iterator1->second); break; } } else { #ifdef DEBUG_COMMENTS Logger::debugLog("Error iterator1 != (*moduleThunkList).end()\r\n"); #endif break; } } } else { //new unknown module addUnknownModuleToModuleList(apiNotFound->rva); module = &(moduleListNew.find(rva)->second); } if (!module) { #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("ImportsHandling::addFunction module not found rva ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT("\r\n"),rva); #endif return false; } import.suspect = true; import.valid = false; import.va = apiNotFound->va; import.rva = apiNotFound->rva; import.apiAddressVA = apiNotFound->apiAddressVA; import.ordinal = 0; wcscpy_s(import.moduleName, MAX_PATH, TEXT("?")); strcpy_s(import.name, MAX_PATH, "?"); module->thunkList.insert(std::pair(import.rva, import)); return true; } bool ImportsHandling::addFunctionToModuleList(ImportThunk * apiFound) { ImportThunk import; ImportModuleThunk * module = 0; std::map::iterator iterator1; if (moduleListNew.size() > 1) { iterator1 = moduleListNew.begin(); while (iterator1 != moduleListNew.end()) { if (apiFound->rva >= iterator1->second.firstThunk) { iterator1++; if (iterator1 == moduleListNew.end()) { iterator1--; module = &(iterator1->second); break; } else if (apiFound->rva < iterator1->second.firstThunk) { iterator1--; module = &(iterator1->second); break; } } else { #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("Error iterator1 != moduleListNew.end()\r\n")); #endif break; } } } else { iterator1 = moduleListNew.begin(); module = &(iterator1->second); } if (!module) { #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("ImportsHandling::addFunction module not found rva ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT("\r\n"),apiFound->rva); #endif return false; } import.suspect = apiFound->suspect; import.valid = apiFound->valid; import.va = apiFound->va; import.rva = apiFound->rva; import.apiAddressVA = apiFound->apiAddressVA; import.ordinal = apiFound->ordinal; import.hint = apiFound->hint; wcscpy_s(import.moduleName, MAX_PATH, apiFound->moduleName); strcpy_s(import.name, MAX_PATH, apiFound->name); module->thunkList.insert(std::pair(import.rva, import)); return true; } void ImportsHandling::expandAllTreeNodes() { changeExpandStateOfTreeNodes(TVE_EXPAND); } void ImportsHandling::collapseAllTreeNodes() { changeExpandStateOfTreeNodes(TVE_COLLAPSE); } void ImportsHandling::changeExpandStateOfTreeNodes(UINT flag) { std::map::iterator iterator1; ImportModuleThunk * moduleThunk; HWND treeControl = GetDlgItem(hWndMainDlg,IDC_TREE_IMPORTS); iterator1 = moduleList.begin(); while (iterator1 != moduleList.end()) { moduleThunk = &(iterator1->second); TreeView_Expand(treeControl, moduleThunk->hTreeItem, flag); iterator1++; } } diff --git a/Scylla/ImportsHandling.h b/Scylla/ImportsHandling.h index 31aff46..8310733 100644 --- a/Scylla/ImportsHandling.h +++ b/Scylla/ImportsHandling.h @@ -1,54 +1,54 @@ #pragma once #include "Thunks.h" #include "MainGui.h" class ImportsHandling : public MainGui { public: std::map moduleList; std::map moduleListNew; //bool addFunction(WCHAR * moduleName, char * name, DWORD_PTR va, DWORD_PTR rva, DWORD_PTR ordinal, bool valid, bool suspect); //bool addModule(WCHAR * moduleName, DWORD_PTR firstThunk); void displayAllImports(); void showImports(bool invalid, bool suspect); bool invalidateFunction(HTREEITEM selectedTreeNode); bool cutThunk( HTREEITEM selectedTreeNode ); bool deleteTreeNode( HTREEITEM selectedTreeNode ); void updateImportInTreeView(ImportThunk * importThunk); void updateModuleInTreeView(ImportModuleThunk * importThunk); DWORD_PTR getApiAddressByNode( HTREEITEM selectedTreeNode ); void scanAndFixModuleList(); void expandAllTreeNodes(); void collapseAllTreeNodes(); private: DWORD numberOfFunctions; - WCHAR tempString[100]; + WCHAR tempString[300]; TV_INSERTSTRUCT tvInsert; HTREEITEM m_hItemFirstSel; HTREEITEM addDllToTreeView(HWND idTreeView, const WCHAR * dllName, DWORD_PTR firstThunk, size_t numberOfFunctions, bool valid); HTREEITEM addApiToTreeView(HWND idTreeView, HTREEITEM parentDll, ImportThunk * importThunk); bool isItemSelected(HWND hwndTV, HTREEITEM hItem); void unselectItem(HWND hwndTV, HTREEITEM htItem); bool selectItem(HWND hwndTV, HTREEITEM hItem, bool select = true); void setFocus(HWND hwndTV, HTREEITEM htItem); bool findNewModules( std::map & thunkList ); bool addModuleToModuleList(const WCHAR * moduleName, DWORD_PTR firstThunk); void addUnknownModuleToModuleList(DWORD_PTR firstThunk); bool addNotFoundApiToModuleList(ImportThunk * apiNotFound); bool addFunctionToModuleList(ImportThunk * apiFound); bool isNewModule(const WCHAR * moduleName); void changeExpandStateOfTreeNodes(UINT flag); }; \ No newline at end of file diff --git a/Scylla/MainGui.cpp b/Scylla/MainGui.cpp index 567fd08..1037389 100644 --- a/Scylla/MainGui.cpp +++ b/Scylla/MainGui.cpp @@ -1,880 +1,930 @@ #include "MainGui.h" #include "ImportsHandling.h" #include "definitions.h" #include "PluginLoader.h" #include "ConfigurationHolder.h" #include "PeDump.h" #include "PeRebuild.h" #include "DllInjectionPlugin.h" #include "DisassemblerGui.h" #include "NativeWinApi.h" #include "ImportRebuild.h" #include "SystemInformation.h" #include "AboutGui.h" #include "OptionsGui.h" HINSTANCE MainGui::hInstance = 0; HWND MainGui::hWndParent = 0; HWND MainGui::hWndMainDlg = 0; Process * MainGui::selectedProcess = 0; -WCHAR MainGui::stringBuffer[300] = {0}; +WCHAR MainGui::stringBuffer[600] = {0}; ProcessLister MainGui::processLister; ImportsHandling MainGui::importsHandling; ProcessAccessHelp MainGui::processAccessHelp; ApiReader MainGui::apiReader; void MainGui::initDialog(HINSTANCE hInstance) { hInstance = hInstance; Logger::getDebugLogFilePath(); ConfigurationHolder::loadConfiguration(); PluginLoader::findAllPlugins(); NativeWinApi::initialize(); SystemInformation::getSystemInformation(); if (SystemInformation::currenOS == UNKNOWN_OS) { MessageBox(0, TEXT("Operating System is not supported"), TEXT("Error Operating System"),MB_OK); return; } processAccessHelp.getProcessModules(GetCurrentProcessId(), processAccessHelp.ownModuleList); //Register controls, required for Windows XP InitCommonControls(); - return; + DialogBox(hInstance, MAKEINTRESOURCE(IDD_DLG_MAIN),hWndParent, (DLGPROC)mainDlgProc); //ConfigurationHolder::saveConfiguration(); } LRESULT CALLBACK MainGui::mainDlgProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { hWndMainDlg = hWndDlg; HTREEITEM selectedTreeNode = 0; switch(uMsg) { case WM_INITDIALOG: //init dialog elements dialogInitActionHandler(); return TRUE; case WM_NOTIFY: switch(LOWORD(wParam)) { case IDC_TREE_IMPORTS: { if(((LPNMHDR)lParam)->code == NM_CLICK) { //Logger::printfDialog(L"NM_CLICK"); } if(((LPNMHDR)lParam)->code == NM_DBLCLK) { //Logger::printfDialog(L"NM_DBLCLK"); } if(((LPNMHDR)lParam)->code == NM_RCLICK) { //Logger::printfDialog(L"NM_RCLICK"); selectedTreeNode=(HTREEITEM)SendDlgItemMessage (hWndMainDlg,IDC_TREE_IMPORTS,TVM_GETNEXTITEM,TVGN_DROPHILITE,0); if(selectedTreeNode != NULL) { SendDlgItemMessage(hWndMainDlg,IDC_TREE_IMPORTS,TVM_SELECTITEM,TVGN_CARET,(LPARAM)selectedTreeNode); } } if(((LPNMHDR)lParam)->code == NM_RDBLCLK) { //Logger::printfDialog(L"NM_RDBLCLK"); } } break; /*case IDC_MODULELIST: LPNMLISTVIEW pnmv = (LPNMLISTVIEW)lParam; if (pnmv->uChanged & LVIF_STATE) { if ((pnmv->uNewState & LVIS_SELECTED) && (!(pnmv->uOldState & LVIS_SELECTED)) && (pnmv->hdr.code == LVN_ITEMCHANGED)) { //sprintf(stringBuffer,"%X",i); //MessageBox(hWndDlg, text,"Display Notification", MB_OK); break; } }*/ } return TRUE; case WM_COMMAND: switch(LOWORD(wParam)) { case IDC_CBO_PROCESSLIST: switch(HIWORD(wParam)) { case CBN_DROPDOWN: //list is about to display fillProcessListComboBox(GetDlgItem(hWndDlg, IDC_CBO_PROCESSLIST)); break; case CBN_SELENDOK: //item selected processSelectedActionHandler(SendMessage(GetDlgItem(hWndDlg, IDC_CBO_PROCESSLIST),CB_GETCURSEL,0,0)); break; } return TRUE; case IDC_BTN_PICKDLL: pickDllActionHandler(); return TRUE; case IDC_BTN_OPTIONS: optionsActionHandler(); return TRUE; case IDC_BTN_DUMP: dumpActionHandler(); return TRUE; case IDC_BTN_FIXDUMP: dumpFixActionHandler(); return TRUE; case IDC_BTN_PEREBUILD: peRebuildActionHandler(); return TRUE; case IDC_BTN_DLLINJECT: dllInjectActionHandler(); return TRUE; case ID_MISC_DLLINJECTION: dllInjectActionHandler(); return TRUE; case ID_MISC_PREFERENCES: optionsActionHandler(); return TRUE; case IDC_BTN_IATAUTOSEARCH: iatAutosearchActionHandler(); return TRUE; case IDC_BTN_GETIMPORTS: getImportsActionHandler(); return TRUE; case IDC_BTN_INVALIDIMPORTS: showInvalidImportsActionHandler(); return TRUE; case IDC_BTN_SUSPECTIMPORTS: showSuspectImportsActionHandler(); return TRUE; case IDC_BTN_CLEARIMPORTS: TreeView_DeleteAllItems(GetDlgItem(hWndDlg, IDC_TREE_IMPORTS)); importsHandling.moduleList.clear(); return TRUE; case IDC_BTN_CLEARLOG: clearOutputLog(); return TRUE; - case IDC_BTN_ABOUT: + /*case IDC_BTN_ABOUT: showAboutDialog(); - return TRUE; + return TRUE;*/ case ID_HELP_ABOUT: showAboutDialog(); return TRUE; - case IDC_BTN_EXIT: + /*case IDC_BTN_EXIT: PostQuitMessage(0); EndDialog(hWndDlg, 0); - return TRUE; + return TRUE;*/ case ID_FILE_EXIT: PostQuitMessage(0); EndDialog(hWndDlg, 0); return TRUE; case IDCANCEL: PostQuitMessage(0); EndDialog(hWndDlg, 0); return TRUE; } return TRUE; case WM_LBUTTONDOWN: //leftButtonDownActionHandler(); //return TRUE; case WM_CONTEXTMENU: return OnContextMenu(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); default: return FALSE; } } void MainGui::setIconAndDialogCaption() { if (hWndMainDlg) { HICON hicon = LoadIcon(GetModuleHandle(0),MAKEINTRESOURCE(IDI_ICON_SCYLLA1)); SendMessage(hWndMainDlg, WM_SETICON, ICON_BIG, (LPARAM)hicon); SendMessage(hWndMainDlg, WM_SETICON, ICON_SMALL, (LPARAM)hicon); swprintf_s(stringBuffer, _countof(stringBuffer),TEXT(APPNAME)TEXT(" ")TEXT(ARCHITECTURE)TEXT(" ")TEXT(APPVERSION)TEXT(" ")); SetWindowText(hWndMainDlg,stringBuffer); } } void MainGui::leftButtonDownActionHandler(WPARAM wParam, LPARAM lParam) { if(wParam & MK_CONTROL) { } else if(wParam & MK_SHIFT) { } else { } } void MainGui::dialogInitActionHandler() { setIconAndDialogCaption(); if (ConfigurationHolder::getConfigObject(DEBUG_PRIVILEGE)->isTrue()) { processLister.setDebugPrivileges(); } enableDialogButtons(FALSE); Edit_LimitText(GetDlgItem(hWndMainDlg,IDC_EDIT_OEPADDRESS), MAX_HEX_VALUE_EDIT_LENGTH); Edit_LimitText(GetDlgItem(hWndMainDlg,IDC_EDIT_IATADDRESS), MAX_HEX_VALUE_EDIT_LENGTH); Edit_LimitText(GetDlgItem(hWndMainDlg,IDC_EDIT_IATSIZE), MAX_HEX_VALUE_EDIT_LENGTH); } void MainGui::pickDllActionHandler() { if (PickDllGui::initDialog(hInstance,hWndMainDlg, processAccessHelp.moduleList)) { //get selected module processAccessHelp.selectedModule = PickDllGui::selectedModule; Logger::printfDialog(TEXT("->>> Module %s selected."), processAccessHelp.selectedModule->getFilename()); Logger::printfDialog(TEXT("Imagebase: ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT(" Size: %08X"),processAccessHelp.selectedModule->modBaseAddr,processAccessHelp.selectedModule->modBaseSize); } else { processAccessHelp.selectedModule = 0; } } void MainGui::startDisassemblerGui(HTREEITEM selectedTreeNode) { DWORD_PTR address = importsHandling.getApiAddressByNode(selectedTreeNode); if (address) { DisassemblerGui::initDialog(hInstance,hWndMainDlg,address); } } void MainGui::processSelectedActionHandler(LRESULT index) { std::vector& processList = processLister.getProcessList(); Process &process = processList.at(index); selectedProcess = &process; enableDialogButtons(TRUE); Logger::printfDialog(TEXT("Analyzing %s"),process.fullPath); if (processAccessHelp.hProcess != 0) { processAccessHelp.closeProcessHandle(); apiReader.clearAll(); } if (!processAccessHelp.openProcessHandle(process.PID)) { Logger::printfDialog(TEXT("Error: Cannot open process handle.")); return; } processAccessHelp.getProcessModules(process.PID, processAccessHelp.moduleList); apiReader.readApisFromModuleList(); Logger::printfDialog(TEXT("Loading modules done.")); //TODO improve processAccessHelp.selectedModule = 0; processAccessHelp.targetSizeOfImage = process.imageSize; processAccessHelp.targetImageBase = process.imageBase; ProcessAccessHelp::getSizeOfImageCurrentProcess(); process.imageSize = (DWORD)processAccessHelp.targetSizeOfImage; Logger::printfDialog(TEXT("Imagebase: ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT(" Size: %08X"),process.imageBase, process.imageSize); selectedProcess->entryPoint = ProcessAccessHelp::getEntryPointFromFile(selectedProcess->fullPath); swprintf_s(stringBuffer, _countof(stringBuffer),TEXT(PRINTF_DWORD_PTR_FULL),selectedProcess->entryPoint + selectedProcess->imageBase); SetDlgItemText(hWndMainDlg, IDC_EDIT_OEPADDRESS, stringBuffer); } void MainGui::fillProcessListComboBox(HWND hCombo) { if (hCombo) { SendMessage(hCombo,CB_RESETCONTENT,0,0); std::vector& processList = processLister.getProcessListSnapshot(); for (size_t i = 0; i < processList.size(); i++) { swprintf_s(stringBuffer, _countof(stringBuffer),TEXT("0x%04X - %s - %s"),processList[i].PID,processList[i].filename,processList[i].fullPath); SendMessage(hCombo,CB_ADDSTRING,0,(LPARAM)stringBuffer); } } } void MainGui::addTextToOutputLog(const WCHAR * text) { if (hWndMainDlg) { HWND hList = GetDlgItem(hWndMainDlg,IDC_LIST_LOG); ListBox_SetCurSel(hList, ListBox_AddString(hList,text)); } } void MainGui::clearOutputLog() { if (hWndMainDlg) { SendDlgItemMessage(hWndMainDlg, IDC_LIST_LOG, LB_RESETCONTENT, 0, 0); } } void MainGui::showInvalidImportsActionHandler() { importsHandling.showImports(true, false); } void MainGui::showSuspectImportsActionHandler() { importsHandling.showImports(false, true); } void MainGui::iatAutosearchActionHandler() { DWORD_PTR searchAddress = 0; DWORD_PTR addressIAT = 0; DWORD sizeIAT = 0; IATSearch iatSearch; GetDlgItemText(hWndMainDlg, IDC_EDIT_OEPADDRESS, stringBuffer, _countof(stringBuffer)); if (wcslen(stringBuffer) > 1) { searchAddress = stringToDwordPtr(stringBuffer); if (searchAddress) { if (iatSearch.searchImportAddressTableInProcess(searchAddress, &addressIAT, &sizeIAT)) { Logger::printfDialog(TEXT("IAT found at VA ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT(" RVA ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT(" Size 0x%04X (%d)"),addressIAT, addressIAT - processAccessHelp.targetImageBase,sizeIAT,sizeIAT); swprintf_s(stringBuffer, _countof(stringBuffer),TEXT(PRINTF_DWORD_PTR_FULL),addressIAT); SetDlgItemText(hWndMainDlg,IDC_EDIT_IATADDRESS,stringBuffer); swprintf_s(stringBuffer, _countof(stringBuffer),TEXT("%08X"),sizeIAT); SetDlgItemText(hWndMainDlg,IDC_EDIT_IATSIZE,stringBuffer); swprintf_s(stringBuffer, _countof(stringBuffer),TEXT("IAT found! Start Address ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT(" Size 0x%04X (%d) "),addressIAT,sizeIAT,sizeIAT); MessageBox(hWndMainDlg,stringBuffer, TEXT("IAT found"), MB_OK); } else { Logger::printfDialog(TEXT("IAT not found at OEP ")TEXT(PRINTF_DWORD_PTR_FULL)TEXT("!"),searchAddress); } } } } void MainGui::getImportsActionHandler() { DWORD_PTR addressIAT = 0; DWORD sizeIAT = 0; GetDlgItemText(hWndMainDlg, IDC_EDIT_IATADDRESS, stringBuffer, sizeof(stringBuffer)); addressIAT = stringToDwordPtr(stringBuffer); GetDlgItemText(hWndMainDlg, IDC_EDIT_IATSIZE, stringBuffer, sizeof(stringBuffer)); sizeIAT = wcstoul(stringBuffer, NULL, 16); if (addressIAT && sizeIAT) { apiReader.readAndParseIAT(addressIAT, sizeIAT,importsHandling.moduleList); importsHandling.displayAllImports(); } } DWORD_PTR MainGui::stringToDwordPtr(WCHAR * hexString) { DWORD_PTR address = 0; #ifdef _WIN64 address = _wcstoui64(hexString, NULL, 16); #else address = wcstoul(hexString, NULL, 16); #endif if (address == 0) { #ifdef DEBUG_COMMENTS Logger::debugLog(L"stringToDwordPtr :: address == 0, %s",hexString); #endif return 0; } else { return address; } } bool MainGui::OnContextMenu(int x, int y) { HWND hwnd = 0; POINT pt = { x, y }; // location of mouse click //TV_ITEM tvi; //WCHAR ttt[260] = {0}; //HTREEITEM selectedTreeNode = 0; if ((hwnd = mouseInDialogItem(IDC_TREE_IMPORTS, pt)) != NULL) { if (TreeView_GetCount(hwnd)) //module list should not be empty { /*selectedTreeNode = (HTREEITEM)SendDlgItemMessage(hWndMainDlg,IDC_TREE_IMPORTS,TVM_GETNEXTITEM,TVGN_CARET,(LPARAM)selectedTreeNode); tvi.mask=TVIF_TEXT; // item text attrivute tvi.pszText=ttt; // Text is the pointer to the text tvi.cchTextMax=260; // size of text to retrieve. tvi.hItem=selectedTreeNode; // the selected item SendDlgItemMessage(hWndMainDlg,IDC_TREE_IMPORTS,TVM_GETITEM,TVGN_CARET,(LPARAM)&tvi); Logger::printfDialog(L"selected %s",tvi.pszText);*/ DisplayContextMenuImports(hwnd, pt); } return true; } //if (PtInRect(&rc, pt)) //{ // ClientToScreen(hwnd, &pt); // DisplayContextMenu(hwnd, pt); // return TRUE; //} // Return FALSE if no menu is displayed. return false; } void MainGui::DisplayContextMenuImports(HWND hwnd, POINT pt) { BOOL menuItem = 0; HTREEITEM selectedTreeNode = 0; - std::vector &pluginList = PluginLoader::getPluginList(); + std::vector &pluginList = PluginLoader::getScyllaPluginList(); HMENU hmenuTrackPopup = getCorrectSubMenu(IDR_MENU_IMPORTS, 0); appendPluginListToMenu(hmenuTrackPopup); if (hmenuTrackPopup) { menuItem = TrackPopupMenu(hmenuTrackPopup, TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD, pt.x, pt.y, 0, hwnd, 0); if (menuItem) { - if ((menuItem >= PLUGIN_MENU_BASE_ID) && (menuItem <= (int)(pluginList.size() + PLUGIN_MENU_BASE_ID))) + if ((menuItem >= PLUGIN_MENU_BASE_ID) && (menuItem <= (int)(PluginLoader::getScyllaPluginList().size() + PluginLoader::getImprecPluginList().size() + PLUGIN_MENU_BASE_ID))) { //wsprintf(stringBuffer, L"%d %s\n",menuItem,pluginList[menuItem - PLUGIN_MENU_BASE_ID].pluginName); //MessageBox(0,stringBuffer,L"plugin selection",0); - DllInjectionPlugin dllInjectionPlugin; - dllInjectionPlugin.hProcess = ProcessAccessHelp::hProcess; - dllInjectionPlugin.apiReader = &apiReader; - dllInjectionPlugin.injectPlugin(pluginList[menuItem - PLUGIN_MENU_BASE_ID], importsHandling.moduleList,selectedProcess->imageBase, selectedProcess->imageSize); - - importsHandling.scanAndFixModuleList(); - importsHandling.displayAllImports(); + pluginActionHandler(menuItem); return; } selectedTreeNode = (HTREEITEM)SendDlgItemMessage(hWndMainDlg,IDC_TREE_IMPORTS,TVM_GETNEXTITEM,TVGN_CARET,(LPARAM)selectedTreeNode); switch (menuItem) { case ID__INVALIDATEFUNCTION: { importsHandling.invalidateFunction(selectedTreeNode); } break; case ID__DISASSEMBLE: { startDisassemblerGui(selectedTreeNode); } break; case ID__CUTTHUNK: { importsHandling.cutThunk(selectedTreeNode); } break; case ID__DELETETREENODE: { importsHandling.deleteTreeNode(selectedTreeNode); } break; case ID__EXPANDALLNODES: { importsHandling.expandAllTreeNodes(); } break; case ID__COLLAPSEALLNODES: { importsHandling.collapseAllTreeNodes(); } break; } } } } HWND MainGui::mouseInDialogItem(int dlgItem, POINT pt) { RECT rc; HWND hwnd = GetDlgItem(hWndMainDlg, dlgItem); if (hwnd) { // Get the bounding rectangle of the client area. GetClientRect(hwnd, &rc); // Convert the mouse position to client coordinates. ScreenToClient(hwnd, &pt); // If the position is in the client area, display a // shortcut menu. if (PtInRect(&rc, pt)) { return hwnd; } else { return 0; } } else { return 0; } } HMENU MainGui::getCorrectSubMenu(int menuItem, int subMenuItem) { HMENU hmenu; // top-level menu HMENU hmenuTrackPopup; // shortcut menu // Load the menu resource. if ((hmenu = LoadMenu(hInstance, MAKEINTRESOURCE(menuItem))) == NULL) return 0; hmenuTrackPopup = GetSubMenu(hmenu, subMenuItem); if (hmenuTrackPopup) { return hmenuTrackPopup; } else { return 0; } } void MainGui::DisplayContextMenu(HWND hwnd, POINT pt) { HMENU hmenu; // top-level menu HMENU hmenuTrackPopup; // shortcut menu int menuItem; // selected menu item // Load the menu resource. if ((hmenu = LoadMenu(hInstance, MAKEINTRESOURCE(IDR_MENU_IMPORTS))) == NULL) return; // TrackPopupMenu cannot display the menu bar so get // a handle to the first shortcut menu. hmenuTrackPopup = GetSubMenu(hmenu, 0); // Display the shortcut menu. Track the right mouse // button. if (!hmenuTrackPopup) { MessageBoxA(0,"hmenuTrackPopup == null","hmenuTrackPopup",0); } menuItem = TrackPopupMenu(hmenuTrackPopup, TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD, pt.x, pt.y, 0, hwnd, NULL); if (menuItem) { /*if (menuItem == ID_LISTCONTROL_SHOWEXPORTS) { MessageBox(0,"exports","dshhhhh",0); }*/ } // Destroy the menu. DestroyMenu(hmenu); } void MainGui::appendPluginListToMenu(HMENU hMenuTrackPopup) { HMENU newMenu = CreatePopupMenu(); - std::vector &pluginList = PluginLoader::getPluginList(); + std::vector &scyllaPluginList = PluginLoader::getScyllaPluginList(); + std::vector &imprecPluginList = PluginLoader::getImprecPluginList(); - if (pluginList.size() > 0) + if (scyllaPluginList.size() > 0) { - for (size_t i = 0; i < pluginList.size(); i++) + for (size_t i = 0; i < scyllaPluginList.size(); i++) { - AppendMenu(newMenu, MF_STRING, i + PLUGIN_MENU_BASE_ID, pluginList[i].pluginName); + AppendMenu(newMenu, MF_STRING, i + PLUGIN_MENU_BASE_ID, scyllaPluginList[i].pluginName); } AppendMenu(hMenuTrackPopup,MF_MENUBARBREAK,0,0); - AppendMenu(hMenuTrackPopup,MF_POPUP,(UINT_PTR)newMenu,TEXT("Plugins")); + AppendMenu(hMenuTrackPopup,MF_POPUP,(UINT_PTR)newMenu,TEXT("Scylla Plugins")); + } + + newMenu = CreatePopupMenu(); + + if (imprecPluginList.size() > 0) + { + for (size_t i = 0; i < imprecPluginList.size(); i++) + { + AppendMenu(newMenu, MF_STRING, scyllaPluginList.size() + i + PLUGIN_MENU_BASE_ID, imprecPluginList[i].pluginName); + } + + AppendMenu(hMenuTrackPopup,MF_MENUBARBREAK,0,0); + AppendMenu(hMenuTrackPopup,MF_POPUP,(UINT_PTR)newMenu,TEXT("ImpREC Plugins")); } } void MainGui::dumpActionHandler() { WCHAR * targetFile = 0; PeDump peDump; if (processAccessHelp.selectedModule) { targetFile = ProcessAccessHelp::selectFileToSave(0, 0); } else { targetFile = ProcessAccessHelp::selectFileToSave(0, 1); } if (targetFile) { if (processAccessHelp.selectedModule) { //dump DLL peDump.imageBase = processAccessHelp.selectedModule->modBaseAddr; peDump.sizeOfImage = processAccessHelp.selectedModule->modBaseSize; //get it from gui peDump.entryPoint = getOEPFromGui(); wcscpy_s(peDump.fullpath, MAX_PATH, processAccessHelp.selectedModule->fullPath); } else { peDump.imageBase = ProcessAccessHelp::targetImageBase; peDump.sizeOfImage = (DWORD)ProcessAccessHelp::targetSizeOfImage; //get it from gui peDump.entryPoint = getOEPFromGui(); wcscpy_s(peDump.fullpath, MAX_PATH, selectedProcess->fullPath); } peDump.useHeaderFromDisk = ConfigurationHolder::getConfigObject(USE_PE_HEADER_FROM_DISK)->isTrue(); if (peDump.dumpCompleteProcessToDisk(targetFile)) { Logger::printfDialog(TEXT("Dump success %s"),targetFile); //MessageBox(hWndMainDlg,TEXT("Image dumped successfully."),TEXT("Success"),MB_OK); } else { Logger::printfDialog(TEXT("Error: Cannot dump image.")); MessageBox(hWndMainDlg,TEXT("Cannot dump image."),TEXT("Failure"),MB_OK); } delete [] targetFile; } } DWORD_PTR MainGui::getOEPFromGui() { if (GetDlgItemText(hWndMainDlg, IDC_EDIT_OEPADDRESS, stringBuffer, _countof(stringBuffer))) { return stringToDwordPtr(stringBuffer); } else { return 0; } } void MainGui::peRebuildActionHandler() { DWORD newSize = 0; WCHAR * targetFile = 0; PeRebuild peRebuild; targetFile = ProcessAccessHelp::selectFileToSave(OFN_FILEMUSTEXIST, 2); if (targetFile) { if (ConfigurationHolder::getConfigObject(CREATE_BACKUP)->isTrue()) { if (!ProcessAccessHelp::createBackupFile(targetFile)) { Logger::printfDialog(TEXT("Creating backup file failed %s"), targetFile); } } LONGLONG fileSize = ProcessAccessHelp::getFileSize(targetFile); LPVOID mapped = peRebuild.createFileMappingViewFull(targetFile); newSize = peRebuild.realignPE(mapped, (DWORD)fileSize); peRebuild.closeAllMappingHandles(); if (newSize < 10) { Logger::printfDialog(TEXT("Rebuild failed %s"), targetFile); MessageBox(hWndMainDlg,TEXT("Rebuild failed."),TEXT("Failure"),MB_OK); } else { peRebuild.truncateFile(targetFile, newSize); Logger::printfDialog(TEXT("Rebuild success %s"), targetFile); Logger::printfDialog(TEXT("-> Old file size 0x%08X new file size 0x%08X (%d %%)"), (DWORD)fileSize, newSize, (DWORD)((newSize * 100) / (DWORD)fileSize) ); //MessageBox(hWndMainDlg,TEXT("Image rebuilded successfully."),TEXT("Success"),MB_OK); } delete [] targetFile; } } void MainGui::dumpFixActionHandler() { WCHAR * targetFile = 0; WCHAR newFilePath[MAX_PATH]; ImportRebuild importRebuild; if (TreeView_GetCount(GetDlgItem(hWndMainDlg, IDC_TREE_IMPORTS)) < 2) { Logger::printfDialog(TEXT("Nothing to rebuild")); return; } if (processAccessHelp.selectedModule) { targetFile = ProcessAccessHelp::selectFileToSave(OFN_FILEMUSTEXIST, 0); } else { targetFile = ProcessAccessHelp::selectFileToSave(OFN_FILEMUSTEXIST, 1); } if (targetFile) { wcscpy_s(newFilePath,MAX_PATH,targetFile); for (size_t i = wcslen(newFilePath) - 1; i >= 0; i--) { if (newFilePath[i] == L'.') { newFilePath[i] = 0; break; } } - wcscat_s(newFilePath,MAX_PATH, L"_SCY.exe"); + if (processAccessHelp.selectedModule) + { + wcscat_s(newFilePath,MAX_PATH, L"_SCY.dll"); + } + else + { + wcscat_s(newFilePath,MAX_PATH, L"_SCY.exe"); + } + if (importRebuild.rebuildImportTable(targetFile,newFilePath,importsHandling.moduleList)) { //MessageBox(hWndMainDlg,L"Imports rebuilding successful",L"Success",MB_OK); Logger::printfDialog(TEXT("Import Rebuild success %s"), newFilePath); } else { Logger::printfDialog(TEXT("Import Rebuild failed, target %s"), targetFile); MessageBox(hWndMainDlg,L"Imports rebuilding failed",L"Failure",MB_OK); } delete [] targetFile; } } void MainGui::enableDialogButtons(BOOL value) { EnableWindow(GetDlgItem(hWndMainDlg, IDC_BTN_PICKDLL), value); EnableWindow(GetDlgItem(hWndMainDlg, IDC_BTN_DUMP), value); EnableWindow(GetDlgItem(hWndMainDlg, IDC_BTN_DLLINJECT), value); EnableWindow(GetDlgItem(hWndMainDlg, IDC_BTN_FIXDUMP), value); EnableWindow(GetDlgItem(hWndMainDlg, IDC_BTN_IATAUTOSEARCH), value); EnableWindow(GetDlgItem(hWndMainDlg, IDC_BTN_GETIMPORTS), value); EnableWindow(GetDlgItem(hWndMainDlg, IDC_BTN_SUSPECTIMPORTS), value); EnableWindow(GetDlgItem(hWndMainDlg, IDC_BTN_INVALIDIMPORTS), value); EnableWindow(GetDlgItem(hWndMainDlg, IDC_BTN_CLEARIMPORTS), value); EnableWindow(GetDlgItem(hWndMainDlg, IDC_BTN_OPTIONS), TRUE); //not yet implemented EnableWindow(GetDlgItem(hWndMainDlg, IDC_BTN_AUTOTRACE), FALSE); EnableWindow(GetDlgItem(hWndMainDlg, IDC_BTN_SAVETREE), FALSE); EnableWindow(GetDlgItem(hWndMainDlg, IDC_BTN_LOADTREE), FALSE); } void MainGui::showAboutDialog() { AboutGui::initDialog(hInstance,hWndMainDlg); } void MainGui::dllInjectActionHandler() { WCHAR * targetFile = 0; HMODULE hMod = 0; DllInjection dllInjection; targetFile = ProcessAccessHelp::selectFileToSave(OFN_FILEMUSTEXIST, 0); if (targetFile) { hMod = dllInjection.dllInjection(ProcessAccessHelp::hProcess, targetFile); if (hMod && ConfigurationHolder::getConfigObject(DLL_INJECTION_AUTO_UNLOAD)->isTrue()) { if (!dllInjection.unloadDllInProcess(ProcessAccessHelp::hProcess, hMod)) { Logger::printfDialog(TEXT("DLL unloading failed, target %s"), targetFile); } } if (hMod) { Logger::printfDialog(TEXT("DLL Injection was successful, target %s"), targetFile); } else { Logger::printfDialog(TEXT("DLL Injection failed, target %s"), targetFile); } delete [] targetFile; } } void MainGui::optionsActionHandler() { OptionsGui::initOptionsDialog(hInstance, hWndMainDlg); } + +void MainGui::pluginActionHandler( int menuItem ) +{ + DllInjectionPlugin dllInjectionPlugin; + + std::vector &scyllaPluginList = PluginLoader::getScyllaPluginList(); + std::vector &imprecPluginList = PluginLoader::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(); +} diff --git a/Scylla/MainGui.h b/Scylla/MainGui.h index e086863..9ff22a1 100644 --- a/Scylla/MainGui.h +++ b/Scylla/MainGui.h @@ -1,95 +1,96 @@ #pragma once //#define _CRTDBG_MAP_ALLOC //#include //#include #include #include #include #include #include #include "resource.h" #include "Logger.h" #include "ProcessLister.h" #include "IATSearch.h" #include "PickDllGui.h" #pragma comment(lib, "comctl32.lib") #define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp)) #define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp)) class ImportsHandling; class MainGui { public: static HWND hWndMainDlg; static Process * selectedProcess; static void initDialog(HINSTANCE hInstance); //Output Window static void addTextToOutputLog(const WCHAR * text); static DWORD_PTR stringToDwordPtr(WCHAR * hexString); protected: static HWND hWndParent; static HINSTANCE hInstance; static ProcessLister processLister; - static WCHAR stringBuffer[300]; + static WCHAR stringBuffer[600]; static ImportsHandling importsHandling; static ProcessAccessHelp processAccessHelp; static ApiReader apiReader; private: static LRESULT CALLBACK mainDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); static void setIconAndDialogCaption(); static void fillProcessListComboBox(HWND hCombo); static void getModuleListItem(int column, int iItem, char * buffer); static void leftButtonDownActionHandler(WPARAM wParam, LPARAM lParam); static void dialogInitActionHandler(); static void pickDllActionHandler(); static void processSelectedActionHandler(LRESULT index); //static bool displayModuleList(HWND hWndDlg, HWND hList, LRESULT index); // POPUP MENU Prototypes static bool OnContextMenu(int, int); static void DisplayContextMenu(HWND, POINT); static HWND mouseInDialogItem(int, POINT); static void DisplayContextMenuImports(HWND, POINT); static HMENU getCorrectSubMenu(int, int); static void clearOutputLog();//Output Window static void showInvalidImportsActionHandler(); static void showSuspectImportsActionHandler(); static void iatAutosearchActionHandler(); static void getImportsActionHandler(); static void appendPluginListToMenu( HMENU hMenuTrackPopup ); static void dumpActionHandler(); static DWORD_PTR getOEPFromGui(); static void peRebuildActionHandler(); static void startDisassemblerGui(HTREEITEM selectedTreeNode); static void dumpFixActionHandler(); static void enableDialogButtons( BOOL value ); static void showAboutDialog(); static void dllInjectActionHandler(); static void optionsActionHandler(); + static void pluginActionHandler( int menuItem ); }; \ No newline at end of file diff --git a/Scylla/MainGui.rc b/Scylla/MainGui.rc index 3e25378..7f30fce 100644 Binary files a/Scylla/MainGui.rc and b/Scylla/MainGui.rc differ diff --git a/Scylla/PluginLoader.cpp b/Scylla/PluginLoader.cpp index 57ca43b..c8c8a8c 100644 --- a/Scylla/PluginLoader.cpp +++ b/Scylla/PluginLoader.cpp @@ -1,258 +1,373 @@ #include "PluginLoader.h" #include "Logger.h" #include "ProcessAccessHelp.h" -std::vector PluginLoader::pluginList; +std::vector PluginLoader::scyllaPluginList; +std::vector PluginLoader::imprecPluginList; WCHAR PluginLoader::dirSearchString[MAX_PATH]; WCHAR PluginLoader::baseDirPath[MAX_PATH]; +WCHAR PluginLoader::imprecWrapperDllPath[MAX_PATH]; //#define DEBUG_COMMENTS -std::vector & PluginLoader::getPluginList() +std::vector & PluginLoader::getScyllaPluginList() { - return pluginList; + return scyllaPluginList; +} + +std::vector & PluginLoader::getImprecPluginList() +{ + return imprecPluginList; } bool PluginLoader::findAllPlugins() { - WIN32_FIND_DATA ffd; - HANDLE hFind = 0; - DWORD dwError = 0; - Plugin pluginData; - if (!pluginList.empty()) + if (!scyllaPluginList.empty()) { - pluginList.clear(); + scyllaPluginList.clear(); + } + + if (!imprecPluginList.empty()) + { + imprecPluginList.clear(); } if (!buildSearchString()) { return false; } - hFind = FindFirstFile(dirSearchString, &ffd); + if (!searchForPlugin(scyllaPluginList, dirSearchString, true)) + { + return false; + } + +#ifndef _WIN64 + if (!buildSearchStringImprecPlugins()) + { + return false; + } + + if (!searchForPlugin(imprecPluginList, dirSearchString, false)) + { + return false; + } +#endif + + return true; +} + +bool PluginLoader::searchForPlugin(std::vector & newPluginList, const WCHAR * searchPath, bool isScyllaPlugin) +{ + WIN32_FIND_DATA ffd; + HANDLE hFind = 0; + DWORD dwError = 0; + Plugin pluginData; + + hFind = FindFirstFile(searchPath, &ffd); dwError = GetLastError(); if (dwError == ERROR_FILE_NOT_FOUND) { #ifdef DEBUG_COMMENTS Logger::debugLog("findAllPlugins :: No files found\r\n"); #endif return true; } if (hFind == INVALID_HANDLE_VALUE) { #ifdef DEBUG_COMMENTS Logger::debugLog("findAllPlugins :: FindFirstFile failed %d\r\n", dwError); #endif return false; } do { if ( !(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) { if ((ffd.nFileSizeHigh != 0) || (ffd.nFileSizeLow < 200)) { #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("findAllPlugins :: Plugin invalid file size: %s\r\n"), ffd.cFileName); #endif } else { pluginData.fileSize = ffd.nFileSizeLow; wcscpy_s(pluginData.fullpath, _countof(baseDirPath), baseDirPath); wcscat_s(pluginData.fullpath, _countof(baseDirPath), ffd.cFileName); #ifdef DEBUG_COMMENTS Logger::debugLog(L"findAllPlugins :: Plugin %s\r\n",pluginData.fullpath); #endif if (isValidDllFile(pluginData.fullpath)) { - if (getPluginName(&pluginData)) + if (isScyllaPlugin) { - //add valid plugin - pluginList.push_back(pluginData); + if (getScyllaPluginName(&pluginData)) + { + //add valid plugin + newPluginList.push_back(pluginData); + } + else + { +#ifdef DEBUG_COMMENTS + Logger::debugLog(TEXT("Cannot get scylla plugin name %s\r\n"),pluginData.fullpath); +#endif + } } else { -#ifdef DEBUG_COMMENTS - Logger::debugLog(TEXT("Cannot get plugin name %s\r\n"),pluginData.fullpath); -#endif + if (isValidImprecPlugin(pluginData.fullpath)) + { + wcscpy_s(pluginData.pluginName, MAX_PATH, ffd.cFileName); + newPluginList.push_back(pluginData); + } } + } } } } while (FindNextFile(hFind, &ffd) != 0); dwError = GetLastError(); + FindClose(hFind); + if (dwError == ERROR_NO_MORE_FILES) { return true; } else { return false; } + } -bool PluginLoader::getPluginName(Plugin * pluginData) +bool PluginLoader::getScyllaPluginName(Plugin * pluginData) { bool retValue = false; char * pluginName = 0; size_t convertedChars = 0; def_ScyllaPluginNameW ScyllaPluginNameW = 0; def_ScyllaPluginNameA ScyllaPluginNameA = 0; HMODULE hModule = LoadLibraryEx(pluginData->fullpath, 0, DONT_RESOLVE_DLL_REFERENCES); //do not call DllMain if (hModule) { ScyllaPluginNameW = (def_ScyllaPluginNameW)GetProcAddress(hModule, "ScyllaPluginNameW"); if (ScyllaPluginNameW) { wcscpy_s(pluginData->pluginName, MAX_PATH, ScyllaPluginNameW()); #ifdef DEBUG_COMMENTS Logger::debugLog(L"getPluginName :: Plugin name %s\r\n", pluginData->pluginName); #endif retValue = true; } else { ScyllaPluginNameA = (def_ScyllaPluginNameA)GetProcAddress(hModule, "ScyllaPluginNameA"); if (ScyllaPluginNameA) { pluginName = ScyllaPluginNameA(); mbstowcs_s(&convertedChars, pluginData->pluginName, strlen(pluginName) + 1, pluginName, _TRUNCATE); #ifdef DEBUG_COMMENTS Logger::debugLog(L"getPluginName :: Plugin name mbstowcs_s %s\r\n", pluginData->pluginName); #endif if (convertedChars > 1) { retValue = true; } else { retValue = false; } } else { retValue = false; } } FreeLibrary(hModule); return retValue; } else { #ifdef DEBUG_COMMENTS Logger::debugLog(L"getPluginName :: LoadLibraryEx failed %s\r\n", pluginData->fullpath); #endif return false; } } bool PluginLoader::buildSearchString() { ZeroMemory(dirSearchString, sizeof(dirSearchString)); ZeroMemory(baseDirPath, sizeof(baseDirPath)); if (!GetModuleFileName(0, dirSearchString, _countof(dirSearchString))) { #ifdef DEBUG_COMMENTS Logger::debugLog("buildSearchString :: GetModuleFileName failed %d\r\n",GetLastError()); #endif return false; } //wprintf(L"dirSearchString 1 %s\n\n", dirSearchString); //remove exe file name for (size_t i = wcslen(dirSearchString) - 1; i >= 0; i--) { if (dirSearchString[i] == L'\\') { dirSearchString[i + 1] = 0; break; } } //wprintf(L"dirSearchString 2 %s\n\n", dirSearchString); wcscat_s(dirSearchString, _countof(dirSearchString), TEXT(PLUGIN_DIR)TEXT("\\") ); wcscpy_s(baseDirPath, _countof(baseDirPath), dirSearchString); wcscat_s(dirSearchString, _countof(dirSearchString), TEXT(PLUGIN_SEARCH_STRING) ); //wprintf(L"dirSearchString 3 %s\n\n", dirSearchString); #ifdef DEBUG_COMMENTS Logger::debugLog(L"dirSearchString final %s\r\n", dirSearchString); #endif return true; } bool PluginLoader::isValidDllFile( const WCHAR * fullpath ) { BYTE * data = 0; DWORD lpNumberOfBytesRead = 0; PIMAGE_DOS_HEADER pDos = 0; PIMAGE_NT_HEADERS pNT = 0; bool retValue = false; HANDLE hFile = CreateFile(fullpath, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); if (hFile != INVALID_HANDLE_VALUE) { data = new BYTE[sizeof(IMAGE_DOS_HEADER) + sizeof(IMAGE_NT_HEADERS) + 0x100]; if (ReadFile(hFile, data, sizeof(IMAGE_DOS_HEADER) + sizeof(IMAGE_NT_HEADERS) + 0x100, &lpNumberOfBytesRead, 0)) { pDos = (PIMAGE_DOS_HEADER)data; if (pDos->e_magic == IMAGE_DOS_SIGNATURE) { pNT = (PIMAGE_NT_HEADERS)((DWORD_PTR)pDos + pDos->e_lfanew); if (pNT->Signature == IMAGE_NT_SIGNATURE) { #ifdef _WIN64 if (pNT->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) #else if (pNT->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) #endif { retValue = true; } } } } delete [] data; CloseHandle(hFile); } return retValue; } + +bool PluginLoader::isValidImprecPlugin(const WCHAR * fullpath) +{ + def_Imprec_Trace Imprec_Trace = 0; + bool retValue = false; + + HMODULE hModule = LoadLibraryEx(fullpath, 0, DONT_RESOLVE_DLL_REFERENCES); //do not call DllMain + + if (hModule) + { + Imprec_Trace = (def_Imprec_Trace)GetProcAddress(hModule, "Trace"); + if (Imprec_Trace) + { + retValue = true; + } + else + { + retValue = false; + } + + FreeLibrary(hModule); + return retValue; + } + else + { +#ifdef DEBUG_COMMENTS + Logger::debugLog(L"isValidImprecPlugin :: LoadLibraryEx failed %s\r\n", pluginData->fullpath); +#endif + return false; + } +} + +bool PluginLoader::buildSearchStringImprecPlugins() +{ + wcscpy_s(dirSearchString, _countof(dirSearchString), baseDirPath); + + wcscat_s(dirSearchString, _countof(dirSearchString), TEXT(PLUGIN_IMPREC_DIR)TEXT("\\") ); + + wcscpy_s(baseDirPath, _countof(baseDirPath), dirSearchString); + + //build imprec wrapper dll path + wcscpy_s(imprecWrapperDllPath, _countof(imprecWrapperDllPath), dirSearchString); + wcscat_s(imprecWrapperDllPath, _countof(imprecWrapperDllPath), TEXT(PLUGIN_IMPREC_WRAPPER_DLL) ); + + if (!fileExists(imprecWrapperDllPath)) + { + return false; + } + + wcscat_s(dirSearchString, _countof(dirSearchString), TEXT(PLUGIN_SEARCH_STRING) ); + + return true; +} + +bool PluginLoader::fileExists(const WCHAR * fileName) +{ + if (GetFileAttributesW(fileName) == INVALID_FILE_ATTRIBUTES) + { + return false; + } + else + { + return true; + } +} diff --git a/Scylla/PluginLoader.h b/Scylla/PluginLoader.h index 27c3f0b..b9d0fd0 100644 --- a/Scylla/PluginLoader.h +++ b/Scylla/PluginLoader.h @@ -1,35 +1,48 @@ #pragma once #include #include #include class Plugin { public: DWORD fileSize; WCHAR fullpath[MAX_PATH]; WCHAR pluginName[MAX_PATH]; }; #define PLUGIN_DIR "Plugins" #define PLUGIN_SEARCH_STRING "*.dll" +#define PLUGIN_IMPREC_DIR "ImpRec_Plugins" +#define PLUGIN_IMPREC_WRAPPER_DLL "Imprec_Wrapper_DLL.dll" typedef wchar_t * (__cdecl * def_ScyllaPluginNameW)(); typedef char * (__cdecl * def_ScyllaPluginNameA)(); +typedef DWORD ( * def_Imprec_Trace)(DWORD hFileMap, DWORD dwSizeMap, DWORD dwTimeOut, DWORD dwToTrace, DWORD dwExactCall); + class PluginLoader { public: + static WCHAR imprecWrapperDllPath[MAX_PATH]; + static bool findAllPlugins(); - static std::vector & getPluginList(); + static std::vector & getScyllaPluginList(); + static std::vector & getImprecPluginList(); private: - static std::vector pluginList; + static std::vector scyllaPluginList; + static std::vector imprecPluginList; static WCHAR dirSearchString[MAX_PATH]; static WCHAR baseDirPath[MAX_PATH]; static bool buildSearchString(); - static bool getPluginName(Plugin * pluginData); + static bool getScyllaPluginName(Plugin * pluginData); static bool isValidDllFile( const WCHAR * fullpath ); + static bool searchForPlugin(std::vector & newPluginList, const WCHAR * searchPath, bool isScyllaPlugin); + static bool isValidImprecPlugin(const WCHAR * fullpath); + static bool buildSearchStringImprecPlugins(); + + static bool fileExists(const WCHAR * fileName); }; \ No newline at end of file diff --git a/Scylla/ProcessAccessHelp.cpp b/Scylla/ProcessAccessHelp.cpp index 06d08e3..59d5143 100644 --- a/Scylla/ProcessAccessHelp.cpp +++ b/Scylla/ProcessAccessHelp.cpp @@ -1,775 +1,775 @@ #include "ProcessAccessHelp.h" #include "Logger.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 Logger::debugLog(TEXT("openProcessHandle :: There is already a process handle, HANDLE %X\r\n"),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 Logger::debugLog(TEXT("openProcessHandle :: Failed to open handle, PID %X\r\n"),dwPID); #endif return false; } } } else { #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("openProcessHandle :: Wrong PID, PID %X \r\n"),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 Logger::debugLog(TEXT("NativeOpenProcess :: Failed to open handle, PID %X Error 0x%X\r\n"),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 Logger::debugLog(TEXT("readMemoryFromProcess :: hProcess == NULL\r\n")); #endif return returnValue; } if (!ReadProcessMemory(hProcess, (LPVOID)address, dataBuffer, size, &lpNumberOfBytesRead)) { if (!VirtualProtectEx(hProcess, (LPVOID)address, size, PAGE_READWRITE, &dwProtect)) { #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("readMemoryFromProcess :: Error VirtualProtectEx %X %X err: %u\r\n"),address,size,GetLastError()); #endif returnValue = false; } else { if (!ReadProcessMemory(hProcess, (LPVOID)address, dataBuffer, size, &lpNumberOfBytesRead)) { #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("readMemoryFromProcess :: Error ReadProcessMemory %X %X err: %u\r\n"),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 Logger::debugLog(TEXT("readMemoryFromProcess :: Error ReadProcessMemory read %d bytes requested %d bytes\r\n"), 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 Logger::debugLog(TEXT("decomposeMemory :: distorm_decompose == DECRES_INPUTERR\r\n")); #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 Logger::debugLog(TEXT("disassembleMemory :: res == DECRES_INPUTERR\r\n")); #endif return false; } else if (res == DECRES_SUCCESS) { //printf("disassembleMemory :: res == DECRES_SUCCESS\n"); return true; } else { #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("disassembleMemory :: res == %d\r\n"),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 Logger::debugLog(TEXT("ProcessAccessHelp::getFileSize :: GetFileSizeEx failed %u\r\n"),GetLastError()); #endif return 0; } else { return lpFileSize.QuadPart; } } else { #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("ProcessAccessHelp::getFileSize hFile invalid\r\n")); #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 Logger::debugLog(TEXT("readMemoryFromFile :: SetFilePointer failed error %u\r\n"),dwError); #endif return false; } else { if (ReadFile(hFile, dataBuffer, size, &lpNumberOfBytesRead, 0)) { return true; } else { #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("readMemoryFromFile :: ReadFile failed - size %d - error %u\r\n"),size,GetLastError()); #endif return false; } } } else { #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("readMemoryFromFile :: hFile invalid\r\n")); #endif return false; } } bool ProcessAccessHelp::writeMemoryToFile(HANDLE hFile, LONG offset, DWORD size, LPVOID 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 Logger::debugLog(TEXT("writeMemoryToFile :: SetFilePointer failed error %u\r\n"),dwError); #endif return false; } else { if (WriteFile(hFile, dataBuffer, size, &lpNumberOfBytesWritten, 0)) { return true; } else { #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("writeMemoryToFile :: WriteFile failed - size %d - error %u\r\n"),size,GetLastError()); #endif return false; } } } else { #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("writeMemoryToFile :: hFile invalid\r\n")); #endif return false; } } bool ProcessAccessHelp::writeMemoryToFileEnd(HANDLE hFile, DWORD size, LPVOID 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 Logger::debugLog(TEXT("writeMemoryToFileEnd :: WriteFile failed - size %d - error %u\r\n"),size,GetLastError()); #endif return false; } } else { #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("writeMemoryToFileEnd :: hFile invalid\r\n")); #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 Logger::debugLog(TEXT("readHeaderFromFile :: INVALID_HANDLE_VALUE %u\r\n"),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 Logger::debugLog(TEXT("createFileMappingView :: INVALID_HANDLE_VALUE %u\r\n"),GetLastError()); #endif return NULL; } HANDLE hMappedFile = CreateFileMapping(hFile, NULL, flProtect, 0, 0, NULL); CloseHandle(hFile); if( hMappedFile == NULL ) { #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("createFileMappingView :: hMappedFile == NULL\r\n")); #endif return NULL; } if (GetLastError() == ERROR_ALREADY_EXISTS) { #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("createFileMappingView :: GetLastError() == ERROR_ALREADY_EXISTS\r\n")); #endif return NULL; } LPVOID addrMappedDll = MapViewOfFile(hMappedFile, accessMap, 0, 0, 0); if( addrMappedDll == NULL ) { #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("createFileMappingView :: addrMappedDll == NULL\r\n")); #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 Logger::debugLog(TEXT("getProcessByName :: Error getting first Process\r\n")); #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(TEXT("\n MODULE NAME: %s"), me32.szModule); module.modBaseAddr = (DWORD_PTR)me32.modBaseAddr; module.modBaseSize = me32.modBaseSize; module.isAlreadyParsed = false; module.parsing = false; wcscpy_s(module.fullPath, MAX_PATH, me32.szExePath); moduleList.push_back(module); } while(Module32Next(hModuleSnap, &me32)); CloseHandle( hModuleSnap ); return true; } bool ProcessAccessHelp::getMemoryRegionFromAddress(DWORD_PTR address, DWORD_PTR * memoryRegionBase, SIZE_T * memoryRegionSize) { MEMORY_BASIC_INFORMATION memBasic; if (VirtualQueryEx(hProcess,(LPCVOID)address,&memBasic,sizeof(MEMORY_BASIC_INFORMATION)) != sizeof(MEMORY_BASIC_INFORMATION)) { #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("getMemoryRegionFromAddress :: VirtualQueryEx error %u\r\n"), 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 Logger::debugLog(TEXT("getSizeOfImageProcess :: VirtualQuery failed %X\r\n"),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; } //OFN_FILEMUSTEXIST WCHAR * ProcessAccessHelp::selectFileToSave(DWORD flags, int type) { OPENFILENAME ofn = {0}; WCHAR * targetFile = new WCHAR[MAX_PATH]; targetFile[0] = 0; ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = 0; switch (type) { case 0: { ofn.lpstrFilter = TEXT("Dynamic Link Library (*.dll)\0*.dll\00"); ofn.lpstrDefExt = TEXT(".dll"); } break; case 1: { ofn.lpstrFilter = TEXT("Executable (*.exe)\0*.exe\00"); ofn.lpstrDefExt = TEXT(".exe"); } break; default: { ofn.lpstrFilter = TEXT("Executable (*.exe)\0*.exe\0Dynamic Link Library (*.dll)\0*.dll\00"); ofn.lpstrDefExt = 0; } } ofn.lpstrCustomFilter = 0; ofn.nFilterIndex = 1; ofn.lpstrFile = targetFile; ofn.nMaxFile = MAX_PATH; ofn.lpstrFileTitle = 0; ofn.nMaxFileTitle = 0; ofn.lpstrInitialDir = 0; ofn.lpstrTitle = TEXT("Select a file"); ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_ENABLESIZING | flags; if(GetOpenFileName(&ofn)) { Logger::printfDialog(TEXT("Selected %s"),targetFile); return targetFile; } else { delete [] targetFile; #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("selectFileToSave :: CommDlgExtendedError 0x%X\r\n"), CommDlgExtendedError()); #endif return 0; } } 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 * sizeof(WCHAR)); //.bak + null BOOL retValue = 0; WCHAR * backupFile = new WCHAR[fileNameLength]; if (backupFile) { wcscpy_s(backupFile, fileNameLength, filePath); wcscat_s(backupFile, fileNameLength, TEXT(".bak")); retValue = CopyFile(filePath, backupFile, FALSE); if (!retValue) { #ifdef DEBUG_COMMENTS Logger::debugLog(TEXT("createBackupFile :: CopyFile failed with error 0x%X\r\n"), GetLastError()); #endif } delete [] backupFile; return retValue != 0; } else { return false; } } \ No newline at end of file diff --git a/Scylla/definitions.h b/Scylla/definitions.h index 588c0bc..70a0e59 100644 --- a/Scylla/definitions.h +++ b/Scylla/definitions.h @@ -1,34 +1,34 @@ #pragma once #define APPNAME "Scylla" #ifdef _WIN64 #define ARCHITECTURE "x64" #define PRINTF_DWORD_PTR "%I64X" #define PRINTF_DWORD_PTR_FULL "%016I64X" #define PRINTF_DWORD_PTR_HALF "%08I64X" #define MAX_HEX_VALUE_EDIT_LENGTH 16 #else #define ARCHITECTURE "x86" #define PRINTF_DWORD_PTR "%X" #define PRINTF_DWORD_PTR_FULL "%08X" #define PRINTF_DWORD_PTR_HALF "%08X" #define MAX_HEX_VALUE_EDIT_LENGTH 8 #endif -#define APPVERSION "v0.2a" +#define APPVERSION "v0.3" #define RECOMMENDED_OS "This tool was designed to work with Windows 7 x64" #define DEVELOPED "Developed with Microsoft Visual Studio 2010, written in pure C/C++" #define CREDIT_DISTORM "This tool uses the diStorm disassembler library http://code.google.com/p/distorm/" #define CREDIT_YODA "The PE Rebuilder engine is based on the Realign DLL version 1.5 by yoda" #define GREETINGS "Greetz: metr0, G36KV and all from the gRn Team" #define VISIT "Visit http://kickme.to/grn and http://forum.tuts4you.com " #define PLUGIN_MENU_BASE_ID 0x10 \ No newline at end of file diff --git a/Scylla/resource.h b/Scylla/resource.h index 2104e9d..51ba47c 100644 Binary files a/Scylla/resource.h and b/Scylla/resource.h differ