diff --git a/Scylla/ConfigurationHolder.cpp b/Scylla/ConfigurationHolder.cpp index 7e6e0c6..52ab836 100644 --- a/Scylla/ConfigurationHolder.cpp +++ b/Scylla/ConfigurationHolder.cpp @@ -1,208 +1,205 @@ #include "ConfigurationHolder.h" #include #include #include "Architecture.h" -const WCHAR ConfigurationHolder::CONFIG_FILE_NAME[] = L"Scylla.ini"; const WCHAR ConfigurationHolder::CONFIG_FILE_SECTION_NAME[] = L"SCYLLA_CONFIG"; //#define DEBUG_COMMENTS -ConfigurationInitializer::ConfigurationInitializer() +ConfigurationHolder::ConfigurationHolder(const WCHAR* fileName) { - ConfigObject configObject; - - mapConfig[USE_PE_HEADER_FROM_DISK] = configObject.newValues(L"USE_PE_HEADER_FROM_DISK", Boolean); - mapConfig[DEBUG_PRIVILEGE] = configObject.newValues(L"DEBUG_PRIVILEGE", Boolean); - mapConfig[CREATE_BACKUP] = configObject.newValues(L"CREATE_BACKUP", Boolean); - mapConfig[DLL_INJECTION_AUTO_UNLOAD] = configObject.newValues(L"DLL_INJECTION_AUTO_UNLOAD", Boolean); - mapConfig[UPDATE_HEADER_CHECKSUM] = configObject.newValues(L"UPDATE_HEADER_CHECKSUM", Boolean); - mapConfig[IAT_SECTION_NAME] = configObject.newValues(L"IAT_SECTION_NAME", String); + config[USE_PE_HEADER_FROM_DISK] = Configuration(L"USE_PE_HEADER_FROM_DISK", Configuration::Boolean); + config[DEBUG_PRIVILEGE] = Configuration(L"DEBUG_PRIVILEGE", Configuration::Boolean); + config[CREATE_BACKUP] = Configuration(L"CREATE_BACKUP", Configuration::Boolean); + config[DLL_INJECTION_AUTO_UNLOAD] = Configuration(L"DLL_INJECTION_AUTO_UNLOAD", Configuration::Boolean); + config[UPDATE_HEADER_CHECKSUM] = Configuration(L"UPDATE_HEADER_CHECKSUM", Configuration::Boolean); + config[IAT_SECTION_NAME] = Configuration(L"IAT_SECTION_NAME", Configuration::String); + + buildConfigFilePath(fileName); } bool ConfigurationHolder::loadConfiguration() { - std::map::iterator mapIter; + std::map::iterator mapIter; - if (!buildConfigFilePath()) + if (configPath[0] == '\0') { return false; } - for (mapIter = config.mapConfig.begin() ; mapIter != config.mapConfig.end(); mapIter++) + for (mapIter = config.begin() ; mapIter != config.end(); mapIter++) { - if (!loadConfig((*mapIter).second)) + Configuration& configObject = mapIter->second; + if (!loadConfig(configObject)) { return false; } } return true; } -bool ConfigurationHolder::saveConfiguration() +bool ConfigurationHolder::saveConfiguration() const { - std::map::iterator mapIter; + std::map::const_iterator mapIter; - if (!buildConfigFilePath()) + if (configPath[0] == '\0') { return false; } - for (mapIter = config.mapConfig.begin() ; mapIter != config.mapConfig.end(); mapIter++) + for (mapIter = config.begin() ; mapIter != config.end(); mapIter++) { - if (!saveConfig((*mapIter).second)) + const Configuration& configObject = mapIter->second; + if (!saveConfig(configObject)) { return false; } } return true; } -bool ConfigurationHolder::saveNumericToConfigFile(ConfigObject & configObject, int nBase) +Configuration& ConfigurationHolder::operator[](ConfigOption option) { + return config[option]; +} - if (nBase == 16) +const Configuration& ConfigurationHolder::operator[](ConfigOption option) const +{ + static const Configuration dummy; + + std::map::const_iterator found = config.find(option); + if(found != config.end()) { - swprintf_s(configObject.valueString, CONFIG_OPTIONS_STRING_LENGTH, PRINTF_DWORD_PTR_FULL, configObject.valueNumeric); + return found->second; } else { - swprintf_s(configObject.valueString, CONFIG_OPTIONS_STRING_LENGTH, PRINTF_INTEGER, configObject.valueNumeric); + return dummy; } +} +bool ConfigurationHolder::saveNumericToConfigFile(const Configuration & configObject, int nBase) const +{ + WCHAR buf[21]; // UINT64_MAX in dec has 20 digits + + if (nBase == 16) + { + swprintf_s(buf, PRINTF_DWORD_PTR_FULL, configObject.getNumeric()); + } + else + { + swprintf_s(buf, PRINTF_INTEGER, configObject.getNumeric()); + } - BOOL ret = WritePrivateProfileString(CONFIG_FILE_SECTION_NAME, configObject.name, configObject.valueString, configPath); + BOOL ret = WritePrivateProfileString(CONFIG_FILE_SECTION_NAME, configObject.getName(), buf, configPath); return ret == TRUE; } -bool ConfigurationHolder::readNumericFromConfigFile(ConfigObject & configObject, int nBase) +bool ConfigurationHolder::readNumericFromConfigFile(Configuration & configObject, int nBase) { - DWORD read = GetPrivateProfileString(CONFIG_FILE_SECTION_NAME, configObject.name, L"", configObject.valueString, _countof(configObject.valueString), configPath); + WCHAR buf[21]; // UINT64_MAX in dec has 20 digits + DWORD read = GetPrivateProfileString(CONFIG_FILE_SECTION_NAME, configObject.getName(), L"", buf, _countof(buf), configPath); - if (read > 0 && wcslen(configObject.valueString) > 0) + if (read > 0 && wcslen(buf) > 0) { - #ifdef _WIN64 - configObject.valueNumeric = _wcstoui64(configObject.valueString, NULL, nBase); + configObject.setNumeric(_wcstoui64(buf, NULL, nBase)); #else - configObject.valueNumeric = wcstoul(configObject.valueString, NULL, nBase); + configObject.setNumeric(wcstoul(buf, NULL, nBase)); #endif - - return (configObject.valueNumeric != 0); - } - else - { - return false; + return true; } + + return false; } -bool ConfigurationHolder::saveStringToConfigFile(ConfigObject & configObject) +bool ConfigurationHolder::saveStringToConfigFile(const Configuration & configObject) const { - BOOL ret = WritePrivateProfileString(CONFIG_FILE_SECTION_NAME, configObject.name, configObject.valueString, configPath); + BOOL ret = WritePrivateProfileString(CONFIG_FILE_SECTION_NAME, configObject.getName(), configObject.getString(), configPath); return ret == TRUE; } -bool ConfigurationHolder::readStringFromConfigFile(ConfigObject & configObject) +bool ConfigurationHolder::readStringFromConfigFile(Configuration & configObject) { - DWORD read = GetPrivateProfileString(CONFIG_FILE_SECTION_NAME, configObject.name, L"", configObject.valueString, _countof(configObject.valueString), configPath); - return (read > 0 && wcslen(configObject.valueString) > 0); + WCHAR buf[Configuration::CONFIG_STRING_LENGTH]; + DWORD read = GetPrivateProfileString(CONFIG_FILE_SECTION_NAME, configObject.getName(), L"", buf, _countof(buf), configPath); + if(read > 0 && wcslen(buf) > 0) + { + configObject.setString(buf); + return true; + } + + return false; } -bool ConfigurationHolder::readBooleanFromConfigFile(ConfigObject & configObject) +bool ConfigurationHolder::readBooleanFromConfigFile(Configuration & configObject) { - UINT val = GetPrivateProfileInt(CONFIG_FILE_SECTION_NAME, configObject.name, 0, configPath); - configObject.valueNumeric = val ? 1 : 0; + UINT val = GetPrivateProfileInt(CONFIG_FILE_SECTION_NAME, configObject.getName(), 0, configPath); + configObject.setBool(val != 0); return true; } -bool ConfigurationHolder::saveBooleanToConfigFile(ConfigObject & configObject) +bool ConfigurationHolder::saveBooleanToConfigFile(const Configuration & configObject) const { - WCHAR *boolValue = 0; - - if (configObject.valueNumeric == 0) - { - boolValue = L"0"; - } - else - { - boolValue = L"1"; - } - - BOOL ret = WritePrivateProfileString(CONFIG_FILE_SECTION_NAME, configObject.name, boolValue, configPath); + const WCHAR *boolValue = configObject.isTrue() ? L"1" : L"0"; + BOOL ret = WritePrivateProfileString(CONFIG_FILE_SECTION_NAME, configObject.getName(), boolValue, configPath); return ret == TRUE; } -bool ConfigurationHolder::loadConfig(ConfigObject & configObject) +bool ConfigurationHolder::loadConfig(Configuration & configObject) { - switch (configObject.configType) + switch (configObject.getType()) { - case String: + case Configuration::String: return readStringFromConfigFile(configObject); - break; - case Boolean: + case Configuration::Boolean: return readBooleanFromConfigFile(configObject); - break; - case Decimal: + case Configuration::Decimal: return readNumericFromConfigFile(configObject, 10); - break; - case Hexadecimal: + case Configuration::Hexadecimal: return readNumericFromConfigFile(configObject, 16); - break; default: return false; } } -bool ConfigurationHolder::saveConfig(ConfigObject & configObject) +bool ConfigurationHolder::saveConfig(const Configuration & configObject) const { - switch (configObject.configType) + switch (configObject.getType()) { - case String: + case Configuration::String: return saveStringToConfigFile(configObject); - break; - case Boolean: + case Configuration::Boolean: return saveBooleanToConfigFile(configObject); - break; - case Decimal: + case Configuration::Decimal: return saveNumericToConfigFile(configObject, 10); - break; - case Hexadecimal: + case Configuration::Hexadecimal: return saveNumericToConfigFile(configObject, 16); - break; default: return false; } } -ConfigObject * ConfigurationHolder::getConfigObject(Configuration configuration) -{ - return &(config.mapConfig[configuration]); -} - -bool ConfigurationHolder::buildConfigFilePath() +bool ConfigurationHolder::buildConfigFilePath(const WCHAR* fileName) { ZeroMemory(configPath, sizeof(configPath)); if (!GetModuleFileName(0, configPath, _countof(configPath))) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"buildConfigFilePath :: GetModuleFileName failed %d", GetLastError()); #endif return false; } PathRemoveFileSpec(configPath); - PathAppend(configPath, CONFIG_FILE_NAME); + PathAppend(configPath, fileName); //wprintf(L"configPath %s\n\n", configPath); return true; } - -std::map & ConfigurationHolder::getConfigList() -{ - return config.mapConfig; -} diff --git a/Scylla/ConfigurationHolder.h b/Scylla/ConfigurationHolder.h index 498b015..174196e 100644 --- a/Scylla/ConfigurationHolder.h +++ b/Scylla/ConfigurationHolder.h @@ -1,94 +1,48 @@ #pragma once #include #include +#include "Configuration.h" -enum ConfigType { - String, - Decimal, - Hexadecimal, - Boolean -}; - -enum Configuration { +enum ConfigOption +{ USE_PE_HEADER_FROM_DISK, DEBUG_PRIVILEGE, CREATE_BACKUP, DLL_INJECTION_AUTO_UNLOAD, IAT_SECTION_NAME, UPDATE_HEADER_CHECKSUM, }; -const size_t CONFIG_OPTIONS_STRING_LENGTH = 100; - -class ConfigObject { +class ConfigurationHolder +{ public: - WCHAR name[MAX_PATH]; - ConfigType configType; - - DWORD_PTR valueNumeric; - WCHAR valueString[CONFIG_OPTIONS_STRING_LENGTH]; - - ConfigObject& newValues(WCHAR * configname, ConfigType config) - { - wcscpy_s(name, MAX_PATH, configname); - configType = config; - valueNumeric = 0; - ZeroMemory(valueString, sizeof(valueString)); - - return *this; - } - - bool isTrue() - { - return (valueNumeric == 1); - } - - void setTrue() - { - valueNumeric = 1; - } - void setFalse() - { - valueNumeric = 0; - } -}; - -class ConfigurationInitializer { -public: - std::map mapConfig; - - ConfigurationInitializer(); -}; - -class ConfigurationHolder { -public: + ConfigurationHolder(const WCHAR* fileName); bool loadConfiguration(); - bool saveConfiguration(); + bool saveConfiguration() const; - ConfigObject * getConfigObject(Configuration configuration); - std::map & getConfigList(); + Configuration& operator[](ConfigOption option); + const Configuration& operator[](ConfigOption option) const; private: - static const WCHAR CONFIG_FILE_NAME[]; static const WCHAR CONFIG_FILE_SECTION_NAME[]; - ConfigurationInitializer config; WCHAR configPath[MAX_PATH]; + std::map config; - bool buildConfigFilePath(); + bool buildConfigFilePath(const WCHAR* fileName); - bool readStringFromConfigFile(ConfigObject & configObject); - bool readBooleanFromConfigFile(ConfigObject & configObject); - bool readNumericFromConfigFile(ConfigObject & configObject, int nBase); + bool readStringFromConfigFile(Configuration & configObject); + bool readBooleanFromConfigFile(Configuration & configObject); + bool readNumericFromConfigFile(Configuration & configObject, int nBase); - bool saveStringToConfigFile(ConfigObject & configObject); - bool saveBooleanToConfigFile(ConfigObject & configObject); - bool saveNumericToConfigFile(ConfigObject & configObject, int nBase); + bool saveStringToConfigFile(const Configuration & configObject) const; + bool saveBooleanToConfigFile(const Configuration & configObject) const; + bool saveNumericToConfigFile(const Configuration & configObject, int nBase) const; - bool loadConfig(ConfigObject & configObject); - bool saveConfig(ConfigObject & configObject); + bool loadConfig(Configuration & configObject); + bool saveConfig(const Configuration & configObject) const; }; diff --git a/Scylla/IATSearch.cpp b/Scylla/IATSearch.cpp index 13e6fca..7c45ca9 100644 --- a/Scylla/IATSearch.cpp +++ b/Scylla/IATSearch.cpp @@ -1,373 +1,371 @@ #include "IATSearch.h" #include "Scylla.h" #include "Architecture.h" //#define DEBUG_COMMENTS bool IATSearch::searchImportAddressTableInProcess(DWORD_PTR startAddress, DWORD_PTR* addressIAT, DWORD* sizeIAT) { DWORD_PTR addressInIAT = 0; addressInIAT = findAPIAddressInIAT(startAddress); if(!addressInIAT) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"searchImportAddressTableInProcess :: addressInIAT not found, startAddress " PRINTF_DWORD_PTR_FULL, startAddress); #endif return false; } else { return findIATStartAndSize(addressInIAT, addressIAT,sizeIAT); } } DWORD_PTR IATSearch::findAPIAddressInIAT(DWORD_PTR startAddress) { - static const int MEMORY_READ_SIZE = 200; - BYTE *dataBuffer = new BYTE[MEMORY_READ_SIZE]; + const size_t MEMORY_READ_SIZE = 200; + BYTE dataBuffer[MEMORY_READ_SIZE]; + DWORD_PTR iatPointer = 0; int counter = 0; // to detect stolen api memoryAddress = 0; memorySize = 0; do { counter++; - if (!readMemoryFromProcess(startAddress,MEMORY_READ_SIZE,dataBuffer)) + if (!readMemoryFromProcess(startAddress, sizeof(dataBuffer), dataBuffer)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"findAPIAddressInIAT :: error reading memory " PRINTF_DWORD_PTR_FULL, startAddress); #endif return 0; } - if (decomposeMemory(dataBuffer, MEMORY_READ_SIZE, startAddress)) + if (decomposeMemory(dataBuffer, sizeof(dataBuffer), startAddress)) { iatPointer = findIATPointer(); if (iatPointer) { if (isIATPointerValid(iatPointer)) { - delete[] dataBuffer; return iatPointer; } } } startAddress = findNextFunctionAddress(); //printf("startAddress %08X\n",startAddress); } while (startAddress != 0 && counter != 8); - - delete[] dataBuffer; return 0; } DWORD_PTR IATSearch::findNextFunctionAddress() { #ifdef DEBUG_COMMENTS _DecodedInst inst; #endif for (unsigned int i = 0; i < decomposerInstructionsCount; i++) { if (decomposerResult[i].flags != FLAG_NOT_DECODABLE) { if (META_GET_FC(decomposerResult[i].meta) == FC_CALL || META_GET_FC(decomposerResult[i].meta) == FC_UNC_BRANCH) { if (decomposerResult[i].size >= 5) { if (decomposerResult[i].ops[0].type == O_PC) { #ifdef DEBUG_COMMENTS distorm_format(&decomposerCi, &decomposerResult[i], &inst); Scylla::debugLog.log(L"%S %S %d %d - target address: " PRINTF_DWORD_PTR_FULL, inst.mnemonic.p, inst.operands.p, decomposerResult[i].ops[0].type, decomposerResult[i].size, INSTRUCTION_GET_TARGET(&decomposerResult[i])); #endif return (DWORD_PTR)INSTRUCTION_GET_TARGET(&decomposerResult[i]); } } } } } return 0; } DWORD_PTR IATSearch::findIATPointer() { #ifdef DEBUG_COMMENTS _DecodedInst inst; #endif for (unsigned int i = 0; i < decomposerInstructionsCount; i++) { if (decomposerResult[i].flags != FLAG_NOT_DECODABLE) { if (META_GET_FC(decomposerResult[i].meta) == FC_CALL || META_GET_FC(decomposerResult[i].meta) == FC_UNC_BRANCH) { if (decomposerResult[i].size >= 5) { #ifdef _WIN64 if (decomposerResult[i].flags & FLAG_RIP_RELATIVE) { #ifdef DEBUG_COMMENTS distorm_format(&decomposerCi, &decomposerResult[i], &inst); Scylla::debugLog.log(L"%S %S %d %d - target address: " PRINTF_DWORD_PTR_FULL, inst.mnemonic.p, inst.operands.p, decomposerResult[i].ops[0].type, decomposerResult[i].size, INSTRUCTION_GET_RIP_TARGET(&decomposerResult[i])); #endif return INSTRUCTION_GET_RIP_TARGET(&decomposerResult[i]); } #else if (decomposerResult[i].ops[0].type == O_DISP) { //jmp dword ptr || call dword ptr #ifdef DEBUG_COMMENTS distorm_format(&decomposerCi, &decomposerResult[i], &inst); Scylla::debugLog.log(L"%S %S %d %d - target address: " PRINTF_DWORD_PTR_FULL, inst.mnemonic.p, inst.operands.p, decomposerResult[i].ops[0].type, decomposerResult[i].size, decomposerResult[i].disp); #endif return (DWORD_PTR)decomposerResult[i].disp; } #endif } } } } return 0; } /*DWORD_PTR IATSearch::findAddressFromWORDString(char * stringBuffer) { char * pAddress = 0; char * pTemp = 0; DWORD_PTR address = 0; //string split it e.g. DWORD [0x40f0fc], QWORD [RIP+0x40f0] pAddress = strchr(stringBuffer, 'x'); if (pAddress) { pAddress++; pTemp = strchr(pAddress, ']'); *pTemp = 0x00; address = strtoul(pAddress, 0, 16); //printf("findAddressFromWORDString :: %08X\n",address); if (address == ULONG_MAX) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"findAddressFromDWORDString :: strtoul ULONG_MAX"); #endif return 0; } else { return address; } } else { return 0; } }*/ /*DWORD_PTR IATSearch::findAddressFromNormalCALLString(char * stringBuffer) { char * pAddress = 0; DWORD_PTR address = 0; //e.g. CALL 0x7238 pAddress = strchr(stringBuffer, 'x'); if (pAddress) { pAddress++; address = strtoul(pAddress, 0, 16); //printf("findAddressFromNormalCALLString :: %08X\n",address); if (address == ULONG_MAX) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"findAddressFromNormalCALLString :: strtoul ULONG_MAX"); #endif return 0; } else { return address; } } else { return 0; } }*/ bool IATSearch::isIATPointerValid(DWORD_PTR iatPointer) { DWORD_PTR apiAddress = 0; if (!readMemoryFromProcess(iatPointer,sizeof(DWORD_PTR),&apiAddress)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"isIATPointerValid :: error reading memory"); #endif return false; } //printf("Win api ? %08X\n",apiAddress); if (isApiAddressValid(apiAddress) != 0) { return true; } else { //maybe redirected import? //if the address is 2 times inside a memory region it is possible a redirected api if (apiAddress > memoryAddress && apiAddress < (memoryAddress+memorySize)) { return true; } else { getMemoryRegionFromAddress(apiAddress, &memoryAddress, &memorySize); return false; } } } bool IATSearch::findIATStartAndSize(DWORD_PTR address, DWORD_PTR * addressIAT, DWORD * sizeIAT) { MEMORY_BASIC_INFORMATION memBasic = {0}; BYTE *dataBuffer = 0; if (VirtualQueryEx(hProcess,(LPCVOID)address, &memBasic, sizeof(MEMORY_BASIC_INFORMATION)) != sizeof(MEMORY_BASIC_INFORMATION)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"findIATStartAddress :: VirtualQueryEx error %u", GetLastError()); #endif return false; } //(sizeof(DWORD_PTR) * 3) added to prevent buffer overflow dataBuffer = new BYTE[memBasic.RegionSize + (sizeof(DWORD_PTR) * 3)]; ZeroMemory(dataBuffer, memBasic.RegionSize + (sizeof(DWORD_PTR) * 3)); if (!readMemoryFromProcess((DWORD_PTR)memBasic.BaseAddress, memBasic.RegionSize, dataBuffer)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"findIATStartAddress :: error reading memory"); #endif return false; } //printf("address %X memBasic.BaseAddress %X memBasic.RegionSize %X\n",address,memBasic.BaseAddress,memBasic.RegionSize); *addressIAT = findIATStartAddress((DWORD_PTR)memBasic.BaseAddress, address, dataBuffer); *sizeIAT = findIATSize((DWORD_PTR)memBasic.BaseAddress, *addressIAT, dataBuffer, (DWORD)memBasic.RegionSize); delete [] dataBuffer; return true; } DWORD_PTR IATSearch::findIATStartAddress(DWORD_PTR baseAddress, DWORD_PTR startAddress, BYTE * dataBuffer) { DWORD_PTR *pIATAddress = 0; pIATAddress = (DWORD_PTR *)((startAddress - baseAddress) + (DWORD_PTR)dataBuffer); while((DWORD_PTR)pIATAddress != (DWORD_PTR)dataBuffer) { if ( (*pIATAddress < 0xFFFF) || !isAddressAccessable(*pIATAddress) ) { if ( (*(pIATAddress - 1) < 0xFFFF) || !isAddressAccessable(*(pIATAddress - 1)) ) { //IAT end if ((DWORD_PTR)(pIATAddress - 2) >= (DWORD_PTR)dataBuffer) { if (!isApiAddressValid(*(pIATAddress - 2))) { return (((DWORD_PTR)pIATAddress - (DWORD_PTR)dataBuffer) + baseAddress); } } else { return (((DWORD_PTR)pIATAddress - (DWORD_PTR)dataBuffer) + baseAddress); } } } pIATAddress--; } return baseAddress; } DWORD IATSearch::findIATSize(DWORD_PTR baseAddress, DWORD_PTR iatAddress, BYTE * dataBuffer, DWORD bufferSize) { DWORD_PTR *pIATAddress = 0; pIATAddress = (DWORD_PTR *)((iatAddress - baseAddress) + (DWORD_PTR)dataBuffer); #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"findIATSize :: baseAddress %X iatAddress %X dataBuffer %X pIATAddress %X", baseAddress, iatAddress, dataBuffer, pIATAddress); #endif while((DWORD_PTR)pIATAddress < ((DWORD_PTR)dataBuffer + bufferSize - 1)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"findIATSize :: %X %X %X", pIATAddress, *pIATAddress, *(pIATAddress + 1)); #endif if ( (*pIATAddress < 0xFFFF) || !isAddressAccessable(*pIATAddress) ) //normal is 0 { if ( (*(pIATAddress + 1) < 0xFFFF) || !isAddressAccessable(*(pIATAddress + 1)) ) { //IAT end if (!isApiAddressValid(*(pIATAddress + 2))) { return (DWORD)((DWORD_PTR)pIATAddress - (DWORD_PTR)dataBuffer - (iatAddress - baseAddress)); } } } pIATAddress++; } return bufferSize; } bool IATSearch::isAddressAccessable(DWORD_PTR address) { BYTE junk[3]; SIZE_T numberOfBytesRead = 0; if (ReadProcessMemory(hProcess, (LPCVOID)address, junk, sizeof(junk), &numberOfBytesRead)) { if (numberOfBytesRead == sizeof(junk)) { if (junk[0] != 0x00) { return true; } } } return false; } \ No newline at end of file diff --git a/Scylla/ImportRebuild.cpp b/Scylla/ImportRebuild.cpp index 088b109..38c56ff 100644 --- a/Scylla/ImportRebuild.cpp +++ b/Scylla/ImportRebuild.cpp @@ -1,715 +1,715 @@ #include "ImportRebuild.h" #include "Scylla.h" //#include "ConfigurationHolder.h" //#define DEBUG_COMMENTS ImportRebuild::ImportRebuild() { imageData = NULL; sizeOfFile = 0; pDosStub = NULL; pOverlay = NULL; sizeOfOverlay = 0; pImportDescriptor = NULL; pThunkData = NULL; pImportByName = NULL; numberOfImportDescriptors = 0; sizeOfImportSection = 0; sizeOfApiAndModuleNames = 0; importSectionIndex = 0; } ImportRebuild::~ImportRebuild() { delete [] pDosStub; delete [] imageData; for (size_t i = 0; i < vecSectionData.size(); i++) { delete [] vecSectionData[i]; } delete [] pOverlay; } bool ImportRebuild::splitTargetFile() { PIMAGE_SECTION_HEADER pSecHeader = 0; BYTE * data = 0; DWORD alignment = 0; DosHeader = *(IMAGE_DOS_HEADER*)imageData; if (DosHeader.e_magic != IMAGE_DOS_SIGNATURE) { return false; } NTHeader = *(IMAGE_NT_HEADERS*)(imageData + DosHeader.e_lfanew); if (NTHeader.Signature != IMAGE_NT_SIGNATURE) { return false; } if (DosHeader.e_lfanew > sizeof(IMAGE_DOS_HEADER)) { size_t sizeOfStub = DosHeader.e_lfanew - sizeof(IMAGE_DOS_HEADER); pDosStub = new BYTE[sizeOfStub]; CopyMemory(pDosStub, imageData + sizeof(IMAGE_DOS_HEADER), sizeOfStub); } pSecHeader = IMAGE_FIRST_SECTION((IMAGE_NT_HEADERS*)(imageData + DosHeader.e_lfanew)); for (WORD i = 0; i < NTHeader.FileHeader.NumberOfSections; i++) { const DWORD SECTION_SIZE_MAX = 300000000; DWORD sizeOfSection = pSecHeader->SizeOfRawData; if (sizeOfSection > SECTION_SIZE_MAX) { sizeOfSection = SECTION_SIZE_MAX; } //TODO better use section alignment because it is better? alignment = alignValue(sizeOfSection, NTHeader.OptionalHeader.SectionAlignment); data = new BYTE[alignment]; ZeroMemory(data, alignment); CopyMemory(data, imageData + pSecHeader->PointerToRawData, sizeOfSection); vecSectionData.push_back(data); vecSectionHeaders.push_back(*pSecHeader); pSecHeader++; } if(NTHeader.FileHeader.NumberOfSections > 0) // ?? { const IMAGE_SECTION_HEADER* pLastSec = &(*vecSectionHeaders.rbegin()); DWORD calcSize = pLastSec->PointerToRawData + pLastSec->SizeOfRawData; if (calcSize < sizeOfFile) { sizeOfOverlay = sizeOfFile - calcSize; pOverlay = new BYTE[sizeOfOverlay]; memcpy(pOverlay, imageData + calcSize, sizeOfOverlay); } } delete [] imageData; imageData = 0; return true; } bool ImportRebuild::alignSectionHeaders() { for (WORD i = 0; i < vecSectionHeaders.size(); i++) { vecSectionHeaders[i].VirtualAddress = alignValue(vecSectionHeaders[i].VirtualAddress, NTHeader.OptionalHeader.SectionAlignment); vecSectionHeaders[i].Misc.VirtualSize = alignValue(vecSectionHeaders[i].Misc.VirtualSize, NTHeader.OptionalHeader.SectionAlignment); vecSectionHeaders[i].PointerToRawData = alignValue(vecSectionHeaders[i].PointerToRawData, NTHeader.OptionalHeader.FileAlignment); vecSectionHeaders[i].SizeOfRawData = alignValue(vecSectionHeaders[i].SizeOfRawData, NTHeader.OptionalHeader.FileAlignment); } return true; } bool ImportRebuild::saveNewFile(const WCHAR * filepath) { DWORD fileOffset = 0; DWORD dwWriteSize = 0; size_t i = 0; if (vecSectionHeaders.size() != vecSectionData.size()) { return false; } HANDLE hFile = CreateFile(filepath, GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, 0,CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); if(hFile == INVALID_HANDLE_VALUE) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"saveNewFile :: INVALID_HANDLE_VALUE %u", GetLastError()); #endif return false; } //alignSectionHeaders(); updatePeHeader(); fileOffset = 0; dwWriteSize = sizeof(IMAGE_DOS_HEADER); ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, dwWriteSize, &DosHeader); fileOffset += dwWriteSize; dwWriteSize = DosHeader.e_lfanew - sizeof(IMAGE_DOS_HEADER); ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, dwWriteSize, pDosStub); fileOffset += dwWriteSize; dwWriteSize = sizeof(IMAGE_NT_HEADERS); ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, dwWriteSize, &NTHeader); fileOffset += dwWriteSize; dwWriteSize = sizeof(IMAGE_SECTION_HEADER); for (i = 0; i < vecSectionHeaders.size(); i++) { if (!ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, dwWriteSize, &vecSectionHeaders[i])) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"saveNewFile :: writeMemoryToFile failed offset %X size %X", fileOffset, dwWriteSize); #endif CloseHandle(hFile); return false; } fileOffset += dwWriteSize; } for (i = 0; i < vecSectionHeaders.size(); i++) { dwWriteSize = vecSectionHeaders[i].PointerToRawData - fileOffset; if (dwWriteSize) { if (!writeZeroMemoryToFile(hFile, fileOffset, dwWriteSize)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"saveNewFile :: writeZeroMemoryToFile failed offset %X size %X", fileOffset, dwWriteSize); #endif CloseHandle(hFile); return false; } fileOffset += dwWriteSize; } dwWriteSize = vecSectionHeaders[i].SizeOfRawData; ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, dwWriteSize, vecSectionData[i]); fileOffset += dwWriteSize; } if(pOverlay) { ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, sizeOfOverlay, pOverlay); fileOffset += sizeOfOverlay; } CloseHandle(hFile); return true; } bool ImportRebuild::writeZeroMemoryToFile(HANDLE hFile, DWORD fileOffset, DWORD size) { bool retValue = false; PVOID zeromemory = calloc(size, 1); if (zeromemory) { retValue = ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, size, zeromemory); free(zeromemory); } else { retValue = false; } return retValue; } bool ImportRebuild::addNewSection(char * sectionName, DWORD sectionSize, BYTE * sectionData) { BYTE * newBuffer = 0; IMAGE_SECTION_HEADER pNewSection = {0}; size_t lastSectionIndex = vecSectionHeaders.size() - 1; size_t nameLength = strlen(sectionName); if (nameLength > IMAGE_SIZEOF_SHORT_NAME) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"addNewSection :: sectionname is too long %d", nameLength); #endif return false; } memcpy_s(pNewSection.Name, IMAGE_SIZEOF_SHORT_NAME, sectionName, nameLength); pNewSection.SizeOfRawData = alignValue(sectionSize, NTHeader.OptionalHeader.FileAlignment); pNewSection.Misc.VirtualSize = alignValue(sectionSize, NTHeader.OptionalHeader.SectionAlignment); pNewSection.PointerToRawData = alignValue(vecSectionHeaders[lastSectionIndex].PointerToRawData + vecSectionHeaders[lastSectionIndex].SizeOfRawData, NTHeader.OptionalHeader.FileAlignment); pNewSection.VirtualAddress = alignValue(vecSectionHeaders[lastSectionIndex].VirtualAddress + vecSectionHeaders[lastSectionIndex].Misc.VirtualSize, NTHeader.OptionalHeader.SectionAlignment); pNewSection.Characteristics = IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE|IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA; vecSectionHeaders.push_back(pNewSection); if ( (sectionSize != pNewSection.SizeOfRawData) || (sectionData == 0) ) { newBuffer = new BYTE[pNewSection.SizeOfRawData]; ZeroMemory(newBuffer, pNewSection.SizeOfRawData); if (sectionData) { CopyMemory(newBuffer, sectionData, sectionSize); } } else { newBuffer = sectionData; } vecSectionData.push_back(newBuffer); return true; } bool ImportRebuild::loadTargetFile(const WCHAR * filepath) { HANDLE hTargetFile = INVALID_HANDLE_VALUE; DWORD fileSize = 0; bool retValue = false; hTargetFile = CreateFile(filepath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if(hTargetFile == INVALID_HANDLE_VALUE) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"loadTargetFile :: INVALID_HANDLE_VALUE %u", GetLastError()); #endif return false; } fileSize = (DWORD)ProcessAccessHelp::getFileSize(hTargetFile); if (!fileSize) { CloseHandle(hTargetFile); hTargetFile = 0; return false; } imageData = new BYTE[fileSize]; if (!imageData) { retValue = false; } else { sizeOfFile = fileSize; retValue = ProcessAccessHelp::readMemoryFromFile(hTargetFile, 0, fileSize, imageData); } CloseHandle(hTargetFile); hTargetFile = 0; return retValue; } DWORD ImportRebuild::alignValue(DWORD badValue, DWORD alignTo) { return (((badValue + alignTo - 1) / alignTo) * alignTo); } DWORD ImportRebuild::convertRVAToOffsetVector(DWORD dwRVA) { for (size_t i = 0; i < vecSectionHeaders.size(); i++) { if ((vecSectionHeaders[i].VirtualAddress <= dwRVA) && ((vecSectionHeaders[i].VirtualAddress + vecSectionHeaders[i].Misc.VirtualSize) > dwRVA)) { return ((dwRVA - vecSectionHeaders[i].VirtualAddress) + vecSectionHeaders[i].PointerToRawData); } } return 0; } /* DWORD ImportRebuild::convertRVAToOffset(DWORD dwRVA) { PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(&NTHeader); for (WORD i = 0; i < NTHeader.FileHeader.NumberOfSections; i++) { if ((pSectionHeader->VirtualAddress <= dwRVA) && ((pSectionHeader->VirtualAddress + pSectionHeader->Misc.VirtualSize) > dwRVA)) { return ((dwRVA - pSectionHeader->VirtualAddress) + pSectionHeader->PointerToRawData); } pSectionHeader++; } return 0; } */ DWORD_PTR ImportRebuild::convertOffsetToRVAVector(DWORD dwOffset) { for (size_t i = 0; i < vecSectionHeaders.size(); i++) { if ((vecSectionHeaders[i].PointerToRawData <= dwOffset) && ((vecSectionHeaders[i].PointerToRawData + vecSectionHeaders[i].SizeOfRawData) > dwOffset)) { return ((dwOffset - vecSectionHeaders[i].PointerToRawData) + vecSectionHeaders[i].VirtualAddress); } } return 0; } /* DWORD ImportRebuild::convertOffsetToRVA(DWORD dwOffset) { PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(&NTHeader); for (WORD i = 0; i < NTHeader.FileHeader.NumberOfSections; i++) { if ((pSectionHeader->PointerToRawData <= dwOffset) && ((pSectionHeader->PointerToRawData + pSectionHeader->SizeOfRawData) > dwOffset)) { return ((dwOffset - pSectionHeader->PointerToRawData) + pSectionHeader->VirtualAddress); } pSectionHeader++; } return 0; } */ void ImportRebuild::updatePeHeader() { size_t lastSectionIndex = vecSectionHeaders.size() - 1; NTHeader.FileHeader.NumberOfSections = (WORD)(lastSectionIndex + 1); NTHeader.OptionalHeader.SizeOfImage = vecSectionHeaders[lastSectionIndex].VirtualAddress + vecSectionHeaders[lastSectionIndex].Misc.VirtualSize; NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0; NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0; if (NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress) { for (size_t i = 0; i < vecSectionHeaders.size(); i++) { if ((vecSectionHeaders[i].VirtualAddress <= NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress) && ((vecSectionHeaders[i].VirtualAddress + vecSectionHeaders[i].Misc.VirtualSize) > NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress)) { //section must be read and writeable vecSectionHeaders[i].Characteristics |= IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE; } } NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = 0; NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = 0; } NTHeader.OptionalHeader.NumberOfRvaAndSizes = 0x10; NTHeader.OptionalHeader.SizeOfHeaders = alignValue(DosHeader.e_lfanew + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + NTHeader.FileHeader.SizeOfOptionalHeader + (NTHeader.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER)), NTHeader.OptionalHeader.FileAlignment); } bool ImportRebuild::buildNewImportTable(std::map & moduleList) { createNewImportSection(moduleList); importSectionIndex = vecSectionHeaders.size() - 1; DWORD dwSize = fillImportSection(moduleList); if (!dwSize) { return false; } setFlagToIATSection((*moduleList.begin()).second.firstThunk); NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = vecSectionHeaders[importSectionIndex].VirtualAddress; NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = (DWORD)(numberOfImportDescriptors * sizeof(IMAGE_IMPORT_DESCRIPTOR)); return true; } bool ImportRebuild::createNewImportSection(std::map & moduleList) { char sectionName[9] = {0}; size_t i = 0; //DWORD sectionSize = calculateMinSize(moduleList); calculateImportSizes(moduleList); - if (wcslen(Scylla::config.getConfigObject(IAT_SECTION_NAME)->valueString) > IMAGE_SIZEOF_SHORT_NAME) + if (wcslen(Scylla::config[IAT_SECTION_NAME].getString()) > IMAGE_SIZEOF_SHORT_NAME) { strcpy_s(sectionName, sizeof(sectionName), ".SCY"); } else { - wcstombs_s(&i, sectionName, sizeof(sectionName), Scylla::config.getConfigObject(IAT_SECTION_NAME)->valueString, _TRUNCATE); + wcstombs_s(&i, sectionName, sizeof(sectionName), Scylla::config[IAT_SECTION_NAME].getString(), _TRUNCATE); } return addNewSection(sectionName, (DWORD)sizeOfImportSection, 0); } /*DWORD ImportRebuild::calculateMinSize(std::map & moduleList) { DWORD dwSize = 0; std::map::iterator mapIt; std::map::iterator mapIt2; dwSize = (DWORD)((moduleList.size() + 1) * sizeof(IMAGE_IMPORT_DESCRIPTOR)); //last is zero'ed for ( mapIt = moduleList.begin() ; mapIt != moduleList.end(); mapIt++ ) { //dwSize += (DWORD)((*mapIt).second.thunkList.size() + sizeof(IMAGE_IMPORT_BY_NAME)); dwSize += (DWORD)(wcslen((*mapIt).second.moduleName) + 1); for ( mapIt2 = (*mapIt).second.thunkList.begin() ; mapIt2 != (*mapIt).second.thunkList.end(); mapIt2++ ) { if((*mapIt2).second.name[0] != '\0') { dwSize += sizeof(IMAGE_IMPORT_BY_NAME); dwSize += (DWORD)strlen((*mapIt2).second.name); } } } return dwSize; }*/ BYTE * ImportRebuild::getMemoryPointerFromRVA(DWORD_PTR dwRVA) { DWORD_PTR offset = convertRVAToOffsetVector((DWORD)dwRVA); for (size_t i = 0; i < vecSectionHeaders.size(); i++) { if ((vecSectionHeaders[i].PointerToRawData <= offset) && ((vecSectionHeaders[i].PointerToRawData + vecSectionHeaders[i].SizeOfRawData) > offset)) { return (BYTE *)((DWORD_PTR)vecSectionData[i] + (offset - vecSectionHeaders[i].PointerToRawData)); } } return 0; } DWORD ImportRebuild::fillImportSection( std::map & moduleList ) { std::map::iterator mapIt; std::map::iterator mapIt2; PIMAGE_IMPORT_DESCRIPTOR pImportDesc = 0; PIMAGE_IMPORT_BY_NAME pImportByName = 0; PIMAGE_THUNK_DATA pThunk = 0; ImportModuleThunk * importModuleThunk = 0; ImportThunk * importThunk = 0; size_t stringLength = 0; DWORD_PTR lastRVA = 0; BYTE * sectionData = vecSectionData[importSectionIndex]; DWORD offset = 0; pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)(sectionData); //skip the IMAGE_IMPORT_DESCRIPTOR offset += (DWORD)(numberOfImportDescriptors * sizeof(IMAGE_IMPORT_DESCRIPTOR)); for ( mapIt = moduleList.begin() ; mapIt != moduleList.end(); mapIt++ ) { importModuleThunk = &((*mapIt).second); stringLength = addImportDescriptor(importModuleThunk, offset); #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"fillImportSection :: importDesc.Name %X", pImportDescriptor->Name); #endif offset += (DWORD)stringLength; //stringLength has null termination char pImportByName = (PIMAGE_IMPORT_BY_NAME)((DWORD_PTR)sectionData + offset); //pThunk = (PIMAGE_THUNK_DATA)(getMemoryPointerFromRVA(importModuleThunk->firstThunk)); lastRVA = importModuleThunk->firstThunk - sizeof(DWORD_PTR); for ( mapIt2 = (*mapIt).second.thunkList.begin() ; mapIt2 != (*mapIt).second.thunkList.end(); mapIt2++ ) { importThunk = &((*mapIt2).second); pThunk = (PIMAGE_THUNK_DATA)(getMemoryPointerFromRVA(importThunk->rva)); //check wrong iat pointer if (!pThunk) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"fillImportSection :: Failed to get pThunk RVA: %X", importThunk->rva); #endif return 0; } if ((lastRVA + sizeof(DWORD_PTR)) != importThunk->rva) { //add additional import desc addSpecialImportDescriptor(importThunk->rva); } lastRVA = importThunk->rva; #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"fillImportSection :: importThunk %X pThunk %X pImportByName %X offset %X", importThunk,pThunk,pImportByName,offset); #endif stringLength = addImportToImportTable(importThunk, pThunk, pImportByName, offset); offset += (DWORD)stringLength; //is 0 bei import by ordinal pImportByName = (PIMAGE_IMPORT_BY_NAME)((DWORD_PTR)pImportByName + stringLength); } pImportDescriptor++; } return offset; } bool ImportRebuild::rebuildImportTable(const WCHAR * targetFilePath, const WCHAR * newFilePath, std::map & moduleList) { bool retValue = false; if (loadTargetFile(targetFilePath)) { splitTargetFile(); retValue = buildNewImportTable(moduleList); if (retValue) { retValue = saveNewFile(newFilePath); } return retValue; } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"rebuildImportTable ::Failed to load target %s", targetFilePath); #endif return false; } } void ImportRebuild::setFlagToIATSection(DWORD_PTR iatAddress) { for (size_t i = 0; i < vecSectionHeaders.size(); i++) { if ((vecSectionHeaders[i].VirtualAddress <= iatAddress) && ((vecSectionHeaders[i].VirtualAddress + vecSectionHeaders[i].Misc.VirtualSize) > iatAddress)) { //section must be read and writeable vecSectionHeaders[i].Characteristics |= IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE; } } } size_t ImportRebuild::addImportToImportTable( ImportThunk * pImport, PIMAGE_THUNK_DATA pThunk, PIMAGE_IMPORT_BY_NAME pImportByName, DWORD sectionOffset) { size_t stringLength = 0; if(pImport->name[0] == '\0') { pThunk->u1.AddressOfData = (IMAGE_ORDINAL(pImport->ordinal) | IMAGE_ORDINAL_FLAG); } else { pImportByName->Hint = pImport->hint; stringLength = strlen(pImport->name) + 1; memcpy(pImportByName->Name, pImport->name, stringLength); pThunk->u1.AddressOfData = convertOffsetToRVAVector(vecSectionHeaders[importSectionIndex].PointerToRawData + sectionOffset); if (!pThunk->u1.AddressOfData) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"addImportToImportTable :: failed to get AddressOfData %X %X", vecSectionHeaders[importSectionIndex].PointerToRawData, sectionOffset); #endif } //next import should be nulled pThunk++; pThunk->u1.AddressOfData = 0; #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"addImportToImportTable :: pThunk->u1.AddressOfData %X %X %X", pThunk->u1.AddressOfData, pThunk, vecSectionHeaders[importSectionIndex].PointerToRawData + sectionOffset); #endif stringLength += sizeof(WORD); } return stringLength; } size_t ImportRebuild::addImportDescriptor(ImportModuleThunk * pImportModule, DWORD sectionOffset) { char dllName[MAX_PATH]; size_t stringLength = 0; wcstombs_s(&stringLength, dllName, (size_t)_countof(dllName), pImportModule->moduleName, (size_t)_countof(pImportModule->moduleName)); memcpy((vecSectionData[importSectionIndex] + sectionOffset), dllName, stringLength); //copy module name to section pImportDescriptor->FirstThunk = (DWORD)pImportModule->firstThunk; pImportDescriptor->Name = (DWORD)convertOffsetToRVAVector(vecSectionHeaders[importSectionIndex].PointerToRawData + sectionOffset); return stringLength; } void ImportRebuild::addSpecialImportDescriptor(DWORD_PTR rvaFirstThunk) { PIMAGE_IMPORT_DESCRIPTOR oldID = pImportDescriptor; pImportDescriptor++; pImportDescriptor->FirstThunk = (DWORD)rvaFirstThunk; pImportDescriptor->Name = oldID->Name; } void ImportRebuild::calculateImportSizes(std::map & moduleList) { std::map::iterator mapIt; std::map::iterator mapIt2; DWORD_PTR lastRVA = 0; numberOfImportDescriptors = 0; sizeOfImportSection = 0; sizeOfApiAndModuleNames = 0; numberOfImportDescriptors = moduleList.size() + 1; //last is zero'd for ( mapIt = moduleList.begin() ; mapIt != moduleList.end(); mapIt++ ) { lastRVA = (*mapIt).second.firstThunk - sizeof(DWORD_PTR); sizeOfApiAndModuleNames += (DWORD)(wcslen((*mapIt).second.moduleName) + 1); for ( mapIt2 = (*mapIt).second.thunkList.begin() ; mapIt2 != (*mapIt).second.thunkList.end(); mapIt2++ ) { if ((lastRVA + sizeof(DWORD_PTR)) != (*mapIt2).second.rva) { numberOfImportDescriptors++; //add additional import desc } if((*mapIt2).second.name[0] != '\0') { sizeOfApiAndModuleNames += sizeof(WORD); //Hint from IMAGE_IMPORT_BY_NAME sizeOfApiAndModuleNames += (DWORD)(strlen((*mapIt2).second.name) + 1); } lastRVA = (*mapIt2).second.rva; } } sizeOfImportSection = sizeOfApiAndModuleNames + (numberOfImportDescriptors * sizeof(IMAGE_IMPORT_DESCRIPTOR)); } \ No newline at end of file diff --git a/Scylla/MainGui.cpp b/Scylla/MainGui.cpp index 9825a45..1391533 100644 --- a/Scylla/MainGui.cpp +++ b/Scylla/MainGui.cpp @@ -1,1248 +1,1248 @@ #include "MainGui.h" #include "Architecture.h" //#include "PluginLoader.h" //#include "ConfigurationHolder.h" #include "PeDump.h" #include "PeRebuild.h" #include "DllInjectionPlugin.h" #include "DisassemblerGui.h" #include "PickApiGui.h" //#include "NativeWinApi.h" #include "ImportRebuild.h" #include "SystemInformation.h" #include "Scylla.h" #include "AboutGui.h" #include "OptionsGui.h" #include "TreeImportExport.h" extern CAppModule _Module; // o_O const WCHAR MainGui::filterExe[] = L"Executable (*.exe)\0*.exe\0All files\0*.*\0"; const WCHAR MainGui::filterDll[] = L"Dynamic Link Library (*.dll)\0*.dll\0All files\0*.*\0"; const WCHAR MainGui::filterExeDll[] = L"Executable (*.exe)\0*.exe\0Dynamic Link Library (*.dll)\0*.dll\0All files\0*.*\0"; const WCHAR MainGui::filterTxt[] = L"Text file (*.txt)\0*.txt\0All files\0*.*\0"; const WCHAR MainGui::filterXml[] = L"XML file (*.xml)\0*.xml\0All files\0*.*\0"; MainGui::MainGui() : selectedProcess(0), importsHandling(TreeImports), TreeImportsSubclass(this, IDC_TREE_IMPORTS) { /* Logger::getDebugLogFilePath(); ConfigurationHolder::loadConfiguration(); PluginLoader::findAllPlugins(); NativeWinApi::initialize(); SystemInformation::getSystemInformation(); if(ConfigurationHolder::getConfigObject(DEBUG_PRIVILEGE)->isTrue()) { processLister.setDebugPrivileges(); } ProcessAccessHelp::getProcessModules(GetCurrentProcessId(), ProcessAccessHelp::ownModuleList); */ Scylla::init(); hIcon.LoadIcon(IDI_ICON_SCYLLA); hMenuImports.LoadMenu(IDR_MENU_IMPORTS); hMenuLog.LoadMenu(IDR_MENU_LOG); accelerators.LoadAccelerators(IDR_ACCELERATOR_MAIN); hIconCheck.LoadIcon(IDI_ICON_CHECK, 16, 16); hIconWarning.LoadIcon(IDI_ICON_WARNING, 16, 16); hIconError.LoadIcon(IDI_ICON_ERROR, 16, 16); } BOOL MainGui::PreTranslateMessage(MSG* pMsg) { if(accelerators.TranslateAccelerator(m_hWnd, pMsg)) { return TRUE; // handled keyboard shortcuts } else if(IsDialogMessage(pMsg)) { return TRUE; // handled dialog messages } return FALSE; } BOOL MainGui::OnInitDialog(CWindow wndFocus, LPARAM lInitParam) { if (SystemInformation::currenOS == UNKNOWN_OS) { if(IDCANCEL == MessageBox(L"Operating System is not supported\r\nContinue anyway?", L"Scylla", MB_ICONWARNING | MB_OKCANCEL)) { SendMessage(WM_CLOSE); return FALSE; } } // register ourselves to receive PreTranslateMessage CMessageLoop* pLoop = _Module.GetMessageLoop(); pLoop->AddMessageFilter(this); setupStatusBar(); DoDataExchange(); // attach controls DlgResize_Init(true, true); // init CDialogResize Scylla::windowLog.setWindow(ListLog); appendPluginListToMenu(hMenuImports.GetSubMenu(0)); appendPluginListToMenu(CMenuHandle(GetMenu()).GetSubMenu(MenuImportsOffsetTrace)); enableDialogControls(FALSE); setIconAndDialogCaption(); return TRUE; } void MainGui::OnDestroy() { PostQuitMessage(0); } void MainGui::OnSize(UINT nType, CSize size) { StatusBar.SendMessage(WM_SIZE); SetMsgHandled(FALSE); } void MainGui::OnContextMenu(CWindow wnd, CPoint point) { switch(wnd.GetDlgCtrlID()) { case IDC_TREE_IMPORTS: DisplayContextMenuImports(wnd, point); return; case IDC_LIST_LOG: DisplayContextMenuLog(wnd, point); return; } SetMsgHandled(FALSE); } void MainGui::OnCommand(UINT uNotifyCode, int nID, CWindow wndCtl) { // Handle plugin trace menu selection if(uNotifyCode == 0 && !wndCtl.IsWindow()) // make sure it's a menu { if ((nID >= PLUGIN_MENU_BASE_ID) && (nID <= (int)(Scylla::plugins.getScyllaPluginList().size() + Scylla::plugins.getImprecPluginList().size() + PLUGIN_MENU_BASE_ID))) { pluginActionHandler(nID); return; } } SetMsgHandled(FALSE); } LRESULT MainGui::OnTreeImportsDoubleClick(const NMHDR* pnmh) { if(TreeImports.GetCount() < 1) return 0; // Get item under cursor CTreeItem over = findTreeItem(CPoint(GetMessagePos()), true); if(over && importsHandling.isImport(over)) { pickApiActionHandler(over); } return 0; } LRESULT MainGui::OnTreeImportsKeyDown(const NMHDR* pnmh) { const NMTVKEYDOWN * tkd = (NMTVKEYDOWN *)pnmh; switch(tkd->wVKey) { case VK_RETURN: { CTreeItem selected = TreeImports.GetFocusItem(); if(!selected.IsNull() && importsHandling.isImport(selected)) { pickApiActionHandler(selected); } } return 1; case VK_DELETE: deleteSelectedImportsActionHandler(); return 1; } SetMsgHandled(FALSE); return 0; } UINT MainGui::OnTreeImportsSubclassGetDlgCode(const MSG * lpMsg) { if(lpMsg) { switch(lpMsg->wParam) { case VK_RETURN: return DLGC_WANTMESSAGE; } } SetMsgHandled(FALSE); return 0; } void MainGui::OnTreeImportsSubclassChar(UINT nChar, UINT nRepCnt, UINT nFlags) { switch(nChar) { case VK_RETURN: break; default: SetMsgHandled(FALSE); break; } } void MainGui::OnProcessListDrop(UINT uNotifyCode, int nID, CWindow wndCtl) { fillProcessListComboBox(ComboProcessList); } void MainGui::OnProcessListSelected(UINT uNotifyCode, int nID, CWindow wndCtl) { processSelectedActionHandler(ComboProcessList.GetCurSel()); } void MainGui::OnPickDLL(UINT uNotifyCode, int nID, CWindow wndCtl) { pickDllActionHandler(); } void MainGui::OnOptions(UINT uNotifyCode, int nID, CWindow wndCtl) { optionsActionHandler(); } void MainGui::OnDump(UINT uNotifyCode, int nID, CWindow wndCtl) { dumpActionHandler(); } void MainGui::OnFixDump(UINT uNotifyCode, int nID, CWindow wndCtl) { dumpFixActionHandler(); } void MainGui::OnPERebuild(UINT uNotifyCode, int nID, CWindow wndCtl) { peRebuildActionHandler(); } void MainGui::OnDLLInject(UINT uNotifyCode, int nID, CWindow wndCtl) { dllInjectActionHandler(); } void MainGui::OnIATAutoSearch(UINT uNotifyCode, int nID, CWindow wndCtl) { iatAutosearchActionHandler(); } void MainGui::OnGetImports(UINT uNotifyCode, int nID, CWindow wndCtl) { getImportsActionHandler(); } void MainGui::OnInvalidImports(UINT uNotifyCode, int nID, CWindow wndCtl) { showInvalidImportsActionHandler(); } void MainGui::OnSuspectImports(UINT uNotifyCode, int nID, CWindow wndCtl) { showSuspectImportsActionHandler(); } void MainGui::OnClearImports(UINT uNotifyCode, int nID, CWindow wndCtl) { clearImportsActionHandler(); } void MainGui::OnInvalidateSelected(UINT uNotifyCode, int nID, CWindow wndCtl) { invalidateSelectedImportsActionHandler(); } void MainGui::OnCutSelected(UINT uNotifyCode, int nID, CWindow wndCtl) { deleteSelectedImportsActionHandler(); } void MainGui::OnSaveTree(UINT uNotifyCode, int nID, CWindow wndCtl) { saveTreeActionHandler(); } void MainGui::OnLoadTree(UINT uNotifyCode, int nID, CWindow wndCtl) { loadTreeActionHandler(); } void MainGui::OnAutotrace(UINT uNotifyCode, int nID, CWindow wndCtl) { // TODO } void MainGui::OnExit(UINT uNotifyCode, int nID, CWindow wndCtl) { DestroyWindow(); } void MainGui::OnAbout(UINT uNotifyCode, int nID, CWindow wndCtl) { showAboutDialog(); } void MainGui::setupStatusBar() { StatusBar.Create(m_hWnd, NULL, L"", WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_TOOLTIPS, NULL, IDC_STATUS_BAR); CRect rcMain, rcStatus; GetClientRect(&rcMain); StatusBar.GetWindowRect(&rcStatus); const int PARTS = 4; int widths[PARTS]; widths[PART_COUNT] = rcMain.Width() / 5; widths[PART_INVALID] = widths[PART_COUNT] + rcMain.Width() / 5; widths[PART_IMAGEBASE] = widths[PART_INVALID] + rcMain.Width() / 3; widths[PART_MODULE] = -1; StatusBar.SetParts(PARTS, widths); ResizeClient(rcMain.Width(), rcMain.Height() + rcStatus.Height(), FALSE); } void MainGui::updateStatusBar() { // Rewrite ImportsHandling so we get these easily unsigned int totalImports = importsHandling.thunkCount(); unsigned int invalidImports = importsHandling.invalidThunkCount(); // \t = center, \t\t = right-align swprintf_s(stringBuffer, _countof(stringBuffer), L"\tImports: %u", totalImports); StatusBar.SetText(PART_COUNT, stringBuffer); if(invalidImports > 0) { StatusBar.SetIcon(PART_INVALID, hIconError); } else { StatusBar.SetIcon(PART_INVALID, hIconCheck); } swprintf_s(stringBuffer, _countof(stringBuffer), L"\tInvalid: %u", invalidImports); StatusBar.SetText(PART_INVALID, stringBuffer); if(selectedProcess) { DWORD_PTR imageBase = 0; const WCHAR * fileName = 0; if(ProcessAccessHelp::selectedModule) { imageBase = ProcessAccessHelp::selectedModule->modBaseAddr; fileName = ProcessAccessHelp::selectedModule->getFilename(); } else { imageBase = selectedProcess->imageBase; fileName = selectedProcess->filename; } swprintf_s(stringBuffer, _countof(stringBuffer), L"\tImagebase: " PRINTF_DWORD_PTR_FULL, imageBase); StatusBar.SetText(PART_IMAGEBASE, stringBuffer); StatusBar.SetText(PART_MODULE, fileName); StatusBar.SetTipText(PART_MODULE, fileName); } else { StatusBar.SetText(PART_IMAGEBASE, L""); StatusBar.SetText(PART_MODULE, L""); } } bool MainGui::showFileDialog(WCHAR * selectedFile, bool save, const WCHAR * defFileName, const WCHAR * filter, const WCHAR * defExtension, const WCHAR * directory) { OPENFILENAME ofn = {0}; // WTL doesn't support new explorer styles on Vista and up // This is because it uses a custom hook, we could remove it or derive // from CFileDialog but this solution is easier and allows more control anyway (e.g. initial dir) if(defFileName) { wcscpy_s(selectedFile, MAX_PATH, defFileName); } else { selectedFile[0] = L'\0'; } ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = m_hWnd; ofn.lpstrFilter = filter; ofn.lpstrDefExt = defExtension; // only first 3 chars are used, no dots! ofn.lpstrFile = selectedFile; ofn.lpstrInitialDir = directory; ofn.nMaxFile = MAX_PATH; ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY; /* *OFN_EXPLORER is automatically used, it only has to be specified *if using a custom hook *OFN_LONGNAMES is automatically used by explorer-style dialogs */ if(save) ofn.Flags |= OFN_OVERWRITEPROMPT; else ofn.Flags |= OFN_FILEMUSTEXIST; if(save) return 0 != GetSaveFileName(&ofn); else return 0 != GetOpenFileName(&ofn); } void MainGui::setIconAndDialogCaption() { SetIcon(hIcon, TRUE); SetIcon(hIcon, FALSE); SetWindowText(APPNAME L" " ARCHITECTURE L" " APPVERSION); } void MainGui::pickDllActionHandler() { if(!selectedProcess) return; PickDllGui dlgPickDll(ProcessAccessHelp::moduleList); if(dlgPickDll.DoModal()) { //get selected module ProcessAccessHelp::selectedModule = dlgPickDll.getSelectedModule(); ProcessAccessHelp::targetImageBase = ProcessAccessHelp::selectedModule->modBaseAddr; Scylla::windowLog.log(L"->>> Module %s selected.", ProcessAccessHelp::selectedModule->getFilename()); Scylla::windowLog.log(L"Imagebase: " PRINTF_DWORD_PTR_FULL L" Size: %08X", ProcessAccessHelp::selectedModule->modBaseAddr, ProcessAccessHelp::selectedModule->modBaseSize); } else { ProcessAccessHelp::selectedModule = 0; } updateStatusBar(); } void MainGui::pickApiActionHandler(CTreeItem item) { if(!importsHandling.isImport(item)) return; // TODO: new node when user picked an API from another DLL? PickApiGui dlgPickApi(ProcessAccessHelp::moduleList); if(dlgPickApi.DoModal()) { const ApiInfo* api = dlgPickApi.getSelectedApi(); if(api && api->module) { importsHandling.setImport(item, api->module->getFilename(), api->name, api->ordinal, api->hint, true, api->isForwarded); } } updateStatusBar(); } void MainGui::startDisassemblerGui(CTreeItem selectedTreeNode) { if(!selectedProcess) return; DWORD_PTR address = importsHandling.getApiAddressByNode(selectedTreeNode); if (address) { BYTE test; if(!ProcessAccessHelp::readMemoryFromProcess(address, sizeof(test), &test)) { swprintf_s(stringBuffer, _countof(stringBuffer), L"Can't read memory at " PRINTF_DWORD_PTR_FULL, address); MessageBox(stringBuffer, L"Failure", MB_ICONERROR); } else { DisassemblerGui dlgDisassembler(address); dlgDisassembler.DoModal(); } } } void MainGui::processSelectedActionHandler(int index) { std::vector& processList = Scylla::processLister.getProcessList(); Process &process = processList.at(index); selectedProcess = 0; clearImportsActionHandler(); Scylla::windowLog.log(L"Analyzing %s", process.fullPath); if (ProcessAccessHelp::hProcess != 0) { ProcessAccessHelp::closeProcessHandle(); apiReader.clearAll(); } if (!ProcessAccessHelp::openProcessHandle(process.PID)) { enableDialogControls(FALSE); Scylla::windowLog.log(L"Error: Cannot open process handle."); updateStatusBar(); return; } ProcessAccessHelp::getProcessModules(process.PID, ProcessAccessHelp::moduleList); apiReader.readApisFromModuleList(); Scylla::windowLog.log(L"Loading modules done."); //TODO improve ProcessAccessHelp::selectedModule = 0; ProcessAccessHelp::targetSizeOfImage = process.imageSize; ProcessAccessHelp::targetImageBase = process.imageBase; ProcessAccessHelp::getSizeOfImageCurrentProcess(); process.imageSize = (DWORD)ProcessAccessHelp::targetSizeOfImage; Scylla::windowLog.log(L"Imagebase: " PRINTF_DWORD_PTR_FULL L" Size: %08X", process.imageBase, process.imageSize); process.entryPoint = ProcessAccessHelp::getEntryPointFromFile(process.fullPath); EditOEPAddress.SetValue(process.entryPoint + process.imageBase); selectedProcess = &process; enableDialogControls(TRUE); updateStatusBar(); } void MainGui::fillProcessListComboBox(CComboBox& hCombo) { hCombo.ResetContent(); std::vector& processList = Scylla::processLister.getProcessListSnapshot(); for (size_t i = 0; i < processList.size(); i++) { swprintf_s(stringBuffer, _countof(stringBuffer), L"0x%04X - %s - %s", processList[i].PID, processList[i].filename, processList[i].fullPath); hCombo.AddString(stringBuffer); } } /* void MainGui::addTextToOutputLog(const WCHAR * text) { if (m_hWnd) { ListLog.SetCurSel(ListLog.AddString(text)); } } */ void MainGui::clearOutputLog() { if (m_hWnd) { ListLog.ResetContent(); } } bool MainGui::saveLogToFile(const WCHAR * file) { const BYTE BOM[] = {0xFF, 0xFE}; // UTF-16 little-endian const WCHAR newLine[] = L"\r\n"; bool success = true; HANDLE hFile = CreateFile(file, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); if(hFile != INVALID_HANDLE_VALUE) { ProcessAccessHelp::writeMemoryToFileEnd(hFile, sizeof(BOM), BOM); WCHAR * buffer = 0; size_t bufsize = 0; for(int i = 0; i < ListLog.GetCount(); i++) { size_t size = ListLog.GetTextLen(i); size += _countof(newLine)-1; if(size+1 > bufsize) { bufsize = size+1; delete[] buffer; try { buffer = new WCHAR[bufsize]; } catch(std::bad_alloc&) { buffer = 0; success = false; break; } } ListLog.GetText(i, buffer); wcscat_s(buffer, bufsize, newLine); ProcessAccessHelp::writeMemoryToFileEnd(hFile, (DWORD)(size * sizeof(WCHAR)), buffer); } delete[] buffer; CloseHandle(hFile); } return success; } void MainGui::showInvalidImportsActionHandler() { importsHandling.selectImports(true, false); GotoDlgCtrl(TreeImports); } void MainGui::showSuspectImportsActionHandler() { importsHandling.selectImports(false, true); GotoDlgCtrl(TreeImports); } void MainGui::deleteSelectedImportsActionHandler() { CTreeItem selected = TreeImports.GetFirstSelectedItem(); while(!selected.IsNull()) { if(importsHandling.isModule(selected)) { importsHandling.cutModule(selected); } else { importsHandling.cutImport(selected); } selected = TreeImports.GetNextSelectedItem(selected); } updateStatusBar(); } void MainGui::invalidateSelectedImportsActionHandler() { CTreeItem selected = TreeImports.GetFirstSelectedItem(); while(!selected.IsNull()) { if(importsHandling.isImport(selected)) { importsHandling.invalidateImport(selected); } selected = TreeImports.GetNextSelectedItem(selected); } updateStatusBar(); } void MainGui::loadTreeActionHandler() { if(!selectedProcess) return; WCHAR selectedFilePath[MAX_PATH]; TreeImportExport treeIO; DWORD_PTR addrOEP = 0; DWORD_PTR addrIAT = 0; DWORD sizeIAT = 0; getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if(showFileDialog(selectedFilePath, false, NULL, filterXml, NULL, stringBuffer)) { if(!treeIO.importTreeList(selectedFilePath, importsHandling.moduleList, &addrOEP, &addrIAT, &sizeIAT)) { Scylla::windowLog.log(L"Loading tree file failed %s", selectedFilePath); MessageBox(L"Loading tree file failed.", L"Failure", MB_ICONERROR); } else { EditOEPAddress.SetValue(addrOEP); EditIATAddress.SetValue(addrIAT); EditIATSize.SetValue(sizeIAT); importsHandling.displayAllImports(); updateStatusBar(); Scylla::windowLog.log(L"Loaded tree file %s", selectedFilePath); Scylla::windowLog.log(L"-> OEP: " PRINTF_DWORD_PTR_FULL, addrOEP); Scylla::windowLog.log(L"-> IAT: " PRINTF_DWORD_PTR_FULL L" Size: " PRINTF_DWORD_PTR, addrIAT, sizeIAT); } } } void MainGui::saveTreeActionHandler() { if(!selectedProcess) return; WCHAR selectedFilePath[MAX_PATH]; TreeImportExport treeIO; DWORD_PTR addrOEP; DWORD_PTR addrIAT; DWORD sizeIAT; getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if(showFileDialog(selectedFilePath, true, NULL, filterXml, L"xml", stringBuffer)) { addrOEP = EditOEPAddress.GetValue(); addrIAT = EditIATAddress.GetValue(); sizeIAT = EditIATSize.GetValue(); if(!treeIO.exportTreeList(selectedFilePath, importsHandling.moduleList, selectedProcess, addrOEP, addrIAT, sizeIAT)) { Scylla::windowLog.log(L"Saving tree file failed %s", selectedFilePath); MessageBox(L"Saving tree file failed.", L"Failure", MB_ICONERROR); } else { Scylla::windowLog.log(L"Saved tree file %s", selectedFilePath); } } } void MainGui::iatAutosearchActionHandler() { DWORD_PTR searchAddress = 0; DWORD_PTR addressIAT = 0; DWORD sizeIAT = 0; IATSearch iatSearch; if(!selectedProcess) return; if(EditOEPAddress.GetWindowTextLength() > 0) { searchAddress = EditOEPAddress.GetValue(); if (searchAddress) { if (iatSearch.searchImportAddressTableInProcess(searchAddress, &addressIAT, &sizeIAT)) { Scylla::windowLog.log(L"IAT found at VA " PRINTF_DWORD_PTR_FULL L" RVA " PRINTF_DWORD_PTR_FULL L" Size 0x%04X (%d)", addressIAT, addressIAT - ProcessAccessHelp::targetImageBase, sizeIAT, sizeIAT); EditIATAddress.SetValue(addressIAT); EditIATSize.SetValue(sizeIAT); swprintf_s(stringBuffer, _countof(stringBuffer), L"IAT found:\r\n\r\nStart: " PRINTF_DWORD_PTR_FULL L"\r\nSize: 0x%04X (%d) ", addressIAT, sizeIAT, sizeIAT); MessageBox(stringBuffer, L"IAT found", MB_ICONINFORMATION); } else { Scylla::windowLog.log(L"IAT not found at OEP " PRINTF_DWORD_PTR_FULL L"!", searchAddress); } } } } void MainGui::getImportsActionHandler() { if(!selectedProcess) return; DWORD_PTR addressIAT = EditIATAddress.GetValue(); DWORD sizeIAT = EditIATSize.GetValue(); if (addressIAT && sizeIAT) { apiReader.readAndParseIAT(addressIAT, sizeIAT, importsHandling.moduleList); importsHandling.displayAllImports(); updateStatusBar(); } } void MainGui::SetupImportsMenuItems(CTreeItem item) { bool isItem, isImport = false; isItem = !item.IsNull(); if(isItem) { isImport = importsHandling.isImport(item); } CMenuHandle hSub = hMenuImports.GetSubMenu(0); UINT itemOnly = isItem ? MF_ENABLED : MF_GRAYED; UINT importOnly = isImport ? MF_ENABLED : MF_GRAYED; hSub.EnableMenuItem(ID__INVALIDATE, itemOnly); hSub.EnableMenuItem(ID__DISASSEMBLE, importOnly); hSub.EnableMenuItem(ID__CUTTHUNK, importOnly); hSub.EnableMenuItem(ID__DELETETREENODE, itemOnly); } void MainGui::DisplayContextMenuImports(CWindow hwnd, CPoint pt) { if(TreeImports.GetCount() < 1) return; CTreeItem over, parent; if(pt.x == -1 && pt.y == -1) // invoked by keyboard { CRect pos; over = TreeImports.GetFocusItem(); if(over) { over.EnsureVisible(); over.GetRect(&pos, TRUE); TreeImports.ClientToScreen(&pos); } else { TreeImports.GetWindowRect(&pos); } pt = pos.TopLeft(); } else { // Get item under cursor over = findTreeItem(pt, true); } SetupImportsMenuItems(over); CMenuHandle hSub = hMenuImports.GetSubMenu(0); BOOL menuItem = hSub.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD, pt.x, pt.y, hwnd); if (menuItem) { if ((menuItem >= PLUGIN_MENU_BASE_ID) && (menuItem <= (int)(Scylla::plugins.getScyllaPluginList().size() + Scylla::plugins.getImprecPluginList().size() + PLUGIN_MENU_BASE_ID))) { //wsprintf(stringBuffer, L"%d %s\n",menuItem,pluginList[menuItem - PLUGIN_MENU_BASE_ID].pluginName); //MessageBox(stringBuffer, L"plugin selection"); pluginActionHandler(menuItem); return; } switch (menuItem) { case ID__INVALIDATE: if(importsHandling.isModule(over)) importsHandling.invalidateModule(over); else importsHandling.invalidateImport(over); break; case ID__DISASSEMBLE: startDisassemblerGui(over); break; case ID__EXPANDALLNODES: importsHandling.expandAllTreeNodes(); break; case ID__COLLAPSEALLNODES: importsHandling.collapseAllTreeNodes(); break; case ID__CUTTHUNK: importsHandling.cutImport(over); break; case ID__DELETETREENODE: importsHandling.cutModule(importsHandling.isImport(over) ? over.GetParent() : over); break; } } updateStatusBar(); } void MainGui::DisplayContextMenuLog(CWindow hwnd, CPoint pt) { if(pt.x == -1 && pt.y == -1) // invoked by keyboard { CRect pos; ListLog.GetWindowRect(&pos); pt = pos.TopLeft(); } CMenuHandle hSub = hMenuLog.GetSubMenu(0); BOOL menuItem = hSub.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD, pt.x, pt.y, hwnd); if (menuItem) { switch (menuItem) { case ID__SAVE: WCHAR selectedFilePath[MAX_PATH]; getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if(showFileDialog(selectedFilePath, true, NULL, filterTxt, L"txt", stringBuffer)) { saveLogToFile(selectedFilePath); } break; case ID__CLEAR: clearOutputLog(); break; } } } void MainGui::appendPluginListToMenu(CMenuHandle hMenu) { std::vector &scyllaPluginList = Scylla::plugins.getScyllaPluginList(); std::vector &imprecPluginList = Scylla::plugins.getImprecPluginList(); if (scyllaPluginList.size() > 0) { CMenuHandle newMenu; newMenu.CreatePopupMenu(); for (size_t i = 0; i < scyllaPluginList.size(); i++) { newMenu.AppendMenu(MF_STRING, i + PLUGIN_MENU_BASE_ID, scyllaPluginList[i].pluginName); } hMenu.AppendMenu(MF_MENUBARBREAK); hMenu.AppendMenu(MF_POPUP, newMenu, L"Scylla Plugins"); } if (imprecPluginList.size() > 0) { CMenuHandle newMenu; newMenu.CreatePopupMenu(); for (size_t i = 0; i < imprecPluginList.size(); i++) { newMenu.AppendMenu(MF_STRING, scyllaPluginList.size() + i + PLUGIN_MENU_BASE_ID, imprecPluginList[i].pluginName); } hMenu.AppendMenu(MF_MENUBARBREAK); hMenu.AppendMenu(MF_POPUP, newMenu, L"ImpREC Plugins"); } } void MainGui::dumpActionHandler() { if(!selectedProcess) return; WCHAR selectedFilePath[MAX_PATH]; const WCHAR * fileFilter; const WCHAR * defExtension; PeDump peDump; if (ProcessAccessHelp::selectedModule) { fileFilter = filterDll; defExtension = L"dll"; } else { fileFilter = filterExe; defExtension = L"exe"; } getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if(showFileDialog(selectedFilePath, true, NULL, fileFilter, defExtension, stringBuffer)) { if (ProcessAccessHelp::selectedModule) { //dump DLL peDump.imageBase = ProcessAccessHelp::selectedModule->modBaseAddr; peDump.sizeOfImage = ProcessAccessHelp::selectedModule->modBaseSize; //get it from gui peDump.entryPoint = EditOEPAddress.GetValue(); wcscpy_s(peDump.fullpath, _countof(peDump.fullpath), ProcessAccessHelp::selectedModule->fullPath); } else { peDump.imageBase = ProcessAccessHelp::targetImageBase; peDump.sizeOfImage = (DWORD)ProcessAccessHelp::targetSizeOfImage; //get it from gui peDump.entryPoint = EditOEPAddress.GetValue(); wcscpy_s(peDump.fullpath, _countof(peDump.fullpath), selectedProcess->fullPath); } - peDump.useHeaderFromDisk = Scylla::config.getConfigObject(USE_PE_HEADER_FROM_DISK)->isTrue(); + peDump.useHeaderFromDisk = Scylla::config[USE_PE_HEADER_FROM_DISK].isTrue(); if (peDump.dumpCompleteProcessToDisk(selectedFilePath)) { Scylla::windowLog.log(L"Dump success %s", selectedFilePath); } else { Scylla::windowLog.log(L"Error: Cannot dump image."); MessageBox(L"Cannot dump image.", L"Failure", MB_ICONERROR); } } } void MainGui::peRebuildActionHandler() { DWORD newSize = 0; WCHAR selectedFilePath[MAX_PATH]; PeRebuild peRebuild; getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if(showFileDialog(selectedFilePath, false, NULL, filterExeDll, NULL, stringBuffer)) { - if (Scylla::config.getConfigObject(CREATE_BACKUP)->isTrue()) + if (Scylla::config[CREATE_BACKUP].isTrue()) { if (!ProcessAccessHelp::createBackupFile(selectedFilePath)) { Scylla::windowLog.log(L"Creating backup file failed %s", selectedFilePath); } } LONGLONG fileSize = ProcessAccessHelp::getFileSize(selectedFilePath); LPVOID mapped = peRebuild.createFileMappingViewFull(selectedFilePath); newSize = peRebuild.realignPE(mapped, (DWORD)fileSize); peRebuild.closeAllMappingHandles(); if (newSize < 10) { Scylla::windowLog.log(L"Rebuild failed %s", selectedFilePath); MessageBox(L"Rebuild failed.", L"Failure", MB_ICONERROR); } else { peRebuild.truncateFile(selectedFilePath, newSize); Scylla::windowLog.log(L"Rebuild success %s", selectedFilePath); Scylla::windowLog.log(L"-> Old file size 0x%08X new file size 0x%08X (%d %%)", (DWORD)fileSize, newSize, (DWORD)((newSize * 100) / (DWORD)fileSize) ); } } } void MainGui::dumpFixActionHandler() { if(!selectedProcess) return; if (TreeImports.GetCount() < 2) { Scylla::windowLog.log(L"Nothing to rebuild"); return; } WCHAR newFilePath[MAX_PATH]; WCHAR selectedFilePath[MAX_PATH]; const WCHAR * fileFilter; if (ProcessAccessHelp::selectedModule) { fileFilter = filterDll; } else { fileFilter = filterExe; } getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if (showFileDialog(selectedFilePath, false, NULL, fileFilter, NULL, stringBuffer)) { wcscpy_s(newFilePath,_countof(newFilePath),selectedFilePath); const WCHAR * extension = 0; WCHAR* dot = wcsrchr(newFilePath, L'.'); if (dot) { *dot = L'\0'; extension = selectedFilePath + (dot - newFilePath); //wcsrchr(selectedFilePath, L'.'); } wcscat_s(newFilePath, _countof(newFilePath), L"_SCY"); if(extension) { wcscat_s(newFilePath, _countof(newFilePath), extension); } ImportRebuild importRebuild; if (importRebuild.rebuildImportTable(selectedFilePath,newFilePath,importsHandling.moduleList)) { Scylla::windowLog.log(L"Import Rebuild success %s", newFilePath); } else { Scylla::windowLog.log(L"Import Rebuild failed %s", selectedFilePath); MessageBox(L"Import Rebuild failed", L"Failure", MB_ICONERROR); } } } void MainGui::enableDialogControls(BOOL value) { BOOL valButton = value ? TRUE : FALSE; GetDlgItem(IDC_BTN_PICKDLL).EnableWindow(valButton); GetDlgItem(IDC_BTN_DUMP).EnableWindow(valButton); GetDlgItem(IDC_BTN_FIXDUMP).EnableWindow(valButton); GetDlgItem(IDC_BTN_IATAUTOSEARCH).EnableWindow(valButton); GetDlgItem(IDC_BTN_GETIMPORTS).EnableWindow(valButton); GetDlgItem(IDC_BTN_SUSPECTIMPORTS).EnableWindow(valButton); GetDlgItem(IDC_BTN_INVALIDIMPORTS).EnableWindow(valButton); GetDlgItem(IDC_BTN_CLEARIMPORTS).EnableWindow(valButton); CMenuHandle menu = GetMenu(); UINT valMenu = value ? MF_ENABLED : MF_GRAYED; menu.EnableMenuItem(ID_FILE_DUMP, valMenu); menu.EnableMenuItem(ID_FILE_FIXDUMP, valMenu); menu.EnableMenuItem(ID_IMPORTS_INVALIDATESELECTED, valMenu); menu.EnableMenuItem(ID_IMPORTS_CUTSELECTED, valMenu); menu.EnableMenuItem(ID_IMPORTS_SAVETREE, valMenu); menu.EnableMenuItem(ID_IMPORTS_LOADTREE, valMenu); menu.EnableMenuItem(ID_MISC_DLLINJECTION, valMenu); menu.GetSubMenu(MenuImportsOffsetTrace).EnableMenuItem(MenuImportsTraceOffsetScylla, MF_BYPOSITION | valMenu); menu.GetSubMenu(MenuImportsOffsetTrace).EnableMenuItem(MenuImportsTraceOffsetImpRec, MF_BYPOSITION | valMenu); //not yet implemented GetDlgItem(IDC_BTN_AUTOTRACE).EnableWindow(FALSE); menu.EnableMenuItem(ID_TRACE_AUTOTRACE, MF_GRAYED); } CTreeItem MainGui::findTreeItem(CPoint pt, bool screenCoordinates) { if(screenCoordinates) { TreeImports.ScreenToClient(&pt); } UINT flags; CTreeItem over = TreeImports.HitTest(pt, &flags); if(over) { if(!(flags & TVHT_ONITEM)) { over.m_hTreeItem = NULL; } } return over; } void MainGui::showAboutDialog() { AboutGui dlgAbout; dlgAbout.DoModal(); } void MainGui::dllInjectActionHandler() { if(!selectedProcess) return; WCHAR selectedFilePath[MAX_PATH]; HMODULE hMod = 0; DllInjection dllInjection; getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if (showFileDialog(selectedFilePath, false, NULL, filterDll, NULL, stringBuffer)) { hMod = dllInjection.dllInjection(ProcessAccessHelp::hProcess, selectedFilePath); - if (hMod && Scylla::config.getConfigObject(DLL_INJECTION_AUTO_UNLOAD)->isTrue()) + if (hMod && Scylla::config[DLL_INJECTION_AUTO_UNLOAD].isTrue()) { if (!dllInjection.unloadDllInProcess(ProcessAccessHelp::hProcess, hMod)) { Scylla::windowLog.log(L"DLL unloading failed, target %s", selectedFilePath); } } if (hMod) { Scylla::windowLog.log(L"DLL Injection was successful, target %s", selectedFilePath); } else { Scylla::windowLog.log(L"DLL Injection failed, target %s", selectedFilePath); } } } void MainGui::optionsActionHandler() { OptionsGui dlgOptions; dlgOptions.DoModal(); } void MainGui::clearImportsActionHandler() { importsHandling.clearAllImports(); updateStatusBar(); } void MainGui::pluginActionHandler( int menuItem ) { if(!selectedProcess) return; DllInjectionPlugin dllInjectionPlugin; std::vector &scyllaPluginList = Scylla::plugins.getScyllaPluginList(); std::vector &imprecPluginList = Scylla::plugins.getImprecPluginList(); menuItem -= PLUGIN_MENU_BASE_ID; dllInjectionPlugin.hProcess = ProcessAccessHelp::hProcess; dllInjectionPlugin.apiReader = &apiReader; if (menuItem < (int)scyllaPluginList.size()) { //scylla plugin dllInjectionPlugin.injectPlugin(scyllaPluginList[menuItem], importsHandling.moduleList,selectedProcess->imageBase, selectedProcess->imageSize); } else { #ifndef _WIN64 menuItem -= (int)scyllaPluginList.size(); //imprec plugin dllInjectionPlugin.injectImprecPlugin(imprecPluginList[menuItem], importsHandling.moduleList,selectedProcess->imageBase, selectedProcess->imageSize); #endif } importsHandling.scanAndFixModuleList(); importsHandling.displayAllImports(); updateStatusBar(); } bool MainGui::getCurrentModulePath(TCHAR * buffer, size_t bufferSize) { if(!selectedProcess) return false; if(ProcessAccessHelp::selectedModule) { wcscpy_s(buffer, bufferSize, ProcessAccessHelp::selectedModule->fullPath); } else { wcscpy_s(buffer, bufferSize, selectedProcess->fullPath); } WCHAR * slash = wcsrchr(buffer, L'\\'); if(slash) { *(slash+1) = L'\0'; } return true; } diff --git a/Scylla/OptionsGui.cpp b/Scylla/OptionsGui.cpp index f29cb36..f56795a 100644 --- a/Scylla/OptionsGui.cpp +++ b/Scylla/OptionsGui.cpp @@ -1,89 +1,48 @@ #include "OptionsGui.h" #include "Scylla.h" BOOL OptionsGui::OnInitDialog(CWindow wndFocus, LPARAM lInitParam) { loadOptions(); DoDataExchange(DDX_LOAD); // show settings EditSectionName.LimitText(IMAGE_SIZEOF_SHORT_NAME); CenterWindow(); return TRUE; } void OptionsGui::OnOK(UINT uNotifyCode, int nID, CWindow wndCtl) { DoDataExchange(DDX_SAVE); saveOptions(); Scylla::config.saveConfiguration(); EndDialog(0); } void OptionsGui::OnCancel(UINT uNotifyCode, int nID, CWindow wndCtl) { EndDialog(0); } -void OptionsGui::saveOptions() +void OptionsGui::saveOptions() const { - std::map::iterator mapIter; - - for (mapIter = Scylla::config.getConfigList().begin() ; mapIter != Scylla::config.getConfigList().end(); mapIter++) - { - switch(mapIter->first) - { - case USE_PE_HEADER_FROM_DISK: - usePEHeaderFromDisk ? mapIter->second.setTrue() : mapIter->second.setFalse(); - break; - case DEBUG_PRIVILEGE: - debugPrivilege ? mapIter->second.setTrue() : mapIter->second.setFalse(); - break; - case CREATE_BACKUP: - createBackup ? mapIter->second.setTrue() : mapIter->second.setFalse(); - break; - case DLL_INJECTION_AUTO_UNLOAD: - dllInjectionAutoUnload ? mapIter->second.setTrue() : mapIter->second.setFalse(); - break; - case UPDATE_HEADER_CHECKSUM: - updateHeaderChecksum ? mapIter->second.setTrue() : mapIter->second.setFalse(); - break; - case IAT_SECTION_NAME: - wcscpy_s(mapIter->second.valueString, _countof(mapIter->second.valueString), iatSectionName); - break; - } - } + Scylla::config[USE_PE_HEADER_FROM_DISK].setBool(usePEHeaderFromDisk); + Scylla::config[DEBUG_PRIVILEGE].setBool(debugPrivilege); + Scylla::config[CREATE_BACKUP].setBool(createBackup); + Scylla::config[DLL_INJECTION_AUTO_UNLOAD].setBool(dllInjectionAutoUnload); + Scylla::config[UPDATE_HEADER_CHECKSUM].setBool(updateHeaderChecksum); + Scylla::config[IAT_SECTION_NAME].setString(iatSectionName); } void OptionsGui::loadOptions() { - std::map::iterator mapIter; - - for (mapIter = Scylla::config.getConfigList().begin() ; mapIter != Scylla::config.getConfigList().end(); mapIter++) - { - switch(mapIter->first) - { - case USE_PE_HEADER_FROM_DISK: - usePEHeaderFromDisk = mapIter->second.isTrue(); - break; - case DEBUG_PRIVILEGE: - debugPrivilege = mapIter->second.isTrue(); - break; - case CREATE_BACKUP: - createBackup = mapIter->second.isTrue(); - break; - case DLL_INJECTION_AUTO_UNLOAD: - dllInjectionAutoUnload = mapIter->second.isTrue(); - break; - case UPDATE_HEADER_CHECKSUM: - updateHeaderChecksum = mapIter->second.isTrue(); - break; - case IAT_SECTION_NAME: - wcsncpy_s(iatSectionName, _countof(iatSectionName), mapIter->second.valueString, _countof(iatSectionName)-1); - iatSectionName[_countof(iatSectionName)-1] = L'\0'; - break; - } - } + usePEHeaderFromDisk = Scylla::config[USE_PE_HEADER_FROM_DISK].getBool(); + debugPrivilege = Scylla::config[DEBUG_PRIVILEGE].getBool(); + createBackup = Scylla::config[CREATE_BACKUP].getBool(); + dllInjectionAutoUnload = Scylla::config[DLL_INJECTION_AUTO_UNLOAD].getBool(); + updateHeaderChecksum = Scylla::config[UPDATE_HEADER_CHECKSUM].getBool(); + wcsncpy_s(iatSectionName, Scylla::config[IAT_SECTION_NAME].getString(), _countof(iatSectionName)-1); } diff --git a/Scylla/OptionsGui.h b/Scylla/OptionsGui.h index 422bfc2..8d3fd95 100644 --- a/Scylla/OptionsGui.h +++ b/Scylla/OptionsGui.h @@ -1,63 +1,63 @@ #pragma once #include #include "resource.h" // WTL #include // base ATL classes #include // base WTL classes #include // ATL GUI classes #include // WTL enhanced msg map macros #include // WTL controls #include // WTL dialog data exchange class OptionsGui : public CDialogImpl, public CWinDataExchange { public: enum { IDD = IDD_DLG_OPTIONS }; BEGIN_DDX_MAP(OptionsGui) DDX_CONTROL_HANDLE(IDC_OPTIONS_SECTIONNAME, EditSectionName) DDX_TEXT(IDC_OPTIONS_SECTIONNAME, iatSectionName) DDX_CHECK(IDC_CHECK_HEADER_CHECKSUM, updateHeaderChecksum) DDX_CHECK(IDC_CHECK_CREATE_BACKUP, createBackup) DDX_CHECK(IDC_CHECK_UNLOAD_DLL, dllInjectionAutoUnload) DDX_CHECK(IDC_CHECK_PE_HEADER_FROM_DISK, usePEHeaderFromDisk) DDX_CHECK(IDC_CHECK_DEBUG_PRIVILEGES, debugPrivilege) END_DDX_MAP() BEGIN_MSG_MAP(OptionsGui) MSG_WM_INITDIALOG(OnInitDialog) COMMAND_ID_HANDLER_EX(IDC_BTN_OPTIONS_OK, OnOK) COMMAND_ID_HANDLER_EX(IDC_BTN_OPTIONS_CANCEL, OnCancel) COMMAND_ID_HANDLER_EX(IDCANCEL, OnCancel) END_MSG_MAP() protected: // Settings (filled by DDX) WCHAR iatSectionName[IMAGE_SIZEOF_SHORT_NAME+1]; bool updateHeaderChecksum; bool createBackup; bool dllInjectionAutoUnload; bool usePEHeaderFromDisk; bool debugPrivilege; // Controls CEdit EditSectionName; // Message handlers BOOL OnInitDialog(CWindow wndFocus, LPARAM lInitParam); void OnOK(UINT uNotifyCode, int nID, CWindow wndCtl); void OnCancel(UINT uNotifyCode, int nID, CWindow wndCtl); // Gui helpers - void saveOptions(); + void saveOptions() const; void loadOptions(); }; diff --git a/Scylla/PeRebuild.cpp b/Scylla/PeRebuild.cpp index a8106af..0d50ec6 100644 --- a/Scylla/PeRebuild.cpp +++ b/Scylla/PeRebuild.cpp @@ -1,736 +1,736 @@ #include "PeRebuild.h" #include #pragma comment(lib,"imagehlp.lib") #include "ProcessAccessHelp.h" #include "Scylla.h" //#include "ConfigurationHolder.h" //#define DEBUG_COMMENTS bool PeRebuild::truncateFile(WCHAR * szFilePath, DWORD dwNewFsize) { bool retValue = true; HANDLE hFile = CreateFile(szFilePath,GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (hFile == INVALID_HANDLE_VALUE) { return false; } if (SetFilePointer(hFile, dwNewFsize, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER) { if (GetLastError() == NO_ERROR) { retValue = true; } else { retValue = false; } } else { retValue = true; } if (!SetEndOfFile(hFile)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"SetEndOfFile failed error %d", GetLastError()); #endif retValue = false; } CloseHandle(hFile); return retValue; } DWORD PeRebuild::validAlignment(DWORD BadSize) { div_t DivRes; DivRes = div(BadSize, FileAlignmentConstant); if (DivRes.rem == 0) return BadSize; return ((DivRes.quot+1) * FileAlignmentConstant); } DWORD PeRebuild::validAlignmentNew(DWORD badAddress) { DWORD moduloResult = badAddress % FileAlignmentConstant; if (moduloResult) { return (FileAlignmentConstant - moduloResult); } else { return 0; } } bool PeRebuild::isRoundedTo(DWORD_PTR dwTarNum, DWORD_PTR dwRoundNum) { return (dwTarNum % dwRoundNum) == 0; // WTF: /* #ifdef _WIN64 lldiv_t d; d = div((__int64)dwTarNum, (__int64)dwRoundNum); #else ldiv_t d; d = div((long)dwTarNum, (long)dwRoundNum); #endif return (d.rem == 0); */ } void PeRebuild::cleanSectionPointer() { if (pSections) { for (int j = 0; j < MAX_SEC_NUM; j++) { if (pSections[j]) { free(pSections[j]); pSections[j] = 0; } } } } DWORD PeRebuild::realignPE(LPVOID AddressOfMapFile, DWORD dwFsize) { PIMAGE_DOS_HEADER pDosh = 0; PIMAGE_NT_HEADERS pPeh = 0; PIMAGE_SECTION_HEADER pSectionh = 0; int i = 0; DWORD extraAlign = 0; ZeroMemory(&pSections, sizeof(pSections)); // get the other parameters pMap = AddressOfMapFile; dwMapBase = (DWORD_PTR)pMap; if (dwFsize == 0 || pMap == NULL) return 1; // access the PE Header and check whether it's a valid one pDosh = (PIMAGE_DOS_HEADER)(pMap); pPeh = (PIMAGE_NT_HEADERS)((DWORD_PTR)pDosh+pDosh->e_lfanew); if (!validatePeHeaders(pDosh)) { return 0; } if (pPeh->FileHeader.NumberOfSections > MAX_SEC_NUM) { return 3; } __try { /* START */ pPeh->OptionalHeader.FileAlignment = FileAlignmentConstant; /* Realign the PE Header */ // get the size of all headers dwTmpNum = FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) + pPeh->FileHeader.SizeOfOptionalHeader + (pPeh->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER)); // kill room between the "win32 pls" message and the PE signature // find the end of the message pW = (WORD*)(dwMapBase + ScanStartDS); while (*pW != 0 || (!isRoundedTo((DWORD_PTR)pW, 0x10))) { pW = (WORD*)((DWORD_PTR)pW + 1); } wTmpNum = (WORD)((DWORD_PTR)pW - dwMapBase); if (wTmpNum < pDosh->e_lfanew) { CopyMemory((LPVOID)pW,(VOID*)pPeh,dwTmpNum); // copy the Header to the right place pDosh->e_lfanew = wTmpNum; } dwSectionBase = validAlignment(dwTmpNum + pDosh->e_lfanew); pPeh = (PIMAGE_NT_HEADERS)(dwMapBase + pDosh->e_lfanew); // because the NT header moved // correct the SizeOfHeaders pPeh->OptionalHeader.SizeOfHeaders = dwSectionBase; /* Realign all sections */ // make a copy of all sections // this is needed if the sections aren't sorted by their RawOffset (e.g. Petite) pSectionh = IMAGE_FIRST_SECTION(pPeh); for (i=0; iFileHeader.NumberOfSections; i++) { if (pSectionh->SizeOfRawData == 0 || pSectionh->PointerToRawData == 0) { ++pSectionh; continue; } // get a valid size dwTmpNum = pSectionh->SizeOfRawData; if ((pSectionh->SizeOfRawData + pSectionh->PointerToRawData) > dwFsize) { dwTmpNum = dwFsize - pSectionh->PointerToRawData; } //dwTmpNum -= 1; // copy the section into some memory // limit max section size to 300 MB = 300000 KB = 300000000 B if (dwTmpNum > 300000000) { dwTmpNum = 300000000; } //because of validAlignment we need some extra space, max 0x200 extra extraAlign = validAlignmentNew(dwTmpNum); pSections[i] = malloc(dwTmpNum + extraAlign); ZeroMemory(pSections[i], dwTmpNum + extraAlign); if (pSections[i] == NULL) // fatal error !!! { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"realignPE :: malloc failed with dwTmpNum %08X %08X", dwTmpNum, extraAlign); #endif cleanSectionPointer(); return 4; } CopyMemory(pSections[i],(LPVOID)(pSectionh->PointerToRawData+dwMapBase),dwTmpNum); ++pSectionh; } // start realigning the sections pSectionh = IMAGE_FIRST_SECTION(pPeh); for (i=0;iFileHeader.NumberOfSections;i++) { // some anti crash code :P if (pSectionh->SizeOfRawData == 0 || pSectionh->PointerToRawData == 0) { ++pSectionh; if (pSectionh->PointerToRawData == 0) { continue; } pSectionh->PointerToRawData = dwSectionBase; continue; } // let pCH point to the end of the current section if ((pSectionh->PointerToRawData+pSectionh->SizeOfRawData) <= dwFsize) { pCH = (char*)(dwMapBase+pSectionh->PointerToRawData+pSectionh->SizeOfRawData-1); } else { pCH = (char*)(dwMapBase+dwFsize-1); } // look for the end of this section while (*pCH == 0) { --pCH; } // calculate the new RawSize dwTmpNum = (DWORD)(((DWORD_PTR)pCH - dwMapBase) + MinSectionTerm - pSectionh->PointerToRawData); if (dwTmpNum < pSectionh->SizeOfRawData) { pSectionh->SizeOfRawData = dwTmpNum; } else // the new size is too BIG { dwTmpNum = pSectionh->SizeOfRawData; } // copy the section to the new place if (i != pPeh->FileHeader.NumberOfSections-1) { dwTmpNum = validAlignment(dwTmpNum); } CopyMemory((LPVOID)(dwMapBase+dwSectionBase), pSections[i], dwTmpNum); // set the RawOffset pSectionh->PointerToRawData = dwSectionBase; // get the RawOffset for the next section dwSectionBase = dwTmpNum+dwSectionBase; // the last section doesn't need to be aligned // go to the next section ++pSectionh; } // delete bound import directories because it is destroyed if present pPeh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0; pPeh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0; // clean up cleanSectionPointer(); } __except(1) { // clean up cleanSectionPointer(); #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"realignPE :: Exception occured"); #endif return 0; } - if (Scylla::config.getConfigObject(UPDATE_HEADER_CHECKSUM)->isTrue()) + if (Scylla::config[UPDATE_HEADER_CHECKSUM].isTrue()) { updatePeHeaderChecksum(AddressOfMapFile, dwSectionBase); } return dwSectionBase; // return the new filesize } // returns: // -1 - access violation // -2 - no relocation found // -3 - no own section // -4 - dll characteristics found // -5 - invalid PE file // else the new raw size DWORD PeRebuild::wipeReloc(void* pMap, DWORD dwFsize) { PIMAGE_DOS_HEADER pDosH; PIMAGE_NT_HEADERS pNTH; PIMAGE_SECTION_HEADER pSecH; PIMAGE_SECTION_HEADER pSH, pSH2; DWORD dwRelocRVA, i; BOOL bOwnSec = FALSE; DWORD dwNewFsize; __try // =) { // get pe header pointers pDosH = (PIMAGE_DOS_HEADER)pMap; if (pDosH->e_magic != IMAGE_DOS_SIGNATURE) return -5; pNTH = (PIMAGE_NT_HEADERS)((DWORD_PTR)pDosH + pDosH->e_lfanew); if (pNTH->Signature != IMAGE_NT_SIGNATURE) return -5; pSecH = IMAGE_FIRST_SECTION(pNTH); // has PE dll characteristics ? if (pNTH->FileHeader.Characteristics & IMAGE_FILE_DLL) return -4; // is there a reloc section ? dwRelocRVA = pNTH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress; if (!dwRelocRVA) return -2; // check whether the relocation has an own section pSH = pSecH; for (i=0; i < pNTH->FileHeader.NumberOfSections; i++) { if (pSH->VirtualAddress == dwRelocRVA) { bOwnSec = TRUE; break; // pSH -> reloc section header and i == section index } ++pSH; } if (!bOwnSec) return -3; if (i+1 == pNTH->FileHeader.NumberOfSections) { //--- relocation is the last section --- // truncate at the start of the reloc section dwNewFsize = pSH->PointerToRawData; } else { //--- relocation isn't the last section --- dwNewFsize = dwFsize - pSH->SizeOfRawData; //-> copy the section(s) after the relocation to the start of the relocation pSH2 = pSH; ++pSH2; // pSH2 -> pointer to first section after relocation memcpy( (void*)(pSH->PointerToRawData + (DWORD)pMap), (const void*)(pSH2->PointerToRawData + (DWORD)pMap), dwFsize - pSH2->PointerToRawData); //-> fix the section headers // (pSH -> reloc section header) // (pSH2 -> first section after reloc section) for (++i; i < pNTH->FileHeader.NumberOfSections; i++) { // apply important values pSH->SizeOfRawData = pSH2->SizeOfRawData; pSH->VirtualAddress = pSH2->VirtualAddress; pSH->Misc.VirtualSize = pSH2->Misc.VirtualSize; // apply section name memcpy( (void*)(pSH->Name), (const void*)(pSH2->Name), sizeof(pSH2->Name)); ++pSH; ++pSH2; } } // dec section number --pNTH->FileHeader.NumberOfSections; // kill reloc directory entry pNTH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = 0; pNTH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = 0; // fix virtual parts of the PE Header (a must for win2k) pSH2 = pSH = pSecH; ++pSH2; for (i=0; i < (DWORD)pNTH->FileHeader.NumberOfSections-1; i++) { pSH->Misc.VirtualSize = pSH2->VirtualAddress - pSH->VirtualAddress; ++pSH; ++pSH2; } // (pSH -> pointer to last section) if (pSH->Misc.PhysicalAddress) pNTH->OptionalHeader.SizeOfImage = pSH->VirtualAddress + pSH->Misc.VirtualSize; else // WATCOM is always a bit special >:-) pNTH->OptionalHeader.SizeOfImage = pSH->VirtualAddress + pSH->SizeOfRawData; } __except(1) { // an access violation occurred :( return -1; } return dwNewFsize; } bool PeRebuild::validatePE(void* pPEImage, DWORD dwFileSize) { PIMAGE_NT_HEADERS pNTh; PIMAGE_SECTION_HEADER pSech,pSH, pSH2, pLastSH; UINT i; DWORD dwHeaderSize; // get PE base information pNTh = ImageNtHeader(pPEImage); if (!pNTh) return FALSE; pSech = IMAGE_FIRST_SECTION(pNTh); // FIX: // ... the SizeOfHeaders pSH = pSech; dwHeaderSize = 0xFFFFFFFF; for(i=0; i < pNTh->FileHeader.NumberOfSections; i++) { if (pSH->PointerToRawData && pSH->PointerToRawData < dwHeaderSize) { dwHeaderSize = pSH->PointerToRawData; } ++pSH; } pNTh->OptionalHeader.SizeOfHeaders = dwHeaderSize; // ...Virtual Sizes pSH2 = pSH = pSech; ++pSH2; for (i=0; i < (DWORD)pNTh->FileHeader.NumberOfSections-1; i++) { pSH->Misc.VirtualSize = pSH2->VirtualAddress - pSH->VirtualAddress; ++pSH; ++pSH2; } // (pSH -> pointer to last section) pLastSH = pSH; // ...RawSize of the last section pLastSH->SizeOfRawData = dwFileSize - pLastSH->PointerToRawData; // ...SizeOfImage if (pLastSH->Misc.PhysicalAddress) { pNTh->OptionalHeader.SizeOfImage = pLastSH->VirtualAddress + pLastSH->Misc.VirtualSize; } else // WATCOM is always a bit special >:-) { pNTh->OptionalHeader.SizeOfImage = pLastSH->VirtualAddress + pLastSH->SizeOfRawData; } return true; } ReBaseErr PeRebuild::reBasePEImage(void* pPE, DWORD_PTR dwNewBase) { PIMAGE_NT_HEADERS pNT; PIMAGE_RELOCATION pR; ReBaseErr ret; DWORD_PTR dwDelta; DWORD *pdwAddr, dwRva, dwType; UINT iItems, i; WORD *pW; // dwNewBase valid ? if (dwNewBase & 0xFFFF) { ret = RB_INVALIDNEWBASE; goto Exit; // ERR } // // get relocation dir ptr // pNT = ImageNtHeader(pPE); if (!pNT) { ret = RB_INVALIDPE; goto Exit; // ERR } // new base = old base ? if (pNT->OptionalHeader.ImageBase == dwNewBase) { ret = RB_OK; goto Exit; // OK } if (!pNT->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress) { ret = RB_NORELOCATIONINFO; goto Exit; // ERR } pR = (PIMAGE_RELOCATION)ImageRvaToVa( pNT, pPE, pNT->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress, NULL); if (!pR) { ret = RB_INVALIDRVA; goto Exit; // ERR } // // add delta to relocation items // dwDelta = dwNewBase - pNT->OptionalHeader.ImageBase; __try { do { // get number of items if (pR->SymbolTableIndex) iItems = (pR->SymbolTableIndex - 8) / 2; else break; // no items in this block // trace/list block items... pW = (WORD*)((DWORD_PTR)pR + 8); for (i = 0; i < iItems; i++) { dwRva = (*pW & 0xFFF) + pR->VirtualAddress; dwType = *pW >> 12; if (dwType != 0) // fully compatible ??? { // add delta pdwAddr = (PDWORD)ImageRvaToVa( pNT, pPE, dwRva, NULL); if (!pdwAddr) { ret = RB_INVALIDRVA; goto Exit; // ERR } *pdwAddr += dwDelta; } // next item ++pW; } pR = (PIMAGE_RELOCATION)pW; // pR -> next block header } while ( *(DWORD*)pW ); } __except(EXCEPTION_EXECUTE_HANDLER) { ret = RB_ACCESSVIOLATION; goto Exit; // ERR } // apply new base to header pNT->OptionalHeader.ImageBase = dwNewBase; ret = RB_OK; // OK Exit: return ret; } bool PeRebuild::updatePeHeaderChecksum(LPVOID AddressOfMapFile, DWORD dwFsize) { PIMAGE_NT_HEADERS32 pNTHeader32 = 0; PIMAGE_NT_HEADERS64 pNTHeader64 = 0; DWORD headerSum = 0; DWORD checkSum = 0; pNTHeader32 = (PIMAGE_NT_HEADERS32)CheckSumMappedFile(AddressOfMapFile, dwFsize, &headerSum, &checkSum); if (!pNTHeader32) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"updatePeHeaderChecksum :: CheckSumMappedFile failed error %X", GetLastError()); #endif return false; } #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"Old checksum %08X new checksum %08X", headerSum, checkSum); #endif if (pNTHeader32->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) { pNTHeader64 = (PIMAGE_NT_HEADERS64)pNTHeader32; pNTHeader64->OptionalHeader.CheckSum = checkSum; } else { pNTHeader32->OptionalHeader.CheckSum = checkSum; } return true; } LPVOID PeRebuild::createFileMappingViewFull(const WCHAR * filePath) { hFileToMap = CreateFile(filePath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if( hFileToMap == INVALID_HANDLE_VALUE ) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"createFileMappingView :: INVALID_HANDLE_VALUE %u", GetLastError()); #endif hMappedFile = 0; hFileToMap = 0; addrMappedDll = 0; return NULL; } hMappedFile = CreateFileMapping(hFileToMap, 0, PAGE_READWRITE, 0, 0, NULL); if( hMappedFile == NULL ) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"createFileMappingViewFull :: hMappedFile == NULL"); #endif CloseHandle(hFileToMap); hMappedFile = 0; hFileToMap = 0; addrMappedDll = 0; return NULL; } if (GetLastError() == ERROR_ALREADY_EXISTS) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"createFileMappingView :: GetLastError() == ERROR_ALREADY_EXISTS"); #endif CloseHandle(hFileToMap); hMappedFile = 0; hFileToMap = 0; addrMappedDll = 0; return NULL; } addrMappedDll = MapViewOfFile(hMappedFile, FILE_MAP_ALL_ACCESS, 0, 0, 0); if(!addrMappedDll) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"createFileMappingView :: addrMappedDll == NULL"); #endif CloseHandle(hFileToMap); CloseHandle(hMappedFile); hMappedFile = 0; hFileToMap = 0; return NULL; } return addrMappedDll; } void PeRebuild::closeAllMappingHandles() { if (addrMappedDll) { if (!FlushViewOfFile(addrMappedDll, 0)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"closeAllMappingHandles :: Could not flush memory to disk (%d)", GetLastError()); #endif } UnmapViewOfFile(addrMappedDll); addrMappedDll = 0; } if (hMappedFile) { CloseHandle(hMappedFile); hMappedFile = 0; } if (hFileToMap) { CloseHandle(hFileToMap); hFileToMap = 0; } } bool PeRebuild::validatePeHeaders( PIMAGE_DOS_HEADER pDosh ) { PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)pDosh + pDosh->e_lfanew); if ((pDosh != 0) && (pDosh->e_magic == IMAGE_DOS_SIGNATURE) && (pNTHeader->Signature == IMAGE_NT_SIGNATURE)) { #ifdef _WIN64 if (pNTHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) #else if (pNTHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) #endif { return true; } else { return false; } } else { return false; } } diff --git a/Scylla/Scylla.vcxproj b/Scylla/Scylla.vcxproj index c38dc6e..0848e32 100644 --- a/Scylla/Scylla.vcxproj +++ b/Scylla/Scylla.vcxproj @@ -1,233 +1,235 @@  Debug Win32 Debug x64 Release Win32 Release x64 {710434C9-FC4B-4F1D-B318-E10ADC78499F} Win32Proj Scylla Application true Unicode Application true Unicode Application false true Unicode v100 Application false true Unicode true $(SolutionDir)$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ true false $(SolutionDir)$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ false Level3 Disabled WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) $(SolutionDir)diStorm\include;$(SolutionDir)tinyxml;%(AdditionalIncludeDirectories) Windows true $(SolutionDir)$(Platform)\$(Configuration)\diStorm.lib;$(SolutionDir)$(Platform)\$(Configuration)\tinyxml.lib;%(AdditionalDependencies) type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' Level3 Disabled WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) $(SolutionDir)diStorm\include;$(SolutionDir)tinyxml;%(AdditionalIncludeDirectories) Windows true $(SolutionDir)$(Platform)\$(Configuration)\diStorm.lib;$(SolutionDir)$(Platform)\$(Configuration)\tinyxml.lib;%(AdditionalDependencies) type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' Level3 MaxSpeed true true WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) MultiThreaded $(SolutionDir)diStorm\include;$(SolutionDir)tinyxml;%(AdditionalIncludeDirectories) true Windows false true true $(SolutionDir)$(Platform)\$(Configuration)\diStorm.lib;$(SolutionDir)$(Platform)\$(Configuration)\tinyxml.lib;%(AdditionalDependencies) type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' Level3 MaxSpeed true true WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) MultiThreaded $(SolutionDir)diStorm\include;$(SolutionDir)tinyxml;%(AdditionalIncludeDirectories) true Windows false true true $(SolutionDir)$(Platform)\$(Configuration)\diStorm.lib;$(SolutionDir)$(Platform)\$(Configuration)\tinyxml.lib;%(AdditionalDependencies) type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' + + \ No newline at end of file diff --git a/Scylla/Scylla.vcxproj.filters b/Scylla/Scylla.vcxproj.filters index b5919e2..2837676 100644 --- a/Scylla/Scylla.vcxproj.filters +++ b/Scylla/Scylla.vcxproj.filters @@ -1,208 +1,214 @@  {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hpp;hxx;hm;inl;inc;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms {e037d0d5-35ad-4034-83db-746a56a4fee7} {6f76186f-b79c-41e2-8939-05d9de028aad} Quelldateien Quelldateien\GUI Quelldateien\GUI Quelldateien Quelldateien\GUI Quelldateien\GUI Quelldateien Quelldateien Quelldateien Quelldateien Quelldateien Quelldateien Quelldateien Quelldateien Quelldateien Quelldateien Quelldateien\GUI Quelldateien Quelldateien Quelldateien\GUI Quelldateien\GUI Quelldateien\GUI Quelldateien Quelldateien Quelldateien + + Quelldateien + Headerdateien Headerdateien\GUI Headerdateien\GUI Headerdateien Headerdateien\GUI Headerdateien\GUI Headerdateien Headerdateien Headerdateien Headerdateien\GUI Headerdateien Headerdateien Headerdateien Headerdateien Headerdateien Headerdateien Headerdateien Headerdateien\GUI Headerdateien\GUI Headerdateien Headerdateien Headerdateien\GUI Headerdateien\GUI Headerdateien\GUI Headerdateien\GUI Headerdateien Headerdateien\GUI Headerdateien Headerdateien + + Headerdateien + Ressourcendateien Ressourcendateien Ressourcendateien Ressourcendateien Ressourcendateien \ No newline at end of file