diff --git a/Scylla/ConfigurationHolder.cpp b/Scylla/ConfigurationHolder.cpp index c04838f..ea530f9 100644 --- a/Scylla/ConfigurationHolder.cpp +++ b/Scylla/ConfigurationHolder.cpp @@ -1,202 +1,203 @@ #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); 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 174196e..ab526d6 100644 --- a/Scylla/ConfigurationHolder.h +++ b/Scylla/ConfigurationHolder.h @@ -1,48 +1,49 @@ #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 }; 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/DumpMemoryGui.cpp b/Scylla/DumpMemoryGui.cpp index 11c9cf3..33f7aae 100644 --- a/Scylla/DumpMemoryGui.cpp +++ b/Scylla/DumpMemoryGui.cpp @@ -1,571 +1,571 @@ #include "DumpMemoryGui.h" #include "Architecture.h" #include "ProcessAccessHelp.h" #include #include "PeParser.h" WCHAR DumpMemoryGui::protectionString[100]; const WCHAR DumpMemoryGui::MemoryUndefined[] = L"UNDEF"; const WCHAR DumpMemoryGui::MemoryUnknown[] = L"UNKNOWN"; const WCHAR * DumpMemoryGui::MemoryStateValues[] = {L"COMMIT",L"FREE",L"RESERVE"}; const WCHAR * DumpMemoryGui::MemoryTypeValues[] = {L"IMAGE",L"MAPPED",L"PRIVATE"}; const WCHAR * DumpMemoryGui::MemoryProtectionValues[] = {L"EXECUTE",L"EXECUTE_READ",L"EXECUTE_READWRITE",L"EXECUTE_WRITECOPY",L"NOACCESS",L"READONLY",L"READWRITE",L"WRITECOPY",L"GUARD",L"NOCACHE",L"WRITECOMBINE"}; DumpMemoryGui::DumpMemoryGui() { dumpedMemory = 0; dumpedMemorySize = 0; deviceNameResolver = new DeviceNameResolver(); } DumpMemoryGui::~DumpMemoryGui() { if (dumpedMemory) { delete [] dumpedMemory; } if (deviceNameResolver) { delete deviceNameResolver; } } BOOL DumpMemoryGui::OnInitDialog(CWindow wndFocus, LPARAM lInitParam) { DoDataExchange(); // attach controls DlgResize_Init(true, true); addColumnsToMemoryList(ListMemorySelect); displayMemoryList(ListMemorySelect); forceDump = false; DoDataExchange(DDX_LOAD); EditMemoryAddress.SetValue(ProcessAccessHelp::targetImageBase); EditMemorySize.SetValue((DWORD)ProcessAccessHelp::targetSizeOfImage); CenterWindow(); return TRUE; } void DumpMemoryGui::addColumnsToMemoryList(CListViewCtrl& list) { list.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT); list.InsertColumn(COL_ADDRESS, L"Address", LVCFMT_CENTER); list.InsertColumn(COL_SIZE, L"Size", LVCFMT_CENTER); list.InsertColumn(COL_FILENAME, L"File", LVCFMT_LEFT); list.InsertColumn(COL_PESECTION, L"PE Section", LVCFMT_LEFT); list.InsertColumn(COL_TYPE, L"Type", LVCFMT_CENTER); list.InsertColumn(COL_PROTECTION, L"Protection", LVCFMT_CENTER); list.InsertColumn(COL_STATE, L"State", LVCFMT_CENTER); list.InsertColumn(COL_MAPPED_FILE, L"Mapped File", LVCFMT_LEFT); } void DumpMemoryGui::displayMemoryList(CListViewCtrl& list) { int count = 0; WCHAR temp[20]; list.DeleteAllItems(); getMemoryList(); std::vector::const_iterator iter; for( iter = memoryList.begin(); iter != memoryList.end(); iter++ , count++) { swprintf_s(temp, PRINTF_DWORD_PTR_FULL, iter->address); list.InsertItem(count,temp); swprintf_s(temp, L"%08X", iter->size); list.SetItemText(count, COL_SIZE, temp); list.SetItemText(count, COL_FILENAME, iter->filename); list.SetItemText(count, COL_PESECTION, iter->peSection); if (iter->state == MEM_FREE) { list.SetItemText(count, COL_TYPE, MemoryUndefined); } else { list.SetItemText(count, COL_TYPE, getMemoryTypeString(iter->type)); } if ( (iter->state == MEM_RESERVE) || (iter->state == MEM_FREE) ) { list.SetItemText(count, COL_PROTECTION, MemoryUndefined); } else { list.SetItemText(count, COL_PROTECTION, getMemoryProtectionString(iter->protect)); } list.SetItemText(count, COL_STATE, getMemoryStateString(iter->state)); list.SetItemText(count, COL_MAPPED_FILE, iter->mappedFilename); list.SetItemData(count, (DWORD_PTR)&(*iter)); } list.SetColumnWidth(COL_ADDRESS, LVSCW_AUTOSIZE_USEHEADER); list.SetColumnWidth(COL_SIZE, LVSCW_AUTOSIZE_USEHEADER); list.SetColumnWidth(COL_FILENAME, LVSCW_AUTOSIZE_USEHEADER); list.SetColumnWidth(COL_PESECTION, LVSCW_AUTOSIZE_USEHEADER); list.SetColumnWidth(COL_TYPE, LVSCW_AUTOSIZE_USEHEADER); list.SetColumnWidth(COL_PROTECTION, LVSCW_AUTOSIZE_USEHEADER); list.SetColumnWidth(COL_STATE, LVSCW_AUTOSIZE_USEHEADER); list.SetColumnWidth(COL_MAPPED_FILE, LVSCW_AUTOSIZE_USEHEADER); } const WCHAR * DumpMemoryGui::getMemoryTypeString(DWORD value) { switch(value) { case MEM_IMAGE: return MemoryTypeValues[TYPE_IMAGE]; case MEM_MAPPED: return MemoryTypeValues[TYPE_MAPPED]; case MEM_PRIVATE: return MemoryTypeValues[TYPE_PRIVATE]; default: return MemoryUnknown; } } const WCHAR * DumpMemoryGui::getMemoryStateString(DWORD value) { switch(value) { case MEM_COMMIT: return MemoryStateValues[STATE_COMMIT]; case MEM_FREE: return MemoryStateValues[STATE_FREE]; case MEM_RESERVE: return MemoryStateValues[STATE_RESERVE]; default: return MemoryUnknown; } } WCHAR * DumpMemoryGui::getMemoryProtectionString(DWORD value) { protectionString[0] = 0; if (value & PAGE_GUARD) { wcscpy_s(protectionString, MemoryProtectionValues[PROT_GUARD]); wcscat_s(protectionString, L" | "); value ^= PAGE_GUARD; } if (value & PAGE_NOCACHE) { wcscpy_s(protectionString, MemoryProtectionValues[PROT_NOCACHE]); wcscat_s(protectionString, L" | "); value ^= PAGE_NOCACHE; } if (value & PAGE_WRITECOMBINE) { wcscpy_s(protectionString, MemoryProtectionValues[PROT_WRITECOMBINE]); wcscat_s(protectionString, L" | "); value ^= PAGE_WRITECOMBINE; } switch(value) { case PAGE_EXECUTE: { wcscat_s(protectionString, MemoryProtectionValues[PROT_EXECUTE]); break; } case PAGE_EXECUTE_READ: { wcscat_s(protectionString, MemoryProtectionValues[PROT_EXECUTE_READ]); break; } case PAGE_EXECUTE_READWRITE: { wcscat_s(protectionString, MemoryProtectionValues[PROT_EXECUTE_READWRITE]); break; } case PAGE_EXECUTE_WRITECOPY: { wcscat_s(protectionString, MemoryProtectionValues[PROT_EXECUTE_WRITECOPY]); break; } case PAGE_NOACCESS: { wcscat_s(protectionString, MemoryProtectionValues[PROT_NOACCESS]); break; } case PAGE_READONLY: { wcscat_s(protectionString, MemoryProtectionValues[PROT_READONLY]); break; } case PAGE_READWRITE: { wcscat_s(protectionString, MemoryProtectionValues[PROT_READWRITE]); break; } case PAGE_WRITECOPY: { wcscat_s(protectionString, MemoryProtectionValues[PROT_WRITECOPY]); break; } default: { wcscat_s(protectionString, MemoryUnknown); } } return protectionString; } LRESULT DumpMemoryGui::OnListMemoryColumnClicked(NMHDR* pnmh) { NMLISTVIEW* list = (NMLISTVIEW*)pnmh; int column = list->iSubItem; if(column == prevColumn) { ascending = !ascending; } else { prevColumn = column; ascending = true; } // lo-byte: column, hi-byte: sort-order ListMemorySelect.SortItems(&listviewCompareFunc, MAKEWORD(column, ascending)); return 0; } LRESULT DumpMemoryGui::OnListMemoryClick(NMHDR* pnmh) { int index = ListMemorySelect.GetSelectionMark(); if (index != -1) { selectedMemory = (Memory *)ListMemorySelect.GetItemData(index); if (selectedMemory) { updateAddressAndSize(selectedMemory); } } return 0; } void DumpMemoryGui::OnOK(UINT uNotifyCode, int nID, CWindow wndCtl) { DoDataExchange(DDX_SAVE); if (EditMemoryAddress.GetValue() == 0 || EditMemorySize.GetValue() == 0) { wndCtl.MessageBoxW(L"Textbox is empty!",L"Error",MB_ICONERROR); } else { if (dumpMemory()) { EndDialog(1); } else { wndCtl.MessageBoxW(L"Reading memory from process failed",L"Error",MB_ICONERROR); } } } void DumpMemoryGui::OnCancel(UINT uNotifyCode, int nID, CWindow wndCtl) { EndDialog(0); } void DumpMemoryGui::updateAddressAndSize( Memory * selectedMemory ) { EditMemoryAddress.SetValue(selectedMemory->address); EditMemorySize.SetValue(selectedMemory->size); } int DumpMemoryGui::listviewCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { const Memory * module1 = (Memory *)lParam1; const Memory * module2 = (Memory *)lParam2; int column = LOBYTE(lParamSort); bool ascending = (HIBYTE(lParamSort) == TRUE); int diff = 0; switch(column) { case COL_ADDRESS: diff = module1->address < module2->address ? -1 : 1; break; case COL_SIZE: diff = module1->size < module2->size ? -1 : 1; break; case COL_FILENAME: diff = _wcsicmp(module1->filename, module2->filename); break; case COL_PESECTION: diff = _wcsicmp(module1->peSection, module2->peSection); break; case COL_TYPE: diff = module1->type < module2->type ? -1 : 1; break; case COL_PROTECTION: diff = module1->protect < module2->protect ? -1 : 1; break; case COL_STATE: diff = _wcsicmp(getMemoryStateString(module1->state), getMemoryStateString(module2->state)); //diff = module1->state < module2->state ? -1 : 1; break; case COL_MAPPED_FILE: diff = _wcsicmp(module1->mappedFilename, module2->mappedFilename); break; } return ascending ? diff : -diff; } void DumpMemoryGui::getMemoryList() { DWORD count = 0; DWORD_PTR address = 0; MEMORY_BASIC_INFORMATION memBasic = {0}; Memory memory; HMODULE * hMods = 0; DWORD cbNeeded = 0; bool notEnough = true; WCHAR target[MAX_PATH]; count = 100; hMods = new HMODULE[count]; if (memoryList.empty()) { memoryList.reserve(20); } else { memoryList.clear(); } memory.filename[0] = 0; memory.peSection[0] = 0; memory.mappedFilename[0] = 0; while(VirtualQueryEx(ProcessAccessHelp::hProcess,(LPCVOID)address,&memBasic,sizeof(memBasic))) { memory.address = (DWORD_PTR)memBasic.BaseAddress; memory.type = memBasic.Type; memory.state = memBasic.State; memory.size = (DWORD)memBasic.RegionSize; memory.protect = memBasic.Protect; if (memory.type == MEM_MAPPED) { if (!getMappedFilename(&memory)) { memory.mappedFilename[0] = 0; } } memoryList.push_back(memory); memory.mappedFilename[0] = 0; address += memBasic.RegionSize; } do { if (!EnumProcessModules(ProcessAccessHelp::hProcess, hMods, count * sizeof(HMODULE), &cbNeeded)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"getMemoryList :: EnumProcessModules failed count %d", count); #endif delete [] hMods; return; } if ( (count * sizeof(HMODULE)) < cbNeeded ) { delete [] hMods; count += 100; hMods = new HMODULE[count]; } else { notEnough = false; } } while (notEnough); for (DWORD i = 0; i < (cbNeeded / sizeof(HMODULE)); i++ ) { if (GetModuleFileNameExW(ProcessAccessHelp::hProcess, hMods[i], target, _countof(target))) { setModuleName((DWORD_PTR)hMods[i],target); setAllSectionNames((DWORD_PTR)hMods[i],target); } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"getMemoryList :: GetModuleFileNameExW failed 0x%X", GetLastError()); #endif } } delete [] hMods; } void DumpMemoryGui::setSectionName(DWORD_PTR sectionAddress, DWORD sectionSize, const WCHAR * sectionName) { bool found = false; std::vector::const_iterator iter; for( iter = memoryList.begin(); iter != memoryList.end(); iter++) { if (!found) { if ( (iter->address <= sectionAddress) && (sectionAddress < (iter->address + iter->size)) ) { if (wcslen(iter->peSection) == 0) { wcscpy_s((WCHAR *)iter->peSection, IMAGE_SIZEOF_SHORT_NAME * 4, sectionName); } else { wcscat_s((WCHAR *)iter->peSection, IMAGE_SIZEOF_SHORT_NAME * 4, L"|"); wcscat_s((WCHAR *)iter->peSection, IMAGE_SIZEOF_SHORT_NAME * 4, sectionName); } found = true; } } else { if ((sectionSize+sectionAddress) < iter->address) { break; } if (wcslen(iter->peSection) == 0) { wcscpy_s((WCHAR *)iter->peSection, IMAGE_SIZEOF_SHORT_NAME * 4, sectionName); } else { wcscat_s((WCHAR *)iter->peSection, IMAGE_SIZEOF_SHORT_NAME * 4, L"|"); wcscat_s((WCHAR *)iter->peSection, IMAGE_SIZEOF_SHORT_NAME * 4, sectionName); } } } } void DumpMemoryGui::setModuleName(DWORD_PTR moduleBase, const WCHAR * moduleName) { bool found = false; std::vector::const_iterator iter; //get filename const WCHAR* slash = wcsrchr(moduleName, L'\\'); if(slash) { moduleName = slash+1; } for( iter = memoryList.begin(); iter != memoryList.end(); iter++) { if (iter->address == moduleBase) { found = true; } if (found) { if (iter->type == MEM_IMAGE) { wcscpy_s((WCHAR *)iter->filename, MAX_PATH, moduleName); } else { break; } } } } void DumpMemoryGui::setAllSectionNames( DWORD_PTR moduleBase, WCHAR * moduleName ) { WCHAR sectionNameW[IMAGE_SIZEOF_SHORT_NAME + 1] = {0}; PeParser peFile(moduleName); if (peFile.isValidPeFile()) { - std::vector & listSectionHeader = peFile.getSectionHeaderList(); + std::vector & listSectionHeader = peFile.getSectionHeaderList(); for (WORD i = 0; i < peFile.getNumberOfSections(); i++) { peFile.getSectionNameUnicode(i, sectionNameW, _countof(sectionNameW)); - setSectionName(moduleBase + listSectionHeader[i].VirtualAddress, listSectionHeader[i].Misc.VirtualSize, sectionNameW); + setSectionName(moduleBase + listSectionHeader[i].sectionHeader.VirtualAddress, listSectionHeader[i].sectionHeader.Misc.VirtualSize, sectionNameW); } } else { MessageBox(moduleName,L"Not a valid PE -> This should never happen",MB_ICONERROR); } } bool DumpMemoryGui::dumpMemory() { DWORD_PTR address = EditMemoryAddress.GetValue(); dumpedMemorySize = EditMemorySize.GetValue(); swprintf_s(dumpFilename,TEXT("MEM_")TEXT(PRINTF_DWORD_PTR_FULL_S)TEXT("_")TEXT("%08X"),address,dumpedMemorySize); dumpedMemory = new BYTE[dumpedMemorySize]; if (dumpedMemory) { if (forceDump) { return ProcessAccessHelp::readMemoryPartlyFromProcess(address,dumpedMemorySize,dumpedMemory); } else { return ProcessAccessHelp::readMemoryFromProcess(address,dumpedMemorySize,dumpedMemory); } } else { return false; } } bool DumpMemoryGui::getMappedFilename( Memory* memory ) { WCHAR filename[MAX_PATH] = {0}; //TODO replace with Nt direct syscall if (GetMappedFileNameW(ProcessAccessHelp::hProcess, (LPVOID)memory->address, filename, _countof(filename)) > 0) { return deviceNameResolver->resolveDeviceLongNameToShort(filename, memory->mappedFilename); } return false; } diff --git a/Scylla/DumpSectionGui.cpp b/Scylla/DumpSectionGui.cpp index 6a044b2..5b2480b 100644 --- a/Scylla/DumpSectionGui.cpp +++ b/Scylla/DumpSectionGui.cpp @@ -1,355 +1,355 @@ #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; } 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) { RECT rect; RECT rect1,rect2; NMITEMACTIVATE* ia = (NMITEMACTIVATE*)pnmh; if (ia->iSubItem != COL_VSize) { return 0; } LVHITTESTINFO hti; 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; 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(); //Draw a Rectangle around the SubItem //Rectangle(ListSectionSelect.GetDC(),rect.left,rect.top-1,rect.right,rect.bottom); //Set the listItem text in the EditBox EditListControl.SetValue(selectedSection->virtualSize); 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(); + 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].VirtualAddress; - peSection.virtualSize = listSectionHeader[i].Misc.VirtualSize; - peSection.rawAddress = listSectionHeader[i].PointerToRawData; - peSection.rawSize = listSectionHeader[i].SizeOfRawData; - peSection.characteristics = listSectionHeader[i].Characteristics; + 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 (selectedSection->virtualSize != newValue) { selectedSection->virtualSize = newValue; 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); } } diff --git a/Scylla/MainGui.cpp b/Scylla/MainGui.cpp index dbdce44..188a08a 100644 --- a/Scylla/MainGui.cpp +++ b/Scylla/MainGui.cpp @@ -1,1318 +1,1334 @@ #include "MainGui.h" #include "Architecture.h" //#include "PluginLoader.h" //#include "ConfigurationHolder.h" #include "PeDump.h" -#include "PeRebuild.h" +//#include "PeRebuild.h" +#include "PeParser.h" #include "DllInjectionPlugin.h" #include "DisassemblerGui.h" #include "PickApiGui.h" //#include "NativeWinApi.h" #include "ImportRebuild.h" #include "SystemInformation.h" #include "Scylla.h" #include "AboutGui.h" #include "OptionsGui.h" #include "TreeImportExport.h" extern CAppModule _Module; // o_O const WCHAR MainGui::filterExe[] = L"Executable (*.exe)\0*.exe\0All files\0*.*\0"; const WCHAR MainGui::filterDll[] = L"Dynamic Link Library (*.dll)\0*.dll\0All files\0*.*\0"; const WCHAR MainGui::filterExeDll[] = L"Executable (*.exe)\0*.exe\0Dynamic Link Library (*.dll)\0*.dll\0All files\0*.*\0"; const WCHAR MainGui::filterTxt[] = L"Text file (*.txt)\0*.txt\0All files\0*.*\0"; const WCHAR MainGui::filterXml[] = L"XML file (*.xml)\0*.xml\0All files\0*.*\0"; const WCHAR MainGui::filterMem[] = L"MEM file (*.mem)\0*.mem\0All files\0*.*\0"; MainGui::MainGui() : selectedProcess(0), importsHandling(TreeImports), TreeImportsSubclass(this, IDC_TREE_IMPORTS) { /* Logger::getDebugLogFilePath(); ConfigurationHolder::loadConfiguration(); PluginLoader::findAllPlugins(); NativeWinApi::initialize(); SystemInformation::getSystemInformation(); if(ConfigurationHolder::getConfigObject(DEBUG_PRIVILEGE)->isTrue()) { processLister.setDebugPrivileges(); } ProcessAccessHelp::getProcessModules(GetCurrentProcessId(), ProcessAccessHelp::ownModuleList); */ Scylla::init(); hIcon.LoadIcon(IDI_ICON_SCYLLA); hMenuImports.LoadMenu(IDR_MENU_IMPORTS); hMenuLog.LoadMenu(IDR_MENU_LOG); accelerators.LoadAccelerators(IDR_ACCELERATOR_MAIN); hIconCheck.LoadIcon(IDI_ICON_CHECK, 16, 16); hIconWarning.LoadIcon(IDI_ICON_WARNING, 16, 16); hIconError.LoadIcon(IDI_ICON_ERROR, 16, 16); } BOOL MainGui::PreTranslateMessage(MSG* pMsg) { if(accelerators.TranslateAccelerator(m_hWnd, pMsg)) { return TRUE; // handled keyboard shortcuts } else if(IsDialogMessage(pMsg)) { return TRUE; // handled dialog messages } return FALSE; } BOOL MainGui::OnInitDialog(CWindow wndFocus, LPARAM lInitParam) { if (SystemInformation::currenOS == UNKNOWN_OS) { if(IDCANCEL == MessageBox(L"Operating System is not supported\r\nContinue anyway?", L"Scylla", MB_ICONWARNING | MB_OKCANCEL)) { SendMessage(WM_CLOSE); return FALSE; } } // register ourselves to receive PreTranslateMessage CMessageLoop* pLoop = _Module.GetMessageLoop(); pLoop->AddMessageFilter(this); setupStatusBar(); DoDataExchange(); // attach controls DlgResize_Init(true, true); // init CDialogResize Scylla::windowLog.setWindow(ListLog); appendPluginListToMenu(hMenuImports.GetSubMenu(0)); appendPluginListToMenu(CMenuHandle(GetMenu()).GetSubMenu(MenuImportsOffsetTrace)); enableDialogControls(FALSE); setIconAndDialogCaption(); return TRUE; } void MainGui::OnDestroy() { PostQuitMessage(0); } void MainGui::OnSize(UINT nType, CSize size) { StatusBar.SendMessage(WM_SIZE); SetMsgHandled(FALSE); } void MainGui::OnContextMenu(CWindow wnd, CPoint point) { switch(wnd.GetDlgCtrlID()) { case IDC_TREE_IMPORTS: DisplayContextMenuImports(wnd, point); return; case IDC_LIST_LOG: DisplayContextMenuLog(wnd, point); return; } SetMsgHandled(FALSE); } void MainGui::OnCommand(UINT uNotifyCode, int nID, CWindow wndCtl) { // Handle plugin trace menu selection if(uNotifyCode == 0 && !wndCtl.IsWindow()) // make sure it's a menu { if ((nID >= PLUGIN_MENU_BASE_ID) && (nID <= (int)(Scylla::plugins.getScyllaPluginList().size() + Scylla::plugins.getImprecPluginList().size() + PLUGIN_MENU_BASE_ID))) { pluginActionHandler(nID); return; } } SetMsgHandled(FALSE); } LRESULT MainGui::OnTreeImportsDoubleClick(const NMHDR* pnmh) { if(TreeImports.GetCount() < 1) return 0; // Get item under cursor CTreeItem over = findTreeItem(CPoint(GetMessagePos()), true); if(over && importsHandling.isImport(over)) { pickApiActionHandler(over); } return 0; } LRESULT MainGui::OnTreeImportsKeyDown(const NMHDR* pnmh) { const NMTVKEYDOWN * tkd = (NMTVKEYDOWN *)pnmh; switch(tkd->wVKey) { case VK_RETURN: { CTreeItem selected = TreeImports.GetFocusItem(); if(!selected.IsNull() && importsHandling.isImport(selected)) { pickApiActionHandler(selected); } } return 1; case VK_DELETE: deleteSelectedImportsActionHandler(); return 1; } SetMsgHandled(FALSE); return 0; } UINT MainGui::OnTreeImportsSubclassGetDlgCode(const MSG * lpMsg) { if(lpMsg) { switch(lpMsg->wParam) { case VK_RETURN: return DLGC_WANTMESSAGE; } } SetMsgHandled(FALSE); return 0; } void MainGui::OnTreeImportsSubclassChar(UINT nChar, UINT nRepCnt, UINT nFlags) { switch(nChar) { case VK_RETURN: break; default: SetMsgHandled(FALSE); break; } } void MainGui::OnProcessListDrop(UINT uNotifyCode, int nID, CWindow wndCtl) { fillProcessListComboBox(ComboProcessList); } void MainGui::OnProcessListSelected(UINT uNotifyCode, int nID, CWindow wndCtl) { processSelectedActionHandler(ComboProcessList.GetCurSel()); } void MainGui::OnPickDLL(UINT uNotifyCode, int nID, CWindow wndCtl) { pickDllActionHandler(); } void MainGui::OnOptions(UINT uNotifyCode, int nID, CWindow wndCtl) { optionsActionHandler(); } void MainGui::OnDump(UINT uNotifyCode, int nID, CWindow wndCtl) { dumpActionHandler(); } void MainGui::OnDumpMemory(UINT uNotifyCode, int nID, CWindow wndCtl) { dumpMemoryActionHandler(); } void MainGui::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; if (ProcessAccessHelp::selectedModule) { //dump DLL dlgDumpSection.imageBase = ProcessAccessHelp::selectedModule->modBaseAddr; dlgDumpSection.sizeOfImage = ProcessAccessHelp::selectedModule->modBaseSize; //get it from gui wcscpy_s(dlgDumpSection.fullpath, ProcessAccessHelp::selectedModule->fullPath); } else { dlgDumpSection.imageBase = ProcessAccessHelp::targetImageBase; dlgDumpSection.sizeOfImage = (DWORD)ProcessAccessHelp::targetSizeOfImage; //get it from gui wcscpy_s(dlgDumpSection.fullpath, selectedProcess->fullPath); } if(dlgDumpSection.DoModal()) { //getCurrentModulePath(stringBuffer, _countof(stringBuffer)); //if(showFileDialog(selectedFilePath, true, dlgDumpMemory.dumpFilename, filterMem, L"mem", stringBuffer)) //{ // if (ProcessAccessHelp::writeMemoryToNewFile(selectedFilePath,dlgDumpMemory.dumpedMemorySize,dlgDumpMemory.dumpedMemory)) // { // Scylla::windowLog.log(L"Memory dump saved %s", selectedFilePath); // } // else // { // Scylla::windowLog.log(L"Error! Cannot write memory dump to disk"); // } //} } } void MainGui::dumpActionHandler() { if(!selectedProcess) return; WCHAR selectedFilePath[MAX_PATH]; const WCHAR * fileFilter; const WCHAR * defExtension; PeDump peDump; if (ProcessAccessHelp::selectedModule) { fileFilter = filterDll; defExtension = L"dll"; } else { fileFilter = filterExe; defExtension = L"exe"; } getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if(showFileDialog(selectedFilePath, true, NULL, fileFilter, defExtension, stringBuffer)) { if (ProcessAccessHelp::selectedModule) { //dump DLL peDump.imageBase = ProcessAccessHelp::selectedModule->modBaseAddr; peDump.sizeOfImage = ProcessAccessHelp::selectedModule->modBaseSize; //get it from gui peDump.entryPoint = EditOEPAddress.GetValue(); wcscpy_s(peDump.fullpath, ProcessAccessHelp::selectedModule->fullPath); } else { peDump.imageBase = ProcessAccessHelp::targetImageBase; peDump.sizeOfImage = (DWORD)ProcessAccessHelp::targetSizeOfImage; //get it from gui peDump.entryPoint = EditOEPAddress.GetValue(); wcscpy_s(peDump.fullpath, selectedProcess->fullPath); } peDump.useHeaderFromDisk = Scylla::config[USE_PE_HEADER_FROM_DISK].isTrue(); if (peDump.dumpCompleteProcessToDisk(selectedFilePath)) { Scylla::windowLog.log(L"Dump success %s", selectedFilePath); } else { Scylla::windowLog.log(L"Error: Cannot dump image."); MessageBox(L"Cannot dump image.", L"Failure", MB_ICONERROR); } } } void MainGui::peRebuildActionHandler() { DWORD newSize = 0; WCHAR selectedFilePath[MAX_PATH]; - PeRebuild peRebuild; getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if(showFileDialog(selectedFilePath, false, NULL, filterExeDll, NULL, stringBuffer)) { if (Scylla::config[CREATE_BACKUP].isTrue()) { if (!ProcessAccessHelp::createBackupFile(selectedFilePath)) { Scylla::windowLog.log(L"Creating backup file failed %s", selectedFilePath); } } - LONGLONG fileSize = ProcessAccessHelp::getFileSize(selectedFilePath); - LPVOID mapped = peRebuild.createFileMappingViewFull(selectedFilePath); + DWORD fileSize = (DWORD)ProcessAccessHelp::getFileSize(selectedFilePath); - newSize = peRebuild.realignPE(mapped, (DWORD)fileSize); - peRebuild.closeAllMappingHandles(); - - if (newSize < 10) + PeParser peFile(selectedFilePath, true); + if (peFile.readPeSectionsFromFile()) { - Scylla::windowLog.log(L"Rebuild failed %s", selectedFilePath); - MessageBox(L"Rebuild failed.", L"Failure", MB_ICONERROR); + 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); + + 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 { - peRebuild.truncateFile(selectedFilePath, newSize); - - Scylla::windowLog.log(L"Rebuild success %s", selectedFilePath); - Scylla::windowLog.log(L"-> Old file size 0x%08X new file size 0x%08X (%d %%)", (DWORD)fileSize, newSize, (DWORD)((newSize * 100) / (DWORD)fileSize) ); + 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; if (ProcessAccessHelp::selectedModule) { fileFilter = filterDll; } else { fileFilter = filterExe; } getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if (showFileDialog(selectedFilePath, false, NULL, fileFilter, NULL, stringBuffer)) { wcscpy_s(newFilePath, selectedFilePath); const WCHAR * extension = 0; WCHAR* dot = wcsrchr(newFilePath, L'.'); if (dot) { *dot = L'\0'; extension = selectedFilePath + (dot - newFilePath); //wcsrchr(selectedFilePath, L'.'); } wcscat_s(newFilePath, L"_SCY"); if(extension) { wcscat_s(newFilePath, extension); } ImportRebuild importRebuild; if (importRebuild.rebuildImportTable(selectedFilePath,newFilePath,importsHandling.moduleList)) { Scylla::windowLog.log(L"Import Rebuild success %s", newFilePath); } else { Scylla::windowLog.log(L"Import Rebuild failed %s", selectedFilePath); MessageBox(L"Import Rebuild failed", L"Failure", MB_ICONERROR); } } } void MainGui::enableDialogControls(BOOL value) { BOOL valButton = value ? TRUE : FALSE; GetDlgItem(IDC_BTN_PICKDLL).EnableWindow(valButton); GetDlgItem(IDC_BTN_DUMP).EnableWindow(valButton); GetDlgItem(IDC_BTN_FIXDUMP).EnableWindow(valButton); GetDlgItem(IDC_BTN_IATAUTOSEARCH).EnableWindow(valButton); GetDlgItem(IDC_BTN_GETIMPORTS).EnableWindow(valButton); GetDlgItem(IDC_BTN_SUSPECTIMPORTS).EnableWindow(valButton); GetDlgItem(IDC_BTN_INVALIDIMPORTS).EnableWindow(valButton); GetDlgItem(IDC_BTN_CLEARIMPORTS).EnableWindow(valButton); CMenuHandle menu = GetMenu(); UINT valMenu = value ? MF_ENABLED : MF_GRAYED; menu.EnableMenuItem(ID_FILE_DUMP, valMenu); menu.EnableMenuItem(ID_FILE_DUMPMEMORY, valMenu); menu.EnableMenuItem(ID_FILE_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 b90752d..544a714 100644 Binary files a/Scylla/MainGui.rc and b/Scylla/MainGui.rc differ diff --git a/Scylla/OptionsGui.cpp b/Scylla/OptionsGui.cpp index 1fc51e4..39083ac 100644 --- a/Scylla/OptionsGui.cpp +++ b/Scylla/OptionsGui.cpp @@ -1,49 +1,52 @@ #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); } 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(); } diff --git a/Scylla/OptionsGui.h b/Scylla/OptionsGui.h index 8d3fd95..6e94ca3 100644 --- a/Scylla/OptionsGui.h +++ b/Scylla/OptionsGui.h @@ -1,63 +1,65 @@ #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) 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; // 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/PeParser.cpp b/Scylla/PeParser.cpp index 135b323..b3584e5 100644 --- a/Scylla/PeParser.cpp +++ b/Scylla/PeParser.cpp @@ -1,703 +1,1046 @@ #include "PeParser.h" #include "ProcessAccessHelp.h" +#include 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; } - listSectionHeaders.clear(); + 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 numberOfBytesRead = 0; - DWORD readSize = 0; DWORD readOffset = 0; - PeFileSection peFileSection; + listPeSection.reserve(getNumberOfSections()); + if (openFileHandle()) { - listPeSection.reserve(getNumberOfSections()); - for (WORD i = 0; i < getNumberOfSections(); i++) { - readOffset = listSectionHeaders[i].PointerToRawData; - readSize = listSectionHeaders[i].SizeOfRawData; + readOffset = listPeSection[i].sectionHeader.PointerToRawData; - peFileSection.normalSize = readSize; + listPeSection[i].normalSize = listPeSection[i].sectionHeader.SizeOfRawData; - if (readSectionFromFile(readOffset, readSize, peFileSection)) - { - listPeSection.push_back(peFileSection); - } - else + if (!readSectionFromFile(readOffset, listPeSection[i])) { retValue = false; } } closeFileHandle(); } else { retValue = false; } return retValue; } bool PeParser::getSectionHeaders() { PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNTHeader32); - listSectionHeaders.clear(); - listSectionHeaders.reserve(getNumberOfSections()); + PeFileSection peFileSection; + + listPeSection.clear(); + listPeSection.reserve(getNumberOfSections()); for (WORD i = 0; i < getNumberOfSections(); i++) { - listSectionHeaders.push_back(*pSection); + 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, listSectionHeaders[sectionIndex].Name, IMAGE_SIZEOF_SHORT_NAME); //not null terminated + 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; } -std::vector & PeParser::getSectionHeaderList() +void PeParser::setNumberOfSections(WORD numberOfSections) +{ + pNTHeader32->FileHeader.NumberOfSections = numberOfSections; +} + +std::vector & PeParser::getSectionHeaderList() { - return listSectionHeaders; + 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 (listSectionHeaders[i].PointerToRawData > lastRawOffset) + if (listPeSection[i].sectionHeader.PointerToRawData > lastRawOffset) { - lastRawOffset = listSectionHeaders[i].PointerToRawData; - lastRawSize = listSectionHeaders[i].SizeOfRawData; + 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, DWORD readSize, PeFileSection & peFileSection) +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) { - readPeSectionFromFile(readOffset, peFileSection); + 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() != listSectionHeaders.size() || getNumberOfSections() != listPeSection.size()) + 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, &listSectionHeaders[i])) + if (!ProcessAccessHelp::writeMemoryToFile(hFile, dwFileOffset, dwWriteSize, &listPeSection[i].sectionHeader)) { retValue = false; break; } dwFileOffset += dwWriteSize; } for (WORD i = 0; i < getNumberOfSections(); i++) { - if (!listSectionHeaders[i].PointerToRawData) + if (!listPeSection[i].sectionHeader.PointerToRawData) continue; - dwWriteSize = listSectionHeaders[i].PointerToRawData - dwFileOffset; //padding - if (dwWriteSize) + 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, dwFileOffset, dwWriteSize, listPeSection[i].data)) + if (!ProcessAccessHelp::writeMemoryToFile(hFile, listPeSection[i].sectionHeader.PointerToRawData, dwWriteSize, listPeSection[i].data)) { retValue = false; break; } dwFileOffset += dwWriteSize; - if (listPeSection[i].dataSize < listSectionHeaders[i].SizeOfRawData) //padding + if (listPeSection[i].dataSize < listPeSection[i].sectionHeader.SizeOfRawData) //padding { - dwWriteSize = listSectionHeaders[i].SizeOfRawData - listPeSection[i].dataSize; + 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); - if (!ReadFile(hFile, peFileSection.data, peFileSection.dataSize, &bytesRead, 0)) + + 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(); + + 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(); + + 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 { - return true; + 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 +} diff --git a/Scylla/PeParser.h b/Scylla/PeParser.h index 600bd79..e4ddfba 100644 --- a/Scylla/PeParser.h +++ b/Scylla/PeParser.h @@ -1,94 +1,122 @@ #pragma once #include #include -class PeFileSection -{ +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(); + std::vector & getSectionHeaderList(); bool hasExportDirectory(); bool hasTLSDirectory(); bool hasRelocationDirectory(); 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(); 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 listSectionHeaders; 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(); - bool readSectionFromFile( DWORD readOffset, DWORD readSize, PeFileSection & peFileSection ); + 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(); }; diff --git a/Scylla/resource.h b/Scylla/resource.h index 8281203..2072e6a 100644 Binary files a/Scylla/resource.h and b/Scylla/resource.h differ