diff --git a/Scylla/ConfigurationHolder.cpp b/Scylla/ConfigurationHolder.cpp index b854b35..37dad7d 100644 --- a/Scylla/ConfigurationHolder.cpp +++ b/Scylla/ConfigurationHolder.cpp @@ -1,203 +1,204 @@ #include "ConfigurationHolder.h" #include #include "Architecture.h" const WCHAR ConfigurationHolder::CONFIG_FILE_SECTION_NAME[] = L"SCYLLA_CONFIG"; //#define DEBUG_COMMENTS ConfigurationHolder::ConfigurationHolder(const WCHAR* fileName) { 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); config[REMOVE_DOS_HEADER_STUB] = Configuration(L"REMOVE_DOS_HEADER_STUB", Configuration::Boolean); config[IAT_FIX_AND_OEP_FIX] = Configuration(L"IAT_FIX_AND_OEP_FIX", Configuration::Boolean); config[SUSPEND_PROCESS_FOR_DUMPING] = Configuration(L"SUSPEND_PROCESS_FOR_DUMPING", Configuration::Boolean); config[OriginalFirstThunk_SUPPORT] = Configuration(L"OriginalFirstThunk_SUPPORT", Configuration::Boolean); config[USE_ADVANCED_IAT_SEARCH] = Configuration(L"USE_ADVANCED_IAT_SEARCH", Configuration::Boolean); + config[SCAN_AND_FIX_DIRECT_IMPORTS] = Configuration(L"SCAN_AND_FIX_DIRECT_IMPORTS", Configuration::Boolean); buildConfigFilePath(fileName); } bool ConfigurationHolder::loadConfiguration() { std::map::iterator mapIter; if (configPath[0] == '\0') { return false; } for (mapIter = config.begin() ; mapIter != config.end(); mapIter++) { Configuration& configObject = mapIter->second; loadConfig(configObject); } return true; } bool ConfigurationHolder::saveConfiguration() const { std::map::const_iterator mapIter; if (configPath[0] == '\0') { return false; } for (mapIter = config.begin() ; mapIter != config.end(); mapIter++) { const Configuration& configObject = mapIter->second; if (!saveConfig(configObject)) { return false; } } return true; } Configuration& ConfigurationHolder::operator[](ConfigOption option) { return config[option]; } const Configuration& ConfigurationHolder::operator[](ConfigOption option) const { static const Configuration dummy; std::map::const_iterator found = config.find(option); if(found != config.end()) { return found->second; } else { 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.getName(), buf, configPath); return ret == TRUE; } bool ConfigurationHolder::readNumericFromConfigFile(Configuration & configObject, int nBase) { 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(buf) > 0) { #ifdef _WIN64 configObject.setNumeric(_wcstoui64(buf, NULL, nBase)); #else configObject.setNumeric(wcstoul(buf, NULL, nBase)); #endif return true; } return false; } bool ConfigurationHolder::saveStringToConfigFile(const Configuration & configObject) const { BOOL ret = WritePrivateProfileString(CONFIG_FILE_SECTION_NAME, configObject.getName(), configObject.getString(), configPath); return ret == TRUE; } bool ConfigurationHolder::readStringFromConfigFile(Configuration & configObject) { 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(Configuration & configObject) { UINT val = GetPrivateProfileInt(CONFIG_FILE_SECTION_NAME, configObject.getName(), 0, configPath); configObject.setBool(val != 0); return true; } bool ConfigurationHolder::saveBooleanToConfigFile(const Configuration & configObject) const { 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(Configuration & configObject) { switch (configObject.getType()) { case Configuration::String: return readStringFromConfigFile(configObject); case Configuration::Boolean: return readBooleanFromConfigFile(configObject); case Configuration::Decimal: return readNumericFromConfigFile(configObject, 10); case Configuration::Hexadecimal: return readNumericFromConfigFile(configObject, 16); default: return false; } } bool ConfigurationHolder::saveConfig(const Configuration & configObject) const { switch (configObject.getType()) { case Configuration::String: return saveStringToConfigFile(configObject); case Configuration::Boolean: return saveBooleanToConfigFile(configObject); case Configuration::Decimal: return saveNumericToConfigFile(configObject, 10); case Configuration::Hexadecimal: return saveNumericToConfigFile(configObject, 16); default: return false; } } 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, fileName); return true; } diff --git a/Scylla/ConfigurationHolder.h b/Scylla/ConfigurationHolder.h index b7ae6ed..c0f3b1f 100644 --- a/Scylla/ConfigurationHolder.h +++ b/Scylla/ConfigurationHolder.h @@ -1,53 +1,54 @@ #pragma once #include #include #include "Configuration.h" enum ConfigOption { USE_PE_HEADER_FROM_DISK, DEBUG_PRIVILEGE, CREATE_BACKUP, DLL_INJECTION_AUTO_UNLOAD, IAT_SECTION_NAME, UPDATE_HEADER_CHECKSUM, REMOVE_DOS_HEADER_STUB, IAT_FIX_AND_OEP_FIX, SUSPEND_PROCESS_FOR_DUMPING, OriginalFirstThunk_SUPPORT, - USE_ADVANCED_IAT_SEARCH + USE_ADVANCED_IAT_SEARCH, + SCAN_AND_FIX_DIRECT_IMPORTS }; class ConfigurationHolder { public: ConfigurationHolder(const WCHAR* fileName); bool loadConfiguration(); bool saveConfiguration() const; Configuration& operator[](ConfigOption option); const Configuration& operator[](ConfigOption option) const; private: static const WCHAR CONFIG_FILE_SECTION_NAME[]; WCHAR configPath[MAX_PATH]; std::map config; bool buildConfigFilePath(const WCHAR* fileName); bool readStringFromConfigFile(Configuration & configObject); bool readBooleanFromConfigFile(Configuration & configObject); bool readNumericFromConfigFile(Configuration & 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(Configuration & configObject); bool saveConfig(const Configuration & configObject) const; }; diff --git a/Scylla/DisassemblerGui.h b/Scylla/DisassemblerGui.h index 17bd15e..c57a405 100644 --- a/Scylla/DisassemblerGui.h +++ b/Scylla/DisassemblerGui.h @@ -1,134 +1,134 @@ #pragma once #include #include "resource.h" // WTL #include // base ATL classes #include // base WTL classes #include // ATL GUI classes #include // WTL window frame helpers #include // WTL utility classes like CString #include // WTL enhanced msg map macros #include // WTL controls #include // WTL dialog data exchange #include #include "hexedit.h" #include "ApiReader.h" enum DisassemblerAddressType { ADDRESS_TYPE_MODULE, ADDRESS_TYPE_API, ADDRESS_TYPE_SPECIAL }; class DisassemblerAddressComment { public: DWORD_PTR address; WCHAR comment[MAX_PATH]; DisassemblerAddressType type; DWORD moduleSize; bool operator<(DisassemblerAddressComment rhs) { return address < rhs.address; } }; class DisassemblerGui : public CDialogImpl, public CWinDataExchange, public CDialogResize { public: enum { IDD = IDD_DLG_DISASSEMBLER }; BEGIN_DDX_MAP(DisassemblerGui) DDX_CONTROL_HANDLE(IDC_LIST_DISASSEMBLER, ListDisassembler) DDX_CONTROL(IDC_EDIT_ADDRESS_DISASSEMBLE, EditAddress) END_DDX_MAP() BEGIN_MSG_MAP(DisassemblerGui) MSG_WM_INITDIALOG(OnInitDialog) MSG_WM_CONTEXTMENU(OnContextMenu) NOTIFY_HANDLER_EX(IDC_LIST_DISASSEMBLER, NM_CUSTOMDRAW, OnNMCustomdraw) COMMAND_ID_HANDLER_EX(IDC_BUTTON_DISASSEMBLE, OnDisassemble) COMMAND_ID_HANDLER_EX(IDC_BUTTON_DISASSEMBLER_BACK, OnDisassembleBack) COMMAND_ID_HANDLER_EX(IDC_BUTTON_DISASSEMBLER_FORWARD, OnDisassembleForward) COMMAND_ID_HANDLER_EX(IDCANCEL, OnExit) COMMAND_ID_HANDLER_EX(IDOK, OnExit) CHAIN_MSG_MAP(CDialogResize) END_MSG_MAP() BEGIN_DLGRESIZE_MAP(DisassemblerGui) DLGRESIZE_CONTROL(IDC_LIST_DISASSEMBLER, DLSZ_SIZE_X | DLSZ_SIZE_Y) DLGRESIZE_CONTROL(IDC_BUTTON_DISASSEMBLE, DLSZ_MOVE_X | DLSZ_MOVE_Y) DLGRESIZE_CONTROL(IDC_BUTTON_DISASSEMBLER_BACK, DLSZ_MOVE_X | DLSZ_MOVE_Y) DLGRESIZE_CONTROL(IDC_BUTTON_DISASSEMBLER_FORWARD, DLSZ_MOVE_X | DLSZ_MOVE_Y) DLGRESIZE_CONTROL(IDC_EDIT_ADDRESS_DISASSEMBLE, DLSZ_MOVE_Y) DLGRESIZE_CONTROL(IDC_STATIC_ADDRESS_DISASSEMBLE, DLSZ_MOVE_Y) END_DLGRESIZE_MAP() DisassemblerGui(DWORD_PTR startAddress, ApiReader * apiReaderObject); protected: // Variables static const size_t DISASSEMBLER_GUI_MEMORY_SIZE = 0x120; - WCHAR tempBuffer[100]; + WCHAR tempBuffer[500]; int addressHistoryIndex; std::vector addressHistory; std::vector addressCommentList; // Controls CListViewCtrl ListDisassembler; CHexEdit EditAddress; enum DisassemblerColumns { COL_ADDRESS = 0, COL_INSTRUCTION_SIZE, COL_OPCODES, COL_INSTRUCTION, COL_COMMENT }; // Handles CMenu hMenuDisassembler; // Message handlers BOOL OnInitDialog(CWindow wndFocus, LPARAM lInitParam); void OnContextMenu(CWindow wnd, CPoint point); void OnExit(UINT uNotifyCode, int nID, CWindow wndCtl); LRESULT OnNMCustomdraw(NMHDR* pnmh); void OnDisassemble(UINT uNotifyCode, int nID, CWindow wndCtl); void OnDisassembleBack(UINT uNotifyCode, int nID, CWindow wndCtl); void OnDisassembleForward(UINT uNotifyCode, int nID, CWindow wndCtl); // GUI functions void addColumnsToDisassembler(CListViewCtrl& list); bool displayDisassembly(); // Misc void copyToClipboard(const WCHAR * text); private: ApiReader * apiReader; BYTE data[DISASSEMBLER_GUI_MEMORY_SIZE]; void toUpperCase(WCHAR * lowercase); void doColorInstruction( LPNMLVCUSTOMDRAW lpLVCustomDraw, DWORD_PTR itemIndex ); void followInstruction(int index); bool getDisassemblyComment(unsigned int index); void disassembleNewAddress(DWORD_PTR address); void initAddressCommentList(); void addModuleAddressCommentEntry( DWORD_PTR address, DWORD moduleSize, const WCHAR * modulePath ); void analyzeAddress( DWORD_PTR address, WCHAR * comment ); }; diff --git a/Scylla/IATReferenceScan.cpp b/Scylla/IATReferenceScan.cpp new file mode 100644 index 0000000..439e25e --- /dev/null +++ b/Scylla/IATReferenceScan.cpp @@ -0,0 +1,405 @@ +#include "IATReferenceScan.h" +#include "Scylla.h" +#include "Architecture.h" + +//#define DEBUG_COMMENTS + + +int IATReferenceScan::numberOfFoundDirectImports() +{ + return (int)iatDirectImportList.size(); +} + +void IATReferenceScan::startScan(DWORD_PTR imageBase, DWORD imageSize, DWORD_PTR iatAddress, DWORD iatSize) +{ + MEMORY_BASIC_INFORMATION memBasic = {0}; + + IatAddressVA = iatAddress; + IatSize = iatSize; + ImageBase = imageBase; + ImageSize = imageSize; + + iatReferenceList.clear(); + iatDirectImportList.clear(); + + iatReferenceList.reserve(200); + iatDirectImportList.reserve(50); + + DWORD_PTR section = imageBase; + + do + { + if (!VirtualQueryEx(ProcessAccessHelp::hProcess, (LPCVOID)section, &memBasic, sizeof(MEMORY_BASIC_INFORMATION))) + { +#ifdef DEBUG_COMMENTS + Scylla::debugLog.log(L"VirtualQueryEx failed %d", GetLastError()); +#endif + + break; + } + else + { + if (isPageExecutable(memBasic.Protect)) + { + //do read and scan + scanMemoryPage(memBasic.BaseAddress, memBasic.RegionSize); + } + } + + section = (DWORD_PTR)((SIZE_T)section + memBasic.RegionSize); + + } while (section < (imageBase + imageSize)); + + +} + +void IATReferenceScan::patchNewIatBaseMemory(DWORD_PTR newIatBaseAddress) +{ + NewIatAddressVA = newIatBaseAddress; + + for (std::vector::iterator iter = iatReferenceList.begin(); iter != iatReferenceList.end(); iter++) + { + patchReferenceInMemory(&(*iter)); + } +} + +void IATReferenceScan::patchNewIatBaseFile(DWORD_PTR newIatBaseAddress) +{ + NewIatAddressVA = newIatBaseAddress; + + for (std::vector::iterator iter = iatReferenceList.begin(); iter != iatReferenceList.end(); iter++) + { + patchReferenceInFile(&(*iter)); + } +} + +void IATReferenceScan::patchDirectImportsMemory() +{ + for (std::vector::iterator iter = iatDirectImportList.begin(); iter != iatDirectImportList.end(); iter++) + { + patchDirectImportInMemory(&(*iter)); + } +} + + +bool IATReferenceScan::isPageExecutable( DWORD Protect ) +{ + if (Protect & PAGE_NOCACHE) Protect ^= PAGE_NOCACHE; + + if (Protect & PAGE_WRITECOMBINE) Protect ^= PAGE_WRITECOMBINE; + + switch(Protect) + { + case PAGE_EXECUTE: + { + return true; + } + case PAGE_EXECUTE_READ: + { + return true; + } + case PAGE_EXECUTE_READWRITE: + { + return true; + } + case PAGE_EXECUTE_WRITECOPY: + { + return true; + } + default: + return false; + } + +} + +void IATReferenceScan::scanMemoryPage( PVOID BaseAddress, SIZE_T RegionSize ) +{ + BYTE * dataBuffer = (BYTE *)calloc(RegionSize, 1); + BYTE * currentPos = dataBuffer; + int currentSize = (int)RegionSize; + DWORD_PTR currentOffset = (DWORD_PTR)BaseAddress; + _DecodeResult res; + unsigned int instructionsCount = 0, next = 0; + + if (!dataBuffer) + return; + + if (ProcessAccessHelp::readMemoryFromProcess((DWORD_PTR)BaseAddress, RegionSize, (LPVOID)dataBuffer)) + { + while (1) + { + ZeroMemory(&ProcessAccessHelp::decomposerCi, sizeof(_CodeInfo)); + ProcessAccessHelp::decomposerCi.code = currentPos; + ProcessAccessHelp::decomposerCi.codeLen = currentSize; + ProcessAccessHelp::decomposerCi.dt = ProcessAccessHelp::dt; + ProcessAccessHelp::decomposerCi.codeOffset = currentOffset; + + instructionsCount = 0; + + res = distorm_decompose(&ProcessAccessHelp::decomposerCi, ProcessAccessHelp::decomposerResult, sizeof(ProcessAccessHelp::decomposerResult)/sizeof(ProcessAccessHelp::decomposerResult[0]), &instructionsCount); + + if (res == DECRES_INPUTERR) + { + break; + } + + for (unsigned int i = 0; i < instructionsCount; i++) + { + if (ProcessAccessHelp::decomposerResult[i].flags != FLAG_NOT_DECODABLE) + { + analyzeInstruction(&ProcessAccessHelp::decomposerResult[i]); + } + } + + if (res == DECRES_SUCCESS) break; // All instructions were decoded. + else if (instructionsCount == 0) break; + + next = (unsigned long)(ProcessAccessHelp::decomposerResult[instructionsCount-1].addr - ProcessAccessHelp::decomposerResult[0].addr); + + if (ProcessAccessHelp::decomposerResult[instructionsCount-1].flags != FLAG_NOT_DECODABLE) + { + next += ProcessAccessHelp::decomposerResult[instructionsCount-1].size; + } + + currentPos += next; + currentOffset += next; + currentSize -= next; + } + } + + free(dataBuffer); +} + +void IATReferenceScan::analyzeInstruction( _DInst * instruction ) +{ + if (ScanForNormalImports) + { + findNormalIatReference(instruction); + } + + if (ScanForDirectImports) + { + findDirectIatReference(instruction); + } +} + +void IATReferenceScan::findNormalIatReference( _DInst * instruction ) +{ +#ifdef DEBUG_COMMENTS + _DecodedInst inst; +#endif + + IATReference ref; + + + if (META_GET_FC(instruction->meta) == FC_CALL || META_GET_FC(instruction->meta) == FC_UNC_BRANCH) + { + if (instruction->size >= 5) + { + if (META_GET_FC(instruction->meta) == FC_CALL) + { + ref.type = IAT_REFERENCE_PTR_CALL; + } + else + { + ref.type = IAT_REFERENCE_PTR_JMP; + } + ref.addressVA = (DWORD_PTR)instruction->addr; + +#ifdef _WIN64 + if (instruction->flags & FLAG_RIP_RELATIVE) + { + +#ifdef DEBUG_COMMENTS + distorm_format(&ProcessAccessHelp::decomposerCi, instruction, &inst); + Scylla::debugLog.log(PRINTF_DWORD_PTR_FULL L" " PRINTF_DWORD_PTR_FULL L" %S %S %d %d - target address: " PRINTF_DWORD_PTR_FULL, (DWORD_PTR)instruction->addr, ImageBase, inst.mnemonic.p, inst.operands.p, instruction->ops[0].type, instruction->size, INSTRUCTION_GET_RIP_TARGET(instruction)); +#endif + + if (INSTRUCTION_GET_RIP_TARGET(instruction) >= IatAddressVA && INSTRUCTION_GET_RIP_TARGET(instruction) < (IatAddressVA + IatSize)) + { + ref.targetPointer = INSTRUCTION_GET_RIP_TARGET(instruction); + + getIatEntryAddress(&ref); + + //Scylla::debugLog.log(L"iat entry "PRINTF_DWORD_PTR_FULL,ref.targetAddressInIat); + + iatReferenceList.push_back(ref); + } + } +#else + + if (instruction->ops[0].type == O_DISP) + { + //jmp dword ptr || call dword ptr +#ifdef DEBUG_COMMENTS + distorm_format(&ProcessAccessHelp::decomposerCi, instruction, &inst); + Scylla::debugLog.log(PRINTF_DWORD_PTR_FULL L" " PRINTF_DWORD_PTR_FULL L" %S %S %d %d - target address: " PRINTF_DWORD_PTR_FULL, (DWORD_PTR)instruction->addr, ImageBase, inst.mnemonic.p, inst.operands.p, instruction->ops[0].type, instruction->size, instruction->disp); +#endif + + if (instruction->disp >= IatAddressVA && instruction->disp < (IatAddressVA + IatSize)) + { + ref.targetPointer = (DWORD_PTR)instruction->disp; + + getIatEntryAddress(&ref); + + //Scylla::debugLog.log(L"iat entry "PRINTF_DWORD_PTR_FULL,ref.targetAddressInIat); + + iatReferenceList.push_back(ref); + } + } +#endif + } + } +} + +void IATReferenceScan::getIatEntryAddress( IATReference * ref ) +{ + if (!ProcessAccessHelp::readMemoryFromProcess(ref->targetPointer, sizeof(DWORD_PTR), &ref->targetAddressInIat)) + { + ref->targetAddressInIat = 0; + } +} + +void IATReferenceScan::findDirectIatReference( _DInst * instruction ) +{ +#ifdef DEBUG_COMMENTS + _DecodedInst inst; +#endif + + IATReference ref; + ref.targetPointer = 0; + + + if (META_GET_FC(instruction->meta) == FC_CALL || META_GET_FC(instruction->meta) == FC_UNC_BRANCH) + { + if ((instruction->size >= 5) && (instruction->ops[0].type == O_PC)) //CALL/JMP 0x00000000 + { + if (META_GET_FC(instruction->meta) == FC_CALL) + { + ref.type = IAT_REFERENCE_DIRECT_CALL; + } + else + { + ref.type = IAT_REFERENCE_DIRECT_JMP; + } + ref.addressVA = (DWORD_PTR)instruction->addr; + ref.targetAddressInIat = (DWORD_PTR)INSTRUCTION_GET_TARGET(instruction); + + if ((ref.targetAddressInIat < ImageBase) || (ref.targetAddressInIat > (ImageBase+ImageSize))) //call/JMP outside pe image + { + if (isAddressValidMemory(ref.targetAddressInIat)) + { +#ifdef DEBUG_COMMENTS + distorm_format(&ProcessAccessHelp::decomposerCi, instruction, &inst); + Scylla::debugLog.log(PRINTF_DWORD_PTR_FULL L" " PRINTF_DWORD_PTR_FULL L" %S %S %d %d - target address: " PRINTF_DWORD_PTR_FULL,(DWORD_PTR)instruction->addr, ImageBase, inst.mnemonic.p, inst.operands.p, instruction->ops[0].type, instruction->size, INSTRUCTION_GET_TARGET(instruction)); +#endif + + iatDirectImportList.push_back(ref); + } + } + } + } +} + +bool IATReferenceScan::isAddressValidMemory( DWORD_PTR address ) +{ + MEMORY_BASIC_INFORMATION memBasic = {0}; + + if (!VirtualQueryEx(ProcessAccessHelp::hProcess, (LPCVOID)address, &memBasic, sizeof(MEMORY_BASIC_INFORMATION))) + { + return false; + } + + return (memBasic.Type == MEM_IMAGE); +} + +void IATReferenceScan::patchReferenceInMemory( IATReference * ref ) +{ + DWORD_PTR newIatAddressPointer = ref->targetPointer - IatAddressVA + NewIatAddressVA; + + DWORD patchBytes = 0; + +#ifdef _WIN64 + patchBytes = (DWORD)(newIatAddressPointer - ref->addressVA - 6); +#else + patchBytes = newIatAddressPointer; +#endif + ProcessAccessHelp::writeMemoryToProcess(ref->addressVA + 2, sizeof(DWORD), &patchBytes); +} + +void IATReferenceScan::patchReferenceInFile( IATReference * ref ) +{ + DWORD_PTR newIatAddressPointer = (ref->targetPointer - IatAddressVA) + NewIatAddressRVA + standardImageBase; + + DWORD patchBytes = 0; + +#ifdef _WIN64 + patchBytes = (DWORD)(newIatAddressPointer - (ref->addressVA - ImageBase + standardImageBase) - 6); +#else + patchBytes = newIatAddressPointer; +#endif + + +} + +void IATReferenceScan::patchDirectImportInMemory( IATReference * ref ) +{ + DWORD patchBytes = 0; + BYTE patchPreBytes[2]; + + ref->targetPointer = lookUpIatForPointer(ref->targetAddressInIat); + if (ref->targetPointer) + { + patchPreBytes[0] = 0xFF; + + if (ref->type == IAT_REFERENCE_DIRECT_CALL) //FF15 + { + patchPreBytes[1] = 0x15; + } + else if (ref->type == IAT_REFERENCE_DIRECT_JMP) //FF25 + { + patchPreBytes[1] = 0x25; + } + else + { + return; + } + + ProcessAccessHelp::writeMemoryToProcess(ref->addressVA, 2, patchPreBytes); + +#ifdef _WIN64 + patchBytes = (DWORD)(ref->targetPointer - ref->addressVA - 6); +#else + patchBytes = ref->targetPointer; +#endif + ProcessAccessHelp::writeMemoryToProcess(ref->addressVA + 2, sizeof(DWORD), &patchBytes); + } +} + +DWORD_PTR IATReferenceScan::lookUpIatForPointer( DWORD_PTR addr ) +{ + if (!iatBackup) + { + iatBackup = (DWORD_PTR *)calloc(IatSize + 1, 1); + if (!iatBackup) + { + return 0; + } + if (!ProcessAccessHelp::readMemoryFromProcess(IatAddressVA, IatSize, iatBackup)) + { + free(iatBackup); + iatBackup = 0; + return 0; + } + } + + for (int i = 0; i < ((int)IatSize / (int)sizeof(DWORD_PTR));i++) + { + if (iatBackup[i] == addr) + { + return (DWORD_PTR)&iatBackup[i] - (DWORD_PTR)iatBackup + IatAddressVA; + } + } + + return 0; +} diff --git a/Scylla/IATReferenceScan.h b/Scylla/IATReferenceScan.h new file mode 100644 index 0000000..a024b89 --- /dev/null +++ b/Scylla/IATReferenceScan.h @@ -0,0 +1,101 @@ +#pragma once +#include +#include "ProcessAccessHelp.h" + +enum IATReferenceType { + IAT_REFERENCE_PTR_JMP, + IAT_REFERENCE_PTR_CALL, + IAT_REFERENCE_DIRECT_JMP, + IAT_REFERENCE_DIRECT_CALL +}; + +class IATReference +{ +public: + DWORD_PTR addressVA; //Address of reference + DWORD_PTR targetPointer; //Place inside IAT + DWORD_PTR targetAddressInIat; //WIN API? + IATReferenceType type; +}; + + +class IATReferenceScan +{ +public: + + IATReferenceScan() + { + IatAddressVA = 0; + IatSize = 0; + ImageBase = 0; + ImageSize = 0; + iatBackup = 0; + ScanForDirectImports = false; + ScanForNormalImports = true; + } + + ~IATReferenceScan() + { + iatReferenceList.clear(); + iatDirectImportList.clear(); + + if (iatBackup) + { + free(iatBackup); + } + } + + bool ScanForDirectImports; + bool ScanForNormalImports; + + + void startScan(DWORD_PTR imageBase, DWORD imageSize, DWORD_PTR iatAddress, DWORD iatSize); + void patchNewIatBaseMemory(DWORD_PTR newIatBaseAddress); + void patchNewIatBaseFile(DWORD_PTR newIatBaseAddress); + void patchDirectImportsMemory(); + int numberOfFoundDirectImports(); +private: + DWORD_PTR NewIatAddressVA; + DWORD_PTR NewIatAddressRVA; + + DWORD_PTR IatAddressVA; + DWORD IatSize; + DWORD_PTR ImageBase; + DWORD ImageSize; + + DWORD_PTR standardImageBase; + + DWORD_PTR * iatBackup; + + std::vector iatReferenceList; + std::vector iatDirectImportList; + + bool isPageExecutable( DWORD Protect ); + void scanMemoryPage( PVOID BaseAddress, SIZE_T RegionSize ); + void analyzeInstruction( _DInst * instruction ); + void findNormalIatReference( _DInst * instruction ); + void getIatEntryAddress( IATReference* ref ); + void findDirectIatReference( _DInst * instruction ); + bool isAddressValidMemory( DWORD_PTR address ); + void patchReferenceInMemory( IATReference * ref ); + void patchReferenceInFile( IATReference* ref ); + void patchDirectImportInMemory( IATReference * iter ); + DWORD_PTR lookUpIatForPointer( DWORD_PTR addr ); +}; + +/* +PE64 +---------- +000000013FF82D87 FF15 137C0A00 CALL QWORD [RIP+0xA7C13] +Result: 000000014002A9A0 + +000000013F65C952 FF25 F8EA0B00 JMP QWORD [RIP+0xBEAF8] +Result: 000000013F71B450 + +PE32 +---------- +0120FFA5 FF15 8C6D2601 CALL DWORD [0x01266D8C] + +0120FF52 FF25 D4722601 JMP DWORD [0x012672D4] +*/ + diff --git a/Scylla/MainGui.cpp b/Scylla/MainGui.cpp index a723e50..4451b2b 100644 --- a/Scylla/MainGui.cpp +++ b/Scylla/MainGui.cpp @@ -1,1558 +1,1607 @@ #include "MainGui.h" #include "Architecture.h" //#include "PluginLoader.h" //#include "ConfigurationHolder.h" #include "PeParser.h" #include "DllInjectionPlugin.h" #include "DisassemblerGui.h" #include "PickApiGui.h" //#include "NativeWinApi.h" #include "ImportRebuilder.h" #include "SystemInformation.h" #include "Scylla.h" #include "AboutGui.h" #include "DonateGui.h" #include "OptionsGui.h" #include "TreeImportExport.h" +#include "IATReferenceScan.h" extern CAppModule _Module; // o_O const WCHAR MainGui::filterExe[] = L"Executable (*.exe)\0*.exe\0All files\0*.*\0"; const WCHAR MainGui::filterDll[] = L"Dynamic Link Library (*.dll)\0*.dll\0All files\0*.*\0"; const WCHAR MainGui::filterExeDll[] = L"Executable (*.exe)\0*.exe\0Dynamic Link Library (*.dll)\0*.dll\0All files\0*.*\0"; const WCHAR MainGui::filterTxt[] = L"Text file (*.txt)\0*.txt\0All files\0*.*\0"; const WCHAR MainGui::filterXml[] = L"XML file (*.xml)\0*.xml\0All files\0*.*\0"; const WCHAR MainGui::filterMem[] = L"MEM file (*.mem)\0*.mem\0All files\0*.*\0"; MainGui::MainGui() : selectedProcess(0), isProcessSuspended(false), 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); */ 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; } void MainGui::InitDllStartWithPreSelect( PGUI_DLL_PARAMETER guiParam ) { ComboProcessList.ResetContent(); std::vector& processList = Scylla::processLister.getProcessListSnapshot(); int newSel = -1; for (size_t i = 0; i < processList.size(); i++) { if (processList[i].PID == guiParam->dwProcessId) newSel = (int)i; swprintf_s(stringBuffer, L"0x%04X - %s - %s", processList[i].PID, processList[i].filename, processList[i].fullPath); ComboProcessList.AddString(stringBuffer); } if (newSel != -1) { ComboProcessList.SetCurSel(newSel); processSelectedActionHandler(newSel); if (guiParam->mod) //init mod { //select DLL size_t len = ProcessAccessHelp::moduleList.size(); newSel = -1; for (size_t i = 0; i < len; i++) { if (ProcessAccessHelp::moduleList.at(i).modBaseAddr == (DWORD_PTR)guiParam->mod) { newSel = (int)i; break; } } if (newSel != -1) { //get selected module ProcessAccessHelp::selectedModule = &ProcessAccessHelp::moduleList.at(newSel); ProcessAccessHelp::targetImageBase = ProcessAccessHelp::selectedModule->modBaseAddr; + ProcessAccessHelp::targetSizeOfImage = ProcessAccessHelp::getSizeOfImageProcess(ProcessAccessHelp::hProcess, ProcessAccessHelp::targetImageBase); DWORD modEntryPoint = ProcessAccessHelp::getEntryPointFromFile(ProcessAccessHelp::selectedModule->fullPath); EditOEPAddress.SetValue(modEntryPoint + ProcessAccessHelp::targetImageBase); Scylla::windowLog.log(L"->>> Module %s selected.", ProcessAccessHelp::selectedModule->getFilename()); Scylla::windowLog.log(L"Imagebase: " PRINTF_DWORD_PTR_FULL L" Size: %08X EntryPoint: %08X", ProcessAccessHelp::selectedModule->modBaseAddr, ProcessAccessHelp::selectedModule->modBaseSize, modEntryPoint); } } } } 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(); if (lInitParam) { InitDllStartWithPreSelect((PGUI_DLL_PARAMETER)lInitParam); } return TRUE; } void MainGui::OnDestroy() { PostQuitMessage(0); } void MainGui::OnSize(UINT nType, CSize size) { StatusBar.SendMessage(WM_SIZE); SetMsgHandled(FALSE); } void MainGui::OnContextMenu(CWindow wnd, CPoint point) { switch(wnd.GetDlgCtrlID()) { case IDC_TREE_IMPORTS: DisplayContextMenuImports(wnd, point); return; case IDC_LIST_LOG: DisplayContextMenuLog(wnd, point); return; } SetMsgHandled(FALSE); } void MainGui::OnCommand(UINT uNotifyCode, int nID, CWindow wndCtl) { // Handle plugin trace menu selection if(uNotifyCode == 0 && !wndCtl.IsWindow()) // make sure it's a menu { if ((nID >= PLUGIN_MENU_BASE_ID) && (nID <= (int)(Scylla::plugins.getScyllaPluginList().size() + Scylla::plugins.getImprecPluginList().size() + PLUGIN_MENU_BASE_ID))) { pluginActionHandler(nID); return; } } SetMsgHandled(FALSE); } LRESULT MainGui::OnTreeImportsDoubleClick(const NMHDR* pnmh) { if(TreeImports.GetCount() < 1) return 0; // Get item under cursor CTreeItem over = findTreeItem(CPoint(GetMessagePos()), true); if(over && importsHandling.isImport(over)) { pickApiActionHandler(over); } return 0; } LRESULT MainGui::OnTreeImportsKeyDown(const NMHDR* pnmh) { const NMTVKEYDOWN * tkd = (NMTVKEYDOWN *)pnmh; switch(tkd->wVKey) { case VK_RETURN: { CTreeItem selected = TreeImports.GetFocusItem(); if(!selected.IsNull() && importsHandling.isImport(selected)) { pickApiActionHandler(selected); } } return 1; case VK_DELETE: deleteSelectedImportsActionHandler(); return 1; } SetMsgHandled(FALSE); return 0; } UINT MainGui::OnTreeImportsSubclassGetDlgCode(const MSG * lpMsg) { if(lpMsg) { switch(lpMsg->wParam) { case VK_RETURN: return DLGC_WANTMESSAGE; } } SetMsgHandled(FALSE); return 0; } void MainGui::OnTreeImportsSubclassChar(UINT nChar, UINT nRepCnt, UINT nFlags) { switch(nChar) { case VK_RETURN: break; default: SetMsgHandled(FALSE); break; } } void MainGui::OnProcessListDrop(UINT uNotifyCode, int nID, CWindow wndCtl) { fillProcessListComboBox(ComboProcessList); } void MainGui::OnProcessListSelected(UINT uNotifyCode, int nID, CWindow wndCtl) { processSelectedActionHandler(ComboProcessList.GetCurSel()); } void MainGui::OnPickDLL(UINT uNotifyCode, int nID, CWindow wndCtl) { pickDllActionHandler(); } void MainGui::OnOptions(UINT uNotifyCode, int nID, CWindow wndCtl) { optionsActionHandler(); } void MainGui::OnDump(UINT uNotifyCode, int nID, CWindow wndCtl) { dumpActionHandler(); } void MainGui::OnDumpMemory(UINT uNotifyCode, int nID, CWindow wndCtl) { dumpMemoryActionHandler(); } void MainGui::OnDumpSection(UINT uNotifyCode, int nID, CWindow wndCtl) { dumpSectionActionHandler(); } 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::OnDisassembler(UINT uNotifyCode, int nID, CWindow wndCtl) { disassemblerActionHandler(); } 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) { if (isProcessSuspended) { int msgboxID = MessageBox(L"Process is suspended. Do you want to terminate the process?\r\n\r\nYES = Terminate Process\r\nNO = Try to resume the process\r\nCancel = Do nothing", L"Information", MB_YESNOCANCEL|MB_ICONINFORMATION); switch (msgboxID) { case IDYES: ProcessAccessHelp::terminateProcess(); break; case IDNO: ProcessAccessHelp::resumeProcess(); break; default: break; } } DestroyWindow(); } void MainGui::OnAbout(UINT uNotifyCode, int nID, CWindow wndCtl) { showAboutDialog(); } void MainGui::OnDonate(UINT uNotifyCode, int nID, CWindow wndCtl) { showDonateDialog(); } void MainGui::setupStatusBar() { StatusBar.Create(m_hWnd, NULL, L"", WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_TOOLTIPS, NULL, IDC_STATUS_BAR); CRect rcMain, rcStatus; GetClientRect(&rcMain); StatusBar.GetWindowRect(&rcStatus); const int PARTS = 4; int widths[PARTS]; widths[PART_COUNT] = rcMain.Width() / 5; widths[PART_INVALID] = widths[PART_COUNT] + rcMain.Width() / 5; widths[PART_IMAGEBASE] = widths[PART_INVALID] + rcMain.Width() / 3; widths[PART_MODULE] = -1; StatusBar.SetParts(PARTS, widths); ResizeClient(rcMain.Width(), rcMain.Height() + rcStatus.Height(), FALSE); } void MainGui::updateStatusBar() { // Rewrite ImportsHandling so we get these easily unsigned int totalImports = importsHandling.thunkCount(); unsigned int invalidImports = importsHandling.invalidThunkCount(); // \t = center, \t\t = right-align swprintf_s(stringBuffer, L"\tImports: %u", totalImports); StatusBar.SetText(PART_COUNT, stringBuffer); if(invalidImports > 0) { StatusBar.SetIcon(PART_INVALID, hIconError); } else { StatusBar.SetIcon(PART_INVALID, hIconCheck); } swprintf_s(stringBuffer, L"\tInvalid: %u", invalidImports); StatusBar.SetText(PART_INVALID, stringBuffer); if(selectedProcess) { DWORD_PTR imageBase = 0; const WCHAR * fileName = 0; if(ProcessAccessHelp::selectedModule) { imageBase = ProcessAccessHelp::selectedModule->modBaseAddr; fileName = ProcessAccessHelp::selectedModule->getFilename(); } else { imageBase = selectedProcess->imageBase; fileName = selectedProcess->filename; } swprintf_s(stringBuffer, L"\tImagebase: " PRINTF_DWORD_PTR_FULL, imageBase); StatusBar.SetText(PART_IMAGEBASE, stringBuffer); StatusBar.SetText(PART_MODULE, fileName); StatusBar.SetTipText(PART_MODULE, fileName); } else { StatusBar.SetText(PART_IMAGEBASE, L""); StatusBar.SetText(PART_MODULE, L""); } } bool MainGui::showFileDialog(WCHAR * selectedFile, bool save, const WCHAR * defFileName, const WCHAR * filter, const WCHAR * defExtension, const WCHAR * directory) { OPENFILENAME ofn = {0}; // WTL doesn't support new explorer styles on Vista and up // This is because it uses a custom hook, we could remove it or derive // from CFileDialog but this solution is easier and allows more control anyway (e.g. initial dir) if(defFileName) { wcscpy_s(selectedFile, MAX_PATH, defFileName); } else { selectedFile[0] = L'\0'; } ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = m_hWnd; ofn.lpstrFilter = filter; ofn.lpstrDefExt = defExtension; // only first 3 chars are used, no dots! ofn.lpstrFile = selectedFile; ofn.lpstrInitialDir = directory; ofn.nMaxFile = MAX_PATH; ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY; /* *OFN_EXPLORER is automatically used, it only has to be specified *if using a custom hook *OFN_LONGNAMES is automatically used by explorer-style dialogs */ if(save) ofn.Flags |= OFN_OVERWRITEPROMPT; else ofn.Flags |= OFN_FILEMUSTEXIST; if(save) return 0 != GetSaveFileName(&ofn); else return 0 != GetOpenFileName(&ofn); } void MainGui::setIconAndDialogCaption() { SetIcon(hIcon, TRUE); SetIcon(hIcon, FALSE); SetWindowText(APPNAME L" " ARCHITECTURE L" " APPVERSION); } void MainGui::pickDllActionHandler() { if(!selectedProcess) return; PickDllGui dlgPickDll(ProcessAccessHelp::moduleList); if(dlgPickDll.DoModal()) { //get selected module ProcessAccessHelp::selectedModule = dlgPickDll.getSelectedModule(); ProcessAccessHelp::targetImageBase = ProcessAccessHelp::selectedModule->modBaseAddr; + ProcessAccessHelp::targetSizeOfImage = ProcessAccessHelp::getSizeOfImageProcess(ProcessAccessHelp::hProcess, ProcessAccessHelp::targetImageBase); DWORD modEntryPoint = ProcessAccessHelp::getEntryPointFromFile(ProcessAccessHelp::selectedModule->fullPath); EditOEPAddress.SetValue(modEntryPoint + ProcessAccessHelp::targetImageBase); Scylla::windowLog.log(L"->>> Module %s selected.", ProcessAccessHelp::selectedModule->getFilename()); Scylla::windowLog.log(L"Imagebase: " PRINTF_DWORD_PTR_FULL L" Size: %08X EntryPoint: %08X", ProcessAccessHelp::selectedModule->modBaseAddr, ProcessAccessHelp::selectedModule->modBaseSize, modEntryPoint); } else { ProcessAccessHelp::selectedModule = 0; } updateStatusBar(); } void MainGui::pickApiActionHandler(CTreeItem item) { if(!importsHandling.isImport(item)) return; // TODO: new node when user picked an API from another DLL? PickApiGui dlgPickApi(ProcessAccessHelp::moduleList); if(dlgPickApi.DoModal()) { const ApiInfo* api = dlgPickApi.getSelectedApi(); if(api && api->module) { importsHandling.setImport(item, api->module->getFilename(), api->name, api->ordinal, api->hint, true, api->isForwarded); } } updateStatusBar(); } void MainGui::startDisassemblerGui(CTreeItem selectedTreeNode) { if(!selectedProcess) return; DWORD_PTR address = importsHandling.getApiAddressByNode(selectedTreeNode); if (address) { BYTE test; if(!ProcessAccessHelp::readMemoryFromProcess(address, sizeof(test), &test)) { swprintf_s(stringBuffer, L"Can't read memory at " PRINTF_DWORD_PTR_FULL, address); MessageBox(stringBuffer, L"Failure", MB_ICONERROR); } else { DisassemblerGui dlgDisassembler(address, &apiReader); 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(); + ProcessAccessHelp::targetImageBase = process.imageBase; + ProcessAccessHelp::targetSizeOfImage = ProcessAccessHelp::getSizeOfImageProcess(ProcessAccessHelp::hProcess, ProcessAccessHelp::targetImageBase); process.imageSize = (DWORD)ProcessAccessHelp::targetSizeOfImage; Scylla::windowLog.log(L"Imagebase: " PRINTF_DWORD_PTR_FULL L" Size: %08X", process.imageBase, process.imageSize); process.entryPoint = ProcessAccessHelp::getEntryPointFromFile(process.fullPath); EditOEPAddress.SetValue(process.entryPoint + process.imageBase); selectedProcess = &process; enableDialogControls(TRUE); updateStatusBar(); } void MainGui::fillProcessListComboBox(CComboBox& hCombo) { hCombo.ResetContent(); std::vector& processList = Scylla::processLister.getProcessListSnapshot(); for (size_t i = 0; i < processList.size(); i++) { swprintf_s(stringBuffer, L"0x%04X - %s - %s", processList[i].PID, processList[i].filename, processList[i].fullPath); hCombo.AddString(stringBuffer); } } /* void MainGui::addTextToOutputLog(const WCHAR * text) { if (m_hWnd) { ListLog.SetCurSel(ListLog.AddString(text)); } } */ void MainGui::clearOutputLog() { if (m_hWnd) { ListLog.ResetContent(); } } bool MainGui::saveLogToFile(const WCHAR * file) { const BYTE BOM[] = {0xFF, 0xFE}; // UTF-16 little-endian const WCHAR newLine[] = L"\r\n"; bool success = true; HANDLE hFile = CreateFile(file, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); if(hFile != INVALID_HANDLE_VALUE) { ProcessAccessHelp::writeMemoryToFileEnd(hFile, sizeof(BOM), BOM); WCHAR * buffer = 0; size_t bufsize = 0; for(int i = 0; i < ListLog.GetCount(); i++) { size_t size = ListLog.GetTextLen(i); size += _countof(newLine)-1; if(size+1 > bufsize) { bufsize = size+1; delete[] buffer; try { buffer = new WCHAR[bufsize]; } catch(std::bad_alloc&) { buffer = 0; success = false; break; } } ListLog.GetText(i, buffer); wcscat_s(buffer, bufsize, newLine); ProcessAccessHelp::writeMemoryToFileEnd(hFile, (DWORD)(size * sizeof(WCHAR)), buffer); } delete[] buffer; CloseHandle(hFile); } return success; } void MainGui::showInvalidImportsActionHandler() { importsHandling.selectImports(true, false); GotoDlgCtrl(TreeImports); } void MainGui::showSuspectImportsActionHandler() { importsHandling.selectImports(false, true); GotoDlgCtrl(TreeImports); } void MainGui::deleteSelectedImportsActionHandler() { CTreeItem selected = TreeImports.GetFirstSelectedItem(); while(!selected.IsNull()) { if(importsHandling.isModule(selected)) { importsHandling.cutModule(selected); } else { importsHandling.cutImport(selected); } selected = TreeImports.GetNextSelectedItem(selected); } updateStatusBar(); } void MainGui::invalidateSelectedImportsActionHandler() { CTreeItem selected = TreeImports.GetFirstSelectedItem(); while(!selected.IsNull()) { if(importsHandling.isImport(selected)) { importsHandling.invalidateImport(selected); } selected = TreeImports.GetNextSelectedItem(selected); } updateStatusBar(); } void MainGui::loadTreeActionHandler() { if(!selectedProcess) return; WCHAR selectedFilePath[MAX_PATH]; getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if(showFileDialog(selectedFilePath, false, NULL, filterXml, NULL, stringBuffer)) { TreeImportExport treeIO(selectedFilePath); DWORD_PTR addrOEP = 0; DWORD_PTR addrIAT = 0; DWORD sizeIAT = 0; if(!treeIO.importTreeList(importsHandling.moduleList, &addrOEP, &addrIAT, &sizeIAT)) { Scylla::windowLog.log(L"Loading tree file failed %s", selectedFilePath); MessageBox(L"Loading tree file failed.", L"Failure", MB_ICONERROR); } else { EditOEPAddress.SetValue(addrOEP); EditIATAddress.SetValue(addrIAT); EditIATSize.SetValue(sizeIAT); importsHandling.displayAllImports(); updateStatusBar(); Scylla::windowLog.log(L"Loaded tree file %s", selectedFilePath); Scylla::windowLog.log(L"-> OEP: " PRINTF_DWORD_PTR_FULL, addrOEP); Scylla::windowLog.log(L"-> IAT: " PRINTF_DWORD_PTR_FULL L" Size: " PRINTF_DWORD_PTR, addrIAT, sizeIAT); } } } void MainGui::saveTreeActionHandler() { if(!selectedProcess) return; WCHAR selectedFilePath[MAX_PATH]; getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if(showFileDialog(selectedFilePath, true, NULL, filterXml, L"xml", stringBuffer)) { TreeImportExport treeIO(selectedFilePath); DWORD_PTR addrOEP = EditOEPAddress.GetValue(); DWORD_PTR addrIAT = EditIATAddress.GetValue(); DWORD sizeIAT = EditIATSize.GetValue(); if(!treeIO.exportTreeList(importsHandling.moduleList, selectedProcess, addrOEP, addrIAT, sizeIAT)) { Scylla::windowLog.log(L"Saving tree file failed %s", selectedFilePath); MessageBox(L"Saving tree file failed.", L"Failure", MB_ICONERROR); } else { Scylla::windowLog.log(L"Saved tree file %s", selectedFilePath); } } } void MainGui::iatAutosearchActionHandler() { DWORD_PTR searchAddress = 0; DWORD_PTR addressIAT = 0, addressIATAdv = 0; DWORD sizeIAT = 0, sizeIATAdv = 0; IATSearch iatSearch; if(!selectedProcess) return; if(EditOEPAddress.GetWindowTextLength() > 0) { searchAddress = EditOEPAddress.GetValue(); if (searchAddress) { if (Scylla::config[USE_ADVANCED_IAT_SEARCH].isTrue()) { if (iatSearch.searchImportAddressTableInProcess(searchAddress, &addressIATAdv, &sizeIATAdv, true)) { Scylla::windowLog.log(L"IAT Search Advanced: IAT VA " PRINTF_DWORD_PTR_FULL L" RVA " PRINTF_DWORD_PTR_FULL L" Size 0x%04X (%d)", addressIATAdv, addressIATAdv - ProcessAccessHelp::targetImageBase, sizeIATAdv, sizeIATAdv); } else { Scylla::windowLog.log(L"IAT Search Advanced: IAT not found at OEP " PRINTF_DWORD_PTR_FULL L"!", searchAddress); } } if (iatSearch.searchImportAddressTableInProcess(searchAddress, &addressIAT, &sizeIAT, false)) { Scylla::windowLog.log(L"IAT Search Normal: IAT VA " PRINTF_DWORD_PTR_FULL L" RVA " PRINTF_DWORD_PTR_FULL L" Size 0x%04X (%d)", addressIAT, addressIAT - ProcessAccessHelp::targetImageBase, sizeIAT, sizeIAT); } else { Scylla::windowLog.log(L"IAT Search Normal: IAT not found at OEP " PRINTF_DWORD_PTR_FULL L"!", searchAddress); } if (addressIAT != 0 && addressIATAdv == 0) { setDialogIATAddressAndSize(addressIAT, sizeIAT); } else if (addressIAT == 0 && addressIATAdv != 0) { setDialogIATAddressAndSize(addressIATAdv, sizeIATAdv); } else if (addressIAT != 0 && addressIATAdv != 0) { if (addressIATAdv != addressIAT || sizeIAT != sizeIATAdv) { int msgboxID = MessageBox(L"Result of advanced and normal search is different. Do you want to use the IAT Search Advanced result?", L"Information", MB_YESNO|MB_ICONINFORMATION); if (msgboxID == IDYES) { setDialogIATAddressAndSize(addressIATAdv, sizeIATAdv); } else { setDialogIATAddressAndSize(addressIAT, sizeIAT); } } else { setDialogIATAddressAndSize(addressIAT, sizeIAT); } } } } } 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(); + + if (Scylla::config[SCAN_AND_FIX_DIRECT_IMPORTS].isTrue()) + { + IATReferenceScan sc; + sc.ScanForDirectImports = true; + sc.ScanForNormalImports = false; + sc.startScan(ProcessAccessHelp::targetImageBase, (DWORD)ProcessAccessHelp::targetSizeOfImage, addressIAT, sizeIAT); + + Scylla::windowLog.log(L"DIRECT IMPORTS - Found %d possible direct imports!", sc.numberOfFoundDirectImports()); + + if (sc.numberOfFoundDirectImports() > 0) + { + sc.patchDirectImportsMemory(); + Scylla::windowLog.log(L"DIRECT IMPORTS - Patched!"); + } + } + + + if (isIATOutsidePeImage(addressIAT)) + { + Scylla::windowLog.log(L"WARNING! IAT is not inside the PE image, requires rebasing!"); + } } } void MainGui::SetupImportsMenuItems(CTreeItem item) { bool isItem, isImport = false; isItem = !item.IsNull(); if(isItem) { isImport = importsHandling.isImport(item); } CMenuHandle hSub = hMenuImports.GetSubMenu(0); UINT itemOnly = isItem ? MF_ENABLED : MF_GRAYED; UINT importOnly = isImport ? MF_ENABLED : MF_GRAYED; hSub.EnableMenuItem(ID__INVALIDATE, itemOnly); hSub.EnableMenuItem(ID__DISASSEMBLE, importOnly); hSub.EnableMenuItem(ID__CUTTHUNK, importOnly); hSub.EnableMenuItem(ID__DELETETREENODE, itemOnly); } void MainGui::DisplayContextMenuImports(CWindow hwnd, CPoint pt) { if(TreeImports.GetCount() < 1) return; CTreeItem over, parent; if(pt.x == -1 && pt.y == -1) // invoked by keyboard { CRect pos; over = TreeImports.GetFocusItem(); if(over) { over.EnsureVisible(); over.GetRect(&pos, TRUE); TreeImports.ClientToScreen(&pos); } else { TreeImports.GetWindowRect(&pos); } pt = pos.TopLeft(); } else { // Get item under cursor over = findTreeItem(pt, true); } SetupImportsMenuItems(over); CMenuHandle hSub = hMenuImports.GetSubMenu(0); BOOL menuItem = hSub.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD, pt.x, pt.y, hwnd); if (menuItem) { if ((menuItem >= PLUGIN_MENU_BASE_ID) && (menuItem <= (int)(Scylla::plugins.getScyllaPluginList().size() + Scylla::plugins.getImprecPluginList().size() + PLUGIN_MENU_BASE_ID))) { //wsprintf(stringBuffer, L"%d %s\n",menuItem,pluginList[menuItem - PLUGIN_MENU_BASE_ID].pluginName); //MessageBox(stringBuffer, L"plugin selection"); pluginActionHandler(menuItem); return; } switch (menuItem) { case ID__INVALIDATE: if(importsHandling.isModule(over)) importsHandling.invalidateModule(over); else importsHandling.invalidateImport(over); break; case ID__DISASSEMBLE: startDisassemblerGui(over); break; case ID__EXPANDALLNODES: importsHandling.expandAllTreeNodes(); break; case ID__COLLAPSEALLNODES: importsHandling.collapseAllTreeNodes(); break; case ID__CUTTHUNK: importsHandling.cutImport(over); break; case ID__DELETETREENODE: importsHandling.cutModule(importsHandling.isImport(over) ? over.GetParent() : over); break; } } updateStatusBar(); } void MainGui::DisplayContextMenuLog(CWindow hwnd, CPoint pt) { if(pt.x == -1 && pt.y == -1) // invoked by keyboard { CRect pos; ListLog.GetWindowRect(&pos); pt = pos.TopLeft(); } CMenuHandle hSub = hMenuLog.GetSubMenu(0); BOOL menuItem = hSub.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD, pt.x, pt.y, hwnd); if (menuItem) { switch (menuItem) { case ID__SAVE: WCHAR selectedFilePath[MAX_PATH]; getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if(showFileDialog(selectedFilePath, true, NULL, filterTxt, L"txt", stringBuffer)) { saveLogToFile(selectedFilePath); } break; case ID__CLEAR: clearOutputLog(); break; } } } void MainGui::appendPluginListToMenu(CMenuHandle hMenu) { std::vector &scyllaPluginList = Scylla::plugins.getScyllaPluginList(); std::vector &imprecPluginList = Scylla::plugins.getImprecPluginList(); if (scyllaPluginList.size() > 0) { CMenuHandle newMenu; newMenu.CreatePopupMenu(); for (size_t i = 0; i < scyllaPluginList.size(); i++) { newMenu.AppendMenu(MF_STRING, i + PLUGIN_MENU_BASE_ID, scyllaPluginList[i].pluginName); } hMenu.AppendMenu(MF_MENUBARBREAK); hMenu.AppendMenu(MF_POPUP, newMenu, L"Scylla Plugins"); } if (imprecPluginList.size() > 0) { CMenuHandle newMenu; newMenu.CreatePopupMenu(); for (size_t i = 0; i < imprecPluginList.size(); i++) { newMenu.AppendMenu(MF_STRING, scyllaPluginList.size() + i + PLUGIN_MENU_BASE_ID, imprecPluginList[i].pluginName); } hMenu.AppendMenu(MF_MENUBARBREAK); hMenu.AppendMenu(MF_POPUP, newMenu, L"ImpREC Plugins"); } } void MainGui::dumpMemoryActionHandler() { WCHAR selectedFilePath[MAX_PATH]; DumpMemoryGui dlgDumpMemory; if(dlgDumpMemory.DoModal()) { getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if(showFileDialog(selectedFilePath, true, dlgDumpMemory.dumpFilename, filterMem, L"mem", stringBuffer)) { if (ProcessAccessHelp::writeMemoryToNewFile(selectedFilePath,dlgDumpMemory.dumpedMemorySize,dlgDumpMemory.dumpedMemory)) { Scylla::windowLog.log(L"Memory dump saved %s", selectedFilePath); } else { Scylla::windowLog.log(L"Error! Cannot write memory dump to disk"); } } } } void MainGui::dumpSectionActionHandler() { WCHAR selectedFilePath[MAX_PATH]; DumpSectionGui dlgDumpSection; const WCHAR * fileFilter; const WCHAR * defExtension; PeParser * peFile = 0; dlgDumpSection.entryPoint = EditOEPAddress.GetValue(); if (ProcessAccessHelp::selectedModule) { //dump DLL fileFilter = filterDll; defExtension = L"dll"; dlgDumpSection.imageBase = ProcessAccessHelp::selectedModule->modBaseAddr; //get it from gui wcscpy_s(dlgDumpSection.fullpath, ProcessAccessHelp::selectedModule->fullPath); } else { fileFilter = filterExe; defExtension = L"exe"; dlgDumpSection.imageBase = ProcessAccessHelp::targetImageBase; //get it from gui wcscpy_s(dlgDumpSection.fullpath, selectedProcess->fullPath); } if(dlgDumpSection.DoModal()) { getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if(showFileDialog(selectedFilePath, true, NULL, fileFilter, defExtension, stringBuffer)) { checkSuspendProcess(); if (Scylla::config[USE_PE_HEADER_FROM_DISK].isTrue()) { peFile = new PeParser(dlgDumpSection.fullpath, true); } else { peFile = new PeParser(dlgDumpSection.imageBase, true); } std::vector & sectionList = dlgDumpSection.getSectionList(); if (peFile->dumpProcess(dlgDumpSection.imageBase, dlgDumpSection.entryPoint, selectedFilePath, sectionList)) { 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); } delete peFile; } } } void MainGui::dumpActionHandler() { if(!selectedProcess) return; WCHAR selectedFilePath[MAX_PATH]; const WCHAR * fileFilter; const WCHAR * defExtension; DWORD_PTR modBase = 0; DWORD_PTR entrypoint = 0; WCHAR * filename = 0; PeParser * peFile = 0; 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)) { entrypoint = EditOEPAddress.GetValue(); checkSuspendProcess(); if (ProcessAccessHelp::selectedModule) { //dump DLL modBase = ProcessAccessHelp::selectedModule->modBaseAddr; filename = ProcessAccessHelp::selectedModule->fullPath; } else { //dump exe modBase = ProcessAccessHelp::targetImageBase; filename = selectedProcess->fullPath; } if (Scylla::config[USE_PE_HEADER_FROM_DISK].isTrue()) { peFile = new PeParser(filename, true); } else { peFile = new PeParser(modBase, true); } if (peFile->dumpProcess(modBase, entrypoint, 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); } delete peFile; } } void MainGui::peRebuildActionHandler() { DWORD newSize = 0; WCHAR selectedFilePath[MAX_PATH]; getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if(showFileDialog(selectedFilePath, false, NULL, filterExeDll, NULL, stringBuffer)) { if (Scylla::config[CREATE_BACKUP].isTrue()) { if (!ProcessAccessHelp::createBackupFile(selectedFilePath)) { Scylla::windowLog.log(L"Creating backup file failed %s", selectedFilePath); } } DWORD fileSize = (DWORD)ProcessAccessHelp::getFileSize(selectedFilePath); PeParser peFile(selectedFilePath, true); if (!peFile.isValidPeFile()) { Scylla::windowLog.log(L"This is not a valid PE file %s", selectedFilePath); MessageBox(L"Not a valid PE file.", L"Failure", MB_ICONERROR); return; } if (peFile.readPeSectionsFromFile()) { peFile.setDefaultFileAlignment(); if (Scylla::config[REMOVE_DOS_HEADER_STUB].isTrue()) { peFile.removeDosStub(); } peFile.alignAllSectionHeaders(); peFile.fixPeHeader(); if (peFile.savePeFileToDisk(selectedFilePath)) { newSize = (DWORD)ProcessAccessHelp::getFileSize(selectedFilePath); if (Scylla::config[UPDATE_HEADER_CHECKSUM].isTrue()) { Scylla::windowLog.log(L"Generating PE header checksum"); if (!PeParser::updatePeHeaderChecksum(selectedFilePath, newSize)) { Scylla::windowLog.log(L"Generating PE header checksum FAILED!"); } } Scylla::windowLog.log(L"Rebuild success %s", selectedFilePath); Scylla::windowLog.log(L"-> Old file size 0x%08X new file size 0x%08X (%d %%)", fileSize, newSize, ((newSize * 100) / fileSize) ); } else { Scylla::windowLog.log(L"Rebuild failed, cannot save file %s", selectedFilePath); MessageBox(L"Rebuild failed. Cannot save file.", L"Failure", MB_ICONERROR); } } else { Scylla::windowLog.log(L"Rebuild failed, cannot read file %s", selectedFilePath); MessageBox(L"Rebuild failed. Cannot read file.", L"Failure", MB_ICONERROR); } } } 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; DWORD_PTR modBase = 0; DWORD_PTR entrypoint = EditOEPAddress.GetValue(); if (ProcessAccessHelp::selectedModule) { modBase = ProcessAccessHelp::selectedModule->modBaseAddr; fileFilter = filterDll; } else { modBase = ProcessAccessHelp::targetImageBase; fileFilter = filterExe; } getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if (showFileDialog(selectedFilePath, false, NULL, fileFilter, NULL, stringBuffer)) { wcscpy_s(newFilePath, selectedFilePath); const WCHAR * extension = 0; WCHAR* dot = wcsrchr(newFilePath, L'.'); if (dot) { *dot = L'\0'; extension = selectedFilePath + (dot - newFilePath); //wcsrchr(selectedFilePath, L'.'); } wcscat_s(newFilePath, L"_SCY"); if(extension) { wcscat_s(newFilePath, extension); } ImportRebuilder importRebuild(selectedFilePath); if (Scylla::config[IAT_FIX_AND_OEP_FIX].isTrue()) { importRebuild.setEntryPointRva((DWORD)(entrypoint - modBase)); } if (Scylla::config[OriginalFirstThunk_SUPPORT].isTrue()) { importRebuild.enableOFTSupport(); } if (importRebuild.rebuildImportTable(newFilePath, importsHandling.moduleList)) { Scylla::windowLog.log(L"Import Rebuild success %s", newFilePath); } else { Scylla::windowLog.log(L"Import Rebuild failed %s", selectedFilePath); MessageBox(L"Import Rebuild failed", L"Failure", MB_ICONERROR); } } } void MainGui::enableDialogControls(BOOL value) { BOOL valButton = value ? TRUE : FALSE; GetDlgItem(IDC_BTN_PICKDLL).EnableWindow(valButton); GetDlgItem(IDC_BTN_DUMP).EnableWindow(valButton); GetDlgItem(IDC_BTN_FIXDUMP).EnableWindow(valButton); GetDlgItem(IDC_BTN_IATAUTOSEARCH).EnableWindow(valButton); GetDlgItem(IDC_BTN_GETIMPORTS).EnableWindow(valButton); GetDlgItem(IDC_BTN_SUSPECTIMPORTS).EnableWindow(valButton); GetDlgItem(IDC_BTN_INVALIDIMPORTS).EnableWindow(valButton); GetDlgItem(IDC_BTN_CLEARIMPORTS).EnableWindow(valButton); CMenuHandle menu = GetMenu(); UINT valMenu = value ? MF_ENABLED : MF_GRAYED; menu.EnableMenuItem(ID_FILE_DUMP, valMenu); menu.EnableMenuItem(ID_FILE_DUMPMEMORY, valMenu); menu.EnableMenuItem(ID_FILE_DUMPSECTION, 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.EnableMenuItem(ID_MISC_DISASSEMBLER, 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::showDonateDialog() { DonateGui dlgDonate; dlgDonate.DoModal(); } void MainGui::dllInjectActionHandler() { if(!selectedProcess) return; WCHAR selectedFilePath[MAX_PATH]; HMODULE hMod = 0; DllInjection dllInjection; getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if (showFileDialog(selectedFilePath, false, NULL, filterDll, NULL, stringBuffer)) { hMod = dllInjection.dllInjection(ProcessAccessHelp::hProcess, selectedFilePath); if (hMod && Scylla::config[DLL_INJECTION_AUTO_UNLOAD].isTrue()) { if (!dllInjection.unloadDllInProcess(ProcessAccessHelp::hProcess, hMod)) { Scylla::windowLog.log(L"DLL unloading failed, target %s", selectedFilePath); } } if (hMod) { Scylla::windowLog.log(L"DLL Injection was successful, target %s", selectedFilePath); } else { Scylla::windowLog.log(L"DLL Injection failed, target %s", selectedFilePath); } } } void MainGui::disassemblerActionHandler() { DWORD_PTR oep = EditOEPAddress.GetValue(); DisassemblerGui disGuiDlg(oep, &apiReader); disGuiDlg.DoModal(); } void MainGui::optionsActionHandler() { OptionsGui dlgOptions; dlgOptions.DoModal(); } void MainGui::clearImportsActionHandler() { importsHandling.clearAllImports(); updateStatusBar(); } void MainGui::pluginActionHandler( int menuItem ) { if(!selectedProcess) return; DllInjectionPlugin dllInjectionPlugin; std::vector &scyllaPluginList = Scylla::plugins.getScyllaPluginList(); std::vector &imprecPluginList = Scylla::plugins.getImprecPluginList(); menuItem -= PLUGIN_MENU_BASE_ID; dllInjectionPlugin.hProcess = ProcessAccessHelp::hProcess; dllInjectionPlugin.apiReader = &apiReader; if (menuItem < (int)scyllaPluginList.size()) { //scylla plugin dllInjectionPlugin.injectPlugin(scyllaPluginList[menuItem], importsHandling.moduleList,selectedProcess->imageBase, selectedProcess->imageSize); } else { #ifndef _WIN64 menuItem -= (int)scyllaPluginList.size(); //imprec plugin dllInjectionPlugin.injectImprecPlugin(imprecPluginList[menuItem], importsHandling.moduleList,selectedProcess->imageBase, selectedProcess->imageSize); #endif } importsHandling.scanAndFixModuleList(); importsHandling.displayAllImports(); updateStatusBar(); } bool MainGui::getCurrentModulePath(WCHAR * buffer, size_t bufferSize) { if(!selectedProcess) return false; if(ProcessAccessHelp::selectedModule) { wcscpy_s(buffer, bufferSize, ProcessAccessHelp::selectedModule->fullPath); } else { wcscpy_s(buffer, bufferSize, selectedProcess->fullPath); } WCHAR * slash = wcsrchr(buffer, L'\\'); if(slash) { *(slash+1) = L'\0'; } return true; } void MainGui::checkSuspendProcess() { if (Scylla::config[SUSPEND_PROCESS_FOR_DUMPING].isTrue()) { if (!ProcessAccessHelp::suspendProcess()) { Scylla::windowLog.log(L"Error: Cannot suspend process."); } else { isProcessSuspended = true; Scylla::windowLog.log(L"Suspending process successful, please resume manually."); } } } void MainGui::setDialogIATAddressAndSize( DWORD_PTR addressIAT, DWORD sizeIAT ) { EditIATAddress.SetValue(addressIAT); EditIATSize.SetValue(sizeIAT); swprintf_s(stringBuffer, L"IAT found:\r\n\r\nStart: " PRINTF_DWORD_PTR_FULL L"\r\nSize: 0x%04X (%d) ", addressIAT, sizeIAT, sizeIAT); MessageBox(stringBuffer, L"IAT found", MB_ICONINFORMATION); } + +bool MainGui::isIATOutsidePeImage( DWORD_PTR addressIAT ) +{ + DWORD_PTR minAdd = 0, maxAdd = 0; + + if(ProcessAccessHelp::selectedModule) + { + minAdd = ProcessAccessHelp::selectedModule->modBaseAddr; + maxAdd = minAdd + ProcessAccessHelp::selectedModule->modBaseSize; + } + else + { + minAdd = selectedProcess->imageBase; + maxAdd = minAdd + selectedProcess->imageSize; + } + + if (addressIAT > minAdd && addressIAT < maxAdd) + { + return false; //inside pe image + } + else + { + return true; //outside pe image, requires rebasing iat + } +} diff --git a/Scylla/MainGui.rc b/Scylla/MainGui.rc index 94e55e9..e2ae354 100644 Binary files a/Scylla/MainGui.rc and b/Scylla/MainGui.rc differ diff --git a/Scylla/OptionsGui.cpp b/Scylla/OptionsGui.cpp index 90f938c..cc8f41d 100644 --- a/Scylla/OptionsGui.cpp +++ b/Scylla/OptionsGui.cpp @@ -1,60 +1,62 @@ #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() const { 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); Scylla::config[REMOVE_DOS_HEADER_STUB].setBool(removeDosHeaderStub); Scylla::config[IAT_FIX_AND_OEP_FIX].setBool(fixIatAndOep); Scylla::config[SUSPEND_PROCESS_FOR_DUMPING].setBool(suspendProcessForDumping); Scylla::config[OriginalFirstThunk_SUPPORT].setBool(oftSupport); Scylla::config[USE_ADVANCED_IAT_SEARCH].setBool(useAdvancedIatSearch); + Scylla::config[SCAN_AND_FIX_DIRECT_IMPORTS].setBool(scanAndFixDirectImports); } void OptionsGui::loadOptions() { 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); iatSectionName[_countof(iatSectionName) - 1] = L'\0'; removeDosHeaderStub = Scylla::config[REMOVE_DOS_HEADER_STUB].getBool(); fixIatAndOep = Scylla::config[IAT_FIX_AND_OEP_FIX].getBool(); suspendProcessForDumping = Scylla::config[SUSPEND_PROCESS_FOR_DUMPING].getBool(); oftSupport = Scylla::config[OriginalFirstThunk_SUPPORT].getBool(); useAdvancedIatSearch = Scylla::config[USE_ADVANCED_IAT_SEARCH].getBool(); + scanAndFixDirectImports = Scylla::config[SCAN_AND_FIX_DIRECT_IMPORTS].getBool(); } diff --git a/Scylla/OptionsGui.h b/Scylla/OptionsGui.h index 09901f7..acaef96 100644 --- a/Scylla/OptionsGui.h +++ b/Scylla/OptionsGui.h @@ -1,72 +1,74 @@ #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) DDX_CHECK(IDC_CHECK_REMOVE_DOS_STUB, removeDosHeaderStub) DDX_CHECK(IDC_CHECK_FIX_IAT_AND_OEP, fixIatAndOep) DDX_CHECK(IDC_CHECK_SUSPEND_PROCESS, suspendProcessForDumping) DDX_CHECK(IDC_CHECKOFTSUPPORT, oftSupport) DDX_CHECK(IDC_CHECK_USEADVANCEDIATSEARCH, useAdvancedIatSearch) + DDX_CHECK(IDC_SCANFIXDIRECTIMPORT, scanAndFixDirectImports) 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; bool removeDosHeaderStub; bool fixIatAndOep; bool suspendProcessForDumping; bool oftSupport; bool useAdvancedIatSearch; + bool scanAndFixDirectImports; // 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() const; void loadOptions(); }; diff --git a/Scylla/ProcessAccessHelp.cpp b/Scylla/ProcessAccessHelp.cpp index ca1a317..028fda0 100644 --- a/Scylla/ProcessAccessHelp.cpp +++ b/Scylla/ProcessAccessHelp.cpp @@ -1,869 +1,884 @@ #include "ProcessAccessHelp.h" #include "Scylla.h" #include "NativeWinApi.h" #include "PeParser.h" HANDLE ProcessAccessHelp::hProcess = 0; ModuleInfo * ProcessAccessHelp::selectedModule; DWORD_PTR ProcessAccessHelp::targetImageBase = 0; DWORD_PTR ProcessAccessHelp::targetSizeOfImage = 0; DWORD_PTR ProcessAccessHelp::maxValidAddress = 0; std::vector ProcessAccessHelp::moduleList; //target process module list std::vector ProcessAccessHelp::ownModuleList; //own module list _DInst ProcessAccessHelp::decomposerResult[MAX_INSTRUCTIONS]; unsigned int ProcessAccessHelp::decomposerInstructionsCount = 0; _CodeInfo ProcessAccessHelp::decomposerCi = {0}; _DecodedInst ProcessAccessHelp::decodedInstructions[MAX_INSTRUCTIONS]; unsigned int ProcessAccessHelp::decodedInstructionsCount = 0; BYTE ProcessAccessHelp::fileHeaderFromDisk[PE_HEADER_BYTES_COUNT]; //#define DEBUG_COMMENTS bool ProcessAccessHelp::openProcessHandle(DWORD dwPID) { if (dwPID > 0) { if (hProcess) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"openProcessHandle :: There is already a process handle, HANDLE %X", hProcess); #endif return false; } else { //hProcess = OpenProcess(PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_QUERY_INFORMATION|PROCESS_VM_READ|PROCESS_VM_WRITE, 0, dwPID); //if (!NT_SUCCESS(NativeWinApi::NtOpenProcess(&hProcess,PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_QUERY_INFORMATION|PROCESS_VM_READ|PROCESS_VM_WRITE,&ObjectAttributes, &cid))) hProcess = NativeOpenProcess(PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_QUERY_INFORMATION|PROCESS_VM_READ|PROCESS_VM_WRITE|PROCESS_SUSPEND_RESUME|PROCESS_TERMINATE, dwPID); if (hProcess) { return true; } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"openProcessHandle :: Failed to open handle, PID %X", dwPID); #endif return false; } } } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"openProcessHandle :: Wrong PID, PID %X", dwPID); #endif return false; } } HANDLE ProcessAccessHelp::NativeOpenProcess(DWORD dwDesiredAccess, DWORD dwProcessId) { HANDLE hProcess = 0; CLIENT_ID cid = {0}; OBJECT_ATTRIBUTES ObjectAttributes; NTSTATUS ntStatus = 0; InitializeObjectAttributes(&ObjectAttributes, 0, 0, 0, 0); cid.UniqueProcess = (HANDLE)dwProcessId; ntStatus = NativeWinApi::NtOpenProcess(&hProcess,dwDesiredAccess,&ObjectAttributes, &cid); if (NT_SUCCESS(ntStatus)) { return hProcess; } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"NativeOpenProcess :: Failed to open handle, PID %X Error 0x%X", dwProcessId, NativeWinApi::RtlNtStatusToDosError(ntStatus)); #endif return 0; } } void ProcessAccessHelp::closeProcessHandle() { if (hProcess) { CloseHandle(hProcess); hProcess = 0; } moduleList.clear(); targetImageBase = 0; selectedModule = 0; } bool ProcessAccessHelp::readMemoryPartlyFromProcess(DWORD_PTR address, SIZE_T size, LPVOID dataBuffer) { DWORD_PTR addressPart = 0; DWORD_PTR readBytes = 0; DWORD_PTR bytesToRead = 0; MEMORY_BASIC_INFORMATION memBasic = {0}; bool returnValue = false; if (!hProcess) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"readMemoryPartlyFromProcess :: hProcess == NULL"); #endif return returnValue; } if (!readMemoryFromProcess(address, size, dataBuffer)) { addressPart = address; do { if (!VirtualQueryEx(ProcessAccessHelp::hProcess,(LPCVOID)addressPart,&memBasic,sizeof(memBasic))) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"readMemoryPartlyFromProcess :: Error VirtualQueryEx %X %X err: %u", addressPart,size, GetLastError()); #endif break; } bytesToRead = memBasic.RegionSize; if ( (readBytes+bytesToRead) > size) { bytesToRead = size - readBytes; } if (memBasic.State == MEM_COMMIT) { if (!readMemoryFromProcess(addressPart, bytesToRead, (LPVOID)((DWORD_PTR)dataBuffer + readBytes))) { break; } } else { ZeroMemory((LPVOID)((DWORD_PTR)dataBuffer + readBytes),bytesToRead); } readBytes += bytesToRead; addressPart += memBasic.RegionSize; } while (readBytes < size); if (readBytes == size) { returnValue = true; } } else { returnValue = true; } return returnValue; } +bool ProcessAccessHelp::writeMemoryToProcess(DWORD_PTR address, SIZE_T size, LPVOID dataBuffer) +{ + SIZE_T lpNumberOfBytesWritten = 0; + if (!hProcess) + { +#ifdef DEBUG_COMMENTS + Scylla::debugLog.log(L"readMemoryFromProcess :: hProcess == NULL"); +#endif + return false; + } + + + return (WriteProcessMemory(hProcess,(LPVOID)address, dataBuffer, size,&lpNumberOfBytesWritten) != FALSE); +} + bool ProcessAccessHelp::readMemoryFromProcess(DWORD_PTR address, SIZE_T size, LPVOID dataBuffer) { SIZE_T lpNumberOfBytesRead = 0; DWORD dwProtect = 0; bool returnValue = false; if (!hProcess) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"readMemoryFromProcess :: hProcess == NULL"); #endif return returnValue; } if (!ReadProcessMemory(hProcess, (LPVOID)address, dataBuffer, size, &lpNumberOfBytesRead)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"readMemoryFromProcess :: Error ReadProcessMemory %X %X err: %u", address, size, GetLastError()); #endif if (!VirtualProtectEx(hProcess, (LPVOID)address, size, PAGE_READWRITE, &dwProtect)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"readMemoryFromProcess :: Error VirtualProtectEx %X %X err: %u", address,size, GetLastError()); #endif returnValue = false; } else { if (!ReadProcessMemory(hProcess, (LPVOID)address, dataBuffer, size, &lpNumberOfBytesRead)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"readMemoryFromProcess :: Error ReadProcessMemory %X %X err: %u", address, size, GetLastError()); #endif returnValue = false; } else { returnValue = true; } VirtualProtectEx(hProcess, (LPVOID)address, size, dwProtect, &dwProtect); } } else { returnValue = true; } if (returnValue) { if (size != lpNumberOfBytesRead) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"readMemoryFromProcess :: Error ReadProcessMemory read %d bytes requested %d bytes", lpNumberOfBytesRead, size); #endif returnValue = false; } else { returnValue = true; } } return returnValue; } bool ProcessAccessHelp::decomposeMemory(BYTE * dataBuffer, SIZE_T bufferSize, DWORD_PTR startAddress) { ZeroMemory(&decomposerCi, sizeof(_CodeInfo)); decomposerCi.code = dataBuffer; decomposerCi.codeLen = (int)bufferSize; decomposerCi.dt = dt; decomposerCi.codeOffset = startAddress; decomposerInstructionsCount = 0; if (distorm_decompose(&decomposerCi, decomposerResult, sizeof(decomposerResult)/sizeof(decomposerResult[0]), &decomposerInstructionsCount) == DECRES_INPUTERR) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"decomposeMemory :: distorm_decompose == DECRES_INPUTERR"); #endif return false; } else { return true; } } bool ProcessAccessHelp::disassembleMemory(BYTE * dataBuffer, SIZE_T bufferSize, DWORD_PTR startOffset) { // Holds the result of the decoding. _DecodeResult res; // next is used for instruction's offset synchronization. // decodedInstructionsCount holds the count of filled instructions' array by the decoder. decodedInstructionsCount = 0; _OffsetType offset = startOffset; res = distorm_decode(offset, dataBuffer, (int)bufferSize, dt, decodedInstructions, MAX_INSTRUCTIONS, &decodedInstructionsCount); /* for (unsigned int i = 0; i < decodedInstructionsCount; i++) { #ifdef SUPPORT_64BIT_OFFSET printf("%0*I64x (%02d) %-24s %s%s%s\n", dt != Decode64Bits ? 8 : 16, decodedInstructions[i].offset, decodedInstructions[i].size, (char*)decodedInstructions[i].instructionHex.p, (char*)decodedInstructions[i].mnemonic.p, decodedInstructions[i].operands.length != 0 ? " " : "", (char*)decodedInstructions[i].operands.p); #else printf("%08x (%02d) %-24s %s%s%s\n", decodedInstructions[i].offset, decodedInstructions[i].size, (char*)decodedInstructions[i].instructionHex.p, (char*)decodedInstructions[i].mnemonic.p, decodedInstructions[i].operands.length != 0 ? " " : "", (char*)decodedInstructions[i].operands.p); #endif }*/ if (res == DECRES_INPUTERR) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"disassembleMemory :: res == DECRES_INPUTERR"); #endif return false; } else if (res == DECRES_SUCCESS) { //printf("disassembleMemory :: res == DECRES_SUCCESS\n"); return true; } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"disassembleMemory :: res == %d", res); #endif - return false; + return true; //not all instructions fit in buffer } } DWORD_PTR ProcessAccessHelp::findPattern(DWORD_PTR startOffset, DWORD size, BYTE * pattern, const char * mask) { DWORD pos = 0; size_t searchLen = strlen(mask) - 1; for(DWORD_PTR retAddress = startOffset; retAddress < startOffset + size; retAddress++) { if( *(BYTE*)retAddress == pattern[pos] || mask[pos] == '?' ) { if(mask[pos+1] == 0x00) { return (retAddress - searchLen); } pos++; } else { pos = 0; } } return 0; } bool ProcessAccessHelp::readHeaderFromCurrentFile(const WCHAR * filePath) { return readHeaderFromFile(fileHeaderFromDisk, sizeof(fileHeaderFromDisk), filePath); } LONGLONG ProcessAccessHelp::getFileSize(const WCHAR * filePath) { LONGLONG fileSize = 0; HANDLE hFile = CreateFile(filePath, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); if (hFile != INVALID_HANDLE_VALUE) { fileSize = getFileSize(hFile); CloseHandle(hFile); } return fileSize; } LONGLONG ProcessAccessHelp::getFileSize(HANDLE hFile) { LARGE_INTEGER lpFileSize = {0}; if ((hFile != INVALID_HANDLE_VALUE) && (hFile != 0)) { if (!GetFileSizeEx(hFile, &lpFileSize)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"ProcessAccessHelp::getFileSize :: GetFileSizeEx failed %u", GetLastError()); #endif return 0; } else { return lpFileSize.QuadPart; } } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"ProcessAccessHelp::getFileSize hFile invalid"); #endif return 0; } } bool ProcessAccessHelp::readMemoryFromFile(HANDLE hFile, LONG offset, DWORD size, LPVOID dataBuffer) { DWORD lpNumberOfBytesRead = 0; DWORD retValue = 0; DWORD dwError = 0; if (hFile != INVALID_HANDLE_VALUE) { retValue = SetFilePointer(hFile, offset, NULL, FILE_BEGIN); dwError = GetLastError(); if ((retValue == INVALID_SET_FILE_POINTER) && (dwError != NO_ERROR)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"readMemoryFromFile :: SetFilePointer failed error %u", dwError); #endif return false; } else { if (ReadFile(hFile, dataBuffer, size, &lpNumberOfBytesRead, 0)) { return true; } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"readMemoryFromFile :: ReadFile failed - size %d - error %u", size, GetLastError()); #endif return false; } } } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"readMemoryFromFile :: hFile invalid"); #endif return false; } } bool ProcessAccessHelp::writeMemoryToNewFile(const WCHAR * file,DWORD size, LPCVOID dataBuffer) { HANDLE hFile = CreateFile(file, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0); if (hFile != INVALID_HANDLE_VALUE) { bool resultValue = writeMemoryToFile(hFile,0,size,dataBuffer); CloseHandle(hFile); return resultValue; } else { return false; } } bool ProcessAccessHelp::writeMemoryToFile(HANDLE hFile, LONG offset, DWORD size, LPCVOID dataBuffer) { DWORD lpNumberOfBytesWritten = 0; DWORD retValue = 0; DWORD dwError = 0; if ((hFile != INVALID_HANDLE_VALUE) && dataBuffer) { retValue = SetFilePointer(hFile, offset, NULL, FILE_BEGIN); dwError = GetLastError(); if ((retValue == INVALID_SET_FILE_POINTER) && (dwError != NO_ERROR)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"writeMemoryToFile :: SetFilePointer failed error %u", dwError); #endif return false; } else { if (WriteFile(hFile, dataBuffer, size, &lpNumberOfBytesWritten, 0)) { return true; } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"writeMemoryToFile :: WriteFile failed - size %d - error %u", size, GetLastError()); #endif return false; } } } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"writeMemoryToFile :: hFile invalid"); #endif return false; } } bool ProcessAccessHelp::writeMemoryToFileEnd(HANDLE hFile, DWORD size, LPCVOID dataBuffer) { DWORD lpNumberOfBytesWritten = 0; DWORD retValue = 0; if ((hFile != INVALID_HANDLE_VALUE) && (hFile != 0)) { SetFilePointer(hFile, 0, 0, FILE_END); if (WriteFile(hFile, dataBuffer, size, &lpNumberOfBytesWritten, 0)) { return true; } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"writeMemoryToFileEnd :: WriteFile failed - size %d - error %u", size, GetLastError()); #endif return false; } } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"writeMemoryToFileEnd :: hFile invalid"); #endif return false; } } bool ProcessAccessHelp::readHeaderFromFile(BYTE * buffer, DWORD bufferSize, const WCHAR * filePath) { DWORD lpNumberOfBytesRead = 0; LONGLONG fileSize = 0; DWORD dwSize = 0; bool returnValue = 0; HANDLE hFile = CreateFile(filePath, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); if( hFile == INVALID_HANDLE_VALUE ) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"readHeaderFromFile :: INVALID_HANDLE_VALUE %u", GetLastError()); #endif returnValue = false; } else { fileSize = getFileSize(hFile); if (fileSize > 0) { if (fileSize > bufferSize) { dwSize = bufferSize; } else { dwSize = (DWORD)(fileSize - 1); } returnValue = readMemoryFromFile(hFile, 0, dwSize, buffer); } CloseHandle(hFile); } return returnValue; } LPVOID ProcessAccessHelp::createFileMappingViewRead(const WCHAR * filePath) { return createFileMappingView(filePath, GENERIC_READ, PAGE_READONLY | SEC_IMAGE, FILE_MAP_READ); } LPVOID ProcessAccessHelp::createFileMappingViewFull(const WCHAR * filePath) { return createFileMappingView(filePath, GENERIC_ALL, PAGE_EXECUTE_READWRITE, FILE_MAP_ALL_ACCESS); } LPVOID ProcessAccessHelp::createFileMappingView(const WCHAR * filePath, DWORD accessFile, DWORD flProtect, DWORD accessMap) { HANDLE hFile = CreateFile(filePath, accessFile, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); if( hFile == INVALID_HANDLE_VALUE ) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"createFileMappingView :: INVALID_HANDLE_VALUE %u", GetLastError()); #endif return NULL; } HANDLE hMappedFile = CreateFileMapping(hFile, NULL, flProtect, 0, 0, NULL); CloseHandle(hFile); if( hMappedFile == NULL ) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"createFileMappingView :: hMappedFile == NULL"); #endif return NULL; } if (GetLastError() == ERROR_ALREADY_EXISTS) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"createFileMappingView :: GetLastError() == ERROR_ALREADY_EXISTS"); #endif return NULL; } LPVOID addrMappedDll = MapViewOfFile(hMappedFile, accessMap, 0, 0, 0); if( addrMappedDll == NULL ) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"createFileMappingView :: addrMappedDll == NULL"); #endif CloseHandle(hMappedFile); return NULL; } CloseHandle(hMappedFile); return addrMappedDll; } DWORD ProcessAccessHelp::getProcessByName(const WCHAR * processName) { DWORD dwPID = 0; HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); PROCESSENTRY32W pe32; pe32.dwSize = sizeof(PROCESSENTRY32W); if( !Process32FirstW( hProcessSnap, &pe32 ) ) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"getProcessByName :: Error getting first Process"); #endif CloseHandle( hProcessSnap ); return 0; } do { if(!_wcsicmp(pe32.szExeFile, processName)) { dwPID = pe32.th32ProcessID; break; } } while(Process32NextW(hProcessSnap, &pe32)); CloseHandle(hProcessSnap); return dwPID; } bool ProcessAccessHelp::getProcessModules(DWORD dwPID, std::vector &moduleList) { HANDLE hModuleSnap = INVALID_HANDLE_VALUE; MODULEENTRY32 me32; ModuleInfo module; // Take a snapshot of all modules in the specified process. hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, dwPID ); if( hModuleSnap == INVALID_HANDLE_VALUE ) { return false; } // Set the size of the structure before using it. me32.dwSize = sizeof( MODULEENTRY32 ); // Retrieve information about the first module, // and exit if unsuccessful if( !Module32First( hModuleSnap, &me32 ) ) { CloseHandle( hModuleSnap ); return false; } // Now walk the module list of the process, // and display information about each module //the first is always the .exe if (!Module32Next(hModuleSnap, &me32)) { CloseHandle( hModuleSnap ); return false; } moduleList.reserve(20); do { //printf(L"\n MODULE NAME: %s", me32.szModule); module.modBaseAddr = (DWORD_PTR)me32.modBaseAddr; module.modBaseSize = me32.modBaseSize; module.isAlreadyParsed = false; module.parsing = false; wcscpy_s(module.fullPath, me32.szExePath); moduleList.push_back(module); } while(Module32Next(hModuleSnap, &me32)); CloseHandle( hModuleSnap ); return true; } bool ProcessAccessHelp::getMemoryRegionFromAddress(DWORD_PTR address, DWORD_PTR * memoryRegionBase, SIZE_T * memoryRegionSize) { MEMORY_BASIC_INFORMATION memBasic; if (VirtualQueryEx(hProcess,(LPCVOID)address,&memBasic,sizeof(MEMORY_BASIC_INFORMATION)) != sizeof(MEMORY_BASIC_INFORMATION)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"getMemoryRegionFromAddress :: VirtualQueryEx error %u", GetLastError()); #endif return false; } else { *memoryRegionBase = (DWORD_PTR)memBasic.BaseAddress; *memoryRegionSize = memBasic.RegionSize; return true; } } bool ProcessAccessHelp::getSizeOfImageCurrentProcess() { DWORD_PTR newSizeOfImage = getSizeOfImageProcess(ProcessAccessHelp::hProcess, ProcessAccessHelp::targetImageBase); if (newSizeOfImage != 0) { ProcessAccessHelp::targetSizeOfImage = newSizeOfImage; return true; } else { return false; } } SIZE_T ProcessAccessHelp::getSizeOfImageProcess(HANDLE processHandle, DWORD_PTR moduleBase) { SIZE_T sizeOfImage = 0; MEMORY_BASIC_INFORMATION lpBuffer = {0}; SIZE_T dwLength = sizeof(MEMORY_BASIC_INFORMATION); do { moduleBase = (DWORD_PTR)((SIZE_T)moduleBase + lpBuffer.RegionSize); sizeOfImage += lpBuffer.RegionSize; //printf("Query 0x"PRINTF_DWORD_PTR_FULL" size 0x%08X\n",moduleBase,sizeOfImage); if (!VirtualQueryEx(processHandle, (LPCVOID)moduleBase, &lpBuffer, dwLength)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"getSizeOfImageProcess :: VirtualQuery failed %X", GetLastError()); #endif lpBuffer.Type = 0; sizeOfImage = 0; } /*else { printf("\nAllocationBase %X\n",lpBuffer.AllocationBase); printf("AllocationProtect %X\n",lpBuffer.AllocationProtect); printf("BaseAddress %X\n",lpBuffer.BaseAddress); printf("Protect %X\n",lpBuffer.Protect); printf("RegionSize %X\n",lpBuffer.RegionSize); printf("State %X\n",lpBuffer.State); printf("Type %X\n",lpBuffer.Type); }*/ } while (lpBuffer.Type == MEM_IMAGE); //printf("Real sizeOfImage %X\n",sizeOfImage); return sizeOfImage; } DWORD ProcessAccessHelp::getEntryPointFromFile(const WCHAR * filePath) { PeParser peFile(filePath, false); return peFile.getEntryPoint(); } bool ProcessAccessHelp::createBackupFile(const WCHAR * filePath) { size_t fileNameLength = wcslen(filePath) + 5; //.bak + null BOOL retValue = 0; WCHAR * backupFile = new WCHAR[fileNameLength]; wcscpy_s(backupFile, fileNameLength, filePath); wcscat_s(backupFile, fileNameLength, L".bak"); retValue = CopyFile(filePath, backupFile, FALSE); if (!retValue) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"createBackupFile :: CopyFile failed with error 0x%X", GetLastError()); #endif } delete [] backupFile; return retValue != 0; } DWORD ProcessAccessHelp::getModuleHandlesFromProcess(const HANDLE hProcess, HMODULE ** hMods) { DWORD count = 30; DWORD cbNeeded = 0; bool notEnough = true; *hMods = new HMODULE[count]; do { if (!EnumProcessModules(hProcess, *hMods, count * sizeof(HMODULE), &cbNeeded)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"getModuleHandlesFromProcess :: EnumProcessModules failed count %d", count); #endif delete [] *hMods; return 0; } if ((count * sizeof(HMODULE)) < cbNeeded) { delete [] *hMods; count = cbNeeded / sizeof(HMODULE); *hMods = new HMODULE[count]; } else { notEnough = false; } } while (notEnough); return cbNeeded / sizeof(HMODULE); } void ProcessAccessHelp::setCurrentProcessAsTarget() { ProcessAccessHelp::hProcess = GetCurrentProcess(); } bool ProcessAccessHelp::suspendProcess() { if (NativeWinApi::NtSuspendProcess) { if (NT_SUCCESS( NativeWinApi::NtSuspendProcess(ProcessAccessHelp::hProcess) )) { return true; } } return false; } bool ProcessAccessHelp::resumeProcess() { if (NativeWinApi::NtResumeProcess) { if (NT_SUCCESS( NativeWinApi::NtResumeProcess(ProcessAccessHelp::hProcess) )) { return true; } } return false; } bool ProcessAccessHelp::terminateProcess() { if (NativeWinApi::NtTerminateProcess) { if (NT_SUCCESS( NativeWinApi::NtTerminateProcess(ProcessAccessHelp::hProcess, 0) )) { return true; } } return false; } \ No newline at end of file diff --git a/Scylla/ProcessAccessHelp.h b/Scylla/ProcessAccessHelp.h index db4dc44..0c1d9db 100644 --- a/Scylla/ProcessAccessHelp.h +++ b/Scylla/ProcessAccessHelp.h @@ -1,225 +1,226 @@ #pragma once #include #include #include /************************************************************************/ /* distorm */ /************************************************************************/ #include // The number of the array of instructions the decoder function will use to return the disassembled instructions. // Play with this value for performance... #define MAX_INSTRUCTIONS (200) /************************************************************************/ class ApiInfo; class ModuleInfo { public: WCHAR fullPath[MAX_PATH]; DWORD_PTR modBaseAddr; DWORD modBaseSize; bool isAlreadyParsed; bool parsing; /* for iat rebuilding with duplicate entries: ntdll = low priority kernelbase = low priority SHLWAPI = low priority kernel32 = high priority priority = 1 -> normal/high priority priority = 0 -> low priority */ int priority; std::vector apiList; ModuleInfo() { modBaseAddr = 0; modBaseSize = 0; priority = 1; isAlreadyParsed = false; parsing = false; } const WCHAR * getFilename() const { const WCHAR* slash = wcsrchr(fullPath, L'\\'); if(slash) { return slash+1; } return fullPath; } }; class ApiInfo { public: char name[MAX_PATH]; WORD hint; DWORD_PTR va; DWORD_PTR rva; WORD ordinal; bool isForwarded; ModuleInfo * module; }; class ProcessAccessHelp { public: static HANDLE hProcess; //OpenProcess handle to target process static DWORD_PTR targetImageBase; static DWORD_PTR targetSizeOfImage; static DWORD_PTR maxValidAddress; static ModuleInfo * selectedModule; static std::vector moduleList; //target process module list static std::vector ownModuleList; //own module list static const size_t PE_HEADER_BYTES_COUNT = 2000; static BYTE fileHeaderFromDisk[PE_HEADER_BYTES_COUNT]; //for decomposer static _DInst decomposerResult[MAX_INSTRUCTIONS]; static unsigned int decomposerInstructionsCount; static _CodeInfo decomposerCi; //distorm :: Decoded instruction information. static _DecodedInst decodedInstructions[MAX_INSTRUCTIONS]; static unsigned int decodedInstructionsCount; #ifdef _WIN64 static const _DecodeType dt = Decode64Bits; #else static const _DecodeType dt = Decode32Bits; #endif /* * Open a new process handle */ static bool openProcessHandle(DWORD dwPID); static HANDLE NativeOpenProcess(DWORD dwDesiredAccess, DWORD dwProcessId); static void closeProcessHandle(); /* * Get all modules from a process */ static bool getProcessModules(DWORD dwPID, std::vector &moduleList); /* * file mapping view with different access level */ static LPVOID createFileMappingViewRead(const WCHAR * filePath); static LPVOID createFileMappingViewFull(const WCHAR * filePath); /* * Create a file mapping view of a file */ static LPVOID createFileMappingView(const WCHAR * filePath, DWORD accessFile, DWORD flProtect, DWORD accessMap); /* * Read memory from target process */ static bool readMemoryFromProcess(DWORD_PTR address, SIZE_T size, LPVOID dataBuffer); + static bool writeMemoryToProcess(DWORD_PTR address, SIZE_T size, LPVOID dataBuffer); /* * Read memory from target process and ignore no data pages */ static bool readMemoryPartlyFromProcess(DWORD_PTR address, SIZE_T size, LPVOID dataBuffer); /* * Read memory from file */ static bool readMemoryFromFile(HANDLE hFile, LONG offset, DWORD size, LPVOID dataBuffer); /* * Write memory to file */ static bool writeMemoryToFile(HANDLE hFile, LONG offset, DWORD size, LPCVOID dataBuffer); /* * Write memory to new file */ static bool writeMemoryToNewFile(const WCHAR * file,DWORD size, LPCVOID dataBuffer); /* * Write memory to file end */ static bool writeMemoryToFileEnd(HANDLE hFile, DWORD size, LPCVOID dataBuffer); /* * Disassemble Memory */ static bool disassembleMemory(BYTE * dataBuffer, SIZE_T bufferSize, DWORD_PTR startOffset); static bool decomposeMemory(BYTE * dataBuffer, SIZE_T bufferSize, DWORD_PTR startAddress); /* * Search for pattern */ static DWORD_PTR findPattern(DWORD_PTR startOffset, DWORD size, BYTE * pattern, const char * mask); /* * Get process ID by process name */ static DWORD getProcessByName(const WCHAR * processName); /* * Get memory region from address */ static bool getMemoryRegionFromAddress(DWORD_PTR address, DWORD_PTR * memoryRegionBase, SIZE_T * memoryRegionSize); /* * Read PE Header from file */ static bool readHeaderFromFile(BYTE * buffer, DWORD bufferSize, const WCHAR * filePath); static bool readHeaderFromCurrentFile(const WCHAR * filePath); /* * Get real sizeOfImage value */ static SIZE_T getSizeOfImageProcess(HANDLE processHandle, DWORD_PTR moduleBase); /* * Get real sizeOfImage value current process */ static bool getSizeOfImageCurrentProcess(); static LONGLONG getFileSize(HANDLE hFile); static LONGLONG getFileSize(const WCHAR * filePath); static DWORD getEntryPointFromFile(const WCHAR * filePath); static bool createBackupFile(const WCHAR * filePath); static DWORD getModuleHandlesFromProcess(const HANDLE hProcess, HMODULE ** hMods ); static void setCurrentProcessAsTarget(); static bool suspendProcess(); static bool resumeProcess(); static bool terminateProcess(); }; diff --git a/Scylla/Scylla.h b/Scylla/Scylla.h index c8b228f..bfe5b6b 100644 --- a/Scylla/Scylla.h +++ b/Scylla/Scylla.h @@ -1,35 +1,35 @@ #pragma once #include "ConfigurationHolder.h" #include "PluginLoader.h" #include "ProcessLister.h" #include "Logger.h" #define APPNAME_S "Scylla" -#define APPVERSION_S "v0.9.3" -#define APPVERSIONDWORD 0x00009300 +#define APPVERSION_S "v0.9.4" +#define APPVERSIONDWORD 0x00009400 #define DONATE_BTC_ADDRESS "1GmVrhWwUhwLohaCLP4SKV5kkz8rd16N8h" #define APPNAME TEXT(APPNAME_S) #define APPVERSION TEXT(APPVERSION_S) class Scylla { public: static void initAsGuiApp(); static void initAsDll(); static ConfigurationHolder config; static PluginLoader plugins; static ProcessLister processLister; static FileLog debugLog; static ListboxLog windowLog; private: static const WCHAR DEBUG_LOG_FILENAME[]; }; diff --git a/Scylla/Scylla.vcxproj b/Scylla/Scylla.vcxproj index 9c9b80d..87e8a37 100644 --- a/Scylla/Scylla.vcxproj +++ b/Scylla/Scylla.vcxproj @@ -1,264 +1,266 @@  Debug Win32 Debug x64 Release Win32 Release x64 {710434C9-FC4B-4F1D-B318-E10ADC78499F} Win32Proj Scylla Application true Unicode v90 Application true Unicode Application false true Unicode v90 Application false true Unicode true $(SolutionDir)$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ $(SolutionDir)WTL81_9127_Include;$(IncludePath) true $(SolutionDir)WTL81_9127_Include;$(IncludePath) false $(SolutionDir)$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ $(SolutionDir)WTL81_9127_Include;$(IncludePath) false $(SolutionDir)WTL81_9127_Include;$(IncludePath) Level3 Disabled WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) $(SolutionDir)tinyxml;$(SolutionDir)diStorm\include;%(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' true $(TargetDir)$(TargetName).map Level3 Disabled WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) $(SolutionDir)tinyxml;$(SolutionDir)diStorm\include;%(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)tinyxml;$(SolutionDir)diStorm\include;%(AdditionalIncludeDirectories) true Speed 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' true Level3 MaxSpeed true true WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) MultiThreaded $(SolutionDir)tinyxml;$(SolutionDir)diStorm\include;%(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' true + + \ No newline at end of file diff --git a/Scylla/resource.h b/Scylla/resource.h index 528f654..0cc56ea 100644 Binary files a/Scylla/resource.h and b/Scylla/resource.h differ