diff --git a/README.md b/README.md index 1e7192a..deda214 100644 --- a/README.md +++ b/README.md @@ -1,106 +1,115 @@ Scylla - x64/x86 Imports Reconstruction ======================================= ImpREC, CHimpREC, Imports Fixer... this are all great tools to rebuild an import table, but they all have some major disadvantages, so I decided to create my own tool for this job. Scylla's key benefits are: - x64 and x86 support - full unicode support (probably some russian or chinese will like this :-) ) - written in C/C++ - plugin support - works great with Windows 7 This tool was designed to be used with Windows 7 x64, so it is recommend to use this operating system. But it may work with XP and Vista, too. Source code is licensed under GNU GENERAL PUBLIC LICENSE v3.0 Known Bugs ---------- ### Only Windows XP x64: Windows XP x64 has some API bugs. 100% correct imports reconstruction is impossible. If you still want to use XP x64, here are some hints: * EncodePointer/DecodePointer exported by kernel32.dll have both the same VA. Scylla, CHimpREC and other tools cannot know which API is correct. You need to fix this manually. Your fixed dump will probably run fine on XP but crash on Vista/7. ### ImpREC plugin support: Some ImpREC Plugins don't work with Windows Vista/7 because they don't "return 1" in the DllMain function. Keyboard Shortcuts ------------------ - CTRL + D: [D]ump - CTRL + F: [F]ix Dump - CTRL + R: PE [R]ebuild - CTRL + O: L[o]ad Tree - CTRL + S: [S]ave Tree - CTRL + T: Auto[t]race - CTRL + G: [G]et Imports - CTRL + I: [I]AT Autosearch Changelog --------- +Version 0.6b + +- internal code changes +- added option: fix iat and oep + +Version 0.6a + +- fixed buffer to small bug in dump memory + Version 0.6 - added dump memory regions - added dump pe sections -> you can edit some values in the dialog - improved dump engine with intelligent dumping - improved pe rebuild engine -> removed yoda's code - fixed various bugs Version 0.5a: - fixed memory leak - improved IAT search Version 0.5: - added save/load import tree feature - multi-select in tree view - fixed black icons problem in tree view - added keyboard shortcuts - dll dump + dll dump fix now working - added support for scattered IATs - pre select target path in open file dialogs - improved import resolving engine with api scoring - api selection dialog - minor bug fixes and improvements Version 0.4: - GUI code improvements - bug fixes - imports by ordinal Version 0.3a: - Improved import resolving - fixed buffer overflow errors Version 0.3: - ImpREC plugin support - minor bug fix Version 0.2a: - improved disassembler dialog - improved iat search Version 0.2: - improved process detection - added some options - new options dialog - improved source code diff --git a/Scylla/ConfigurationHolder.cpp b/Scylla/ConfigurationHolder.cpp index ea530f9..e555062 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); 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; if (!loadConfig(configObject)) { return false; } } 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 ab526d6..90659e1 100644 --- a/Scylla/ConfigurationHolder.h +++ b/Scylla/ConfigurationHolder.h @@ -1,49 +1,50 @@ #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 + REMOVE_DOS_HEADER_STUB, + IAT_FIX_AND_OEP_FIX }; 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/DumpSectionGui.cpp b/Scylla/DumpSectionGui.cpp index 7823f7c..2954bf2 100644 --- a/Scylla/DumpSectionGui.cpp +++ b/Scylla/DumpSectionGui.cpp @@ -1,394 +1,400 @@ #include "DumpSectionGui.h" #include "Architecture.h" #include "ProcessAccessHelp.h" #include "PeParser.h" bool PeSection::highlightVirtualSize() { //highlight big virtual sizes -> anti-dump protection return (virtualSize > 0x2000000); } std::vector & DumpSectionGui::getSectionList() { return sectionList; } DumpSectionGui::DumpSectionGui() { imageBase = 0; entryPoint = 0; fullpath[0] = 0; } DumpSectionGui::~DumpSectionGui() { sectionList.clear(); } BOOL DumpSectionGui::OnInitDialog(CWindow wndFocus, LPARAM lInitParam) { DoDataExchange(); // attach controls DlgResize_Init(true, true); addColumnsToSectionList(ListSectionSelect); displaySectionList(ListSectionSelect); selectOrDeselectAll(); isEditing = false; selectedSection = 0; CenterWindow(); return TRUE; } LRESULT DumpSectionGui::OnListSectionColumnClicked(NMHDR* pnmh) { NMLISTVIEW* list = (NMLISTVIEW*)pnmh; int column = list->iSubItem; if(column == prevColumn) { ascending = !ascending; } else { prevColumn = column; ascending = true; } // lo-byte: column, hi-byte: sort-order ListSectionSelect.SortItems(&listviewCompareFunc, MAKEWORD(column, ascending)); return 0; } LRESULT DumpSectionGui::OnListSectionClick(NMHDR* pnmh) { //int index = ListSectionSelect.GetSelectionMark(); //if (index != -1) //{ //} return 0; } LRESULT DumpSectionGui::OnListDoubleClick(NMHDR* pnmh) { LVHITTESTINFO hti; RECT rect, rect1, rect2; NMITEMACTIVATE* ia = (NMITEMACTIVATE*)pnmh; editingSubItem = ia->iSubItem; - if (editingSubItem == COL_NAME || editingSubItem == COL_VA || editingSubItem == COL_RVA) + if (editingSubItem == COL_NAME || editingSubItem == COL_VA) { return 0; } hti.pt = ia->ptAction; int clicked = ListSectionSelect.HitTest(&hti); if(clicked != -1) { selectedSection = (PeSection *)ListSectionSelect.GetItemData(clicked); } ListSectionSelect.GetSubItemRect(ia->iItem,ia->iSubItem,LVIR_BOUNDS,&rect); //Get the Rectange of the listControl ListSectionSelect.GetWindowRect(&rect1); //Get the Rectange of the Dialog GetWindowRect(&rect2); int x = rect1.left - rect2.left; int y = rect1.top - rect2.top; isEditing = true; switch (editingSubItem) { case COL_VSize: valueBeforeEditing = selectedSection->virtualSize; break; + case COL_RVA: + valueBeforeEditing = selectedSection->rawAddress; + break; case COL_RSize: valueBeforeEditing = selectedSection->rawSize; break; case COL_Characteristics: valueBeforeEditing = selectedSection->characteristics; break; default: valueBeforeEditing = 0; } EditListControl.SetValue(valueBeforeEditing); EditListControl.SetWindowPos(HWND_TOP,rect.left + 7, rect.top + 7, rect.right - rect.left, rect.bottom - rect.top, NULL); EditListControl.ShowWindow(SW_SHOW); EditListControl.SetFocus(); return 0; } void DumpSectionGui::OnSectionSelectAll(UINT uNotifyCode, int nID, CWindow wndCtl) { selectOrDeselectAll(); } void DumpSectionGui::OnEditList(UINT uNotifyCode, int nID, CWindow wndCtl) { switch (uNotifyCode) { case EN_KILLFOCUS: { isEditing = false; updateEditedItem(); EditListControl.ShowWindow(SW_HIDE); } break; } } void DumpSectionGui::OnOK(UINT uNotifyCode, int nID, CWindow wndCtl) { if (isEditing) //EN_KILLFOCUS not sent? { updateEditedItem(); } updateCheckState(); EndDialog(1); } void DumpSectionGui::OnCancel(UINT uNotifyCode, int nID, CWindow wndCtl) { EndDialog(0); } int DumpSectionGui::listviewCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { const PeSection * module1 = (PeSection *)lParam1; const PeSection * module2 = (PeSection *)lParam2; int column = LOBYTE(lParamSort); bool ascending = (HIBYTE(lParamSort) == TRUE); int diff = 0; switch(column) { case COL_NAME: diff = _wcsicmp(module1->name, module2->name); break; case COL_VA: diff = module1->virtualAddress < module2->virtualAddress ? -1 : 1; break; case COL_VSize: diff = module1->virtualSize < module2->virtualSize ? -1 : 1; break; case COL_RVA: diff = module1->rawAddress < module2->rawAddress ? -1 : 1; break; case COL_RSize: diff = module1->rawSize < module2->rawSize ? -1 : 1; break; case COL_Characteristics: diff = module1->characteristics < module2->characteristics ? -1 : 1; break; } return ascending ? diff : -diff; } void DumpSectionGui::addColumnsToSectionList(CListViewCtrl& list) { list.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT|LVS_EX_CHECKBOXES|LVS_EX_GRIDLINES, LVS_EX_FULLROWSELECT|LVS_EX_CHECKBOXES|LVS_EX_GRIDLINES); list.InsertColumn(COL_NAME, L"Name", LVCFMT_CENTER); list.InsertColumn(COL_VA, L"Virtual Address", LVCFMT_CENTER); list.InsertColumn(COL_VSize, L"Virtual Size", LVCFMT_CENTER); list.InsertColumn(COL_RVA, L"Raw Address", LVCFMT_CENTER); list.InsertColumn(COL_RSize, L"Raw Size", LVCFMT_CENTER); list.InsertColumn(COL_Characteristics, L"Characteristics", LVCFMT_CENTER); } void DumpSectionGui::displaySectionList(CListViewCtrl& list) { int count = 0; WCHAR temp[20]; list.DeleteAllItems(); if (sectionList.empty()) { getAllSectionsFromFile(); } std::vector::const_iterator iter; for( iter = sectionList.begin(); iter != sectionList.end(); iter++ , count++) { list.InsertItem(count, iter->name); swprintf_s(temp, PRINTF_DWORD_PTR_FULL, iter->virtualAddress); list.SetItemText(count, COL_VA, temp); swprintf_s(temp, L"%08X", iter->virtualSize); list.SetItemText(count, COL_VSize, temp); swprintf_s(temp, L"%08X", iter->rawAddress); list.SetItemText(count, COL_RVA, temp); swprintf_s(temp, L"%08X", iter->rawSize); list.SetItemText(count, COL_RSize, temp); swprintf_s(temp, L"%08X", iter->characteristics); list.SetItemText(count, COL_Characteristics, temp); list.SetItemData(count, (DWORD_PTR)&(*iter)); } list.SetColumnWidth(COL_NAME, LVSCW_AUTOSIZE_USEHEADER); list.SetColumnWidth(COL_VA, LVSCW_AUTOSIZE_USEHEADER); list.SetColumnWidth(COL_VSize, LVSCW_AUTOSIZE_USEHEADER); list.SetColumnWidth(COL_RVA, LVSCW_AUTOSIZE_USEHEADER); list.SetColumnWidth(COL_RSize, LVSCW_AUTOSIZE_USEHEADER); list.SetColumnWidth(COL_Characteristics, LVSCW_AUTOSIZE_USEHEADER); } LRESULT DumpSectionGui::OnNMCustomdraw(NMHDR* pnmh) { LRESULT pResult = 0; unsigned int vectorIndex = 0; LPNMLVCUSTOMDRAW lpLVCustomDraw = (LPNMLVCUSTOMDRAW)(pnmh); switch(lpLVCustomDraw->nmcd.dwDrawStage) { case CDDS_ITEMPREPAINT: case CDDS_ITEMPREPAINT | CDDS_SUBITEM: { vectorIndex = (unsigned int)lpLVCustomDraw->nmcd.dwItemSpec; if (lpLVCustomDraw->iSubItem == COL_VSize) { if (sectionList[vectorIndex].highlightVirtualSize()) { lpLVCustomDraw->clrText = RGB(255,255,255); // white text lpLVCustomDraw->clrTextBk = RGB(255,0,0); // red background } } else { lpLVCustomDraw->clrText = CLR_DEFAULT; lpLVCustomDraw->clrTextBk = CLR_DEFAULT; } } break; default: break; } pResult |= CDRF_NOTIFYPOSTPAINT; pResult |= CDRF_NOTIFYITEMDRAW; pResult |= CDRF_NOTIFYSUBITEMDRAW; return pResult; } void DumpSectionGui::getAllSectionsFromFile() { PeSection peSection; if (sectionList.empty()) { sectionList.reserve(3); } else { sectionList.clear(); } PeParser peFile(fullpath); if (peFile.isValidPeFile()) { std::vector & listSectionHeader = peFile.getSectionHeaderList(); for (WORD i = 0; i < peFile.getNumberOfSections(); i++) { peFile.getSectionNameUnicode(i, peSection.name, _countof(peSection.name)); peSection.virtualAddress = imageBase + listSectionHeader[i].sectionHeader.VirtualAddress; peSection.virtualSize = listSectionHeader[i].sectionHeader.Misc.VirtualSize; peSection.rawAddress = listSectionHeader[i].sectionHeader.PointerToRawData; peSection.rawSize = listSectionHeader[i].sectionHeader.SizeOfRawData; peSection.characteristics = listSectionHeader[i].sectionHeader.Characteristics; peSection.isDumped = true; sectionList.push_back(peSection); } } else { MessageBox(fullpath, L"Not a valid PE -> This should never happen", MB_ICONERROR); } } void DumpSectionGui::updateEditedItem() { if (selectedSection) { DWORD newValue = EditListControl.GetValue(); if (valueBeforeEditing != newValue) { switch (editingSubItem) { case COL_VSize: selectedSection->virtualSize = newValue; break; + case COL_RVA: + selectedSection->rawAddress = newValue; + break; case COL_RSize: selectedSection->rawSize = newValue; break; case COL_Characteristics: selectedSection->characteristics = newValue; break; } displaySectionList(ListSectionSelect); selectOrDeselectAll(); } } } void DumpSectionGui::updateCheckState() { PeSection * pesection; for (size_t i = 0; i < sectionList.size(); i++) { pesection = (PeSection *)ListSectionSelect.GetItemData((int)i); pesection->isDumped = ListSectionSelect.GetCheckState((int)i) == TRUE; } } void DumpSectionGui::selectOrDeselectAll() { BOOL checkState = ListSectionSelect.GetCheckState((int)0) ? FALSE : TRUE; for (size_t i = 0; i < sectionList.size(); i++) { ListSectionSelect.SetCheckState((int)i, checkState); } } \ No newline at end of file diff --git a/Scylla/DumpSectionGui.h b/Scylla/DumpSectionGui.h index 17bfe02..5c433f8 100644 --- a/Scylla/DumpSectionGui.h +++ b/Scylla/DumpSectionGui.h @@ -1,127 +1,127 @@ #pragma once #include #include "resource.h" // WTL #include // base ATL classes #include // base WTL classes #include // ATL GUI classes #include // WTL window frame helpers #include // WTL utility classes #include // WTL enhanced msg map macros #include // WTL controls #include // WTL dialog data exchange #include #include "hexedit.h" class PeSection { public: WCHAR name[IMAGE_SIZEOF_SHORT_NAME + 1]; DWORD_PTR virtualAddress; DWORD virtualSize; - DWORD_PTR rawAddress; + DWORD rawAddress; DWORD rawSize; DWORD characteristics; bool isDumped; bool highlightVirtualSize(); }; class DumpSectionGui : public CDialogImpl, public CWinDataExchange, public CDialogResize { public: enum { IDD = IDD_DLG_DUMPSECTION }; BEGIN_DDX_MAP(DumpSectionGui) DDX_CONTROL_HANDLE(IDC_LIST_DUMPSECTION, ListSectionSelect) DDX_CONTROL(IDC_EDIT_LISTCONTROL, EditListControl) END_DDX_MAP() BEGIN_MSG_MAP(DumpSectionGui) MSG_WM_INITDIALOG(OnInitDialog) NOTIFY_HANDLER_EX(IDC_LIST_DUMPSECTION, LVN_COLUMNCLICK, OnListSectionColumnClicked) NOTIFY_HANDLER_EX(IDC_LIST_DUMPSECTION, NM_CLICK, OnListSectionClick) NOTIFY_HANDLER_EX(IDC_LIST_DUMPSECTION, NM_CUSTOMDRAW, OnNMCustomdraw) NOTIFY_HANDLER_EX(IDC_LIST_DUMPSECTION, NM_DBLCLK, OnListDoubleClick) COMMAND_ID_HANDLER_EX(IDC_BUTTON_SELECT_DESELECT, OnSectionSelectAll) COMMAND_ID_HANDLER_EX(IDC_BTN_DUMPSECTION_OK, OnOK) COMMAND_ID_HANDLER_EX(IDC_EDIT_LISTCONTROL, OnEditList) COMMAND_ID_HANDLER_EX(IDC_BTN_DUMPSECTION_CANCEL, OnCancel) COMMAND_ID_HANDLER_EX(IDCANCEL, OnCancel) CHAIN_MSG_MAP(CDialogResize) END_MSG_MAP() BEGIN_DLGRESIZE_MAP(DumpSectionGui) DLGRESIZE_CONTROL(IDC_LIST_DUMPSECTION, DLSZ_SIZE_X | DLSZ_SIZE_Y) DLGRESIZE_CONTROL(IDC_BTN_DUMPSECTION_OK, DLSZ_MOVE_X | DLSZ_MOVE_Y) DLGRESIZE_CONTROL(IDC_BTN_DUMPSECTION_CANCEL, DLSZ_MOVE_X | DLSZ_MOVE_Y) DLGRESIZE_CONTROL(IDC_BUTTON_SELECT_DESELECT, DLSZ_MOVE_Y) END_DLGRESIZE_MAP() DumpSectionGui(); ~DumpSectionGui(); DWORD_PTR imageBase; //VA DWORD_PTR entryPoint; WCHAR fullpath[MAX_PATH]; std::vector & getSectionList(); private: CListViewCtrl ListSectionSelect; CHexEdit EditListControl; std::vector sectionList; PeSection *selectedSection; bool isEditing; int editingSubItem; DWORD valueBeforeEditing; enum ListColumns { COL_NAME = 0, COL_VA, COL_VSize, COL_RVA, COL_RSize, COL_Characteristics }; int prevColumn; bool ascending; // Message handlers BOOL OnInitDialog(CWindow wndFocus, LPARAM lInitParam); LRESULT OnListSectionColumnClicked(NMHDR* pnmh); LRESULT OnListSectionClick(NMHDR* pnmh); LRESULT OnNMCustomdraw(NMHDR* pnmh); LRESULT OnListDoubleClick(NMHDR* pnmh); void OnSectionSelectAll(UINT uNotifyCode, int nID, CWindow wndCtl); void OnEditList(UINT uNotifyCode, int nID, CWindow wndCtl); void OnOK(UINT uNotifyCode, int nID, CWindow wndCtl); void OnCancel(UINT uNotifyCode, int nID, CWindow wndCtl); // GUI functions void addColumnsToSectionList(CListViewCtrl& list); void displaySectionList(CListViewCtrl& list); static int CALLBACK listviewCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort); WCHAR * getCharacteristicsString( DWORD characteristics ); void getAllSectionsFromFile(); void updateEditedItem(); void updateCheckState(); void selectOrDeselectAll(); }; \ No newline at end of file diff --git a/Scylla/ImportRebuild.cpp b/Scylla/ImportRebuild.cpp deleted file mode 100644 index c134187..0000000 --- a/Scylla/ImportRebuild.cpp +++ /dev/null @@ -1,717 +0,0 @@ -#include "ImportRebuild.h" - -#include "Scylla.h" -#include "StringConversion.h" - -//#define DEBUG_COMMENTS - -ImportRebuild::ImportRebuild() -{ - imageData = NULL; - sizeOfFile = 0; - - pDosStub = NULL; - - pOverlay = NULL; - sizeOfOverlay = 0; - - pImportDescriptor = NULL; - pThunkData = NULL; - pImportByName = NULL; - - numberOfImportDescriptors = 0; - sizeOfImportSection = 0; - sizeOfApiAndModuleNames = 0; - importSectionIndex = 0; -} - -ImportRebuild::~ImportRebuild() -{ - delete [] pDosStub; - delete [] imageData; - - for (size_t i = 0; i < vecSectionData.size(); i++) - { - delete [] vecSectionData[i]; - } - - delete [] pOverlay; -} - -bool ImportRebuild::splitTargetFile() -{ - PIMAGE_SECTION_HEADER pSecHeader = 0; - BYTE * data = 0; - DWORD alignment = 0; - - DosHeader = *(IMAGE_DOS_HEADER*)imageData; - - if (DosHeader.e_magic != IMAGE_DOS_SIGNATURE) - { - return false; - } - - NTHeader = *(IMAGE_NT_HEADERS*)(imageData + DosHeader.e_lfanew); - - if (NTHeader.Signature != IMAGE_NT_SIGNATURE) - { - return false; - } - - if (DosHeader.e_lfanew > sizeof(IMAGE_DOS_HEADER)) - { - size_t sizeOfStub = DosHeader.e_lfanew - sizeof(IMAGE_DOS_HEADER); - pDosStub = new BYTE[sizeOfStub]; - CopyMemory(pDosStub, imageData + sizeof(IMAGE_DOS_HEADER), sizeOfStub); - } - - pSecHeader = IMAGE_FIRST_SECTION((IMAGE_NT_HEADERS*)(imageData + DosHeader.e_lfanew)); - - for (WORD i = 0; i < NTHeader.FileHeader.NumberOfSections; i++) - { - const DWORD SECTION_SIZE_MAX = 300000000; - DWORD sizeOfSection = pSecHeader->SizeOfRawData; - - if (sizeOfSection > SECTION_SIZE_MAX) - { - sizeOfSection = SECTION_SIZE_MAX; - } - - //TODO better use section alignment because it is better? - alignment = alignValue(sizeOfSection, NTHeader.OptionalHeader.SectionAlignment); - data = new BYTE[alignment]; - - ZeroMemory(data, alignment); - CopyMemory(data, imageData + pSecHeader->PointerToRawData, sizeOfSection); - - vecSectionData.push_back(data); - vecSectionHeaders.push_back(*pSecHeader); - - pSecHeader++; - } - - if(NTHeader.FileHeader.NumberOfSections > 0) // ?? - { - const IMAGE_SECTION_HEADER* pLastSec = &(*vecSectionHeaders.rbegin()); - DWORD calcSize = pLastSec->PointerToRawData + pLastSec->SizeOfRawData; - if (calcSize < sizeOfFile) - { - sizeOfOverlay = sizeOfFile - calcSize; - pOverlay = new BYTE[sizeOfOverlay]; - memcpy(pOverlay, imageData + calcSize, sizeOfOverlay); - } - } - - delete [] imageData; - imageData = 0; - - return true; -} - -bool ImportRebuild::alignSectionHeaders() -{ - for (WORD i = 0; i < vecSectionHeaders.size(); i++) - { - vecSectionHeaders[i].VirtualAddress = alignValue(vecSectionHeaders[i].VirtualAddress, NTHeader.OptionalHeader.SectionAlignment); - vecSectionHeaders[i].Misc.VirtualSize = alignValue(vecSectionHeaders[i].Misc.VirtualSize, NTHeader.OptionalHeader.SectionAlignment); - - vecSectionHeaders[i].PointerToRawData = alignValue(vecSectionHeaders[i].PointerToRawData, NTHeader.OptionalHeader.FileAlignment); - vecSectionHeaders[i].SizeOfRawData = alignValue(vecSectionHeaders[i].SizeOfRawData, NTHeader.OptionalHeader.FileAlignment); - } - - return true; -} - -bool ImportRebuild::saveNewFile(const WCHAR * filepath) -{ - DWORD fileOffset = 0; - DWORD dwWriteSize = 0; - size_t i = 0; - - if (vecSectionHeaders.size() != vecSectionData.size()) - { - return false; - } - - HANDLE hFile = CreateFile(filepath, GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, 0,CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); - - if(hFile == INVALID_HANDLE_VALUE) - { -#ifdef DEBUG_COMMENTS - Scylla::debugLog.log(L"saveNewFile :: INVALID_HANDLE_VALUE %u", GetLastError()); -#endif - - return false; - } - - //alignSectionHeaders(); - updatePeHeader(); - - fileOffset = 0; - dwWriteSize = sizeof(IMAGE_DOS_HEADER); - ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, dwWriteSize, &DosHeader); - - fileOffset += dwWriteSize; - dwWriteSize = DosHeader.e_lfanew - sizeof(IMAGE_DOS_HEADER); - ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, dwWriteSize, pDosStub); - - fileOffset += dwWriteSize; - dwWriteSize = sizeof(IMAGE_NT_HEADERS); - ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, dwWriteSize, &NTHeader); - - fileOffset += dwWriteSize; - dwWriteSize = sizeof(IMAGE_SECTION_HEADER); - - for (i = 0; i < vecSectionHeaders.size(); i++) - { - if (!ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, dwWriteSize, &vecSectionHeaders[i])) - { -#ifdef DEBUG_COMMENTS - Scylla::debugLog.log(L"saveNewFile :: writeMemoryToFile failed offset %X size %X", fileOffset, dwWriteSize); -#endif - CloseHandle(hFile); - return false; - } - fileOffset += dwWriteSize; - } - - for (i = 0; i < vecSectionHeaders.size(); i++) - { - dwWriteSize = vecSectionHeaders[i].PointerToRawData - fileOffset; - - if (dwWriteSize) - { - if (!writeZeroMemoryToFile(hFile, fileOffset, dwWriteSize)) - { -#ifdef DEBUG_COMMENTS - Scylla::debugLog.log(L"saveNewFile :: writeZeroMemoryToFile failed offset %X size %X", fileOffset, dwWriteSize); -#endif - CloseHandle(hFile); - return false; - } - fileOffset += dwWriteSize; - } - - dwWriteSize = vecSectionHeaders[i].SizeOfRawData; - - ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, dwWriteSize, vecSectionData[i]); - fileOffset += dwWriteSize; - } - - if(pOverlay) - { - ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, (DWORD)sizeOfOverlay, pOverlay); - fileOffset += (DWORD)sizeOfOverlay; - } - - CloseHandle(hFile); - return true; -} - -bool ImportRebuild::writeZeroMemoryToFile(HANDLE hFile, DWORD fileOffset, DWORD size) -{ - bool retValue = false; - PVOID zeromemory = calloc(size, 1); - - if (zeromemory) - { - retValue = ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, size, zeromemory); - free(zeromemory); - } - else - { - retValue = false; - } - - return retValue; -} - -bool ImportRebuild::addNewSection(char * sectionName, DWORD sectionSize, BYTE * sectionData) -{ - BYTE * newBuffer = 0; - IMAGE_SECTION_HEADER pNewSection = {0}; - size_t lastSectionIndex = vecSectionHeaders.size() - 1; - size_t nameLength = strlen(sectionName); - - if (nameLength > IMAGE_SIZEOF_SHORT_NAME) - { -#ifdef DEBUG_COMMENTS - Scylla::debugLog.log(L"addNewSection :: sectionname is too long %d", nameLength); -#endif - return false; - } - - memcpy_s(pNewSection.Name, IMAGE_SIZEOF_SHORT_NAME, sectionName, nameLength); - - pNewSection.SizeOfRawData = alignValue(sectionSize, NTHeader.OptionalHeader.FileAlignment); - pNewSection.Misc.VirtualSize = alignValue(sectionSize, NTHeader.OptionalHeader.SectionAlignment); - - pNewSection.PointerToRawData = alignValue(vecSectionHeaders[lastSectionIndex].PointerToRawData + vecSectionHeaders[lastSectionIndex].SizeOfRawData, NTHeader.OptionalHeader.FileAlignment); - pNewSection.VirtualAddress = alignValue(vecSectionHeaders[lastSectionIndex].VirtualAddress + vecSectionHeaders[lastSectionIndex].Misc.VirtualSize, NTHeader.OptionalHeader.SectionAlignment); - - pNewSection.Characteristics = IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE|IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA; - - vecSectionHeaders.push_back(pNewSection); - - if ( (sectionSize != pNewSection.SizeOfRawData) || (sectionData == 0) ) - { - newBuffer = new BYTE[pNewSection.SizeOfRawData]; - ZeroMemory(newBuffer, pNewSection.SizeOfRawData); - - if (sectionData) - { - CopyMemory(newBuffer, sectionData, sectionSize); - } - - } - else - { - newBuffer = sectionData; - } - - vecSectionData.push_back(newBuffer); - - return true; -} - -bool ImportRebuild::loadTargetFile(const WCHAR * filepath) -{ - HANDLE hTargetFile = INVALID_HANDLE_VALUE; - DWORD fileSize = 0; - bool retValue = false; - - hTargetFile = CreateFile(filepath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); - - if(hTargetFile == INVALID_HANDLE_VALUE) - { -#ifdef DEBUG_COMMENTS - Scylla::debugLog.log(L"loadTargetFile :: INVALID_HANDLE_VALUE %u", GetLastError()); -#endif - - return false; - } - - fileSize = (DWORD)ProcessAccessHelp::getFileSize(hTargetFile); - - if (!fileSize) - { - CloseHandle(hTargetFile); - hTargetFile = 0; - return false; - } - - imageData = new BYTE[fileSize]; - - if (!imageData) - { - retValue = false; - } - else - { - sizeOfFile = fileSize; - retValue = ProcessAccessHelp::readMemoryFromFile(hTargetFile, 0, fileSize, imageData); - } - - CloseHandle(hTargetFile); - hTargetFile = 0; - - return retValue; -} - -DWORD ImportRebuild::alignValue(DWORD badValue, DWORD alignTo) -{ - return (((badValue + alignTo - 1) / alignTo) * alignTo); -} - -DWORD ImportRebuild::convertRVAToOffsetVector(DWORD dwRVA) -{ - for (size_t i = 0; i < vecSectionHeaders.size(); i++) - { - if ((vecSectionHeaders[i].VirtualAddress <= dwRVA) && ((vecSectionHeaders[i].VirtualAddress + vecSectionHeaders[i].Misc.VirtualSize) > dwRVA)) - { - return ((dwRVA - vecSectionHeaders[i].VirtualAddress) + vecSectionHeaders[i].PointerToRawData); - } - } - - return 0; -} - -/* -DWORD ImportRebuild::convertRVAToOffset(DWORD dwRVA) -{ - PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(&NTHeader); - - for (WORD i = 0; i < NTHeader.FileHeader.NumberOfSections; i++) - { - if ((pSectionHeader->VirtualAddress <= dwRVA) && ((pSectionHeader->VirtualAddress + pSectionHeader->Misc.VirtualSize) > dwRVA)) - { - return ((dwRVA - pSectionHeader->VirtualAddress) + pSectionHeader->PointerToRawData); - } - pSectionHeader++; - } - - return 0; -} -*/ -DWORD_PTR ImportRebuild::convertOffsetToRVAVector(DWORD dwOffset) -{ - for (size_t i = 0; i < vecSectionHeaders.size(); i++) - { - if ((vecSectionHeaders[i].PointerToRawData <= dwOffset) && ((vecSectionHeaders[i].PointerToRawData + vecSectionHeaders[i].SizeOfRawData) > dwOffset)) - { - return ((dwOffset - vecSectionHeaders[i].PointerToRawData) + vecSectionHeaders[i].VirtualAddress); - } - } - - return 0; -} - -/* -DWORD ImportRebuild::convertOffsetToRVA(DWORD dwOffset) -{ - PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(&NTHeader); - - for (WORD i = 0; i < NTHeader.FileHeader.NumberOfSections; i++) - { - if ((pSectionHeader->PointerToRawData <= dwOffset) && ((pSectionHeader->PointerToRawData + pSectionHeader->SizeOfRawData) > dwOffset)) - { - return ((dwOffset - pSectionHeader->PointerToRawData) + pSectionHeader->VirtualAddress); - } - pSectionHeader++; - } - - return 0; -} -*/ - -void ImportRebuild::updatePeHeader() -{ - size_t lastSectionIndex = vecSectionHeaders.size() - 1; - - NTHeader.FileHeader.NumberOfSections = (WORD)(lastSectionIndex + 1); - NTHeader.OptionalHeader.SizeOfImage = vecSectionHeaders[lastSectionIndex].VirtualAddress + vecSectionHeaders[lastSectionIndex].Misc.VirtualSize; - - NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0; - NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0; - - if (NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress) - { - for (size_t i = 0; i < vecSectionHeaders.size(); i++) - { - if ((vecSectionHeaders[i].VirtualAddress <= NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress) && ((vecSectionHeaders[i].VirtualAddress + vecSectionHeaders[i].Misc.VirtualSize) > NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress)) - { - //section must be read and writeable - vecSectionHeaders[i].Characteristics |= IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE; - } - } - - NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = 0; - NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = 0; - } - - - NTHeader.OptionalHeader.NumberOfRvaAndSizes = 0x10; - - NTHeader.OptionalHeader.SizeOfHeaders = alignValue(DosHeader.e_lfanew + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + NTHeader.FileHeader.SizeOfOptionalHeader + (NTHeader.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER)), NTHeader.OptionalHeader.FileAlignment); - -} - - - -bool ImportRebuild::buildNewImportTable(std::map & moduleList) -{ - createNewImportSection(moduleList); - - importSectionIndex = vecSectionHeaders.size() - 1; - - DWORD dwSize = fillImportSection(moduleList); - - if (!dwSize) - { - return false; - } - - setFlagToIATSection((*moduleList.begin()).second.firstThunk); - - NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = vecSectionHeaders[importSectionIndex].VirtualAddress; - NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = (DWORD)(numberOfImportDescriptors * sizeof(IMAGE_IMPORT_DESCRIPTOR)); - return true; -} - -bool ImportRebuild::createNewImportSection(std::map & moduleList) -{ - char sectionName[9] = {0}; - - //DWORD sectionSize = calculateMinSize(moduleList); - calculateImportSizes(moduleList); - - if (wcslen(Scylla::config[IAT_SECTION_NAME].getString()) > IMAGE_SIZEOF_SHORT_NAME) - { - strcpy_s(sectionName, ".SCY"); - } - else - { - StringConversion::ToASCII(Scylla::config[IAT_SECTION_NAME].getString(), sectionName, _countof(sectionName)); - } - - return addNewSection(sectionName, (DWORD)sizeOfImportSection, 0); -} - -/*DWORD ImportRebuild::calculateMinSize(std::map & moduleList) -{ - DWORD dwSize = 0; - std::map::iterator mapIt; - std::map::iterator mapIt2; - - dwSize = (DWORD)((moduleList.size() + 1) * sizeof(IMAGE_IMPORT_DESCRIPTOR)); //last is zero'ed - - for ( mapIt = moduleList.begin() ; mapIt != moduleList.end(); mapIt++ ) - { - - //dwSize += (DWORD)((*mapIt).second.thunkList.size() + sizeof(IMAGE_IMPORT_BY_NAME)); - dwSize += (DWORD)(wcslen((*mapIt).second.moduleName) + 1); - - for ( mapIt2 = (*mapIt).second.thunkList.begin() ; mapIt2 != (*mapIt).second.thunkList.end(); mapIt2++ ) - { - if((*mapIt2).second.name[0] != '\0') - { - dwSize += sizeof(IMAGE_IMPORT_BY_NAME); - dwSize += (DWORD)strlen((*mapIt2).second.name); - } - } - } - - return dwSize; -}*/ - -BYTE * ImportRebuild::getMemoryPointerFromRVA(DWORD_PTR dwRVA) -{ - DWORD_PTR offset = convertRVAToOffsetVector((DWORD)dwRVA); - - for (size_t i = 0; i < vecSectionHeaders.size(); i++) - { - if ((vecSectionHeaders[i].PointerToRawData <= offset) && ((vecSectionHeaders[i].PointerToRawData + vecSectionHeaders[i].SizeOfRawData) > offset)) - { - return (BYTE *)((DWORD_PTR)vecSectionData[i] + (offset - vecSectionHeaders[i].PointerToRawData)); - } - } - - return 0; -} - -DWORD ImportRebuild::fillImportSection( std::map & moduleList ) -{ - std::map::iterator mapIt; - std::map::iterator mapIt2; - PIMAGE_IMPORT_DESCRIPTOR pImportDesc = 0; - PIMAGE_IMPORT_BY_NAME pImportByName = 0; - PIMAGE_THUNK_DATA pThunk = 0; - ImportModuleThunk * importModuleThunk = 0; - ImportThunk * importThunk = 0; - - size_t stringLength = 0; - DWORD_PTR lastRVA = 0; - - BYTE * sectionData = vecSectionData[importSectionIndex]; - DWORD offset = 0; - - pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)(sectionData); - - //skip the IMAGE_IMPORT_DESCRIPTOR - offset += (DWORD)(numberOfImportDescriptors * sizeof(IMAGE_IMPORT_DESCRIPTOR)); - - for ( mapIt = moduleList.begin() ; mapIt != moduleList.end(); mapIt++ ) - { - importModuleThunk = &((*mapIt).second); - - stringLength = addImportDescriptor(importModuleThunk, offset); - -#ifdef DEBUG_COMMENTS - Scylla::debugLog.log(L"fillImportSection :: importDesc.Name %X", pImportDescriptor->Name); -#endif - - offset += (DWORD)stringLength; //stringLength has null termination char - - pImportByName = (PIMAGE_IMPORT_BY_NAME)((DWORD_PTR)sectionData + offset); - - //pThunk = (PIMAGE_THUNK_DATA)(getMemoryPointerFromRVA(importModuleThunk->firstThunk)); - - lastRVA = importModuleThunk->firstThunk - sizeof(DWORD_PTR); - - for ( mapIt2 = (*mapIt).second.thunkList.begin() ; mapIt2 != (*mapIt).second.thunkList.end(); mapIt2++ ) - { - importThunk = &((*mapIt2).second); - - pThunk = (PIMAGE_THUNK_DATA)(getMemoryPointerFromRVA(importThunk->rva)); - - //check wrong iat pointer - if (!pThunk) - { -#ifdef DEBUG_COMMENTS - Scylla::debugLog.log(L"fillImportSection :: Failed to get pThunk RVA: %X", importThunk->rva); -#endif - return 0; - } - - if ((lastRVA + sizeof(DWORD_PTR)) != importThunk->rva) - { - //add additional import desc - addSpecialImportDescriptor(importThunk->rva); - } - lastRVA = importThunk->rva; - -#ifdef DEBUG_COMMENTS - Scylla::debugLog.log(L"fillImportSection :: importThunk %X pThunk %X pImportByName %X offset %X", importThunk,pThunk,pImportByName,offset); -#endif - stringLength = addImportToImportTable(importThunk, pThunk, pImportByName, offset); - - offset += (DWORD)stringLength; //is 0 bei import by ordinal - pImportByName = (PIMAGE_IMPORT_BY_NAME)((DWORD_PTR)pImportByName + stringLength); - } - - pImportDescriptor++; - } - - return offset; -} - -bool ImportRebuild::rebuildImportTable(const WCHAR * targetFilePath, const WCHAR * newFilePath, std::map & moduleList) -{ - bool retValue = false; - - if (loadTargetFile(targetFilePath)) - { - splitTargetFile(); - - retValue = buildNewImportTable(moduleList); - - if (retValue) - { - retValue = saveNewFile(newFilePath); - } - - return retValue; - } - else - { -#ifdef DEBUG_COMMENTS - Scylla::debugLog.log(L"rebuildImportTable ::Failed to load target %s", targetFilePath); -#endif - return false; - } -} - -void ImportRebuild::setFlagToIATSection(DWORD_PTR iatAddress) -{ - for (size_t i = 0; i < vecSectionHeaders.size(); i++) - { - if ((vecSectionHeaders[i].VirtualAddress <= iatAddress) && ((vecSectionHeaders[i].VirtualAddress + vecSectionHeaders[i].Misc.VirtualSize) > iatAddress)) - { - //section must be read and writeable - vecSectionHeaders[i].Characteristics |= IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE; - } - } -} - -size_t ImportRebuild::addImportToImportTable( ImportThunk * pImport, PIMAGE_THUNK_DATA pThunk, PIMAGE_IMPORT_BY_NAME pImportByName, DWORD sectionOffset) -{ - size_t stringLength = 0; - - if(pImport->name[0] == '\0') - { - pThunk->u1.AddressOfData = (IMAGE_ORDINAL(pImport->ordinal) | IMAGE_ORDINAL_FLAG); - } - else - { - pImportByName->Hint = pImport->hint; - - stringLength = strlen(pImport->name) + 1; - memcpy(pImportByName->Name, pImport->name, stringLength); - - pThunk->u1.AddressOfData = convertOffsetToRVAVector(vecSectionHeaders[importSectionIndex].PointerToRawData + sectionOffset); - - if (!pThunk->u1.AddressOfData) - { -#ifdef DEBUG_COMMENTS - Scylla::debugLog.log(L"addImportToImportTable :: failed to get AddressOfData %X %X", vecSectionHeaders[importSectionIndex].PointerToRawData, sectionOffset); -#endif - } - - //next import should be nulled - pThunk++; - pThunk->u1.AddressOfData = 0; - -#ifdef DEBUG_COMMENTS - Scylla::debugLog.log(L"addImportToImportTable :: pThunk->u1.AddressOfData %X %X %X", pThunk->u1.AddressOfData, pThunk, vecSectionHeaders[importSectionIndex].PointerToRawData + sectionOffset); -#endif - stringLength += sizeof(WORD); - } - - return stringLength; -} - -size_t ImportRebuild::addImportDescriptor(ImportModuleThunk * pImportModule, DWORD sectionOffset) -{ - char dllName[MAX_PATH]; - - StringConversion::ToASCII(pImportModule->moduleName, dllName, _countof(dllName)); - size_t stringLength = strlen(dllName) + 1; - - /* - Warning: stringLength MUST include null termination char - */ - - memcpy((vecSectionData[importSectionIndex] + sectionOffset), dllName, stringLength); //copy module name to section - - pImportDescriptor->FirstThunk = (DWORD)pImportModule->firstThunk; - pImportDescriptor->Name = (DWORD)convertOffsetToRVAVector(vecSectionHeaders[importSectionIndex].PointerToRawData + sectionOffset); - - return stringLength; -} - -void ImportRebuild::addSpecialImportDescriptor(DWORD_PTR rvaFirstThunk) -{ - PIMAGE_IMPORT_DESCRIPTOR oldID = pImportDescriptor; - pImportDescriptor++; - - pImportDescriptor->FirstThunk = (DWORD)rvaFirstThunk; - pImportDescriptor->Name = oldID->Name; -} - -void ImportRebuild::calculateImportSizes(std::map & moduleList) -{ - std::map::iterator mapIt; - std::map::iterator mapIt2; - DWORD_PTR lastRVA = 0; - - numberOfImportDescriptors = 0; - sizeOfImportSection = 0; - sizeOfApiAndModuleNames = 0; - - numberOfImportDescriptors = moduleList.size() + 1; //last is zero'd - - for ( mapIt = moduleList.begin() ; mapIt != moduleList.end(); mapIt++ ) - { - lastRVA = (*mapIt).second.firstThunk - sizeof(DWORD_PTR); - - sizeOfApiAndModuleNames += (DWORD)(wcslen((*mapIt).second.moduleName) + 1); - - for ( mapIt2 = (*mapIt).second.thunkList.begin() ; mapIt2 != (*mapIt).second.thunkList.end(); mapIt2++ ) - { - if ((lastRVA + sizeof(DWORD_PTR)) != (*mapIt2).second.rva) - { - numberOfImportDescriptors++; //add additional import desc - } - - if((*mapIt2).second.name[0] != '\0') - { - sizeOfApiAndModuleNames += sizeof(WORD); //Hint from IMAGE_IMPORT_BY_NAME - sizeOfApiAndModuleNames += (DWORD)(strlen((*mapIt2).second.name) + 1); - } - - lastRVA = (*mapIt2).second.rva; - } - } - - sizeOfImportSection = sizeOfApiAndModuleNames + (numberOfImportDescriptors * sizeof(IMAGE_IMPORT_DESCRIPTOR)); -} \ No newline at end of file diff --git a/Scylla/ImportRebuild.h b/Scylla/ImportRebuild.h deleted file mode 100644 index 27bad7f..0000000 --- a/Scylla/ImportRebuild.h +++ /dev/null @@ -1,73 +0,0 @@ -#pragma once - -#include -#include "ProcessAccessHelp.h" -#include "Thunks.h" - -class ImportRebuild -{ -public: - - ImportRebuild(); - ~ImportRebuild(); - - bool rebuildImportTable(const WCHAR * targetFilePath, const WCHAR * newFilePath, std::map & moduleList); - - //DWORD convertRVAToOffset(DWORD dwRVA); - //DWORD convertOffsetToRVA(DWORD dwOffset); - - bool addNewSection(char * sectionName, DWORD sectionSize, BYTE * sectionData); - - bool writeZeroMemoryToFile(HANDLE hFile, DWORD fileOffset, DWORD size); - -private: - std::vector vecSectionHeaders; - std::vector vecSectionData; - - BYTE * imageData; - size_t sizeOfFile; - - BYTE * pDosStub; - IMAGE_DOS_HEADER DosHeader; - IMAGE_NT_HEADERS NTHeader; - - BYTE * pOverlay; - size_t sizeOfOverlay; - - PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor; - PIMAGE_THUNK_DATA pThunkData; - PIMAGE_IMPORT_BY_NAME pImportByName; - - size_t numberOfImportDescriptors; - size_t sizeOfImportSection; - size_t sizeOfApiAndModuleNames; - size_t importSectionIndex; - - DWORD getOffsetLastSection(); - - void updatePeHeader(); - DWORD fillImportSection( std::map & moduleList ); - bool splitTargetFile(); - - DWORD convertRVAToOffsetVector(DWORD dwRVA); - DWORD_PTR convertOffsetToRVAVector(DWORD dwOffset); - - BYTE * getMemoryPointerFromRVA(DWORD_PTR dwRVA); - - DWORD alignValue(DWORD badValue, DWORD alignTo); - - bool alignSectionHeaders(); - - bool saveNewFile(const WCHAR * filepath); - bool loadTargetFile(const WCHAR * filepath); - - bool createNewImportSection(std::map & moduleList); - bool buildNewImportTable(std::map & moduleList); - void setFlagToIATSection( DWORD_PTR iatAddress ); - size_t addImportToImportTable( ImportThunk * pImport, PIMAGE_THUNK_DATA pThunk, PIMAGE_IMPORT_BY_NAME pImportByName, DWORD sectionOffset); - size_t addImportDescriptor(ImportModuleThunk * pImportModule, DWORD sectionOffset); - - void calculateImportSizes(std::map & moduleList); - - void addSpecialImportDescriptor(DWORD_PTR rvaFirstThunk); -}; \ No newline at end of file diff --git a/Scylla/ImportRebuilder.cpp b/Scylla/ImportRebuilder.cpp new file mode 100644 index 0000000..016d3dd --- /dev/null +++ b/Scylla/ImportRebuilder.cpp @@ -0,0 +1,288 @@ + +#include "ImportRebuilder.h" +#include "Scylla.h" +#include "StringConversion.h" + +#define DEBUG_COMMENTS + + +bool ImportRebuilder::rebuildImportTable(const WCHAR * newFilePath, std::map & moduleList) +{ + bool retValue = false; + + if (isValidPeFile()) + { + if (readPeSectionsFromFile()) + { + setDefaultFileAlignment(); + + retValue = buildNewImportTable(moduleList); + + if (retValue) + { + alignAllSectionHeaders(); + fixPeHeader(); + retValue = savePeFileToDisk(newFilePath); + } + } + } + + return retValue; +} + +bool ImportRebuilder::buildNewImportTable(std::map & moduleList) +{ + createNewImportSection(moduleList); + + importSectionIndex = listPeSection.size() - 1; + + DWORD dwSize = fillImportSection(moduleList); + + if (!dwSize) + { + return false; + } + + setFlagToIATSection((*moduleList.begin()).second.firstThunk); + + if (isPE32()) + { + pNTHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = listPeSection[importSectionIndex].sectionHeader.VirtualAddress; + pNTHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = (DWORD)(numberOfImportDescriptors * sizeof(IMAGE_IMPORT_DESCRIPTOR)); + } + else + { + pNTHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = listPeSection[importSectionIndex].sectionHeader.VirtualAddress; + pNTHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = (DWORD)(numberOfImportDescriptors * sizeof(IMAGE_IMPORT_DESCRIPTOR)); + } + + + return true; +} + +bool ImportRebuilder::createNewImportSection(std::map & moduleList) +{ + char sectionName[IMAGE_SIZEOF_SHORT_NAME + 1] = {0}; + + const WCHAR * sectionNameW = Scylla::config[IAT_SECTION_NAME].getString(); + + calculateImportSizes(moduleList); + + if (wcslen(sectionNameW) > IMAGE_SIZEOF_SHORT_NAME) + { + strcpy_s(sectionName, ".SCY"); + } + else + { + StringConversion::ToASCII(sectionNameW, sectionName, _countof(sectionName)); + } + + return addNewLastSection(sectionName, (DWORD)sizeOfImportSection, 0); +} + +void ImportRebuilder::setFlagToIATSection(DWORD_PTR iatAddress) +{ + for (size_t i = 0; i < listPeSection.size(); i++) + { + if ((listPeSection[i].sectionHeader.VirtualAddress <= iatAddress) && ((listPeSection[i].sectionHeader.VirtualAddress + listPeSection[i].sectionHeader.Misc.VirtualSize) > iatAddress)) + { + //section must be read and writeable + listPeSection[i].sectionHeader.Characteristics |= IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE; + } + } +} + +DWORD ImportRebuilder::fillImportSection(std::map & moduleList) +{ + std::map::iterator mapIt; + std::map::iterator mapIt2; + PIMAGE_IMPORT_DESCRIPTOR pImportDesc = 0; + PIMAGE_IMPORT_BY_NAME pImportByName = 0; + PIMAGE_THUNK_DATA pThunk = 0; + ImportModuleThunk * importModuleThunk = 0; + ImportThunk * importThunk = 0; + + size_t stringLength = 0; + DWORD_PTR lastRVA = 0; + + BYTE * sectionData = listPeSection[importSectionIndex].data; + DWORD offset = 0; + + pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)(sectionData); + + //skip the IMAGE_IMPORT_DESCRIPTOR + offset += (DWORD)(numberOfImportDescriptors * sizeof(IMAGE_IMPORT_DESCRIPTOR)); + + for ( mapIt = moduleList.begin() ; mapIt != moduleList.end(); mapIt++ ) + { + importModuleThunk = &((*mapIt).second); + + stringLength = addImportDescriptor(importModuleThunk, offset); + +#ifdef DEBUG_COMMENTS + Scylla::debugLog.log(L"fillImportSection :: importDesc.Name %X", pImportDescriptor->Name); +#endif + + offset += (DWORD)stringLength; //stringLength has null termination char + + pImportByName = (PIMAGE_IMPORT_BY_NAME)((DWORD_PTR)sectionData + offset); + + //pThunk = (PIMAGE_THUNK_DATA)(getMemoryPointerFromRVA(importModuleThunk->firstThunk)); + + lastRVA = importModuleThunk->firstThunk - sizeof(DWORD_PTR); + + for ( mapIt2 = (*mapIt).second.thunkList.begin() ; mapIt2 != (*mapIt).second.thunkList.end(); mapIt2++ ) + { + importThunk = &((*mapIt2).second); + + pThunk = (PIMAGE_THUNK_DATA)(getMemoryPointerFromRVA(importThunk->rva)); + + //check wrong iat pointer + if (!pThunk) + { +#ifdef DEBUG_COMMENTS + Scylla::debugLog.log(L"fillImportSection :: Failed to get pThunk RVA: %X", importThunk->rva); +#endif + return 0; + } + + if ((lastRVA + sizeof(DWORD_PTR)) != importThunk->rva) + { + //add additional import desc + addSpecialImportDescriptor(importThunk->rva); + } + lastRVA = importThunk->rva; + +#ifdef DEBUG_COMMENTS + Scylla::debugLog.log(L"fillImportSection :: importThunk %X pThunk %X pImportByName %X offset %X", importThunk,pThunk,pImportByName,offset); +#endif + stringLength = addImportToImportTable(importThunk, pThunk, pImportByName, offset); + + offset += (DWORD)stringLength; //is 0 bei import by ordinal + pImportByName = (PIMAGE_IMPORT_BY_NAME)((DWORD_PTR)pImportByName + stringLength); + } + + pImportDescriptor++; + } + + return offset; +} + +size_t ImportRebuilder::addImportDescriptor(ImportModuleThunk * pImportModule, DWORD sectionOffset) +{ + char dllName[MAX_PATH]; + + StringConversion::ToASCII(pImportModule->moduleName, dllName, _countof(dllName)); + size_t stringLength = strlen(dllName) + 1; + + /* + Warning: stringLength MUST include null termination char + */ + + memcpy((listPeSection[importSectionIndex].data + sectionOffset), dllName, stringLength); //copy module name to section + + pImportDescriptor->FirstThunk = (DWORD)pImportModule->firstThunk; + pImportDescriptor->Name = (DWORD)convertOffsetToRVAVector(listPeSection[importSectionIndex].sectionHeader.PointerToRawData + sectionOffset); + + return stringLength; +} + +void ImportRebuilder::addSpecialImportDescriptor(DWORD_PTR rvaFirstThunk) +{ + PIMAGE_IMPORT_DESCRIPTOR oldID = pImportDescriptor; + pImportDescriptor++; + + pImportDescriptor->FirstThunk = (DWORD)rvaFirstThunk; + pImportDescriptor->Name = oldID->Name; +} + +void ImportRebuilder::calculateImportSizes(std::map & moduleList) +{ + std::map::iterator mapIt; + std::map::iterator mapIt2; + DWORD_PTR lastRVA = 0; + + numberOfImportDescriptors = 0; + sizeOfImportSection = 0; + sizeOfApiAndModuleNames = 0; + + numberOfImportDescriptors = moduleList.size() + 1; //last is zero'd + + for ( mapIt = moduleList.begin() ; mapIt != moduleList.end(); mapIt++ ) + { + lastRVA = (*mapIt).second.firstThunk - sizeof(DWORD_PTR); + + sizeOfApiAndModuleNames += (DWORD)(wcslen((*mapIt).second.moduleName) + 1); + + for ( mapIt2 = (*mapIt).second.thunkList.begin() ; mapIt2 != (*mapIt).second.thunkList.end(); mapIt2++ ) + { + if ((lastRVA + sizeof(DWORD_PTR)) != (*mapIt2).second.rva) + { + numberOfImportDescriptors++; //add additional import desc + } + + if((*mapIt2).second.name[0] != '\0') + { + sizeOfApiAndModuleNames += sizeof(WORD); //Hint from IMAGE_IMPORT_BY_NAME + sizeOfApiAndModuleNames += (DWORD)(strlen((*mapIt2).second.name) + 1); + } + + lastRVA = (*mapIt2).second.rva; + } + } + + sizeOfImportSection = sizeOfApiAndModuleNames + (numberOfImportDescriptors * sizeof(IMAGE_IMPORT_DESCRIPTOR)); +} + +size_t ImportRebuilder::addImportToImportTable( ImportThunk * pImport, PIMAGE_THUNK_DATA pThunk, PIMAGE_IMPORT_BY_NAME pImportByName, DWORD sectionOffset) +{ + size_t stringLength = 0; + + if(pImport->name[0] == '\0') + { + pThunk->u1.AddressOfData = (IMAGE_ORDINAL(pImport->ordinal) | IMAGE_ORDINAL_FLAG); + } + else + { + pImportByName->Hint = pImport->hint; + + stringLength = strlen(pImport->name) + 1; + memcpy(pImportByName->Name, pImport->name, stringLength); + + pThunk->u1.AddressOfData = convertOffsetToRVAVector(listPeSection[importSectionIndex].sectionHeader.PointerToRawData + sectionOffset); + + if (!pThunk->u1.AddressOfData) + { +#ifdef DEBUG_COMMENTS + Scylla::debugLog.log(L"addImportToImportTable :: failed to get AddressOfData %X %X", listPeSection[importSectionIndex].sectionHeader.PointerToRawData, sectionOffset); +#endif + } + + //next import should be nulled + pThunk++; + pThunk->u1.AddressOfData = 0; + +#ifdef DEBUG_COMMENTS + Scylla::debugLog.log(L"addImportToImportTable :: pThunk->u1.AddressOfData %X %X %X", pThunk->u1.AddressOfData, pThunk, listPeSection[importSectionIndex].sectionHeader.PointerToRawData + sectionOffset); +#endif + stringLength += sizeof(WORD); + } + + return stringLength; +} + +BYTE * ImportRebuilder::getMemoryPointerFromRVA(DWORD_PTR dwRVA) +{ + DWORD_PTR offset = convertRVAToOffsetVector(dwRVA); + + for (size_t i = 0; i < listPeSection.size(); i++) + { + if ((listPeSection[i].sectionHeader.PointerToRawData <= offset) && ((listPeSection[i].sectionHeader.PointerToRawData + listPeSection[i].sectionHeader.SizeOfRawData) > offset)) + { + return (BYTE *)((DWORD_PTR)listPeSection[i].data + (offset - listPeSection[i].sectionHeader.PointerToRawData)); + } + } + + return 0; +} + diff --git a/Scylla/ImportRebuilder.h b/Scylla/ImportRebuilder.h new file mode 100644 index 0000000..e176bae --- /dev/null +++ b/Scylla/ImportRebuilder.h @@ -0,0 +1,46 @@ +#pragma once + +#include +#include "PeParser.h" +#include "Thunks.h" + + +class ImportRebuilder : public PeParser { +public: + ImportRebuilder(const WCHAR * file) : PeParser(file, true) + { + pImportDescriptor = 0; + pThunkData = 0; + pImportByName = 0; + + numberOfImportDescriptors = 0; + sizeOfImportSection = 0; + sizeOfApiAndModuleNames = 0; + importSectionIndex = 0; + } + + bool rebuildImportTable(const WCHAR * newFilePath, std::map & moduleList); + +private: + PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor; + PIMAGE_THUNK_DATA pThunkData; + PIMAGE_IMPORT_BY_NAME pImportByName; + + size_t numberOfImportDescriptors; + size_t sizeOfImportSection; + size_t sizeOfApiAndModuleNames; + size_t importSectionIndex; + + DWORD fillImportSection(std::map & moduleList); + BYTE * getMemoryPointerFromRVA(DWORD_PTR dwRVA); + + bool createNewImportSection(std::map & moduleList); + bool buildNewImportTable(std::map & moduleList); + void setFlagToIATSection(DWORD_PTR iatAddress); + size_t addImportToImportTable( ImportThunk * pImport, PIMAGE_THUNK_DATA pThunk, PIMAGE_IMPORT_BY_NAME pImportByName, DWORD sectionOffset); + size_t addImportDescriptor(ImportModuleThunk * pImportModule, DWORD sectionOffset); + + void calculateImportSizes(std::map & moduleList); + + void addSpecialImportDescriptor(DWORD_PTR rvaFirstThunk); +}; \ No newline at end of file diff --git a/Scylla/MainGui.cpp b/Scylla/MainGui.cpp index 22ccdda..a40e1c2 100644 --- a/Scylla/MainGui.cpp +++ b/Scylla/MainGui.cpp @@ -1,1365 +1,1386 @@ #include "MainGui.h" #include "Architecture.h" //#include "PluginLoader.h" //#include "ConfigurationHolder.h" //#include "PeDump.h" //#include "PeRebuild.h" #include "PeParser.h" #include "DllInjectionPlugin.h" #include "DisassemblerGui.h" #include "PickApiGui.h" //#include "NativeWinApi.h" -#include "ImportRebuild.h" +//#include "ImportRebuild.h" +#include "ImportRebuilder.h" #include "SystemInformation.h" #include "Scylla.h" #include "AboutGui.h" #include "OptionsGui.h" #include "TreeImportExport.h" extern CAppModule _Module; // o_O const WCHAR MainGui::filterExe[] = L"Executable (*.exe)\0*.exe\0All files\0*.*\0"; const WCHAR MainGui::filterDll[] = L"Dynamic Link Library (*.dll)\0*.dll\0All files\0*.*\0"; const WCHAR MainGui::filterExeDll[] = L"Executable (*.exe)\0*.exe\0Dynamic Link Library (*.dll)\0*.dll\0All files\0*.*\0"; const WCHAR MainGui::filterTxt[] = L"Text file (*.txt)\0*.txt\0All files\0*.*\0"; const WCHAR MainGui::filterXml[] = L"XML file (*.xml)\0*.xml\0All files\0*.*\0"; const WCHAR MainGui::filterMem[] = L"MEM file (*.mem)\0*.mem\0All files\0*.*\0"; MainGui::MainGui() : selectedProcess(0), importsHandling(TreeImports), TreeImportsSubclass(this, IDC_TREE_IMPORTS) { /* Logger::getDebugLogFilePath(); ConfigurationHolder::loadConfiguration(); PluginLoader::findAllPlugins(); NativeWinApi::initialize(); SystemInformation::getSystemInformation(); if(ConfigurationHolder::getConfigObject(DEBUG_PRIVILEGE)->isTrue()) { processLister.setDebugPrivileges(); } ProcessAccessHelp::getProcessModules(GetCurrentProcessId(), ProcessAccessHelp::ownModuleList); */ Scylla::init(); hIcon.LoadIcon(IDI_ICON_SCYLLA); hMenuImports.LoadMenu(IDR_MENU_IMPORTS); hMenuLog.LoadMenu(IDR_MENU_LOG); accelerators.LoadAccelerators(IDR_ACCELERATOR_MAIN); hIconCheck.LoadIcon(IDI_ICON_CHECK, 16, 16); hIconWarning.LoadIcon(IDI_ICON_WARNING, 16, 16); hIconError.LoadIcon(IDI_ICON_ERROR, 16, 16); } BOOL MainGui::PreTranslateMessage(MSG* pMsg) { if(accelerators.TranslateAccelerator(m_hWnd, pMsg)) { return TRUE; // handled keyboard shortcuts } else if(IsDialogMessage(pMsg)) { return TRUE; // handled dialog messages } return FALSE; } BOOL MainGui::OnInitDialog(CWindow wndFocus, LPARAM lInitParam) { if (SystemInformation::currenOS == UNKNOWN_OS) { if(IDCANCEL == MessageBox(L"Operating System is not supported\r\nContinue anyway?", L"Scylla", MB_ICONWARNING | MB_OKCANCEL)) { SendMessage(WM_CLOSE); return FALSE; } } // register ourselves to receive PreTranslateMessage CMessageLoop* pLoop = _Module.GetMessageLoop(); pLoop->AddMessageFilter(this); setupStatusBar(); DoDataExchange(); // attach controls DlgResize_Init(true, true); // init CDialogResize Scylla::windowLog.setWindow(ListLog); appendPluginListToMenu(hMenuImports.GetSubMenu(0)); appendPluginListToMenu(CMenuHandle(GetMenu()).GetSubMenu(MenuImportsOffsetTrace)); enableDialogControls(FALSE); setIconAndDialogCaption(); return TRUE; } void MainGui::OnDestroy() { PostQuitMessage(0); } void MainGui::OnSize(UINT nType, CSize size) { StatusBar.SendMessage(WM_SIZE); SetMsgHandled(FALSE); } void MainGui::OnContextMenu(CWindow wnd, CPoint point) { switch(wnd.GetDlgCtrlID()) { case IDC_TREE_IMPORTS: DisplayContextMenuImports(wnd, point); return; case IDC_LIST_LOG: DisplayContextMenuLog(wnd, point); return; } SetMsgHandled(FALSE); } void MainGui::OnCommand(UINT uNotifyCode, int nID, CWindow wndCtl) { // Handle plugin trace menu selection if(uNotifyCode == 0 && !wndCtl.IsWindow()) // make sure it's a menu { if ((nID >= PLUGIN_MENU_BASE_ID) && (nID <= (int)(Scylla::plugins.getScyllaPluginList().size() + Scylla::plugins.getImprecPluginList().size() + PLUGIN_MENU_BASE_ID))) { pluginActionHandler(nID); return; } } SetMsgHandled(FALSE); } LRESULT MainGui::OnTreeImportsDoubleClick(const NMHDR* pnmh) { if(TreeImports.GetCount() < 1) return 0; // Get item under cursor CTreeItem over = findTreeItem(CPoint(GetMessagePos()), true); if(over && importsHandling.isImport(over)) { pickApiActionHandler(over); } return 0; } LRESULT MainGui::OnTreeImportsKeyDown(const NMHDR* pnmh) { const NMTVKEYDOWN * tkd = (NMTVKEYDOWN *)pnmh; switch(tkd->wVKey) { case VK_RETURN: { CTreeItem selected = TreeImports.GetFocusItem(); if(!selected.IsNull() && importsHandling.isImport(selected)) { pickApiActionHandler(selected); } } return 1; case VK_DELETE: deleteSelectedImportsActionHandler(); return 1; } SetMsgHandled(FALSE); return 0; } UINT MainGui::OnTreeImportsSubclassGetDlgCode(const MSG * lpMsg) { if(lpMsg) { switch(lpMsg->wParam) { case VK_RETURN: return DLGC_WANTMESSAGE; } } SetMsgHandled(FALSE); return 0; } void MainGui::OnTreeImportsSubclassChar(UINT nChar, UINT nRepCnt, UINT nFlags) { switch(nChar) { case VK_RETURN: break; default: SetMsgHandled(FALSE); break; } } void MainGui::OnProcessListDrop(UINT uNotifyCode, int nID, CWindow wndCtl) { fillProcessListComboBox(ComboProcessList); } void MainGui::OnProcessListSelected(UINT uNotifyCode, int nID, CWindow wndCtl) { processSelectedActionHandler(ComboProcessList.GetCurSel()); } void MainGui::OnPickDLL(UINT uNotifyCode, int nID, CWindow wndCtl) { pickDllActionHandler(); } void MainGui::OnOptions(UINT uNotifyCode, int nID, CWindow wndCtl) { optionsActionHandler(); } void MainGui::OnDump(UINT uNotifyCode, int nID, CWindow wndCtl) { dumpActionHandler(); } void MainGui::OnDumpMemory(UINT uNotifyCode, int nID, CWindow wndCtl) { dumpMemoryActionHandler(); } void MainGui::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::OnIATAutoSearch(UINT uNotifyCode, int nID, CWindow wndCtl) { iatAutosearchActionHandler(); } void MainGui::OnGetImports(UINT uNotifyCode, int nID, CWindow wndCtl) { getImportsActionHandler(); } void MainGui::OnInvalidImports(UINT uNotifyCode, int nID, CWindow wndCtl) { showInvalidImportsActionHandler(); } void MainGui::OnSuspectImports(UINT uNotifyCode, int nID, CWindow wndCtl) { showSuspectImportsActionHandler(); } void MainGui::OnClearImports(UINT uNotifyCode, int nID, CWindow wndCtl) { clearImportsActionHandler(); } void MainGui::OnInvalidateSelected(UINT uNotifyCode, int nID, CWindow wndCtl) { invalidateSelectedImportsActionHandler(); } void MainGui::OnCutSelected(UINT uNotifyCode, int nID, CWindow wndCtl) { deleteSelectedImportsActionHandler(); } void MainGui::OnSaveTree(UINT uNotifyCode, int nID, CWindow wndCtl) { saveTreeActionHandler(); } void MainGui::OnLoadTree(UINT uNotifyCode, int nID, CWindow wndCtl) { loadTreeActionHandler(); } void MainGui::OnAutotrace(UINT uNotifyCode, int nID, CWindow wndCtl) { // TODO } void MainGui::OnExit(UINT uNotifyCode, int nID, CWindow wndCtl) { DestroyWindow(); } void MainGui::OnAbout(UINT uNotifyCode, int nID, CWindow wndCtl) { showAboutDialog(); } void MainGui::setupStatusBar() { StatusBar.Create(m_hWnd, NULL, L"", WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_TOOLTIPS, NULL, IDC_STATUS_BAR); CRect rcMain, rcStatus; GetClientRect(&rcMain); StatusBar.GetWindowRect(&rcStatus); const int PARTS = 4; int widths[PARTS]; widths[PART_COUNT] = rcMain.Width() / 5; widths[PART_INVALID] = widths[PART_COUNT] + rcMain.Width() / 5; widths[PART_IMAGEBASE] = widths[PART_INVALID] + rcMain.Width() / 3; widths[PART_MODULE] = -1; StatusBar.SetParts(PARTS, widths); ResizeClient(rcMain.Width(), rcMain.Height() + rcStatus.Height(), FALSE); } void MainGui::updateStatusBar() { // Rewrite ImportsHandling so we get these easily unsigned int totalImports = importsHandling.thunkCount(); unsigned int invalidImports = importsHandling.invalidThunkCount(); // \t = center, \t\t = right-align swprintf_s(stringBuffer, L"\tImports: %u", totalImports); StatusBar.SetText(PART_COUNT, stringBuffer); if(invalidImports > 0) { StatusBar.SetIcon(PART_INVALID, hIconError); } else { StatusBar.SetIcon(PART_INVALID, hIconCheck); } swprintf_s(stringBuffer, L"\tInvalid: %u", invalidImports); StatusBar.SetText(PART_INVALID, stringBuffer); if(selectedProcess) { DWORD_PTR imageBase = 0; const WCHAR * fileName = 0; if(ProcessAccessHelp::selectedModule) { imageBase = ProcessAccessHelp::selectedModule->modBaseAddr; fileName = ProcessAccessHelp::selectedModule->getFilename(); } else { imageBase = selectedProcess->imageBase; fileName = selectedProcess->filename; } swprintf_s(stringBuffer, L"\tImagebase: " PRINTF_DWORD_PTR_FULL, imageBase); StatusBar.SetText(PART_IMAGEBASE, stringBuffer); StatusBar.SetText(PART_MODULE, fileName); StatusBar.SetTipText(PART_MODULE, fileName); } else { StatusBar.SetText(PART_IMAGEBASE, L""); StatusBar.SetText(PART_MODULE, L""); } } bool MainGui::showFileDialog(WCHAR * selectedFile, bool save, const WCHAR * defFileName, const WCHAR * filter, const WCHAR * defExtension, const WCHAR * directory) { OPENFILENAME ofn = {0}; // WTL doesn't support new explorer styles on Vista and up // This is because it uses a custom hook, we could remove it or derive // from CFileDialog but this solution is easier and allows more control anyway (e.g. initial dir) if(defFileName) { wcscpy_s(selectedFile, MAX_PATH, defFileName); } else { selectedFile[0] = L'\0'; } ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = m_hWnd; ofn.lpstrFilter = filter; ofn.lpstrDefExt = defExtension; // only first 3 chars are used, no dots! ofn.lpstrFile = selectedFile; ofn.lpstrInitialDir = directory; ofn.nMaxFile = MAX_PATH; ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY; /* *OFN_EXPLORER is automatically used, it only has to be specified *if using a custom hook *OFN_LONGNAMES is automatically used by explorer-style dialogs */ if(save) ofn.Flags |= OFN_OVERWRITEPROMPT; else ofn.Flags |= OFN_FILEMUSTEXIST; if(save) return 0 != GetSaveFileName(&ofn); else return 0 != GetOpenFileName(&ofn); } void MainGui::setIconAndDialogCaption() { SetIcon(hIcon, TRUE); SetIcon(hIcon, FALSE); SetWindowText(APPNAME L" " ARCHITECTURE L" " APPVERSION); } void MainGui::pickDllActionHandler() { if(!selectedProcess) return; PickDllGui dlgPickDll(ProcessAccessHelp::moduleList); if(dlgPickDll.DoModal()) { //get selected module ProcessAccessHelp::selectedModule = dlgPickDll.getSelectedModule(); ProcessAccessHelp::targetImageBase = ProcessAccessHelp::selectedModule->modBaseAddr; Scylla::windowLog.log(L"->>> Module %s selected.", ProcessAccessHelp::selectedModule->getFilename()); Scylla::windowLog.log(L"Imagebase: " PRINTF_DWORD_PTR_FULL L" Size: %08X", ProcessAccessHelp::selectedModule->modBaseAddr, ProcessAccessHelp::selectedModule->modBaseSize); } else { ProcessAccessHelp::selectedModule = 0; } updateStatusBar(); } void MainGui::pickApiActionHandler(CTreeItem item) { if(!importsHandling.isImport(item)) return; // TODO: new node when user picked an API from another DLL? PickApiGui dlgPickApi(ProcessAccessHelp::moduleList); if(dlgPickApi.DoModal()) { const ApiInfo* api = dlgPickApi.getSelectedApi(); if(api && api->module) { importsHandling.setImport(item, api->module->getFilename(), api->name, api->ordinal, api->hint, true, api->isForwarded); } } updateStatusBar(); } void MainGui::startDisassemblerGui(CTreeItem selectedTreeNode) { if(!selectedProcess) return; DWORD_PTR address = importsHandling.getApiAddressByNode(selectedTreeNode); if (address) { BYTE test; if(!ProcessAccessHelp::readMemoryFromProcess(address, sizeof(test), &test)) { swprintf_s(stringBuffer, L"Can't read memory at " PRINTF_DWORD_PTR_FULL, address); MessageBox(stringBuffer, L"Failure", MB_ICONERROR); } else { DisassemblerGui dlgDisassembler(address); dlgDisassembler.DoModal(); } } } void MainGui::processSelectedActionHandler(int index) { std::vector& processList = Scylla::processLister.getProcessList(); Process &process = processList.at(index); selectedProcess = 0; clearImportsActionHandler(); Scylla::windowLog.log(L"Analyzing %s", process.fullPath); if (ProcessAccessHelp::hProcess != 0) { ProcessAccessHelp::closeProcessHandle(); apiReader.clearAll(); } if (!ProcessAccessHelp::openProcessHandle(process.PID)) { enableDialogControls(FALSE); Scylla::windowLog.log(L"Error: Cannot open process handle."); updateStatusBar(); return; } ProcessAccessHelp::getProcessModules(process.PID, ProcessAccessHelp::moduleList); apiReader.readApisFromModuleList(); Scylla::windowLog.log(L"Loading modules done."); //TODO improve ProcessAccessHelp::selectedModule = 0; ProcessAccessHelp::targetSizeOfImage = process.imageSize; ProcessAccessHelp::targetImageBase = process.imageBase; ProcessAccessHelp::getSizeOfImageCurrentProcess(); process.imageSize = (DWORD)ProcessAccessHelp::targetSizeOfImage; Scylla::windowLog.log(L"Imagebase: " PRINTF_DWORD_PTR_FULL L" Size: %08X", process.imageBase, process.imageSize); process.entryPoint = ProcessAccessHelp::getEntryPointFromFile(process.fullPath); EditOEPAddress.SetValue(process.entryPoint + process.imageBase); selectedProcess = &process; enableDialogControls(TRUE); updateStatusBar(); } void MainGui::fillProcessListComboBox(CComboBox& hCombo) { hCombo.ResetContent(); std::vector& processList = Scylla::processLister.getProcessListSnapshot(); for (size_t i = 0; i < processList.size(); i++) { swprintf_s(stringBuffer, L"0x%04X - %s - %s", processList[i].PID, processList[i].filename, processList[i].fullPath); hCombo.AddString(stringBuffer); } } /* void MainGui::addTextToOutputLog(const WCHAR * text) { if (m_hWnd) { ListLog.SetCurSel(ListLog.AddString(text)); } } */ void MainGui::clearOutputLog() { if (m_hWnd) { ListLog.ResetContent(); } } bool MainGui::saveLogToFile(const WCHAR * file) { const BYTE BOM[] = {0xFF, 0xFE}; // UTF-16 little-endian const WCHAR newLine[] = L"\r\n"; bool success = true; HANDLE hFile = CreateFile(file, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); if(hFile != INVALID_HANDLE_VALUE) { ProcessAccessHelp::writeMemoryToFileEnd(hFile, sizeof(BOM), BOM); WCHAR * buffer = 0; size_t bufsize = 0; for(int i = 0; i < ListLog.GetCount(); i++) { size_t size = ListLog.GetTextLen(i); size += _countof(newLine)-1; if(size+1 > bufsize) { bufsize = size+1; delete[] buffer; try { buffer = new WCHAR[bufsize]; } catch(std::bad_alloc&) { buffer = 0; success = false; break; } } ListLog.GetText(i, buffer); wcscat_s(buffer, bufsize, newLine); ProcessAccessHelp::writeMemoryToFileEnd(hFile, (DWORD)(size * sizeof(WCHAR)), buffer); } delete[] buffer; CloseHandle(hFile); } return success; } void MainGui::showInvalidImportsActionHandler() { importsHandling.selectImports(true, false); GotoDlgCtrl(TreeImports); } void MainGui::showSuspectImportsActionHandler() { importsHandling.selectImports(false, true); GotoDlgCtrl(TreeImports); } void MainGui::deleteSelectedImportsActionHandler() { CTreeItem selected = TreeImports.GetFirstSelectedItem(); while(!selected.IsNull()) { if(importsHandling.isModule(selected)) { importsHandling.cutModule(selected); } else { importsHandling.cutImport(selected); } selected = TreeImports.GetNextSelectedItem(selected); } updateStatusBar(); } void MainGui::invalidateSelectedImportsActionHandler() { CTreeItem selected = TreeImports.GetFirstSelectedItem(); while(!selected.IsNull()) { if(importsHandling.isImport(selected)) { importsHandling.invalidateImport(selected); } selected = TreeImports.GetNextSelectedItem(selected); } updateStatusBar(); } void MainGui::loadTreeActionHandler() { if(!selectedProcess) return; WCHAR selectedFilePath[MAX_PATH]; getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if(showFileDialog(selectedFilePath, false, NULL, filterXml, NULL, stringBuffer)) { TreeImportExport treeIO(selectedFilePath); DWORD_PTR addrOEP = 0; DWORD_PTR addrIAT = 0; DWORD sizeIAT = 0; if(!treeIO.importTreeList(importsHandling.moduleList, &addrOEP, &addrIAT, &sizeIAT)) { Scylla::windowLog.log(L"Loading tree file failed %s", selectedFilePath); MessageBox(L"Loading tree file failed.", L"Failure", MB_ICONERROR); } else { EditOEPAddress.SetValue(addrOEP); EditIATAddress.SetValue(addrIAT); EditIATSize.SetValue(sizeIAT); importsHandling.displayAllImports(); updateStatusBar(); Scylla::windowLog.log(L"Loaded tree file %s", selectedFilePath); Scylla::windowLog.log(L"-> OEP: " PRINTF_DWORD_PTR_FULL, addrOEP); Scylla::windowLog.log(L"-> IAT: " PRINTF_DWORD_PTR_FULL L" Size: " PRINTF_DWORD_PTR, addrIAT, sizeIAT); } } } void MainGui::saveTreeActionHandler() { if(!selectedProcess) return; WCHAR selectedFilePath[MAX_PATH]; getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if(showFileDialog(selectedFilePath, true, NULL, filterXml, L"xml", stringBuffer)) { TreeImportExport treeIO(selectedFilePath); DWORD_PTR addrOEP = EditOEPAddress.GetValue(); DWORD_PTR addrIAT = EditIATAddress.GetValue(); DWORD sizeIAT = EditIATSize.GetValue(); if(!treeIO.exportTreeList(importsHandling.moduleList, selectedProcess, addrOEP, addrIAT, sizeIAT)) { Scylla::windowLog.log(L"Saving tree file failed %s", selectedFilePath); MessageBox(L"Saving tree file failed.", L"Failure", MB_ICONERROR); } else { Scylla::windowLog.log(L"Saved tree file %s", selectedFilePath); } } } void MainGui::iatAutosearchActionHandler() { DWORD_PTR searchAddress = 0; DWORD_PTR addressIAT = 0; DWORD sizeIAT = 0; IATSearch iatSearch; if(!selectedProcess) return; if(EditOEPAddress.GetWindowTextLength() > 0) { searchAddress = EditOEPAddress.GetValue(); if (searchAddress) { if (iatSearch.searchImportAddressTableInProcess(searchAddress, &addressIAT, &sizeIAT)) { Scylla::windowLog.log(L"IAT found at VA " PRINTF_DWORD_PTR_FULL L" RVA " PRINTF_DWORD_PTR_FULL L" Size 0x%04X (%d)", addressIAT, addressIAT - ProcessAccessHelp::targetImageBase, sizeIAT, sizeIAT); EditIATAddress.SetValue(addressIAT); EditIATSize.SetValue(sizeIAT); swprintf_s(stringBuffer, L"IAT found:\r\n\r\nStart: " PRINTF_DWORD_PTR_FULL L"\r\nSize: 0x%04X (%d) ", addressIAT, sizeIAT, sizeIAT); MessageBox(stringBuffer, L"IAT found", MB_ICONINFORMATION); } else { Scylla::windowLog.log(L"IAT not found at OEP " PRINTF_DWORD_PTR_FULL L"!", searchAddress); } } } } void MainGui::getImportsActionHandler() { if(!selectedProcess) return; DWORD_PTR addressIAT = EditIATAddress.GetValue(); DWORD sizeIAT = EditIATSize.GetValue(); if (addressIAT && sizeIAT) { apiReader.readAndParseIAT(addressIAT, sizeIAT, importsHandling.moduleList); importsHandling.displayAllImports(); updateStatusBar(); } } void MainGui::SetupImportsMenuItems(CTreeItem item) { bool isItem, isImport = false; isItem = !item.IsNull(); if(isItem) { isImport = importsHandling.isImport(item); } CMenuHandle hSub = hMenuImports.GetSubMenu(0); UINT itemOnly = isItem ? MF_ENABLED : MF_GRAYED; UINT importOnly = isImport ? MF_ENABLED : MF_GRAYED; hSub.EnableMenuItem(ID__INVALIDATE, itemOnly); hSub.EnableMenuItem(ID__DISASSEMBLE, importOnly); hSub.EnableMenuItem(ID__CUTTHUNK, importOnly); hSub.EnableMenuItem(ID__DELETETREENODE, itemOnly); } void MainGui::DisplayContextMenuImports(CWindow hwnd, CPoint pt) { if(TreeImports.GetCount() < 1) return; CTreeItem over, parent; if(pt.x == -1 && pt.y == -1) // invoked by keyboard { CRect pos; over = TreeImports.GetFocusItem(); if(over) { over.EnsureVisible(); over.GetRect(&pos, TRUE); TreeImports.ClientToScreen(&pos); } else { TreeImports.GetWindowRect(&pos); } pt = pos.TopLeft(); } else { // Get item under cursor over = findTreeItem(pt, true); } SetupImportsMenuItems(over); CMenuHandle hSub = hMenuImports.GetSubMenu(0); BOOL menuItem = hSub.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD, pt.x, pt.y, hwnd); if (menuItem) { if ((menuItem >= PLUGIN_MENU_BASE_ID) && (menuItem <= (int)(Scylla::plugins.getScyllaPluginList().size() + Scylla::plugins.getImprecPluginList().size() + PLUGIN_MENU_BASE_ID))) { //wsprintf(stringBuffer, L"%d %s\n",menuItem,pluginList[menuItem - PLUGIN_MENU_BASE_ID].pluginName); //MessageBox(stringBuffer, L"plugin selection"); pluginActionHandler(menuItem); return; } switch (menuItem) { case ID__INVALIDATE: if(importsHandling.isModule(over)) importsHandling.invalidateModule(over); else importsHandling.invalidateImport(over); break; case ID__DISASSEMBLE: startDisassemblerGui(over); break; case ID__EXPANDALLNODES: importsHandling.expandAllTreeNodes(); break; case ID__COLLAPSEALLNODES: importsHandling.collapseAllTreeNodes(); break; case ID__CUTTHUNK: importsHandling.cutImport(over); break; case ID__DELETETREENODE: importsHandling.cutModule(importsHandling.isImport(over) ? over.GetParent() : over); break; } } updateStatusBar(); } void MainGui::DisplayContextMenuLog(CWindow hwnd, CPoint pt) { if(pt.x == -1 && pt.y == -1) // invoked by keyboard { CRect pos; ListLog.GetWindowRect(&pos); pt = pos.TopLeft(); } CMenuHandle hSub = hMenuLog.GetSubMenu(0); BOOL menuItem = hSub.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD, pt.x, pt.y, hwnd); if (menuItem) { switch (menuItem) { case ID__SAVE: WCHAR selectedFilePath[MAX_PATH]; getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if(showFileDialog(selectedFilePath, true, NULL, filterTxt, L"txt", stringBuffer)) { saveLogToFile(selectedFilePath); } break; case ID__CLEAR: clearOutputLog(); break; } } } void MainGui::appendPluginListToMenu(CMenuHandle hMenu) { std::vector &scyllaPluginList = Scylla::plugins.getScyllaPluginList(); std::vector &imprecPluginList = Scylla::plugins.getImprecPluginList(); if (scyllaPluginList.size() > 0) { CMenuHandle newMenu; newMenu.CreatePopupMenu(); for (size_t i = 0; i < scyllaPluginList.size(); i++) { newMenu.AppendMenu(MF_STRING, i + PLUGIN_MENU_BASE_ID, scyllaPluginList[i].pluginName); } hMenu.AppendMenu(MF_MENUBARBREAK); hMenu.AppendMenu(MF_POPUP, newMenu, L"Scylla Plugins"); } if (imprecPluginList.size() > 0) { CMenuHandle newMenu; newMenu.CreatePopupMenu(); for (size_t i = 0; i < imprecPluginList.size(); i++) { newMenu.AppendMenu(MF_STRING, scyllaPluginList.size() + i + PLUGIN_MENU_BASE_ID, imprecPluginList[i].pluginName); } hMenu.AppendMenu(MF_MENUBARBREAK); hMenu.AppendMenu(MF_POPUP, newMenu, L"ImpREC Plugins"); } } void MainGui::dumpMemoryActionHandler() { WCHAR selectedFilePath[MAX_PATH]; DumpMemoryGui dlgDumpMemory; if(dlgDumpMemory.DoModal()) { getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if(showFileDialog(selectedFilePath, true, dlgDumpMemory.dumpFilename, filterMem, L"mem", stringBuffer)) { if (ProcessAccessHelp::writeMemoryToNewFile(selectedFilePath,dlgDumpMemory.dumpedMemorySize,dlgDumpMemory.dumpedMemory)) { Scylla::windowLog.log(L"Memory dump saved %s", selectedFilePath); } else { Scylla::windowLog.log(L"Error! Cannot write memory dump to disk"); } } } } void MainGui::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)) { 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(); 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.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); } - ImportRebuild importRebuild; - if (importRebuild.rebuildImportTable(selectedFilePath,newFilePath,importsHandling.moduleList)) + ImportRebuilder importRebuild(selectedFilePath); + + if (Scylla::config[IAT_FIX_AND_OEP_FIX].isTrue()) + { + importRebuild.setEntryPointRva((DWORD)(entrypoint - modBase)); + } + + + 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.GetSubMenu(MenuImportsOffsetTrace).EnableMenuItem(MenuImportsTraceOffsetScylla, MF_BYPOSITION | valMenu); menu.GetSubMenu(MenuImportsOffsetTrace).EnableMenuItem(MenuImportsTraceOffsetImpRec, MF_BYPOSITION | valMenu); //not yet implemented GetDlgItem(IDC_BTN_AUTOTRACE).EnableWindow(FALSE); menu.EnableMenuItem(ID_TRACE_AUTOTRACE, MF_GRAYED); } CTreeItem MainGui::findTreeItem(CPoint pt, bool screenCoordinates) { if(screenCoordinates) { TreeImports.ScreenToClient(&pt); } UINT flags; CTreeItem over = TreeImports.HitTest(pt, &flags); if(over) { if(!(flags & TVHT_ONITEM)) { over.m_hTreeItem = NULL; } } return over; } void MainGui::showAboutDialog() { AboutGui dlgAbout; dlgAbout.DoModal(); } void MainGui::dllInjectActionHandler() { if(!selectedProcess) return; WCHAR selectedFilePath[MAX_PATH]; HMODULE hMod = 0; DllInjection dllInjection; getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if (showFileDialog(selectedFilePath, false, NULL, filterDll, NULL, stringBuffer)) { hMod = dllInjection.dllInjection(ProcessAccessHelp::hProcess, selectedFilePath); if (hMod && Scylla::config[DLL_INJECTION_AUTO_UNLOAD].isTrue()) { if (!dllInjection.unloadDllInProcess(ProcessAccessHelp::hProcess, hMod)) { Scylla::windowLog.log(L"DLL unloading failed, target %s", selectedFilePath); } } if (hMod) { Scylla::windowLog.log(L"DLL Injection was successful, target %s", selectedFilePath); } else { Scylla::windowLog.log(L"DLL Injection failed, target %s", selectedFilePath); } } } void MainGui::optionsActionHandler() { OptionsGui dlgOptions; dlgOptions.DoModal(); } void MainGui::clearImportsActionHandler() { importsHandling.clearAllImports(); updateStatusBar(); } void MainGui::pluginActionHandler( int menuItem ) { if(!selectedProcess) return; DllInjectionPlugin dllInjectionPlugin; std::vector &scyllaPluginList = Scylla::plugins.getScyllaPluginList(); std::vector &imprecPluginList = Scylla::plugins.getImprecPluginList(); menuItem -= PLUGIN_MENU_BASE_ID; dllInjectionPlugin.hProcess = ProcessAccessHelp::hProcess; dllInjectionPlugin.apiReader = &apiReader; if (menuItem < (int)scyllaPluginList.size()) { //scylla plugin dllInjectionPlugin.injectPlugin(scyllaPluginList[menuItem], importsHandling.moduleList,selectedProcess->imageBase, selectedProcess->imageSize); } else { #ifndef _WIN64 menuItem -= (int)scyllaPluginList.size(); //imprec plugin dllInjectionPlugin.injectImprecPlugin(imprecPluginList[menuItem], importsHandling.moduleList,selectedProcess->imageBase, selectedProcess->imageSize); #endif } importsHandling.scanAndFixModuleList(); importsHandling.displayAllImports(); updateStatusBar(); } bool MainGui::getCurrentModulePath(WCHAR * buffer, size_t bufferSize) { if(!selectedProcess) return false; if(ProcessAccessHelp::selectedModule) { wcscpy_s(buffer, bufferSize, ProcessAccessHelp::selectedModule->fullPath); } else { wcscpy_s(buffer, bufferSize, selectedProcess->fullPath); } WCHAR * slash = wcsrchr(buffer, L'\\'); if(slash) { *(slash+1) = L'\0'; } return true; } diff --git a/Scylla/MainGui.rc b/Scylla/MainGui.rc index 544a714..3bc169c 100644 Binary files a/Scylla/MainGui.rc and b/Scylla/MainGui.rc differ diff --git a/Scylla/OptionsGui.cpp b/Scylla/OptionsGui.cpp index 39083ac..3d1eb25 100644 --- a/Scylla/OptionsGui.cpp +++ b/Scylla/OptionsGui.cpp @@ -1,52 +1,54 @@ #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); } 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(); } diff --git a/Scylla/OptionsGui.h b/Scylla/OptionsGui.h index 6e94ca3..1e600fa 100644 --- a/Scylla/OptionsGui.h +++ b/Scylla/OptionsGui.h @@ -1,65 +1,67 @@ #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) 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; // 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/PeDump.cpp b/Scylla/PeDump.cpp deleted file mode 100644 index 8da6b6b..0000000 --- a/Scylla/PeDump.cpp +++ /dev/null @@ -1,383 +0,0 @@ -#include "PeDump.h" -#include "ProcessAccessHelp.h" - -#include "Scylla.h" -#include "Architecture.h" -#include "PeParser.h" - -bool PeDump::useHeaderFromDisk = true; -bool PeDump::appendOverlayData = true; - -//#define DEBUG_COMMENTS - -bool PeDump::fillPeHeaderStructs(bool fromDisk) -{ - DWORD dwSize = ProcessAccessHelp::PE_HEADER_BYTES_COUNT; - - if (dwSize > sizeOfImage) - { - dwSize = (DWORD)sizeOfImage; - } - - headerData = new BYTE[dwSize]; - - if (!headerData) - return false; - - if (fromDisk) - { - //from disk - if (!ProcessAccessHelp::readHeaderFromFile(headerData, dwSize, fullpath)) - { -#ifdef DEBUG_COMMENTS - Scylla::debugLog.log(L"fillPeHeaderStructs -> ProcessAccessHelp::readHeaderFromFile failed - %X %s", dwSize, fullpath); -#endif - return false; - } - } - else - { - //from memory - if (!ProcessAccessHelp::readMemoryPartlyFromProcess(imageBase, dwSize, headerData)) - { -#ifdef DEBUG_COMMENTS - Scylla::debugLog.log(L"fillPeHeaderStructs -> ProcessAccessHelp::readMemoryFromProcess failed - " PRINTF_DWORD_PTR_FULL L" %X " PRINTF_DWORD_PTR_FULL, imageBase, dwSize, headerData); -#endif - return false; - } - } - - pDOSHeader = (PIMAGE_DOS_HEADER)headerData; - pNTHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)headerData + (DWORD_PTR)pDOSHeader->e_lfanew); - pSectionHeader = IMAGE_FIRST_SECTION(pNTHeader); - - return true; -} - -bool PeDump::validateHeaders() -{ - if ((pDOSHeader != 0) && (pDOSHeader->e_magic == IMAGE_DOS_SIGNATURE) && (pNTHeader->Signature == IMAGE_NT_SIGNATURE)) - { -#ifdef _WIN64 - if (pNTHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) -#else - if (pNTHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) -#endif - { - return true; - } - else - { - return false; - } - } - else - { - return false; - } -} - -bool PeDump::dumpCompleteProcessToDisk(const WCHAR * dumpFilePath) -{ - if (!fillPeHeaderStructs(useHeaderFromDisk)) - { -#ifdef DEBUG_COMMENTS - Scylla::debugLog.log(L"dumpCompleteProcessToDisk -> fillPeHeaderStructs failed"); -#endif - return false; - } - - if (!validateHeaders()) - { -#ifdef DEBUG_COMMENTS - Scylla::debugLog.log(L"dumpCompleteProcessToDisk -> validateHeaders failed"); -#endif - return false; - } - - dumpData = new BYTE[sizeOfImage]; - - if (dumpData) - { - if (!ProcessAccessHelp::readMemoryPartlyFromProcess(imageBase,sizeOfImage,dumpData)) - { -#ifdef DEBUG_COMMENTS - Scylla::debugLog.log(L"dumpCompleteProcessToDisk -> readMemoryFromProcess failed"); -#endif - return false; - } - else - { - - fixDump(dumpData); - - if (saveDumpToDisk(dumpFilePath, dumpData, (DWORD)sizeOfImage)) - { - - if (appendOverlayData) - { - appendOverlayDataToDump(dumpFilePath); - } - - //printf("dump success\n"); - return true; - } - else - { - return false; - } - } - } - else - { -#ifdef DEBUG_COMMENTS - Scylla::debugLog.log(L"dumpCompleteProcessToDisk -> new BYTE[sizeOfImage] failed %X", sizeOfImage); -#endif - return false; - } -} - -bool PeDump::appendOverlayDataToDump(const WCHAR *dumpFilePath) -{ - DWORD_PTR offset = 0; - DWORD size = 0; - - if (getOverlayData(fullpath,&offset,&size)) - { - if (offset == 0) - { -#ifdef DEBUG_COMMENTS - Scylla::debugLog.log(L"appendOverlayDataToDump :: No overlay exists"); -#endif - return true; - } - else - { - if (copyFileDataFromOffset(fullpath, dumpFilePath, offset, size)) - { -#ifdef DEBUG_COMMENTS - Scylla::debugLog.log(L"appendOverlayDataToDump :: appending overlay success"); -#endif - return true; - } - else - { -#ifdef DEBUG_COMMENTS - Scylla::debugLog.log(L"appendOverlayDataToDump :: appending overlay failed"); -#endif - return false; - } - } - } - else - { -#ifdef DEBUG_COMMENTS - Scylla::debugLog.log(L"appendOverlayDataToDump :: getOverlayData failed"); -#endif - return false; - } -} - -bool PeDump::copyFileDataFromOffset(const WCHAR * sourceFile, const WCHAR * destFile, DWORD_PTR fileOffset, DWORD dwSize) -{ - HANDLE hSourceFile, hDestFile; - BYTE * dataBuffer = 0; - bool retValue = false; - - hSourceFile = CreateFile(sourceFile, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); - - if(hSourceFile == INVALID_HANDLE_VALUE) - { -#ifdef DEBUG_COMMENTS - Scylla::debugLog.log(L"copyFileDataFromOffset :: failed to open source file"); -#endif - return false; - } - - hDestFile = CreateFile(destFile, GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0); - - if(hSourceFile == INVALID_HANDLE_VALUE) - { -#ifdef DEBUG_COMMENTS - Scylla::debugLog.log(L"copyFileDataFromOffset :: failed to open destination file"); -#endif - CloseHandle(hSourceFile); - return false; - } - - dataBuffer = new BYTE[dwSize]; - - if (ProcessAccessHelp::readMemoryFromFile(hSourceFile, (LONG)fileOffset, dwSize, dataBuffer)) - { - if (ProcessAccessHelp::writeMemoryToFileEnd(hDestFile,dwSize,dataBuffer)) - { - retValue = true; - } - else - { -#ifdef DEBUG_COMMENTS - Scylla::debugLog.log(L"copyFileDataFromOffset :: writeMemoryToFileEnd failed"); -#endif - retValue = false; - } - } - else - { -#ifdef DEBUG_COMMENTS - Scylla::debugLog.log(L"copyFileDataFromOffset :: readMemoryFromFile failed to read from source file"); -#endif - retValue = false; - } - - delete [] dataBuffer; - - CloseHandle(hSourceFile); - CloseHandle(hDestFile); - - return retValue; -} - -void PeDump::fixDump(BYTE * dumpBuffer) -{ - int counter = 0; - PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)dumpBuffer; - PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)((DWORD_PTR)dumpBuffer + pDos->e_lfanew); - PIMAGE_SECTION_HEADER pSec = IMAGE_FIRST_SECTION(pNt); - - fixNtHeaderForDump(pNt, pNTHeader); - - do - { - fixSectionHeaderForDump(pSec, pSectionHeader); - - pSectionHeader++; - pSec++; - - counter++; - } while (counter < pNt->FileHeader.NumberOfSections); - - -} - -void PeDump::fixBadNtHeaderValues(PIMAGE_NT_HEADERS pNtHead) -{ - //maybe imagebase in process is not real imagebase - pNtHead->OptionalHeader.ImageBase = imageBase; - pNtHead->OptionalHeader.AddressOfEntryPoint = (DWORD)(entryPoint - imageBase); - pNtHead->OptionalHeader.SizeOfImage = sizeOfImage; -} - -void PeDump::fixSectionHeaderForDump(PIMAGE_SECTION_HEADER oldSecHead, PIMAGE_SECTION_HEADER newSecHead) -{ - memcpy_s(oldSecHead->Name, IMAGE_SIZEOF_SHORT_NAME, newSecHead->Name, IMAGE_SIZEOF_SHORT_NAME); - - oldSecHead->Characteristics = newSecHead->Characteristics; - - oldSecHead->Misc.VirtualSize = newSecHead->Misc.VirtualSize; - oldSecHead->VirtualAddress = newSecHead->VirtualAddress; - - oldSecHead->SizeOfRawData = newSecHead->Misc.VirtualSize; - oldSecHead->PointerToRawData = newSecHead->VirtualAddress; -} - -void PeDump::fixNtHeaderForDump(PIMAGE_NT_HEADERS oldNtHead, PIMAGE_NT_HEADERS newNtHead) -{ - //some special - fixBadNtHeaderValues(newNtHead); - - //fix FileHeader - oldNtHead->FileHeader.NumberOfSections = newNtHead->FileHeader.NumberOfSections; - - //fix OptionalHeader - oldNtHead->OptionalHeader.ImageBase = newNtHead->OptionalHeader.ImageBase; - oldNtHead->OptionalHeader.SizeOfImage = newNtHead->OptionalHeader.SizeOfImage; - oldNtHead->OptionalHeader.BaseOfCode = newNtHead->OptionalHeader.BaseOfCode; - oldNtHead->OptionalHeader.AddressOfEntryPoint = newNtHead->OptionalHeader.AddressOfEntryPoint; - oldNtHead->OptionalHeader.SectionAlignment = newNtHead->OptionalHeader.SectionAlignment; - oldNtHead->OptionalHeader.FileAlignment = newNtHead->OptionalHeader.SectionAlignment; - - //deleted in x64 PE -#ifndef _WIN64 - oldNtHead->OptionalHeader.BaseOfData = newNtHead->OptionalHeader.BaseOfData; -#endif -} - -bool PeDump::saveDumpToDisk(const WCHAR * dumpFilePath, BYTE *dumpBuffer, DWORD dumpSize) -{ - DWORD lpNumberOfBytesWritten = 0; - bool retValue = false; - - HANDLE hFile = CreateFile(dumpFilePath, GENERIC_WRITE, FILE_SHARE_WRITE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); - - if(hFile == INVALID_HANDLE_VALUE) - { -#ifdef DEBUG_COMMENTS - Scylla::debugLog.log(L"saveDumpToDisk :: INVALID_HANDLE_VALUE %u", GetLastError()); -#endif - retValue = false; - } - else - { - if (WriteFile(hFile, dumpBuffer, dumpSize, &lpNumberOfBytesWritten, 0)) - { - if (lpNumberOfBytesWritten != dumpSize) - { -#ifdef DEBUG_COMMENTS - Scylla::debugLog.log(L"saveDumpToDisk :: lpNumberOfBytesWritten != dumpSize %d %d", lpNumberOfBytesWritten,dumpSize); -#endif - retValue = false; - } - else - { - retValue = true; - } - } - else - { -#ifdef DEBUG_COMMENTS - Scylla::debugLog.log(L"saveDumpToDisk :: WriteFile failed %u",GetLastError()); -#endif - retValue = false; - } - - CloseHandle(hFile); - } - - return retValue; -} - -bool PeDump::getOverlayData(const WCHAR * filepath, DWORD_PTR * overlayFileOffset, DWORD * overlaySize) -{ - LONGLONG fileSize = 0; - bool returnValue = false; - DWORD calcSize = 0; - - PeParser peFile(filepath); - - if (peFile.isValidPeFile()) - { - fileSize = ProcessAccessHelp::getFileSize(fullpath); - - if (fileSize > 0) - { - calcSize = peFile.getSectionHeaderBasedFileSize(); - - if (calcSize < fileSize) - { - //overlay found - *overlayFileOffset = calcSize; - *overlaySize = (DWORD)(fileSize - calcSize); - } - else - { - *overlayFileOffset = 0; - *overlaySize = 0; - } - - returnValue = true; - } - - } - - return returnValue; -} \ No newline at end of file diff --git a/Scylla/PeDump.h b/Scylla/PeDump.h deleted file mode 100644 index 6f7785e..0000000 --- a/Scylla/PeDump.h +++ /dev/null @@ -1,67 +0,0 @@ -#pragma once - -#include - -class PeDump -{ -public: - - DWORD_PTR entryPoint; //VA - DWORD_PTR imageBase; //VA - DWORD sizeOfImage; - WCHAR fullpath[MAX_PATH]; - - //Settings - static bool useHeaderFromDisk; - static bool appendOverlayData; - - PeDump() - { - imageBase = 0; - sizeOfImage = 0; - dumpData = 0; - headerData = 0; - pNTHeader = 0; - pDOSHeader = 0; - pSectionHeader = 0; - } - - ~PeDump() - { - if (dumpData != 0) - { - delete [] dumpData; - } - - if (headerData != 0) - { - delete [] headerData; - } - } - - bool dumpCompleteProcessToDisk(const WCHAR * dumpFilePath); - - bool saveDumpToDisk(const WCHAR * dumpFilePath, BYTE *dumpBuffer, DWORD dumpSize); - - - bool copyFileDataFromOffset(const WCHAR * sourceFile, const WCHAR * destFile, DWORD_PTR fileOffset, DWORD dwSize); - bool appendOverlayDataToDump(const WCHAR * dumpFilePath); - bool getOverlayData(const WCHAR * filepath, DWORD_PTR * overlayFileOffset, DWORD * overlaySize); - -private: - - BYTE * dumpData; - BYTE * headerData; - - PIMAGE_DOS_HEADER pDOSHeader; - PIMAGE_NT_HEADERS pNTHeader; - PIMAGE_SECTION_HEADER pSectionHeader; - - bool validateHeaders(); - bool fillPeHeaderStructs(bool fromDisk); - - void fixDump(BYTE * dumpBuffer); - void fixBadNtHeaderValues(PIMAGE_NT_HEADERS pNtHead); - void fixSectionHeaderForDump(PIMAGE_SECTION_HEADER oldSecHead, PIMAGE_SECTION_HEADER newSecHead); - void fixNtHeaderForDump(PIMAGE_NT_HEADERS oldNtHead, PIMAGE_NT_HEADERS newNtHead); -}; diff --git a/Scylla/PeParser.cpp b/Scylla/PeParser.cpp index cfba855..a1cbce0 100644 --- a/Scylla/PeParser.cpp +++ b/Scylla/PeParser.cpp @@ -1,1162 +1,1220 @@ #include "PeParser.h" #include "ProcessAccessHelp.h" #include +#include + +#pragma comment(lib, "Imagehlp.lib") PeParser::PeParser() { initClass(); } PeParser::PeParser(const WCHAR * file, bool readSectionHeaders) { initClass(); filename = file; if (filename && wcslen(filename) > 3) { readPeHeaderFromFile(readSectionHeaders); if (readSectionHeaders) { if (isValidPeFile()) { getSectionHeaders(); } } } } PeParser::PeParser(const DWORD_PTR moduleBase, bool readSectionHeaders) { initClass(); moduleBaseAddress = moduleBase; if (moduleBaseAddress) { readPeHeaderFromProcess(readSectionHeaders); if (readSectionHeaders) { if (isValidPeFile()) { getSectionHeaders(); } } } } PeParser::~PeParser() { if (headerMemory) { delete [] headerMemory; } if (fileMemory) { delete [] fileMemory; } for (size_t i = 0; i < listPeSection.size(); i++) { if (listPeSection[i].data) { delete [] listPeSection[i].data; } } listPeSection.clear(); } void PeParser::initClass() { fileMemory = 0; headerMemory = 0; pDosHeader = 0; pDosStub = 0; dosStubSize = 0; pNTHeader32 = 0; pNTHeader64 = 0; overlayData = 0; overlaySize = 0; filename = 0; fileSize = 0; moduleBaseAddress = 0; hFile = INVALID_HANDLE_VALUE; } bool PeParser::isPE64() { if (isValidPeFile()) { return (pNTHeader32->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC); } else { return false; } } bool PeParser::isPE32() { if (isValidPeFile()) { return (pNTHeader32->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC); } else { return false; } } bool PeParser::isTargetFileSamePeFormat() { #ifdef _WIN64 return isPE64(); #else return isPE32(); #endif } bool PeParser::isValidPeFile() { bool retValue = false; if (pDosHeader) { if (pDosHeader->e_magic == IMAGE_DOS_SIGNATURE) { if (pNTHeader32) { if (pNTHeader32->Signature == IMAGE_NT_SIGNATURE) { retValue = true; } } } } return retValue; } bool PeParser::hasDirectory(const int directoryIndex) { if (isPE32()) { return (pNTHeader32->OptionalHeader.DataDirectory[directoryIndex].VirtualAddress != 0); } else if (isPE64()) { return (pNTHeader64->OptionalHeader.DataDirectory[directoryIndex].VirtualAddress != 0); } else { return false; } } bool PeParser::hasExportDirectory() { return hasDirectory(IMAGE_DIRECTORY_ENTRY_EXPORT); } bool PeParser::hasTLSDirectory() { return hasDirectory(IMAGE_DIRECTORY_ENTRY_TLS); } bool PeParser::hasRelocationDirectory() { return hasDirectory(IMAGE_DIRECTORY_ENTRY_BASERELOC); } DWORD PeParser::getEntryPoint() { if (isPE32()) { return pNTHeader32->OptionalHeader.AddressOfEntryPoint; } else if (isPE64()) { return pNTHeader64->OptionalHeader.AddressOfEntryPoint; } else { return 0; } } bool PeParser::readPeHeaderFromProcess(bool readSectionHeaders) { bool retValue = false; DWORD correctSize = 0; DWORD readSize = getInitialHeaderReadSize(readSectionHeaders); headerMemory = new BYTE[readSize]; if (ProcessAccessHelp::readMemoryPartlyFromProcess(moduleBaseAddress, readSize, headerMemory)) { retValue = true; getDosAndNtHeader(headerMemory, (LONG)readSize); if (isValidPeFile()) { correctSize = calcCorrectPeHeaderSize(readSectionHeaders); if (readSize < correctSize) { readSize = correctSize; delete [] headerMemory; headerMemory = new BYTE[readSize]; if (ProcessAccessHelp::readMemoryPartlyFromProcess(moduleBaseAddress, readSize, headerMemory)) { getDosAndNtHeader(headerMemory, (LONG)readSize); } } } } return retValue; } bool PeParser::readPeHeaderFromFile(bool readSectionHeaders) { bool retValue = false; DWORD correctSize = 0; DWORD numberOfBytesRead = 0; DWORD readSize = getInitialHeaderReadSize(readSectionHeaders); headerMemory = new BYTE[readSize]; if (openFileHandle()) { fileSize = (DWORD)ProcessAccessHelp::getFileSize(hFile); if (ReadFile(hFile, headerMemory, readSize, &numberOfBytesRead, 0)) { retValue = true; getDosAndNtHeader(headerMemory, (LONG)readSize); if (isValidPeFile()) { correctSize = calcCorrectPeHeaderSize(readSectionHeaders); if (readSize < correctSize) { readSize = correctSize; if (fileSize > 0) { if (fileSize < correctSize) { readSize = fileSize; } } delete [] headerMemory; headerMemory = new BYTE[readSize]; SetFilePointer(hFile, 0, 0, FILE_BEGIN); if (ReadFile(hFile, headerMemory, readSize, &numberOfBytesRead, 0)) { getDosAndNtHeader(headerMemory, (LONG)readSize); } } } } closeFileHandle(); } return retValue; } bool PeParser::readPeSectionsFromProcess() { bool retValue = true; DWORD_PTR readOffset = 0; listPeSection.reserve(getNumberOfSections()); for (WORD i = 0; i < getNumberOfSections(); i++) { readOffset = listPeSection[i].sectionHeader.VirtualAddress + moduleBaseAddress; listPeSection[i].normalSize = listPeSection[i].sectionHeader.Misc.VirtualSize; if (!readSectionFromProcess(readOffset, listPeSection[i])) { retValue = false; } } return retValue; } bool PeParser::readPeSectionsFromFile() { bool retValue = true; DWORD readOffset = 0; listPeSection.reserve(getNumberOfSections()); if (openFileHandle()) { for (WORD i = 0; i < getNumberOfSections(); i++) { readOffset = listPeSection[i].sectionHeader.PointerToRawData; listPeSection[i].normalSize = listPeSection[i].sectionHeader.SizeOfRawData; if (!readSectionFromFile(readOffset, listPeSection[i])) { retValue = false; } } closeFileHandle(); } else { retValue = false; } return retValue; } bool PeParser::getSectionHeaders() { PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNTHeader32); PeFileSection peFileSection; listPeSection.clear(); listPeSection.reserve(getNumberOfSections()); for (WORD i = 0; i < getNumberOfSections(); i++) { memcpy_s(&peFileSection.sectionHeader, sizeof(IMAGE_SECTION_HEADER), pSection, sizeof(IMAGE_SECTION_HEADER)); listPeSection.push_back(peFileSection); pSection++; } return true; } bool PeParser::getSectionNameUnicode(const int sectionIndex, WCHAR * output, const int outputLen) { CHAR sectionNameA[IMAGE_SIZEOF_SHORT_NAME + 1] = {0}; output[0] = 0; memcpy(sectionNameA, listPeSection[sectionIndex].sectionHeader.Name, IMAGE_SIZEOF_SHORT_NAME); //not null terminated return (swprintf_s(output, outputLen, L"%S", sectionNameA) != -1); } WORD PeParser::getNumberOfSections() { return pNTHeader32->FileHeader.NumberOfSections; } void PeParser::setNumberOfSections(WORD numberOfSections) { pNTHeader32->FileHeader.NumberOfSections = numberOfSections; } std::vector & PeParser::getSectionHeaderList() { return listPeSection; } void PeParser::getDosAndNtHeader(BYTE * memory, LONG size) { pDosHeader = (PIMAGE_DOS_HEADER)memory; pNTHeader32 = 0; pNTHeader64 = 0; dosStubSize = 0; pDosStub = 0; if (pDosHeader->e_lfanew > 0 && pDosHeader->e_lfanew < size) //malformed PE { pNTHeader32 = (PIMAGE_NT_HEADERS32)((DWORD_PTR)pDosHeader + pDosHeader->e_lfanew); pNTHeader64 = (PIMAGE_NT_HEADERS64)((DWORD_PTR)pDosHeader + pDosHeader->e_lfanew); if (pDosHeader->e_lfanew > sizeof(IMAGE_DOS_HEADER)) { dosStubSize = pDosHeader->e_lfanew - sizeof(IMAGE_DOS_HEADER); pDosStub = (BYTE *)((DWORD_PTR)pDosHeader + sizeof(IMAGE_DOS_HEADER)); } } } DWORD PeParser::calcCorrectPeHeaderSize(bool readSectionHeaders) { DWORD correctSize = pDosHeader->e_lfanew + 50; //extra buffer if (readSectionHeaders) { correctSize += getNumberOfSections() * sizeof(IMAGE_SECTION_HEADER); } if (isPE32()) { correctSize += sizeof(IMAGE_NT_HEADERS32); } else if(isPE64()) { correctSize += sizeof(IMAGE_NT_HEADERS64); } else { correctSize = 0; //not a valid PE } return correctSize; } DWORD PeParser::getInitialHeaderReadSize(bool readSectionHeaders) { DWORD readSize = sizeof(IMAGE_DOS_HEADER) + 200 + sizeof(IMAGE_NT_HEADERS64); if (readSectionHeaders) { readSize += (10 * sizeof(IMAGE_SECTION_HEADER)); } return readSize; } DWORD PeParser::getSectionHeaderBasedFileSize() { DWORD lastRawOffset = 0, lastRawSize = 0; //this is needed if the sections aren't sorted by their RawOffset (e.g. Petite) for (WORD i = 0; i < getNumberOfSections(); i++) { if (listPeSection[i].sectionHeader.PointerToRawData > lastRawOffset) { lastRawOffset = listPeSection[i].sectionHeader.PointerToRawData; lastRawSize = listPeSection[i].sectionHeader.SizeOfRawData; } } return (lastRawSize + lastRawOffset); } DWORD PeParser::getSectionHeaderBasedSizeOfImage() { DWORD lastVirtualOffset = 0, lastVirtualSize = 0; //this is needed if the sections aren't sorted by their RawOffset (e.g. Petite) for (WORD i = 0; i < getNumberOfSections(); i++) { if (listPeSection[i].sectionHeader.VirtualAddress > lastVirtualOffset) { lastVirtualOffset = listPeSection[i].sectionHeader.VirtualAddress; lastVirtualSize = listPeSection[i].sectionHeader.Misc.VirtualSize; } } return (lastVirtualSize + lastVirtualOffset); } bool PeParser::openFileHandle() { if (hFile == INVALID_HANDLE_VALUE) { if (filename) { hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); } else { hFile = INVALID_HANDLE_VALUE; } } return (hFile != INVALID_HANDLE_VALUE); } bool PeParser::openWriteFileHandle( const WCHAR * newFile ) { if (newFile) { hFile = CreateFile(newFile, GENERIC_WRITE, FILE_SHARE_WRITE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); } else { hFile = INVALID_HANDLE_VALUE; } return (hFile != INVALID_HANDLE_VALUE); } void PeParser::closeFileHandle() { if (hFile != INVALID_HANDLE_VALUE) { CloseHandle(hFile); hFile = INVALID_HANDLE_VALUE; } } bool PeParser::readSectionFromFile(DWORD readOffset, PeFileSection & peFileSection) { const DWORD maxReadSize = 100; BYTE data[maxReadSize]; DWORD bytesRead = 0; bool retValue = true; DWORD valuesFound = 0; DWORD currentOffset = 0; DWORD readSize = 0; peFileSection.data = 0; peFileSection.dataSize = 0; readSize = peFileSection.normalSize; if (!readOffset || !readSize) { return true; //section without data is valid } if (readSize <= maxReadSize) { peFileSection.dataSize = readSize; peFileSection.normalSize = readSize; return readPeSectionFromFile(readOffset, peFileSection); } currentOffset = readOffset + readSize - maxReadSize; while(currentOffset >= readOffset) //start from the end { SetFilePointer(hFile, currentOffset, 0, FILE_BEGIN); ZeroMemory(data, sizeof(data)); if (!ReadFile(hFile, data, sizeof(data), &bytesRead, 0)) { retValue = false; break; } valuesFound = isMemoryNotNull(data, sizeof(data)); if (valuesFound) { //found some real code currentOffset += valuesFound; if (readOffset < currentOffset) { //real size peFileSection.dataSize = currentOffset - readOffset; } break; } currentOffset -= maxReadSize; } if (peFileSection.dataSize) { retValue = readPeSectionFromFile(readOffset, peFileSection); } return retValue; } DWORD PeParser::isMemoryNotNull( BYTE * data, int dataSize ) { for (int i = (dataSize - 1); i >= 0; i--) { if (data[i] != 0) { return i + 1; } } return 0; } bool PeParser::savePeFileToDisk( const WCHAR * newFile ) { bool retValue = true; DWORD dwFileOffset = 0, dwWriteSize = 0; if (getNumberOfSections() != listPeSection.size()) { return false; } if (openWriteFileHandle(newFile)) { //Dos header dwWriteSize = sizeof(IMAGE_DOS_HEADER); if (!ProcessAccessHelp::writeMemoryToFile(hFile, dwFileOffset, dwWriteSize, pDosHeader)) { retValue = false; } dwFileOffset += dwWriteSize; if (dosStubSize && pDosStub) { //Dos Stub dwWriteSize = dosStubSize; if (!ProcessAccessHelp::writeMemoryToFile(hFile, dwFileOffset, dwWriteSize, pDosStub)) { retValue = false; } dwFileOffset += dwWriteSize; } //Pe Header if (isPE32()) { dwWriteSize = sizeof(IMAGE_NT_HEADERS32); } else { dwWriteSize = sizeof(IMAGE_NT_HEADERS64); } if (!ProcessAccessHelp::writeMemoryToFile(hFile, dwFileOffset, dwWriteSize, pNTHeader32)) { retValue = false; } dwFileOffset += dwWriteSize; //section headers dwWriteSize = sizeof(IMAGE_SECTION_HEADER); for (WORD i = 0; i < getNumberOfSections(); i++) { if (!ProcessAccessHelp::writeMemoryToFile(hFile, dwFileOffset, dwWriteSize, &listPeSection[i].sectionHeader)) { retValue = false; break; } dwFileOffset += dwWriteSize; } for (WORD i = 0; i < getNumberOfSections(); i++) { if (!listPeSection[i].sectionHeader.PointerToRawData) continue; if (listPeSection[i].sectionHeader.PointerToRawData > dwFileOffset) { dwWriteSize = listPeSection[i].sectionHeader.PointerToRawData - dwFileOffset; //padding if (!writeZeroMemoryToFile(hFile, dwFileOffset, dwWriteSize)) { retValue = false; break; } dwFileOffset += dwWriteSize; } dwWriteSize = listPeSection[i].dataSize; if (dwWriteSize) { if (!ProcessAccessHelp::writeMemoryToFile(hFile, listPeSection[i].sectionHeader.PointerToRawData, dwWriteSize, listPeSection[i].data)) { retValue = false; break; } dwFileOffset += dwWriteSize; if (listPeSection[i].dataSize < listPeSection[i].sectionHeader.SizeOfRawData) //padding { dwWriteSize = listPeSection[i].sectionHeader.SizeOfRawData - listPeSection[i].dataSize; if (!writeZeroMemoryToFile(hFile, dwFileOffset, dwWriteSize)) { retValue = false; break; } dwFileOffset += dwWriteSize; } } } //add overlay? if (overlaySize && overlayData) { dwWriteSize = overlaySize; if (!ProcessAccessHelp::writeMemoryToFile(hFile, dwFileOffset, dwWriteSize, overlayData)) { retValue = false; } dwFileOffset += dwWriteSize; } SetEndOfFile(hFile); closeFileHandle(); } return retValue; } bool PeParser::writeZeroMemoryToFile(HANDLE hFile, DWORD fileOffset, DWORD size) { bool retValue = false; PVOID zeromemory = calloc(size, 1); if (zeromemory) { retValue = ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, size, zeromemory); free(zeromemory); } return retValue; } void PeParser::removeDosStub() { if (pDosHeader) { dosStubSize = 0; pDosStub = 0; //must not delete [] pDosHeader->e_lfanew = sizeof(IMAGE_DOS_HEADER); } } bool PeParser::readPeSectionFromFile(DWORD readOffset, PeFileSection & peFileSection) { DWORD bytesRead = 0; peFileSection.data = new BYTE[peFileSection.dataSize]; SetFilePointer(hFile, readOffset, 0, FILE_BEGIN); return (ReadFile(hFile, peFileSection.data, peFileSection.dataSize, &bytesRead, 0) != FALSE); } bool PeParser::readSectionFromProcess( DWORD_PTR readOffset, PeFileSection & peFileSection ) { const DWORD maxReadSize = 100; BYTE data[maxReadSize]; bool retValue = true; DWORD valuesFound = 0; DWORD readSize = 0; DWORD_PTR currentOffset = 0; peFileSection.data = 0; peFileSection.dataSize = 0; readSize = peFileSection.normalSize; if (!readOffset || !readSize) { return true; //section without data is valid } if (readSize <= maxReadSize) { peFileSection.dataSize = readSize; peFileSection.normalSize = readSize; return readPeSectionFromProcess(readOffset, peFileSection); } currentOffset = readOffset + readSize - maxReadSize; while(currentOffset >= readOffset) //start from the end { if (!ProcessAccessHelp::readMemoryPartlyFromProcess(currentOffset, sizeof(data), data)) { retValue = false; break; } valuesFound = isMemoryNotNull(data, sizeof(data)); if (valuesFound) { //found some real code currentOffset += valuesFound; if (readOffset < currentOffset) { //real size peFileSection.dataSize = (DWORD)(currentOffset - readOffset); } break; } currentOffset -= maxReadSize; } if (peFileSection.dataSize) { retValue = readPeSectionFromProcess(readOffset, peFileSection); } return retValue; } bool PeParser::readPeSectionFromProcess(DWORD_PTR readOffset, PeFileSection & peFileSection) { peFileSection.data = new BYTE[peFileSection.dataSize]; return ProcessAccessHelp::readMemoryPartlyFromProcess(readOffset, peFileSection.dataSize, peFileSection.data); } DWORD PeParser::alignValue(DWORD badValue, DWORD alignTo) { return (((badValue + alignTo - 1) / alignTo) * alignTo); } bool PeParser::addNewLastSection(const CHAR * sectionName, DWORD sectionSize, BYTE * sectionData) { size_t nameLength = strlen(sectionName); DWORD fileAlignment = 0, sectionAlignment = 0; PeFileSection peFileSection; if (nameLength > IMAGE_SIZEOF_SHORT_NAME) { return false; } if (isPE32()) { fileAlignment = pNTHeader32->OptionalHeader.FileAlignment; sectionAlignment = pNTHeader32->OptionalHeader.SectionAlignment; } else { fileAlignment = pNTHeader64->OptionalHeader.FileAlignment; sectionAlignment = pNTHeader64->OptionalHeader.SectionAlignment; } memcpy_s(peFileSection.sectionHeader.Name, IMAGE_SIZEOF_SHORT_NAME, sectionName, nameLength); //last section doesn't need SizeOfRawData alignment peFileSection.sectionHeader.SizeOfRawData = sectionSize; //alignValue(sectionSize, fileAlignment); peFileSection.sectionHeader.Misc.VirtualSize = alignValue(sectionSize, sectionAlignment); peFileSection.sectionHeader.PointerToRawData = alignValue(getSectionHeaderBasedFileSize(), fileAlignment); peFileSection.sectionHeader.VirtualAddress = alignValue(getSectionHeaderBasedSizeOfImage(), sectionAlignment); peFileSection.sectionHeader.Characteristics = IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE|IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA; peFileSection.normalSize = peFileSection.sectionHeader.SizeOfRawData; peFileSection.dataSize = peFileSection.sectionHeader.SizeOfRawData; if (sectionData == 0) { peFileSection.data = new BYTE[peFileSection.sectionHeader.SizeOfRawData]; ZeroMemory(peFileSection.data , peFileSection.sectionHeader.SizeOfRawData); } else { peFileSection.data = sectionData; } listPeSection.push_back(peFileSection); setNumberOfSections(getNumberOfSections() + 1); return true; } DWORD_PTR PeParser::convertRVAToOffsetVector(DWORD_PTR dwRVA) { for (WORD i = 0; i < getNumberOfSections(); i++) { if ((listPeSection[i].sectionHeader.VirtualAddress <= dwRVA) && ((listPeSection[i].sectionHeader.VirtualAddress + listPeSection[i].sectionHeader.Misc.VirtualSize) > dwRVA)) { return ((dwRVA - listPeSection[i].sectionHeader.VirtualAddress) + listPeSection[i].sectionHeader.PointerToRawData); } } return 0; } DWORD_PTR PeParser::convertOffsetToRVAVector(DWORD_PTR dwOffset) { for (WORD i = 0; i < getNumberOfSections(); i++) { if ((listPeSection[i].sectionHeader.PointerToRawData <= dwOffset) && ((listPeSection[i].sectionHeader.PointerToRawData + listPeSection[i].sectionHeader.SizeOfRawData) > dwOffset)) { return ((dwOffset - listPeSection[i].sectionHeader.PointerToRawData) + listPeSection[i].sectionHeader.VirtualAddress); } } return 0; } void PeParser::fixPeHeader() { DWORD dwSize = pDosHeader->e_lfanew + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER); if (isPE32()) { //delete bound import directories pNTHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0; pNTHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0; //max 16 if (pNTHeader64->OptionalHeader.NumberOfRvaAndSizes > 0x10) { pNTHeader64->OptionalHeader.NumberOfRvaAndSizes = 0x10; } pNTHeader32->OptionalHeader.SizeOfImage = getSectionHeaderBasedSizeOfImage(); if (moduleBaseAddress) { pNTHeader32->OptionalHeader.ImageBase = (DWORD)moduleBaseAddress; } pNTHeader32->OptionalHeader.SizeOfHeaders = alignValue(dwSize + pNTHeader32->FileHeader.SizeOfOptionalHeader + (getNumberOfSections() * sizeof(IMAGE_SECTION_HEADER)), pNTHeader32->OptionalHeader.FileAlignment); } else { //delete bound import directories pNTHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0; pNTHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0; //max 16 if (pNTHeader64->OptionalHeader.NumberOfRvaAndSizes > 0x10) { pNTHeader64->OptionalHeader.NumberOfRvaAndSizes = 0x10; } pNTHeader64->OptionalHeader.SizeOfImage = getSectionHeaderBasedSizeOfImage(); if (moduleBaseAddress) { pNTHeader64->OptionalHeader.ImageBase = moduleBaseAddress; } pNTHeader64->OptionalHeader.SizeOfHeaders = alignValue(dwSize + pNTHeader64->FileHeader.SizeOfOptionalHeader + (getNumberOfSections() * sizeof(IMAGE_SECTION_HEADER)), pNTHeader64->OptionalHeader.FileAlignment); } removeIatDirectory(); } void PeParser::removeIatDirectory() { DWORD searchAddress = 0; if (isPE32()) { searchAddress = pNTHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress; pNTHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = 0; pNTHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = 0; } else { searchAddress = pNTHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress; pNTHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = 0; pNTHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = 0; } if (searchAddress) { for (WORD i = 0; i < getNumberOfSections(); i++) { if ((listPeSection[i].sectionHeader.VirtualAddress <= searchAddress) && ((listPeSection[i].sectionHeader.VirtualAddress + listPeSection[i].sectionHeader.Misc.VirtualSize) > searchAddress)) { //section must be read and writable listPeSection[i].sectionHeader.Characteristics |= IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE; } } } } void PeParser::setDefaultFileAlignment() { if (isPE32()) { pNTHeader32->OptionalHeader.FileAlignment = FileAlignmentConstant; } else { pNTHeader64->OptionalHeader.FileAlignment = FileAlignmentConstant; } } bool PeFileSectionSortByPointerToRawData(const PeFileSection& d1, const PeFileSection& d2) { return d1.sectionHeader.PointerToRawData < d2.sectionHeader.PointerToRawData; } bool PeFileSectionSortByVirtualAddress(const PeFileSection& d1, const PeFileSection& d2) { return d1.sectionHeader.VirtualAddress < d2.sectionHeader.VirtualAddress; } void PeParser::alignAllSectionHeaders() { DWORD sectionAlignment = 0; DWORD fileAlignment = 0; DWORD newFileSize = 0; if (isPE32()) { sectionAlignment = pNTHeader32->OptionalHeader.SectionAlignment; fileAlignment = pNTHeader32->OptionalHeader.FileAlignment; } else { sectionAlignment = pNTHeader64->OptionalHeader.SectionAlignment; fileAlignment = pNTHeader64->OptionalHeader.FileAlignment; } std::sort(listPeSection.begin(), listPeSection.end(), PeFileSectionSortByPointerToRawData); //sort by PointerToRawData ascending newFileSize = pDosHeader->e_lfanew + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + pNTHeader32->FileHeader.SizeOfOptionalHeader + (getNumberOfSections() * sizeof(IMAGE_SECTION_HEADER)); for (WORD i = 0; i < getNumberOfSections(); i++) { listPeSection[i].sectionHeader.VirtualAddress = alignValue(listPeSection[i].sectionHeader.VirtualAddress, sectionAlignment); listPeSection[i].sectionHeader.Misc.VirtualSize = alignValue(listPeSection[i].sectionHeader.Misc.VirtualSize, sectionAlignment); listPeSection[i].sectionHeader.PointerToRawData = alignValue(newFileSize, fileAlignment); listPeSection[i].sectionHeader.SizeOfRawData = alignValue(listPeSection[i].dataSize, fileAlignment); newFileSize = listPeSection[i].sectionHeader.PointerToRawData + listPeSection[i].sectionHeader.SizeOfRawData; } std::sort(listPeSection.begin(), listPeSection.end(), PeFileSectionSortByVirtualAddress); //sort by VirtualAddress ascending } bool PeParser::dumpProcess(DWORD_PTR modBase, DWORD_PTR entryPoint, const WCHAR * dumpFilePath) { moduleBaseAddress = modBase; if (readPeSectionsFromProcess()) { setDefaultFileAlignment(); setEntryPointVa(entryPoint); alignAllSectionHeaders(); fixPeHeader(); getFileOverlay(); return savePeFileToDisk(dumpFilePath); } return false; } bool PeParser::dumpProcess(DWORD_PTR modBase, DWORD_PTR entryPoint, const WCHAR * dumpFilePath, std::vector & sectionList) { if (listPeSection.size() == sectionList.size()) { for (int i = (getNumberOfSections() - 1); i >= 0; i--) { if (!sectionList[i].isDumped) { listPeSection.erase(listPeSection.begin() + i); setNumberOfSections(getNumberOfSections() - 1); } else { listPeSection[i].sectionHeader.Misc.VirtualSize = sectionList[i].virtualSize; listPeSection[i].sectionHeader.SizeOfRawData = sectionList[i].rawSize; listPeSection[i].sectionHeader.Characteristics = sectionList[i].characteristics; } } } return dumpProcess(modBase, entryPoint, dumpFilePath); } void PeParser::setEntryPointVa(DWORD_PTR entryPoint) { DWORD entryPointRva = (DWORD)(entryPoint - moduleBaseAddress); + setEntryPointRva(entryPointRva); +} + +void PeParser::setEntryPointRva(DWORD entryPoint) +{ if (isPE32()) { - pNTHeader32->OptionalHeader.AddressOfEntryPoint = entryPointRva; + pNTHeader32->OptionalHeader.AddressOfEntryPoint = entryPoint; } - else + else if (isPE64()) { - pNTHeader64->OptionalHeader.AddressOfEntryPoint = entryPointRva; + pNTHeader64->OptionalHeader.AddressOfEntryPoint = entryPoint; } - } bool PeParser::getFileOverlay() { DWORD numberOfBytesRead; bool retValue = false; if (!hasOverlayData()) { return false; } if (openFileHandle()) { DWORD overlayOffset = getSectionHeaderBasedFileSize(); DWORD fileSize = (DWORD)ProcessAccessHelp::getFileSize(hFile); overlaySize = fileSize - overlayOffset; overlayData = new BYTE[overlaySize]; SetFilePointer(hFile, overlayOffset, 0, FILE_BEGIN); if (ReadFile(hFile, overlayData, overlaySize, &numberOfBytesRead, 0)) { retValue = true; } closeFileHandle(); } return retValue; } bool PeParser::hasOverlayData() { if (!filename) return false; if (isValidPeFile()) { DWORD fileSize = (DWORD)ProcessAccessHelp::getFileSize(filename); return (fileSize > getSectionHeaderBasedFileSize()); } else { return false; } } +bool PeParser::updatePeHeaderChecksum(const WCHAR * targetFile, DWORD fileSize) +{ + PIMAGE_NT_HEADERS32 pNTHeader32 = 0; + PIMAGE_NT_HEADERS64 pNTHeader64 = 0; + DWORD headerSum = 0; + DWORD checkSum = 0; + bool retValue = false; + + if (!fileSize) + return retValue; + + HANDLE hFileToMap = CreateFile(targetFile, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + + if(hFileToMap != INVALID_HANDLE_VALUE) + { + HANDLE hMappedFile = CreateFileMapping(hFileToMap, 0, PAGE_READWRITE, 0, 0, 0); + if(hMappedFile) + { + if (GetLastError() != ERROR_ALREADY_EXISTS) + { + LPVOID addrMappedDll = MapViewOfFile(hMappedFile, FILE_MAP_ALL_ACCESS, 0, 0, 0); + + if (addrMappedDll) + { + pNTHeader32 = (PIMAGE_NT_HEADERS32)CheckSumMappedFile(addrMappedDll, fileSize, &headerSum, &checkSum); + + if (pNTHeader32) + { + if (pNTHeader32->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) + { + pNTHeader64 = (PIMAGE_NT_HEADERS64)pNTHeader32; + pNTHeader64->OptionalHeader.CheckSum = checkSum; + } + else + { + pNTHeader32->OptionalHeader.CheckSum = checkSum; + } + + retValue = true; + } + + UnmapViewOfFile(addrMappedDll); + } + } + CloseHandle(hMappedFile); + } + CloseHandle(hFileToMap); + } + + return retValue; +} \ No newline at end of file diff --git a/Scylla/PeParser.h b/Scylla/PeParser.h index d0a39f1..687c318 100644 --- a/Scylla/PeParser.h +++ b/Scylla/PeParser.h @@ -1,127 +1,131 @@ #pragma once #include #include #include "DumpSectionGui.h" class PeFileSection { public: IMAGE_SECTION_HEADER sectionHeader; BYTE * data; DWORD dataSize; DWORD normalSize; PeFileSection() { ZeroMemory(§ionHeader, sizeof(IMAGE_SECTION_HEADER)); data = 0; dataSize = 0; normalSize = 0; } }; class PeParser { public: PeParser(const WCHAR * file, bool readSectionHeaders = true); PeParser(const DWORD_PTR moduleBase, bool readSectionHeaders = true); ~PeParser(); bool isValidPeFile(); bool isPE64(); bool isPE32(); bool isTargetFileSamePeFormat(); WORD getNumberOfSections(); std::vector & getSectionHeaderList(); bool hasExportDirectory(); bool hasTLSDirectory(); bool hasRelocationDirectory(); bool hasOverlayData(); DWORD getEntryPoint(); bool getSectionNameUnicode(const int sectionIndex, WCHAR * output, const int outputLen); DWORD getSectionHeaderBasedFileSize(); DWORD getSectionHeaderBasedSizeOfImage(); bool readPeSectionsFromProcess(); bool readPeSectionsFromFile(); bool savePeFileToDisk(const WCHAR * newFile); void removeDosStub(); void alignAllSectionHeaders(); void fixPeHeader(); void setDefaultFileAlignment(); bool dumpProcess(DWORD_PTR modBase, DWORD_PTR entryPoint, const WCHAR * dumpFilePath); bool dumpProcess(DWORD_PTR modBase, DWORD_PTR entryPoint, const WCHAR * dumpFilePath, std::vector & sectionList); + + void setEntryPointVa(DWORD_PTR entryPoint); + void setEntryPointRva(DWORD entryPoint); + + static bool updatePeHeaderChecksum(const WCHAR * targetFile, DWORD fileSize); protected: PeParser(); static const DWORD FileAlignmentConstant = 0x200; const WCHAR * filename; DWORD_PTR moduleBaseAddress; /************************************************************************/ /* PE FILE */ /* */ /* IMAGE_DOS_HEADER 64 0x40 */ /* IMAGE_NT_HEADERS32 248 0xF8 */ /* IMAGE_NT_HEADERS64 264 0x108 */ /* IMAGE_SECTION_HEADER 40 0x28 */ /************************************************************************/ PIMAGE_DOS_HEADER pDosHeader; BYTE * pDosStub; //between dos header and section header DWORD dosStubSize; PIMAGE_NT_HEADERS32 pNTHeader32; PIMAGE_NT_HEADERS64 pNTHeader64; std::vector listPeSection; BYTE * overlayData; DWORD overlaySize; /************************************************************************/ BYTE * fileMemory; BYTE * headerMemory; HANDLE hFile; DWORD fileSize; bool readPeHeaderFromFile(bool readSectionHeaders); bool readPeHeaderFromProcess(bool readSectionHeaders); bool hasDirectory(const int directoryIndex); bool getSectionHeaders(); void getDosAndNtHeader(BYTE * memory, LONG size); DWORD calcCorrectPeHeaderSize( bool readSectionHeaders ); DWORD getInitialHeaderReadSize( bool readSectionHeaders ); bool openFileHandle(); void closeFileHandle(); void initClass(); DWORD isMemoryNotNull( BYTE * data, int dataSize ); bool openWriteFileHandle( const WCHAR * newFile ); bool writeZeroMemoryToFile(HANDLE hFile, DWORD fileOffset, DWORD size); bool readPeSectionFromFile( DWORD readOffset, PeFileSection & peFileSection ); bool readPeSectionFromProcess( DWORD_PTR readOffset, PeFileSection & peFileSection ); bool readSectionFromFile( DWORD readOffset, PeFileSection & peFileSection ); bool readSectionFromProcess( DWORD_PTR readOffset, PeFileSection & peFileSection ); bool addNewLastSection(const CHAR * sectionName, DWORD sectionSize, BYTE * sectionData); DWORD alignValue(DWORD badValue, DWORD alignTo); DWORD_PTR convertOffsetToRVAVector(DWORD_PTR dwOffset); DWORD_PTR convertRVAToOffsetVector(DWORD_PTR dwRVA); void setNumberOfSections(WORD numberOfSections); void removeIatDirectory(); - void setEntryPointVa( DWORD_PTR entryPoint ); bool getFileOverlay(); }; diff --git a/Scylla/Scylla.h b/Scylla/Scylla.h index 5478853..0da536d 100644 --- a/Scylla/Scylla.h +++ b/Scylla/Scylla.h @@ -1,31 +1,31 @@ #pragma once #include "ConfigurationHolder.h" #include "PluginLoader.h" #include "ProcessLister.h" #include "Logger.h" #define APPNAME_S "Scylla" -#define APPVERSION_S "v0.6a" +#define APPVERSION_S "v0.6b" #define APPNAME TEXT(APPNAME_S) #define APPVERSION TEXT(APPVERSION_S) class Scylla { public: static void init(); static ConfigurationHolder config; static PluginLoader plugins; static ProcessLister processLister; static FileLog debugLog; static ListboxLog windowLog; private: static const WCHAR DEBUG_LOG_FILENAME[]; }; diff --git a/Scylla/Scylla.vcxproj b/Scylla/Scylla.vcxproj index 8397a2f..f533d27 100644 --- a/Scylla/Scylla.vcxproj +++ b/Scylla/Scylla.vcxproj @@ -1,252 +1,248 @@  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' 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' - + - - - + - - \ No newline at end of file diff --git a/Scylla/resource.h b/Scylla/resource.h index 2072e6a..9ecb538 100644 Binary files a/Scylla/resource.h and b/Scylla/resource.h differ