diff --git a/Scylla/DisassemblerGui.cpp b/Scylla/DisassemblerGui.cpp index d0d1e2c..4b9257b 100644 --- a/Scylla/DisassemblerGui.cpp +++ b/Scylla/DisassemblerGui.cpp @@ -1,362 +1,385 @@ #include "DisassemblerGui.h" #include "ProcessAccessHelp.h" #include "Architecture.h" -DisassemblerGui::DisassemblerGui(DWORD_PTR startAddress) : startAddress(startAddress) +DisassemblerGui::DisassemblerGui(DWORD_PTR startAddress) { - prevAddress = startAddress; + addressHistoryIndex = 0; + addressHistory.push_back(startAddress); hMenuDisassembler.LoadMenu(IDR_MENU_DISASSEMBLER); } BOOL DisassemblerGui::OnInitDialog(CWindow wndFocus, LPARAM lInitParam) { DoDataExchange(); // attach controls DlgResize_Init(true, true); addColumnsToDisassembler(ListDisassembler); displayDisassembly(); - EditAddress.SetValue(startAddress); + EditAddress.SetValue(addressHistory[addressHistoryIndex]); CenterWindow(); return TRUE; } void DisassemblerGui::OnContextMenu(CWindow wnd, CPoint point) { if (wnd.GetDlgCtrlID() == IDC_LIST_DISASSEMBLER) { int selection = ListDisassembler.GetSelectionMark(); if(selection == -1) // no item selected return; if(point.x == -1 && point.y == -1) // invoked by keyboard { ListDisassembler.EnsureVisible(selection, TRUE); ListDisassembler.GetItemPosition(selection, &point); ListDisassembler.ClientToScreen(&point); } CMenuHandle hSub = hMenuDisassembler.GetSubMenu(0); BOOL menuItem = hSub.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD, point.x, point.y, wnd); if (menuItem) { int column = -1; switch (menuItem) { case ID__DIS_ADDRESS: column = COL_ADDRESS; break; case ID__DIS_SIZE: column = COL_INSTRUCTION_SIZE; break; case ID__DIS_OPCODES: column = COL_OPCODES; break; case ID__DIS_INSTRUCTIONS: column = COL_INSTRUCTION; break; case ID__DIS_FOLLOW: followInstruction(selection); break; + case ID__DIS_DISASSEMBLEHERE: + { + disassembleNewAddress((DWORD_PTR)ProcessAccessHelp::decomposerResult[selection].addr); + } + } if(column != -1) { tempBuffer[0] = '\0'; ListDisassembler.GetItemText(selection, column, tempBuffer, _countof(tempBuffer)); copyToClipboard(tempBuffer); } } } } LRESULT DisassemblerGui::OnNMCustomdraw(NMHDR* pnmh) { LRESULT pResult = 0; LPNMLVCUSTOMDRAW lpLVCustomDraw = (LPNMLVCUSTOMDRAW)(pnmh); DWORD_PTR itemIndex = 0; switch(lpLVCustomDraw->nmcd.dwDrawStage) { case CDDS_ITEMPREPAINT: case CDDS_ITEMPREPAINT | CDDS_SUBITEM: { itemIndex = lpLVCustomDraw->nmcd.dwItemSpec; if (lpLVCustomDraw->iSubItem == COL_INSTRUCTION) { doColorInstruction(lpLVCustomDraw, itemIndex); } else { lpLVCustomDraw->clrText = CLR_DEFAULT; lpLVCustomDraw->clrTextBk = CLR_DEFAULT; } } break; } pResult |= CDRF_NOTIFYPOSTPAINT; pResult |= CDRF_NOTIFYITEMDRAW; pResult |= CDRF_NOTIFYSUBITEMDRAW; return pResult; } void DisassemblerGui::OnExit(UINT uNotifyCode, int nID, CWindow wndCtl) { EndDialog(0); } void DisassemblerGui::OnDisassemble(UINT uNotifyCode, int nID, CWindow wndCtl) { DWORD_PTR address = EditAddress.GetValue(); if (address) { - prevAddress = startAddress; - startAddress = address; + disassembleNewAddress(address); + } +} + +void DisassemblerGui::disassembleNewAddress(DWORD_PTR address) +{ + if (addressHistory[addressHistory.size() - 1] != address) + { + addressHistory.push_back(address); + addressHistoryIndex = (int)addressHistory.size() - 1; + EditAddress.SetValue(addressHistory[addressHistoryIndex]); + + if (!displayDisassembly()) + { + MessageBox(L"Cannot disassemble memory at this address",L"Error",MB_ICONERROR); + } + } + +} + +void DisassemblerGui::OnDisassembleForward(UINT uNotifyCode, int nID, CWindow wndCtl) +{ + if (addressHistoryIndex != (addressHistory.size() - 1)) + { + addressHistoryIndex++; + EditAddress.SetValue(addressHistory[addressHistoryIndex]); if (!displayDisassembly()) { MessageBox(L"Cannot disassemble memory at this address",L"Error",MB_ICONERROR); } } } void DisassemblerGui::OnDisassembleBack(UINT uNotifyCode, int nID, CWindow wndCtl) { - startAddress = prevAddress; - EditAddress.SetValue(startAddress); - if (!displayDisassembly()) + if (addressHistoryIndex != 0) { - MessageBox(L"Cannot disassemble memory at this address",L"Error",MB_ICONERROR); + addressHistoryIndex--; + EditAddress.SetValue(addressHistory[addressHistoryIndex]); + if (!displayDisassembly()) + { + MessageBox(L"Cannot disassemble memory at this address",L"Error",MB_ICONERROR); + } } } void DisassemblerGui::addColumnsToDisassembler(CListViewCtrl& list) { list.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT); list.InsertColumn(COL_ADDRESS, L"Address", LVCFMT_LEFT); list.InsertColumn(COL_INSTRUCTION_SIZE, L"Size", LVCFMT_CENTER); list.InsertColumn(COL_OPCODES, L"Opcodes", LVCFMT_LEFT); list.InsertColumn(COL_INSTRUCTION, L"Instructions", LVCFMT_LEFT); list.InsertColumn(COL_COMMENT, L"Comment", LVCFMT_LEFT); } bool DisassemblerGui::displayDisassembly() { ListDisassembler.DeleteAllItems(); - if(!ProcessAccessHelp::readMemoryFromProcess(startAddress, sizeof(data), data)) + if(!ProcessAccessHelp::readMemoryFromProcess(addressHistory[addressHistoryIndex], sizeof(data), data)) return false; - if (!ProcessAccessHelp::decomposeMemory(data, sizeof(data), startAddress)) + if (!ProcessAccessHelp::decomposeMemory(data, sizeof(data), addressHistory[addressHistoryIndex])) return false; - if (!ProcessAccessHelp::disassembleMemory(data, sizeof(data), startAddress)) + if (!ProcessAccessHelp::disassembleMemory(data, sizeof(data), addressHistory[addressHistoryIndex])) return false; for (unsigned int i = 0; i < ProcessAccessHelp::decodedInstructionsCount; i++) { swprintf_s(tempBuffer, PRINTF_DWORD_PTR_FULL,ProcessAccessHelp::decodedInstructions[i].offset); ListDisassembler.InsertItem(i, tempBuffer); swprintf_s(tempBuffer, L"%02d",ProcessAccessHelp::decodedInstructions[i].size); ListDisassembler.SetItemText(i, COL_INSTRUCTION_SIZE, tempBuffer); swprintf_s(tempBuffer, L"%S", (char *)ProcessAccessHelp::decodedInstructions[i].instructionHex.p); toUpperCase(tempBuffer); ListDisassembler.SetItemText(i, COL_OPCODES, tempBuffer); swprintf_s(tempBuffer, L"%S%S%S",(char*)ProcessAccessHelp::decodedInstructions[i].mnemonic.p, ProcessAccessHelp::decodedInstructions[i].operands.length != 0 ? " " : "", (char*)ProcessAccessHelp::decodedInstructions[i].operands.p); toUpperCase(tempBuffer); ListDisassembler.SetItemText(i, COL_INSTRUCTION, tempBuffer); tempBuffer[0] = 0; if (getDisassemblyComment(i)) { ListDisassembler.SetItemText(i, COL_COMMENT, tempBuffer); } } ListDisassembler.SetColumnWidth(COL_ADDRESS, LVSCW_AUTOSIZE_USEHEADER); ListDisassembler.SetColumnWidth(COL_INSTRUCTION_SIZE, LVSCW_AUTOSIZE_USEHEADER); - ListDisassembler.SetColumnWidth(COL_OPCODES, LVSCW_AUTOSIZE_USEHEADER); + ListDisassembler.SetColumnWidth(COL_OPCODES, 140); ListDisassembler.SetColumnWidth(COL_INSTRUCTION, LVSCW_AUTOSIZE_USEHEADER); ListDisassembler.SetColumnWidth(COL_COMMENT, LVSCW_AUTOSIZE_USEHEADER); return true; } void DisassemblerGui::copyToClipboard(const WCHAR * text) { if(OpenClipboard()) { EmptyClipboard(); size_t len = wcslen(text); HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, (len + 1) * sizeof(WCHAR)); if(hMem) { wcscpy_s(static_cast(GlobalLock(hMem)), len + 1, text); GlobalUnlock(hMem); if(!SetClipboardData(CF_UNICODETEXT, hMem)) { GlobalFree(hMem); } } CloseClipboard(); } } void DisassemblerGui::toUpperCase(WCHAR * lowercase) { for (size_t i = 0; i < wcslen(lowercase); i++) { if (lowercase[i] != L'x') { lowercase[i] = towupper(lowercase[i]); } } } void DisassemblerGui::doColorInstruction( LPNMLVCUSTOMDRAW lpLVCustomDraw, DWORD_PTR itemIndex ) { if (ProcessAccessHelp::decomposerResult[itemIndex].flags == FLAG_NOT_DECODABLE) { lpLVCustomDraw->clrText = RGB(255,255,255); // white text lpLVCustomDraw->clrTextBk = RGB(255,0,0); // red background } else if (META_GET_FC(ProcessAccessHelp::decomposerResult[itemIndex].meta) == FC_RET) { lpLVCustomDraw->clrTextBk = RGB(0,255,255); // aqua } else if (META_GET_FC(ProcessAccessHelp::decomposerResult[itemIndex].meta) == FC_CALL) { lpLVCustomDraw->clrTextBk = RGB(255,255,0); // yellow } else if (META_GET_FC(ProcessAccessHelp::decomposerResult[itemIndex].meta) == FC_UNC_BRANCH) { lpLVCustomDraw->clrTextBk = RGB(0x32,0xCD,0x32); // limegreen } else if (META_GET_FC(ProcessAccessHelp::decomposerResult[itemIndex].meta) == FC_CND_BRANCH) { lpLVCustomDraw->clrTextBk = RGB(0xAD,0xFF,0x2F); // greenyellow } } void DisassemblerGui::followInstruction(int index) { DWORD_PTR address = 0; DWORD_PTR addressTemp = 0; DWORD type = META_GET_FC(ProcessAccessHelp::decomposerResult[index].meta); if (ProcessAccessHelp::decomposerResult[index].flags != FLAG_NOT_DECODABLE) { if (type == FC_CALL || type == FC_UNC_BRANCH || type == FC_CND_BRANCH) { #ifdef _WIN64 if (ProcessAccessHelp::decomposerResult[index].flags & FLAG_RIP_RELATIVE) { addressTemp = INSTRUCTION_GET_RIP_TARGET(&ProcessAccessHelp::decomposerResult[index]); if(!ProcessAccessHelp::readMemoryFromProcess(addressTemp, sizeof(DWORD_PTR), &address)) { address = 0; } } #endif if (ProcessAccessHelp::decomposerResult[index].ops[0].type == O_PC) { address = (DWORD_PTR)INSTRUCTION_GET_TARGET(&ProcessAccessHelp::decomposerResult[index]); } if (ProcessAccessHelp::decomposerResult[index].ops[0].type == O_DISP) { addressTemp = (DWORD_PTR)ProcessAccessHelp::decomposerResult[index].disp; if(!ProcessAccessHelp::readMemoryFromProcess(addressTemp, sizeof(DWORD_PTR), &address)) { address = 0; } } if (address != 0) { - prevAddress = startAddress; - startAddress = address; - - if (displayDisassembly()) - { - EditAddress.SetValue(startAddress); - } - else - { - MessageBox(L"Cannot disassemble memory at this address",L"Error",MB_ICONERROR); - } + disassembleNewAddress(address); } } } } bool DisassemblerGui::getDisassemblyComment(unsigned int index) { DWORD_PTR address = 0; DWORD_PTR addressTemp = 0; DWORD type = META_GET_FC(ProcessAccessHelp::decomposerResult[index].meta); tempBuffer[0] = 0; if (ProcessAccessHelp::decomposerResult[index].flags != FLAG_NOT_DECODABLE) { if (type == FC_CALL || type == FC_UNC_BRANCH || type == FC_CND_BRANCH) { #ifdef _WIN64 if (ProcessAccessHelp::decomposerResult[index].flags & FLAG_RIP_RELATIVE) { addressTemp = (DWORD_PTR)INSTRUCTION_GET_RIP_TARGET(&ProcessAccessHelp::decomposerResult[index]); swprintf_s(tempBuffer,L"-> "PRINTF_DWORD_PTR_FULL,addressTemp); if(ProcessAccessHelp::readMemoryFromProcess(addressTemp, sizeof(DWORD_PTR), &address)) { swprintf_s(tempBuffer,L"%s -> "PRINTF_DWORD_PTR_FULL,tempBuffer,address); return true; } } #endif if (ProcessAccessHelp::decomposerResult[index].ops[0].type == O_PC) { address = (DWORD_PTR)INSTRUCTION_GET_TARGET(&ProcessAccessHelp::decomposerResult[index]); swprintf_s(tempBuffer,L"-> "PRINTF_DWORD_PTR_FULL,address); return true; } if (ProcessAccessHelp::decomposerResult[index].ops[0].type == O_DISP) { addressTemp = (DWORD_PTR)ProcessAccessHelp::decomposerResult[index].disp; swprintf_s(tempBuffer,L"-> "PRINTF_DWORD_PTR_FULL,addressTemp); if(ProcessAccessHelp::readMemoryFromProcess(addressTemp, sizeof(DWORD_PTR), &address)) { swprintf_s(tempBuffer,L"%s -> "PRINTF_DWORD_PTR_FULL,tempBuffer,address); return true; } } } } return false; } diff --git a/Scylla/DisassemblerGui.h b/Scylla/DisassemblerGui.h index d6802aa..a789605 100644 --- a/Scylla/DisassemblerGui.h +++ b/Scylla/DisassemblerGui.h @@ -1,106 +1,111 @@ #pragma once #include #include "resource.h" // WTL #include // base ATL classes #include // base WTL classes #include // ATL GUI classes #include // WTL window frame helpers #include // WTL utility classes like CString #include // WTL enhanced msg map macros #include // WTL controls #include // WTL dialog data exchange - +#include #include "hexedit.h" class DisassemblerGui : public CDialogImpl, public CWinDataExchange, public CDialogResize { public: enum { IDD = IDD_DLG_DISASSEMBLER }; BEGIN_DDX_MAP(DisassemblerGui) DDX_CONTROL_HANDLE(IDC_LIST_DISASSEMBLER, ListDisassembler) DDX_CONTROL(IDC_EDIT_ADDRESS_DISASSEMBLE, EditAddress) END_DDX_MAP() BEGIN_MSG_MAP(DisassemblerGui) MSG_WM_INITDIALOG(OnInitDialog) MSG_WM_CONTEXTMENU(OnContextMenu) NOTIFY_HANDLER_EX(IDC_LIST_DISASSEMBLER, NM_CUSTOMDRAW, OnNMCustomdraw) COMMAND_ID_HANDLER_EX(IDC_BUTTON_DISASSEMBLE, OnDisassemble) COMMAND_ID_HANDLER_EX(IDC_BUTTON_DISASSEMBLER_BACK, OnDisassembleBack) + COMMAND_ID_HANDLER_EX(IDC_BUTTON_DISASSEMBLER_FORWARD, OnDisassembleForward) COMMAND_ID_HANDLER_EX(IDCANCEL, OnExit) COMMAND_ID_HANDLER_EX(IDOK, OnExit) CHAIN_MSG_MAP(CDialogResize) END_MSG_MAP() BEGIN_DLGRESIZE_MAP(DisassemblerGui) DLGRESIZE_CONTROL(IDC_LIST_DISASSEMBLER, DLSZ_SIZE_X | DLSZ_SIZE_Y) DLGRESIZE_CONTROL(IDC_BUTTON_DISASSEMBLE, DLSZ_MOVE_X | DLSZ_MOVE_Y) DLGRESIZE_CONTROL(IDC_BUTTON_DISASSEMBLER_BACK, DLSZ_MOVE_X | DLSZ_MOVE_Y) + DLGRESIZE_CONTROL(IDC_BUTTON_DISASSEMBLER_FORWARD, DLSZ_MOVE_X | DLSZ_MOVE_Y) DLGRESIZE_CONTROL(IDC_EDIT_ADDRESS_DISASSEMBLE, DLSZ_MOVE_Y) DLGRESIZE_CONTROL(IDC_STATIC_ADDRESS_DISASSEMBLE, DLSZ_MOVE_Y) END_DLGRESIZE_MAP() DisassemblerGui(DWORD_PTR startAddress); protected: // Variables static const size_t DISASSEMBLER_GUI_MEMORY_SIZE = 0x120; WCHAR tempBuffer[100]; - DWORD_PTR startAddress; - DWORD_PTR prevAddress; + int addressHistoryIndex; + + std::vector addressHistory; // Controls CListViewCtrl ListDisassembler; CHexEdit EditAddress; enum DisassemblerColumns { COL_ADDRESS = 0, COL_INSTRUCTION_SIZE, COL_OPCODES, COL_INSTRUCTION, COL_COMMENT }; // Handles CMenu hMenuDisassembler; protected: // Message handlers BOOL OnInitDialog(CWindow wndFocus, LPARAM lInitParam); void OnContextMenu(CWindow wnd, CPoint point); void OnExit(UINT uNotifyCode, int nID, CWindow wndCtl); LRESULT OnNMCustomdraw(NMHDR* pnmh); void OnDisassemble(UINT uNotifyCode, int nID, CWindow wndCtl); void OnDisassembleBack(UINT uNotifyCode, int nID, CWindow wndCtl); - + void OnDisassembleForward(UINT uNotifyCode, int nID, CWindow wndCtl); // GUI functions void addColumnsToDisassembler(CListViewCtrl& list); bool displayDisassembly(); // Misc void copyToClipboard(const WCHAR * text); private: BYTE data[DISASSEMBLER_GUI_MEMORY_SIZE]; void toUpperCase(WCHAR * lowercase); void doColorInstruction( LPNMLVCUSTOMDRAW lpLVCustomDraw, DWORD_PTR itemIndex ); void followInstruction(int index); bool getDisassemblyComment(unsigned int index); + + void disassembleNewAddress(DWORD_PTR address); }; diff --git a/Scylla/ImportRebuilder.cpp b/Scylla/ImportRebuilder.cpp index ab0afdf..c477585 100644 --- a/Scylla/ImportRebuilder.cpp +++ b/Scylla/ImportRebuilder.cpp @@ -1,288 +1,309 @@ #include "ImportRebuilder.h" #include "Scylla.h" #include "StringConversion.h" //#define DEBUG_COMMENTS bool ImportRebuilder::rebuildImportTable(const WCHAR * newFilePath, std::map & moduleList) { bool retValue = false; if (isValidPeFile()) { if (readPeSectionsFromFile()) { setDefaultFileAlignment(); retValue = buildNewImportTable(moduleList); if (retValue) { alignAllSectionHeaders(); fixPeHeader(); retValue = savePeFileToDisk(newFilePath); } } } return retValue; } bool ImportRebuilder::buildNewImportTable(std::map & moduleList) { createNewImportSection(moduleList); importSectionIndex = listPeSection.size() - 1; DWORD dwSize = fillImportSection(moduleList); if (!dwSize) { return false; } setFlagToIATSection((*moduleList.begin()).second.firstThunk); if (isPE32()) { pNTHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = listPeSection[importSectionIndex].sectionHeader.VirtualAddress; pNTHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = (DWORD)(numberOfImportDescriptors * sizeof(IMAGE_IMPORT_DESCRIPTOR)); } else { pNTHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = listPeSection[importSectionIndex].sectionHeader.VirtualAddress; pNTHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = (DWORD)(numberOfImportDescriptors * sizeof(IMAGE_IMPORT_DESCRIPTOR)); } return true; } bool ImportRebuilder::createNewImportSection(std::map & moduleList) { char sectionName[IMAGE_SIZEOF_SHORT_NAME + 1] = {0}; const WCHAR * sectionNameW = Scylla::config[IAT_SECTION_NAME].getString(); calculateImportSizes(moduleList); if (wcslen(sectionNameW) > IMAGE_SIZEOF_SHORT_NAME) { strcpy_s(sectionName, ".SCY"); } else { StringConversion::ToASCII(sectionNameW, sectionName, _countof(sectionName)); } return addNewLastSection(sectionName, (DWORD)sizeOfImportSection, 0); } void ImportRebuilder::setFlagToIATSection(DWORD_PTR iatAddress) { for (size_t i = 0; i < listPeSection.size(); i++) { if ((listPeSection[i].sectionHeader.VirtualAddress <= iatAddress) && ((listPeSection[i].sectionHeader.VirtualAddress + listPeSection[i].sectionHeader.Misc.VirtualSize) > iatAddress)) { //section must be read and writeable listPeSection[i].sectionHeader.Characteristics |= IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE; } } } DWORD ImportRebuilder::fillImportSection(std::map & moduleList) { std::map::iterator mapIt; std::map::iterator mapIt2; PIMAGE_IMPORT_DESCRIPTOR pImportDesc = 0; PIMAGE_IMPORT_BY_NAME pImportByName = 0; PIMAGE_THUNK_DATA pThunk = 0; ImportModuleThunk * importModuleThunk = 0; ImportThunk * importThunk = 0; size_t stringLength = 0; DWORD_PTR lastRVA = 0; BYTE * sectionData = listPeSection[importSectionIndex].data; DWORD offset = 0; pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)(sectionData); //skip the IMAGE_IMPORT_DESCRIPTOR offset += (DWORD)(numberOfImportDescriptors * sizeof(IMAGE_IMPORT_DESCRIPTOR)); for ( mapIt = moduleList.begin() ; mapIt != moduleList.end(); mapIt++ ) { importModuleThunk = &((*mapIt).second); stringLength = addImportDescriptor(importModuleThunk, offset); #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"fillImportSection :: importDesc.Name %X", pImportDescriptor->Name); #endif offset += (DWORD)stringLength; //stringLength has null termination char pImportByName = (PIMAGE_IMPORT_BY_NAME)((DWORD_PTR)sectionData + offset); //pThunk = (PIMAGE_THUNK_DATA)(getMemoryPointerFromRVA(importModuleThunk->firstThunk)); lastRVA = importModuleThunk->firstThunk - sizeof(DWORD_PTR); for ( mapIt2 = (*mapIt).second.thunkList.begin() ; mapIt2 != (*mapIt).second.thunkList.end(); mapIt2++ ) { importThunk = &((*mapIt2).second); pThunk = (PIMAGE_THUNK_DATA)(getMemoryPointerFromRVA(importThunk->rva)); //check wrong iat pointer if (!pThunk) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"fillImportSection :: Failed to get pThunk RVA: %X", importThunk->rva); #endif return 0; } if ((lastRVA + sizeof(DWORD_PTR)) != importThunk->rva) { //add additional import desc addSpecialImportDescriptor(importThunk->rva); } lastRVA = importThunk->rva; #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"fillImportSection :: importThunk %X pThunk %X pImportByName %X offset %X", importThunk,pThunk,pImportByName,offset); #endif stringLength = addImportToImportTable(importThunk, pThunk, pImportByName, offset); offset += (DWORD)stringLength; //is 0 bei import by ordinal pImportByName = (PIMAGE_IMPORT_BY_NAME)((DWORD_PTR)pImportByName + stringLength); } pImportDescriptor++; } return offset; } size_t ImportRebuilder::addImportDescriptor(ImportModuleThunk * pImportModule, DWORD sectionOffset) { char dllName[MAX_PATH]; StringConversion::ToASCII(pImportModule->moduleName, dllName, _countof(dllName)); size_t stringLength = strlen(dllName) + 1; /* Warning: stringLength MUST include null termination char */ memcpy((listPeSection[importSectionIndex].data + sectionOffset), dllName, stringLength); //copy module name to section pImportDescriptor->FirstThunk = (DWORD)pImportModule->firstThunk; pImportDescriptor->Name = (DWORD)convertOffsetToRVAVector(listPeSection[importSectionIndex].sectionHeader.PointerToRawData + sectionOffset); return stringLength; } void ImportRebuilder::addSpecialImportDescriptor(DWORD_PTR rvaFirstThunk) { PIMAGE_IMPORT_DESCRIPTOR oldID = pImportDescriptor; pImportDescriptor++; pImportDescriptor->FirstThunk = (DWORD)rvaFirstThunk; pImportDescriptor->Name = oldID->Name; } void ImportRebuilder::calculateImportSizes(std::map & moduleList) { std::map::iterator mapIt; std::map::iterator mapIt2; DWORD_PTR lastRVA = 0; numberOfImportDescriptors = 0; sizeOfImportSection = 0; sizeOfApiAndModuleNames = 0; numberOfImportDescriptors = moduleList.size() + 1; //last is zero'd for ( mapIt = moduleList.begin() ; mapIt != moduleList.end(); mapIt++ ) { lastRVA = (*mapIt).second.firstThunk - sizeof(DWORD_PTR); sizeOfApiAndModuleNames += (DWORD)(wcslen((*mapIt).second.moduleName) + 1); for ( mapIt2 = (*mapIt).second.thunkList.begin() ; mapIt2 != (*mapIt).second.thunkList.end(); mapIt2++ ) { if ((lastRVA + sizeof(DWORD_PTR)) != (*mapIt2).second.rva) { numberOfImportDescriptors++; //add additional import desc } if((*mapIt2).second.name[0] != '\0') { sizeOfApiAndModuleNames += sizeof(WORD); //Hint from IMAGE_IMPORT_BY_NAME sizeOfApiAndModuleNames += (DWORD)(strlen((*mapIt2).second.name) + 1); } lastRVA = (*mapIt2).second.rva; } } sizeOfImportSection = sizeOfApiAndModuleNames + (numberOfImportDescriptors * sizeof(IMAGE_IMPORT_DESCRIPTOR)); } size_t ImportRebuilder::addImportToImportTable( ImportThunk * pImport, PIMAGE_THUNK_DATA pThunk, PIMAGE_IMPORT_BY_NAME pImportByName, DWORD sectionOffset) { size_t stringLength = 0; if(pImport->name[0] == '\0') { pThunk->u1.AddressOfData = (IMAGE_ORDINAL(pImport->ordinal) | IMAGE_ORDINAL_FLAG); } else { pImportByName->Hint = pImport->hint; stringLength = strlen(pImport->name) + 1; memcpy(pImportByName->Name, pImport->name, stringLength); pThunk->u1.AddressOfData = convertOffsetToRVAVector(listPeSection[importSectionIndex].sectionHeader.PointerToRawData + sectionOffset); if (!pThunk->u1.AddressOfData) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"addImportToImportTable :: failed to get AddressOfData %X %X", listPeSection[importSectionIndex].sectionHeader.PointerToRawData, sectionOffset); #endif } //next import should be nulled pThunk++; pThunk->u1.AddressOfData = 0; #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"addImportToImportTable :: pThunk->u1.AddressOfData %X %X %X", pThunk->u1.AddressOfData, pThunk, listPeSection[importSectionIndex].sectionHeader.PointerToRawData + sectionOffset); #endif stringLength += sizeof(WORD); } return stringLength; } BYTE * ImportRebuilder::getMemoryPointerFromRVA(DWORD_PTR dwRVA) { - DWORD_PTR offset = convertRVAToOffsetVector(dwRVA); + int peSectionIndex = convertRVAToOffsetVectorIndex(dwRVA); - for (size_t i = 0; i < listPeSection.size(); i++) + if (peSectionIndex == -1) { - if ((listPeSection[i].sectionHeader.PointerToRawData <= offset) && ((listPeSection[i].sectionHeader.PointerToRawData + listPeSection[i].sectionHeader.SizeOfRawData) > offset)) - { - return (BYTE *)((DWORD_PTR)listPeSection[i].data + (offset - listPeSection[i].sectionHeader.PointerToRawData)); - } + return 0; + } + + DWORD rvaPointer = ((DWORD)dwRVA - listPeSection[peSectionIndex].sectionHeader.VirtualAddress); + DWORD minSectionSize = rvaPointer + (sizeof(DWORD_PTR) * 2); //add space for 1 IAT address + + if (listPeSection[peSectionIndex].data == 0 || listPeSection[peSectionIndex].dataSize == 0) + { + listPeSection[peSectionIndex].dataSize = minSectionSize; + listPeSection[peSectionIndex].normalSize = minSectionSize; + listPeSection[peSectionIndex].data = new BYTE[listPeSection[peSectionIndex].dataSize]; + + listPeSection[peSectionIndex].sectionHeader.SizeOfRawData = listPeSection[peSectionIndex].dataSize; + } + else if(listPeSection[peSectionIndex].dataSize < minSectionSize) + { + BYTE * temp = new BYTE[minSectionSize]; + memcpy(temp, listPeSection[peSectionIndex].data, listPeSection[peSectionIndex].dataSize); + delete [] listPeSection[peSectionIndex].data; + + listPeSection[peSectionIndex].data = temp; + listPeSection[peSectionIndex].dataSize = minSectionSize; + listPeSection[peSectionIndex].normalSize = minSectionSize; + + listPeSection[peSectionIndex].sectionHeader.SizeOfRawData = listPeSection[peSectionIndex].dataSize; } - return 0; + return (BYTE *)((DWORD_PTR)listPeSection[peSectionIndex].data + rvaPointer); } diff --git a/Scylla/MainGui.rc b/Scylla/MainGui.rc index 6673fdd..923ace0 100644 Binary files a/Scylla/MainGui.rc and b/Scylla/MainGui.rc differ diff --git a/Scylla/PeParser.cpp b/Scylla/PeParser.cpp index a1cbce0..39d57f7 100644 --- a/Scylla/PeParser.cpp +++ b/Scylla/PeParser.cpp @@ -1,1220 +1,1233 @@ #include "PeParser.h" #include "ProcessAccessHelp.h" #include #include #pragma comment(lib, "Imagehlp.lib") PeParser::PeParser() { initClass(); } PeParser::PeParser(const WCHAR * file, bool readSectionHeaders) { initClass(); filename = file; if (filename && wcslen(filename) > 3) { readPeHeaderFromFile(readSectionHeaders); if (readSectionHeaders) { if (isValidPeFile()) { getSectionHeaders(); } } } } PeParser::PeParser(const DWORD_PTR moduleBase, bool readSectionHeaders) { initClass(); moduleBaseAddress = moduleBase; if (moduleBaseAddress) { readPeHeaderFromProcess(readSectionHeaders); if (readSectionHeaders) { if (isValidPeFile()) { getSectionHeaders(); } } } } PeParser::~PeParser() { if (headerMemory) { delete [] headerMemory; } if (fileMemory) { delete [] fileMemory; } for (size_t i = 0; i < listPeSection.size(); i++) { if (listPeSection[i].data) { delete [] listPeSection[i].data; } } listPeSection.clear(); } void PeParser::initClass() { fileMemory = 0; headerMemory = 0; pDosHeader = 0; pDosStub = 0; dosStubSize = 0; pNTHeader32 = 0; pNTHeader64 = 0; overlayData = 0; overlaySize = 0; filename = 0; fileSize = 0; moduleBaseAddress = 0; hFile = INVALID_HANDLE_VALUE; } bool PeParser::isPE64() { if (isValidPeFile()) { return (pNTHeader32->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC); } else { return false; } } bool PeParser::isPE32() { if (isValidPeFile()) { return (pNTHeader32->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC); } else { return false; } } bool PeParser::isTargetFileSamePeFormat() { #ifdef _WIN64 return isPE64(); #else return isPE32(); #endif } bool PeParser::isValidPeFile() { bool retValue = false; if (pDosHeader) { if (pDosHeader->e_magic == IMAGE_DOS_SIGNATURE) { if (pNTHeader32) { if (pNTHeader32->Signature == IMAGE_NT_SIGNATURE) { retValue = true; } } } } return retValue; } bool PeParser::hasDirectory(const int directoryIndex) { if (isPE32()) { return (pNTHeader32->OptionalHeader.DataDirectory[directoryIndex].VirtualAddress != 0); } else if (isPE64()) { return (pNTHeader64->OptionalHeader.DataDirectory[directoryIndex].VirtualAddress != 0); } else { return false; } } bool PeParser::hasExportDirectory() { return hasDirectory(IMAGE_DIRECTORY_ENTRY_EXPORT); } bool PeParser::hasTLSDirectory() { return hasDirectory(IMAGE_DIRECTORY_ENTRY_TLS); } bool PeParser::hasRelocationDirectory() { return hasDirectory(IMAGE_DIRECTORY_ENTRY_BASERELOC); } DWORD PeParser::getEntryPoint() { if (isPE32()) { return pNTHeader32->OptionalHeader.AddressOfEntryPoint; } else if (isPE64()) { return pNTHeader64->OptionalHeader.AddressOfEntryPoint; } else { return 0; } } bool PeParser::readPeHeaderFromProcess(bool readSectionHeaders) { bool retValue = false; DWORD correctSize = 0; DWORD readSize = getInitialHeaderReadSize(readSectionHeaders); headerMemory = new BYTE[readSize]; if (ProcessAccessHelp::readMemoryPartlyFromProcess(moduleBaseAddress, readSize, headerMemory)) { retValue = true; getDosAndNtHeader(headerMemory, (LONG)readSize); if (isValidPeFile()) { correctSize = calcCorrectPeHeaderSize(readSectionHeaders); if (readSize < correctSize) { readSize = correctSize; delete [] headerMemory; headerMemory = new BYTE[readSize]; if (ProcessAccessHelp::readMemoryPartlyFromProcess(moduleBaseAddress, readSize, headerMemory)) { getDosAndNtHeader(headerMemory, (LONG)readSize); } } } } return retValue; } bool PeParser::readPeHeaderFromFile(bool readSectionHeaders) { bool retValue = false; DWORD correctSize = 0; DWORD numberOfBytesRead = 0; DWORD readSize = getInitialHeaderReadSize(readSectionHeaders); headerMemory = new BYTE[readSize]; if (openFileHandle()) { fileSize = (DWORD)ProcessAccessHelp::getFileSize(hFile); if (ReadFile(hFile, headerMemory, readSize, &numberOfBytesRead, 0)) { retValue = true; getDosAndNtHeader(headerMemory, (LONG)readSize); if (isValidPeFile()) { correctSize = calcCorrectPeHeaderSize(readSectionHeaders); if (readSize < correctSize) { readSize = correctSize; if (fileSize > 0) { if (fileSize < correctSize) { readSize = fileSize; } } delete [] headerMemory; headerMemory = new BYTE[readSize]; SetFilePointer(hFile, 0, 0, FILE_BEGIN); if (ReadFile(hFile, headerMemory, readSize, &numberOfBytesRead, 0)) { getDosAndNtHeader(headerMemory, (LONG)readSize); } } } } closeFileHandle(); } return retValue; } bool PeParser::readPeSectionsFromProcess() { bool retValue = true; DWORD_PTR readOffset = 0; listPeSection.reserve(getNumberOfSections()); for (WORD i = 0; i < getNumberOfSections(); i++) { readOffset = listPeSection[i].sectionHeader.VirtualAddress + moduleBaseAddress; listPeSection[i].normalSize = listPeSection[i].sectionHeader.Misc.VirtualSize; if (!readSectionFromProcess(readOffset, listPeSection[i])) { retValue = false; } } return retValue; } bool PeParser::readPeSectionsFromFile() { bool retValue = true; DWORD readOffset = 0; listPeSection.reserve(getNumberOfSections()); if (openFileHandle()) { for (WORD i = 0; i < getNumberOfSections(); i++) { readOffset = listPeSection[i].sectionHeader.PointerToRawData; listPeSection[i].normalSize = listPeSection[i].sectionHeader.SizeOfRawData; if (!readSectionFromFile(readOffset, listPeSection[i])) { retValue = false; } } closeFileHandle(); } else { retValue = false; } return retValue; } bool PeParser::getSectionHeaders() { PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNTHeader32); PeFileSection peFileSection; listPeSection.clear(); listPeSection.reserve(getNumberOfSections()); for (WORD i = 0; i < getNumberOfSections(); i++) { memcpy_s(&peFileSection.sectionHeader, sizeof(IMAGE_SECTION_HEADER), pSection, sizeof(IMAGE_SECTION_HEADER)); listPeSection.push_back(peFileSection); pSection++; } return true; } bool PeParser::getSectionNameUnicode(const int sectionIndex, WCHAR * output, const int outputLen) { CHAR sectionNameA[IMAGE_SIZEOF_SHORT_NAME + 1] = {0}; output[0] = 0; memcpy(sectionNameA, listPeSection[sectionIndex].sectionHeader.Name, IMAGE_SIZEOF_SHORT_NAME); //not null terminated return (swprintf_s(output, outputLen, L"%S", sectionNameA) != -1); } WORD PeParser::getNumberOfSections() { return pNTHeader32->FileHeader.NumberOfSections; } void PeParser::setNumberOfSections(WORD numberOfSections) { pNTHeader32->FileHeader.NumberOfSections = numberOfSections; } std::vector & PeParser::getSectionHeaderList() { return listPeSection; } void PeParser::getDosAndNtHeader(BYTE * memory, LONG size) { pDosHeader = (PIMAGE_DOS_HEADER)memory; pNTHeader32 = 0; pNTHeader64 = 0; dosStubSize = 0; pDosStub = 0; if (pDosHeader->e_lfanew > 0 && pDosHeader->e_lfanew < size) //malformed PE { pNTHeader32 = (PIMAGE_NT_HEADERS32)((DWORD_PTR)pDosHeader + pDosHeader->e_lfanew); pNTHeader64 = (PIMAGE_NT_HEADERS64)((DWORD_PTR)pDosHeader + pDosHeader->e_lfanew); if (pDosHeader->e_lfanew > sizeof(IMAGE_DOS_HEADER)) { dosStubSize = pDosHeader->e_lfanew - sizeof(IMAGE_DOS_HEADER); pDosStub = (BYTE *)((DWORD_PTR)pDosHeader + sizeof(IMAGE_DOS_HEADER)); } } } DWORD PeParser::calcCorrectPeHeaderSize(bool readSectionHeaders) { DWORD correctSize = pDosHeader->e_lfanew + 50; //extra buffer if (readSectionHeaders) { correctSize += getNumberOfSections() * sizeof(IMAGE_SECTION_HEADER); } if (isPE32()) { correctSize += sizeof(IMAGE_NT_HEADERS32); } else if(isPE64()) { correctSize += sizeof(IMAGE_NT_HEADERS64); } else { correctSize = 0; //not a valid PE } return correctSize; } DWORD PeParser::getInitialHeaderReadSize(bool readSectionHeaders) { DWORD readSize = sizeof(IMAGE_DOS_HEADER) + 200 + sizeof(IMAGE_NT_HEADERS64); if (readSectionHeaders) { readSize += (10 * sizeof(IMAGE_SECTION_HEADER)); } return readSize; } DWORD PeParser::getSectionHeaderBasedFileSize() { DWORD lastRawOffset = 0, lastRawSize = 0; //this is needed if the sections aren't sorted by their RawOffset (e.g. Petite) for (WORD i = 0; i < getNumberOfSections(); i++) { if (listPeSection[i].sectionHeader.PointerToRawData > lastRawOffset) { lastRawOffset = listPeSection[i].sectionHeader.PointerToRawData; lastRawSize = listPeSection[i].sectionHeader.SizeOfRawData; } } return (lastRawSize + lastRawOffset); } DWORD PeParser::getSectionHeaderBasedSizeOfImage() { DWORD lastVirtualOffset = 0, lastVirtualSize = 0; //this is needed if the sections aren't sorted by their RawOffset (e.g. Petite) for (WORD i = 0; i < getNumberOfSections(); i++) { if (listPeSection[i].sectionHeader.VirtualAddress > lastVirtualOffset) { lastVirtualOffset = listPeSection[i].sectionHeader.VirtualAddress; lastVirtualSize = listPeSection[i].sectionHeader.Misc.VirtualSize; } } return (lastVirtualSize + lastVirtualOffset); } bool PeParser::openFileHandle() { if (hFile == INVALID_HANDLE_VALUE) { if (filename) { hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); } else { hFile = INVALID_HANDLE_VALUE; } } return (hFile != INVALID_HANDLE_VALUE); } bool PeParser::openWriteFileHandle( const WCHAR * newFile ) { if (newFile) { hFile = CreateFile(newFile, GENERIC_WRITE, FILE_SHARE_WRITE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); } else { hFile = INVALID_HANDLE_VALUE; } return (hFile != INVALID_HANDLE_VALUE); } void PeParser::closeFileHandle() { if (hFile != INVALID_HANDLE_VALUE) { CloseHandle(hFile); hFile = INVALID_HANDLE_VALUE; } } bool PeParser::readSectionFromFile(DWORD readOffset, PeFileSection & peFileSection) { const DWORD maxReadSize = 100; BYTE data[maxReadSize]; DWORD bytesRead = 0; bool retValue = true; DWORD valuesFound = 0; DWORD currentOffset = 0; DWORD readSize = 0; peFileSection.data = 0; peFileSection.dataSize = 0; readSize = peFileSection.normalSize; if (!readOffset || !readSize) { return true; //section without data is valid } if (readSize <= maxReadSize) { peFileSection.dataSize = readSize; peFileSection.normalSize = readSize; return readPeSectionFromFile(readOffset, peFileSection); } currentOffset = readOffset + readSize - maxReadSize; while(currentOffset >= readOffset) //start from the end { SetFilePointer(hFile, currentOffset, 0, FILE_BEGIN); ZeroMemory(data, sizeof(data)); if (!ReadFile(hFile, data, sizeof(data), &bytesRead, 0)) { retValue = false; break; } valuesFound = isMemoryNotNull(data, sizeof(data)); if (valuesFound) { //found some real code currentOffset += valuesFound; if (readOffset < currentOffset) { //real size peFileSection.dataSize = currentOffset - readOffset; } break; } currentOffset -= maxReadSize; } if (peFileSection.dataSize) { retValue = readPeSectionFromFile(readOffset, peFileSection); } return retValue; } DWORD PeParser::isMemoryNotNull( BYTE * data, int dataSize ) { for (int i = (dataSize - 1); i >= 0; i--) { if (data[i] != 0) { return i + 1; } } return 0; } bool PeParser::savePeFileToDisk( const WCHAR * newFile ) { bool retValue = true; DWORD dwFileOffset = 0, dwWriteSize = 0; if (getNumberOfSections() != listPeSection.size()) { return false; } if (openWriteFileHandle(newFile)) { //Dos header dwWriteSize = sizeof(IMAGE_DOS_HEADER); if (!ProcessAccessHelp::writeMemoryToFile(hFile, dwFileOffset, dwWriteSize, pDosHeader)) { retValue = false; } dwFileOffset += dwWriteSize; if (dosStubSize && pDosStub) { //Dos Stub dwWriteSize = dosStubSize; if (!ProcessAccessHelp::writeMemoryToFile(hFile, dwFileOffset, dwWriteSize, pDosStub)) { retValue = false; } dwFileOffset += dwWriteSize; } //Pe Header if (isPE32()) { dwWriteSize = sizeof(IMAGE_NT_HEADERS32); } else { dwWriteSize = sizeof(IMAGE_NT_HEADERS64); } if (!ProcessAccessHelp::writeMemoryToFile(hFile, dwFileOffset, dwWriteSize, pNTHeader32)) { retValue = false; } dwFileOffset += dwWriteSize; //section headers dwWriteSize = sizeof(IMAGE_SECTION_HEADER); for (WORD i = 0; i < getNumberOfSections(); i++) { if (!ProcessAccessHelp::writeMemoryToFile(hFile, dwFileOffset, dwWriteSize, &listPeSection[i].sectionHeader)) { retValue = false; break; } dwFileOffset += dwWriteSize; } for (WORD i = 0; i < getNumberOfSections(); i++) { if (!listPeSection[i].sectionHeader.PointerToRawData) continue; if (listPeSection[i].sectionHeader.PointerToRawData > dwFileOffset) { dwWriteSize = listPeSection[i].sectionHeader.PointerToRawData - dwFileOffset; //padding if (!writeZeroMemoryToFile(hFile, dwFileOffset, dwWriteSize)) { retValue = false; break; } dwFileOffset += dwWriteSize; } dwWriteSize = listPeSection[i].dataSize; if (dwWriteSize) { if (!ProcessAccessHelp::writeMemoryToFile(hFile, listPeSection[i].sectionHeader.PointerToRawData, dwWriteSize, listPeSection[i].data)) { retValue = false; break; } dwFileOffset += dwWriteSize; if (listPeSection[i].dataSize < listPeSection[i].sectionHeader.SizeOfRawData) //padding { dwWriteSize = listPeSection[i].sectionHeader.SizeOfRawData - listPeSection[i].dataSize; if (!writeZeroMemoryToFile(hFile, dwFileOffset, dwWriteSize)) { retValue = false; break; } dwFileOffset += dwWriteSize; } } } //add overlay? if (overlaySize && overlayData) { dwWriteSize = overlaySize; if (!ProcessAccessHelp::writeMemoryToFile(hFile, dwFileOffset, dwWriteSize, overlayData)) { retValue = false; } dwFileOffset += dwWriteSize; } SetEndOfFile(hFile); closeFileHandle(); } return retValue; } bool PeParser::writeZeroMemoryToFile(HANDLE hFile, DWORD fileOffset, DWORD size) { bool retValue = false; PVOID zeromemory = calloc(size, 1); if (zeromemory) { retValue = ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, size, zeromemory); free(zeromemory); } return retValue; } void PeParser::removeDosStub() { if (pDosHeader) { dosStubSize = 0; pDosStub = 0; //must not delete [] pDosHeader->e_lfanew = sizeof(IMAGE_DOS_HEADER); } } bool PeParser::readPeSectionFromFile(DWORD readOffset, PeFileSection & peFileSection) { DWORD bytesRead = 0; peFileSection.data = new BYTE[peFileSection.dataSize]; SetFilePointer(hFile, readOffset, 0, FILE_BEGIN); return (ReadFile(hFile, peFileSection.data, peFileSection.dataSize, &bytesRead, 0) != FALSE); } bool PeParser::readSectionFromProcess( DWORD_PTR readOffset, PeFileSection & peFileSection ) { const DWORD maxReadSize = 100; BYTE data[maxReadSize]; bool retValue = true; DWORD valuesFound = 0; DWORD readSize = 0; DWORD_PTR currentOffset = 0; peFileSection.data = 0; peFileSection.dataSize = 0; readSize = peFileSection.normalSize; if (!readOffset || !readSize) { return true; //section without data is valid } if (readSize <= maxReadSize) { peFileSection.dataSize = readSize; peFileSection.normalSize = readSize; return readPeSectionFromProcess(readOffset, peFileSection); } currentOffset = readOffset + readSize - maxReadSize; while(currentOffset >= readOffset) //start from the end { if (!ProcessAccessHelp::readMemoryPartlyFromProcess(currentOffset, sizeof(data), data)) { retValue = false; break; } valuesFound = isMemoryNotNull(data, sizeof(data)); if (valuesFound) { //found some real code currentOffset += valuesFound; if (readOffset < currentOffset) { //real size peFileSection.dataSize = (DWORD)(currentOffset - readOffset); } break; } currentOffset -= maxReadSize; } if (peFileSection.dataSize) { retValue = readPeSectionFromProcess(readOffset, peFileSection); } return retValue; } bool PeParser::readPeSectionFromProcess(DWORD_PTR readOffset, PeFileSection & peFileSection) { peFileSection.data = new BYTE[peFileSection.dataSize]; return ProcessAccessHelp::readMemoryPartlyFromProcess(readOffset, peFileSection.dataSize, peFileSection.data); } DWORD PeParser::alignValue(DWORD badValue, DWORD alignTo) { return (((badValue + alignTo - 1) / alignTo) * alignTo); } bool PeParser::addNewLastSection(const CHAR * sectionName, DWORD sectionSize, BYTE * sectionData) { size_t nameLength = strlen(sectionName); DWORD fileAlignment = 0, sectionAlignment = 0; PeFileSection peFileSection; if (nameLength > IMAGE_SIZEOF_SHORT_NAME) { return false; } if (isPE32()) { fileAlignment = pNTHeader32->OptionalHeader.FileAlignment; sectionAlignment = pNTHeader32->OptionalHeader.SectionAlignment; } else { fileAlignment = pNTHeader64->OptionalHeader.FileAlignment; sectionAlignment = pNTHeader64->OptionalHeader.SectionAlignment; } memcpy_s(peFileSection.sectionHeader.Name, IMAGE_SIZEOF_SHORT_NAME, sectionName, nameLength); //last section doesn't need SizeOfRawData alignment peFileSection.sectionHeader.SizeOfRawData = sectionSize; //alignValue(sectionSize, fileAlignment); peFileSection.sectionHeader.Misc.VirtualSize = alignValue(sectionSize, sectionAlignment); peFileSection.sectionHeader.PointerToRawData = alignValue(getSectionHeaderBasedFileSize(), fileAlignment); peFileSection.sectionHeader.VirtualAddress = alignValue(getSectionHeaderBasedSizeOfImage(), sectionAlignment); peFileSection.sectionHeader.Characteristics = IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE|IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA; peFileSection.normalSize = peFileSection.sectionHeader.SizeOfRawData; peFileSection.dataSize = peFileSection.sectionHeader.SizeOfRawData; if (sectionData == 0) { peFileSection.data = new BYTE[peFileSection.sectionHeader.SizeOfRawData]; ZeroMemory(peFileSection.data , peFileSection.sectionHeader.SizeOfRawData); } else { peFileSection.data = sectionData; } listPeSection.push_back(peFileSection); setNumberOfSections(getNumberOfSections() + 1); return true; } +int PeParser::convertRVAToOffsetVectorIndex(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 i; + } + } + + return -1; +} + DWORD_PTR PeParser::convertRVAToOffsetVector(DWORD_PTR dwRVA) { for (WORD i = 0; i < getNumberOfSections(); i++) { if ((listPeSection[i].sectionHeader.VirtualAddress <= dwRVA) && ((listPeSection[i].sectionHeader.VirtualAddress + listPeSection[i].sectionHeader.Misc.VirtualSize) > dwRVA)) { return ((dwRVA - listPeSection[i].sectionHeader.VirtualAddress) + listPeSection[i].sectionHeader.PointerToRawData); } } return 0; } DWORD_PTR PeParser::convertOffsetToRVAVector(DWORD_PTR dwOffset) { for (WORD i = 0; i < getNumberOfSections(); i++) { if ((listPeSection[i].sectionHeader.PointerToRawData <= dwOffset) && ((listPeSection[i].sectionHeader.PointerToRawData + listPeSection[i].sectionHeader.SizeOfRawData) > dwOffset)) { return ((dwOffset - listPeSection[i].sectionHeader.PointerToRawData) + listPeSection[i].sectionHeader.VirtualAddress); } } return 0; } void PeParser::fixPeHeader() { DWORD dwSize = pDosHeader->e_lfanew + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER); if (isPE32()) { //delete bound import directories pNTHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0; pNTHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0; //max 16 if (pNTHeader64->OptionalHeader.NumberOfRvaAndSizes > 0x10) { pNTHeader64->OptionalHeader.NumberOfRvaAndSizes = 0x10; } pNTHeader32->OptionalHeader.SizeOfImage = getSectionHeaderBasedSizeOfImage(); if (moduleBaseAddress) { pNTHeader32->OptionalHeader.ImageBase = (DWORD)moduleBaseAddress; } pNTHeader32->OptionalHeader.SizeOfHeaders = alignValue(dwSize + pNTHeader32->FileHeader.SizeOfOptionalHeader + (getNumberOfSections() * sizeof(IMAGE_SECTION_HEADER)), pNTHeader32->OptionalHeader.FileAlignment); } else { //delete bound import directories pNTHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0; pNTHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0; //max 16 if (pNTHeader64->OptionalHeader.NumberOfRvaAndSizes > 0x10) { pNTHeader64->OptionalHeader.NumberOfRvaAndSizes = 0x10; } pNTHeader64->OptionalHeader.SizeOfImage = getSectionHeaderBasedSizeOfImage(); if (moduleBaseAddress) { pNTHeader64->OptionalHeader.ImageBase = moduleBaseAddress; } pNTHeader64->OptionalHeader.SizeOfHeaders = alignValue(dwSize + pNTHeader64->FileHeader.SizeOfOptionalHeader + (getNumberOfSections() * sizeof(IMAGE_SECTION_HEADER)), pNTHeader64->OptionalHeader.FileAlignment); } removeIatDirectory(); } void PeParser::removeIatDirectory() { DWORD searchAddress = 0; if (isPE32()) { searchAddress = pNTHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress; pNTHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = 0; pNTHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = 0; } else { searchAddress = pNTHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress; pNTHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = 0; pNTHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = 0; } if (searchAddress) { for (WORD i = 0; i < getNumberOfSections(); i++) { if ((listPeSection[i].sectionHeader.VirtualAddress <= searchAddress) && ((listPeSection[i].sectionHeader.VirtualAddress + listPeSection[i].sectionHeader.Misc.VirtualSize) > searchAddress)) { //section must be read and writable listPeSection[i].sectionHeader.Characteristics |= IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE; } } } } void PeParser::setDefaultFileAlignment() { if (isPE32()) { pNTHeader32->OptionalHeader.FileAlignment = FileAlignmentConstant; } else { pNTHeader64->OptionalHeader.FileAlignment = FileAlignmentConstant; } } bool PeFileSectionSortByPointerToRawData(const PeFileSection& d1, const PeFileSection& d2) { return d1.sectionHeader.PointerToRawData < d2.sectionHeader.PointerToRawData; } bool PeFileSectionSortByVirtualAddress(const PeFileSection& d1, const PeFileSection& d2) { return d1.sectionHeader.VirtualAddress < d2.sectionHeader.VirtualAddress; } void PeParser::alignAllSectionHeaders() { DWORD sectionAlignment = 0; DWORD fileAlignment = 0; DWORD newFileSize = 0; if (isPE32()) { sectionAlignment = pNTHeader32->OptionalHeader.SectionAlignment; fileAlignment = pNTHeader32->OptionalHeader.FileAlignment; } else { sectionAlignment = pNTHeader64->OptionalHeader.SectionAlignment; fileAlignment = pNTHeader64->OptionalHeader.FileAlignment; } std::sort(listPeSection.begin(), listPeSection.end(), PeFileSectionSortByPointerToRawData); //sort by PointerToRawData ascending newFileSize = pDosHeader->e_lfanew + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + pNTHeader32->FileHeader.SizeOfOptionalHeader + (getNumberOfSections() * sizeof(IMAGE_SECTION_HEADER)); for (WORD i = 0; i < getNumberOfSections(); i++) { listPeSection[i].sectionHeader.VirtualAddress = alignValue(listPeSection[i].sectionHeader.VirtualAddress, sectionAlignment); listPeSection[i].sectionHeader.Misc.VirtualSize = alignValue(listPeSection[i].sectionHeader.Misc.VirtualSize, sectionAlignment); listPeSection[i].sectionHeader.PointerToRawData = alignValue(newFileSize, fileAlignment); listPeSection[i].sectionHeader.SizeOfRawData = alignValue(listPeSection[i].dataSize, fileAlignment); newFileSize = listPeSection[i].sectionHeader.PointerToRawData + listPeSection[i].sectionHeader.SizeOfRawData; } std::sort(listPeSection.begin(), listPeSection.end(), PeFileSectionSortByVirtualAddress); //sort by VirtualAddress ascending } bool PeParser::dumpProcess(DWORD_PTR modBase, DWORD_PTR entryPoint, const WCHAR * dumpFilePath) { moduleBaseAddress = modBase; if (readPeSectionsFromProcess()) { setDefaultFileAlignment(); setEntryPointVa(entryPoint); alignAllSectionHeaders(); fixPeHeader(); getFileOverlay(); return savePeFileToDisk(dumpFilePath); } return false; } bool PeParser::dumpProcess(DWORD_PTR modBase, DWORD_PTR entryPoint, const WCHAR * dumpFilePath, std::vector & sectionList) { if (listPeSection.size() == sectionList.size()) { for (int i = (getNumberOfSections() - 1); i >= 0; i--) { if (!sectionList[i].isDumped) { listPeSection.erase(listPeSection.begin() + i); setNumberOfSections(getNumberOfSections() - 1); } else { listPeSection[i].sectionHeader.Misc.VirtualSize = sectionList[i].virtualSize; listPeSection[i].sectionHeader.SizeOfRawData = sectionList[i].rawSize; listPeSection[i].sectionHeader.Characteristics = sectionList[i].characteristics; } } } return dumpProcess(modBase, entryPoint, dumpFilePath); } void PeParser::setEntryPointVa(DWORD_PTR entryPoint) { DWORD entryPointRva = (DWORD)(entryPoint - moduleBaseAddress); setEntryPointRva(entryPointRva); } void PeParser::setEntryPointRva(DWORD entryPoint) { if (isPE32()) { pNTHeader32->OptionalHeader.AddressOfEntryPoint = entryPoint; } else if (isPE64()) { pNTHeader64->OptionalHeader.AddressOfEntryPoint = entryPoint; } } bool PeParser::getFileOverlay() { DWORD numberOfBytesRead; bool retValue = false; if (!hasOverlayData()) { return false; } if (openFileHandle()) { DWORD overlayOffset = getSectionHeaderBasedFileSize(); DWORD fileSize = (DWORD)ProcessAccessHelp::getFileSize(hFile); overlaySize = fileSize - overlayOffset; overlayData = new BYTE[overlaySize]; SetFilePointer(hFile, overlayOffset, 0, FILE_BEGIN); if (ReadFile(hFile, overlayData, overlaySize, &numberOfBytesRead, 0)) { retValue = true; } closeFileHandle(); } return retValue; } bool PeParser::hasOverlayData() { if (!filename) return false; if (isValidPeFile()) { DWORD fileSize = (DWORD)ProcessAccessHelp::getFileSize(filename); return (fileSize > getSectionHeaderBasedFileSize()); } else { return false; } } bool PeParser::updatePeHeaderChecksum(const WCHAR * targetFile, DWORD fileSize) { PIMAGE_NT_HEADERS32 pNTHeader32 = 0; PIMAGE_NT_HEADERS64 pNTHeader64 = 0; DWORD headerSum = 0; DWORD checkSum = 0; bool retValue = false; if (!fileSize) return retValue; HANDLE hFileToMap = CreateFile(targetFile, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if(hFileToMap != INVALID_HANDLE_VALUE) { HANDLE hMappedFile = CreateFileMapping(hFileToMap, 0, PAGE_READWRITE, 0, 0, 0); if(hMappedFile) { if (GetLastError() != ERROR_ALREADY_EXISTS) { LPVOID addrMappedDll = MapViewOfFile(hMappedFile, FILE_MAP_ALL_ACCESS, 0, 0, 0); if (addrMappedDll) { pNTHeader32 = (PIMAGE_NT_HEADERS32)CheckSumMappedFile(addrMappedDll, fileSize, &headerSum, &checkSum); if (pNTHeader32) { if (pNTHeader32->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) { pNTHeader64 = (PIMAGE_NT_HEADERS64)pNTHeader32; pNTHeader64->OptionalHeader.CheckSum = checkSum; } else { pNTHeader32->OptionalHeader.CheckSum = checkSum; } retValue = true; } UnmapViewOfFile(addrMappedDll); } } CloseHandle(hMappedFile); } CloseHandle(hFileToMap); } return retValue; } \ No newline at end of file diff --git a/Scylla/PeParser.h b/Scylla/PeParser.h index 687c318..329354b 100644 --- a/Scylla/PeParser.h +++ b/Scylla/PeParser.h @@ -1,131 +1,132 @@ #pragma once #include #include #include "DumpSectionGui.h" class PeFileSection { public: IMAGE_SECTION_HEADER sectionHeader; BYTE * data; DWORD dataSize; DWORD normalSize; PeFileSection() { ZeroMemory(§ionHeader, sizeof(IMAGE_SECTION_HEADER)); data = 0; dataSize = 0; normalSize = 0; } }; class PeParser { public: PeParser(const WCHAR * file, bool readSectionHeaders = true); PeParser(const DWORD_PTR moduleBase, bool readSectionHeaders = true); ~PeParser(); bool isValidPeFile(); bool isPE64(); bool isPE32(); bool isTargetFileSamePeFormat(); WORD getNumberOfSections(); std::vector & getSectionHeaderList(); bool hasExportDirectory(); bool hasTLSDirectory(); bool hasRelocationDirectory(); bool hasOverlayData(); DWORD getEntryPoint(); bool getSectionNameUnicode(const int sectionIndex, WCHAR * output, const int outputLen); DWORD getSectionHeaderBasedFileSize(); DWORD getSectionHeaderBasedSizeOfImage(); bool readPeSectionsFromProcess(); bool readPeSectionsFromFile(); bool savePeFileToDisk(const WCHAR * newFile); void removeDosStub(); void alignAllSectionHeaders(); void fixPeHeader(); void setDefaultFileAlignment(); bool dumpProcess(DWORD_PTR modBase, DWORD_PTR entryPoint, const WCHAR * dumpFilePath); bool dumpProcess(DWORD_PTR modBase, DWORD_PTR entryPoint, const WCHAR * dumpFilePath, std::vector & sectionList); void setEntryPointVa(DWORD_PTR entryPoint); void setEntryPointRva(DWORD entryPoint); static bool updatePeHeaderChecksum(const WCHAR * targetFile, DWORD fileSize); protected: PeParser(); static const DWORD FileAlignmentConstant = 0x200; const WCHAR * filename; DWORD_PTR moduleBaseAddress; /************************************************************************/ /* PE FILE */ /* */ /* IMAGE_DOS_HEADER 64 0x40 */ /* IMAGE_NT_HEADERS32 248 0xF8 */ /* IMAGE_NT_HEADERS64 264 0x108 */ /* IMAGE_SECTION_HEADER 40 0x28 */ /************************************************************************/ PIMAGE_DOS_HEADER pDosHeader; BYTE * pDosStub; //between dos header and section header DWORD dosStubSize; PIMAGE_NT_HEADERS32 pNTHeader32; PIMAGE_NT_HEADERS64 pNTHeader64; std::vector listPeSection; BYTE * overlayData; DWORD overlaySize; /************************************************************************/ BYTE * fileMemory; BYTE * headerMemory; HANDLE hFile; DWORD fileSize; bool readPeHeaderFromFile(bool readSectionHeaders); bool readPeHeaderFromProcess(bool readSectionHeaders); bool hasDirectory(const int directoryIndex); bool getSectionHeaders(); void getDosAndNtHeader(BYTE * memory, LONG size); DWORD calcCorrectPeHeaderSize( bool readSectionHeaders ); DWORD getInitialHeaderReadSize( bool readSectionHeaders ); bool openFileHandle(); void closeFileHandle(); void initClass(); DWORD isMemoryNotNull( BYTE * data, int dataSize ); bool openWriteFileHandle( const WCHAR * newFile ); bool writeZeroMemoryToFile(HANDLE hFile, DWORD fileOffset, DWORD size); bool readPeSectionFromFile( DWORD readOffset, PeFileSection & peFileSection ); bool readPeSectionFromProcess( DWORD_PTR readOffset, PeFileSection & peFileSection ); bool readSectionFromFile( DWORD readOffset, PeFileSection & peFileSection ); bool readSectionFromProcess( DWORD_PTR readOffset, PeFileSection & peFileSection ); bool addNewLastSection(const CHAR * sectionName, DWORD sectionSize, BYTE * sectionData); DWORD alignValue(DWORD badValue, DWORD alignTo); + int convertRVAToOffsetVectorIndex(DWORD_PTR dwRVA); DWORD_PTR convertOffsetToRVAVector(DWORD_PTR dwOffset); DWORD_PTR convertRVAToOffsetVector(DWORD_PTR dwRVA); void setNumberOfSections(WORD numberOfSections); void removeIatDirectory(); bool getFileOverlay(); }; diff --git a/Scylla/Scylla.h b/Scylla/Scylla.h index fe39f06..2e6a862 100644 --- a/Scylla/Scylla.h +++ b/Scylla/Scylla.h @@ -1,31 +1,31 @@ #pragma once #include "ConfigurationHolder.h" #include "PluginLoader.h" #include "ProcessLister.h" #include "Logger.h" #define APPNAME_S "Scylla" -#define APPVERSION_S "v0.7 Beta 1" +#define APPVERSION_S "v0.7 Beta 2" #define APPNAME TEXT(APPNAME_S) #define APPVERSION TEXT(APPVERSION_S) class Scylla { public: static void init(); static ConfigurationHolder config; static PluginLoader plugins; static ProcessLister processLister; static FileLog debugLog; static ListboxLog windowLog; private: static const WCHAR DEBUG_LOG_FILENAME[]; }; diff --git a/Scylla/resource.h b/Scylla/resource.h index 09a2ab4..dd0cdbb 100644 Binary files a/Scylla/resource.h and b/Scylla/resource.h differ