diff --git a/Scylla/DisassemblerGui.cpp b/Scylla/DisassemblerGui.cpp index 4b9257b..1365699 100644 --- a/Scylla/DisassemblerGui.cpp +++ b/Scylla/DisassemblerGui.cpp @@ -1,385 +1,481 @@ #include "DisassemblerGui.h" - +#include #include "ProcessAccessHelp.h" #include "Architecture.h" +#include +#pragma comment(lib, "Psapi.lib") -DisassemblerGui::DisassemblerGui(DWORD_PTR startAddress) +DisassemblerGui::DisassemblerGui(DWORD_PTR startAddress, ApiReader * apiReaderObject) { + apiReader = apiReaderObject; addressHistoryIndex = 0; addressHistory.push_back(startAddress); hMenuDisassembler.LoadMenu(IDR_MENU_DISASSEMBLER); + + initAddressCommentList(); } BOOL DisassemblerGui::OnInitDialog(CWindow wndFocus, LPARAM lInitParam) { DoDataExchange(); // attach controls DlgResize_Init(true, true); addColumnsToDisassembler(ListDisassembler); displayDisassembly(); 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) { 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) { if (addressHistoryIndex != 0) { 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(addressHistory[addressHistoryIndex], sizeof(data), data)) return false; if (!ProcessAccessHelp::decomposeMemory(data, sizeof(data), addressHistory[addressHistoryIndex])) return false; 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, 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) { 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) { + #ifdef _WIN64 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 } -#endif - - if (ProcessAccessHelp::decomposerResult[index].ops[0].type == O_PC) + else 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) + else 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); + address = 0; if(ProcessAccessHelp::readMemoryFromProcess(addressTemp, sizeof(DWORD_PTR), &address)) { swprintf_s(tempBuffer,L"%s -> "PRINTF_DWORD_PTR_FULL,tempBuffer,address); - return true; } } } + } + + if (address != 0) + { + analyzeAddress(address, tempBuffer); + return true; + } + else + { + return false; + } +} + +void DisassemblerGui::initAddressCommentList() +{ + HMODULE * hMods = 0; + HMODULE hModResult = 0; + WCHAR target[MAX_PATH]; + + DWORD numHandles = ProcessAccessHelp::getModuleHandlesFromProcess(ProcessAccessHelp::hProcess, &hMods); + if (numHandles == 0) + { + return; + } + + for (DWORD i = 0; i < numHandles; i++) + { + if (ProcessAccessHelp::targetImageBase != (DWORD_PTR)hMods[i]) + { + if (GetModuleFileNameExW(ProcessAccessHelp::hProcess, hMods[i], target, _countof(target))) + { + addModuleAddressCommentEntry((DWORD_PTR)hMods[i], (DWORD)ProcessAccessHelp::getSizeOfImageProcess(ProcessAccessHelp::hProcess, (DWORD_PTR)hMods[i]), target); + } + else + { +#ifdef DEBUG_COMMENTS + Scylla::debugLog.log(L"DllInjection::getModuleHandle :: GetModuleFileNameExW failed 0x%X", GetLastError()); +#endif + } + } + } + + std::sort(addressCommentList.begin(), addressCommentList.end()); +} +void DisassemblerGui::addModuleAddressCommentEntry( DWORD_PTR address, DWORD moduleSize, const WCHAR * modulePath ) +{ + DisassemblerAddressComment commentObj; + //get filename + const WCHAR* slash = wcsrchr(modulePath, L'\\'); + if(slash) + { + modulePath = slash+1; } - return false; + wcscpy_s(commentObj.comment, _countof(commentObj.comment), modulePath); + commentObj.address = address; + commentObj.type = ADDRESS_TYPE_MODULE; + commentObj.moduleSize = moduleSize; + + addressCommentList.push_back(commentObj); +} + +void DisassemblerGui::analyzeAddress( DWORD_PTR address, WCHAR * comment ) +{ + if (addressCommentList[0].address > address) //list is sorted, TODO: binary search + { + return; + } + bool isSuspect; + ApiInfo * api = apiReader->getApiByVirtualAddress(address, &isSuspect); + + if (api != 0 && api != (ApiInfo *)1) + { + if (api->name[0] == 0) + { + swprintf_s(tempBuffer,L"%s = %s.%04X", comment, api->module->getFilename(), api->ordinal); + } + else + { + swprintf_s(tempBuffer,L"%s = %s.%S", comment, api->module->getFilename(), api->name); + } + } + else + { + for (size_t i = 0; i < addressCommentList.size(); i++) + { + if (addressCommentList[i].type == ADDRESS_TYPE_MODULE) + { + if (address >= addressCommentList[i].address && address < (addressCommentList[i].address + addressCommentList[i].moduleSize)) + { + swprintf_s(tempBuffer,L"%s = %s", comment, addressCommentList[i].comment); + return; + } + } + } + } + + } diff --git a/Scylla/DisassemblerGui.h b/Scylla/DisassemblerGui.h index a789605..17bd15e 100644 --- a/Scylla/DisassemblerGui.h +++ b/Scylla/DisassemblerGui.h @@ -1,111 +1,134 @@ #pragma once #include #include "resource.h" // WTL #include // base ATL classes #include // base WTL classes #include // ATL GUI classes #include // WTL window frame helpers #include // WTL utility classes like CString #include // WTL enhanced msg map macros #include // WTL controls #include // WTL dialog data exchange #include #include "hexedit.h" +#include "ApiReader.h" + +enum DisassemblerAddressType { + ADDRESS_TYPE_MODULE, + ADDRESS_TYPE_API, + ADDRESS_TYPE_SPECIAL +}; + +class DisassemblerAddressComment +{ +public: + DWORD_PTR address; + WCHAR comment[MAX_PATH]; + DisassemblerAddressType type; + DWORD moduleSize; + + bool operator<(DisassemblerAddressComment rhs) { return address < rhs.address; } +}; + class DisassemblerGui : public CDialogImpl, public CWinDataExchange, public CDialogResize { public: enum { IDD = IDD_DLG_DISASSEMBLER }; BEGIN_DDX_MAP(DisassemblerGui) DDX_CONTROL_HANDLE(IDC_LIST_DISASSEMBLER, ListDisassembler) DDX_CONTROL(IDC_EDIT_ADDRESS_DISASSEMBLE, EditAddress) END_DDX_MAP() BEGIN_MSG_MAP(DisassemblerGui) MSG_WM_INITDIALOG(OnInitDialog) MSG_WM_CONTEXTMENU(OnContextMenu) NOTIFY_HANDLER_EX(IDC_LIST_DISASSEMBLER, NM_CUSTOMDRAW, OnNMCustomdraw) COMMAND_ID_HANDLER_EX(IDC_BUTTON_DISASSEMBLE, OnDisassemble) COMMAND_ID_HANDLER_EX(IDC_BUTTON_DISASSEMBLER_BACK, OnDisassembleBack) COMMAND_ID_HANDLER_EX(IDC_BUTTON_DISASSEMBLER_FORWARD, OnDisassembleForward) COMMAND_ID_HANDLER_EX(IDCANCEL, OnExit) COMMAND_ID_HANDLER_EX(IDOK, OnExit) CHAIN_MSG_MAP(CDialogResize) END_MSG_MAP() BEGIN_DLGRESIZE_MAP(DisassemblerGui) DLGRESIZE_CONTROL(IDC_LIST_DISASSEMBLER, DLSZ_SIZE_X | DLSZ_SIZE_Y) DLGRESIZE_CONTROL(IDC_BUTTON_DISASSEMBLE, DLSZ_MOVE_X | DLSZ_MOVE_Y) DLGRESIZE_CONTROL(IDC_BUTTON_DISASSEMBLER_BACK, DLSZ_MOVE_X | DLSZ_MOVE_Y) DLGRESIZE_CONTROL(IDC_BUTTON_DISASSEMBLER_FORWARD, DLSZ_MOVE_X | DLSZ_MOVE_Y) DLGRESIZE_CONTROL(IDC_EDIT_ADDRESS_DISASSEMBLE, DLSZ_MOVE_Y) DLGRESIZE_CONTROL(IDC_STATIC_ADDRESS_DISASSEMBLE, DLSZ_MOVE_Y) END_DLGRESIZE_MAP() - DisassemblerGui(DWORD_PTR startAddress); + DisassemblerGui(DWORD_PTR startAddress, ApiReader * apiReaderObject); protected: // Variables static const size_t DISASSEMBLER_GUI_MEMORY_SIZE = 0x120; WCHAR tempBuffer[100]; int addressHistoryIndex; std::vector addressHistory; + std::vector addressCommentList; + // Controls CListViewCtrl ListDisassembler; CHexEdit EditAddress; enum DisassemblerColumns { COL_ADDRESS = 0, COL_INSTRUCTION_SIZE, COL_OPCODES, COL_INSTRUCTION, COL_COMMENT }; // Handles CMenu hMenuDisassembler; -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: + ApiReader * apiReader; BYTE data[DISASSEMBLER_GUI_MEMORY_SIZE]; void toUpperCase(WCHAR * lowercase); void doColorInstruction( LPNMLVCUSTOMDRAW lpLVCustomDraw, DWORD_PTR itemIndex ); void followInstruction(int index); bool getDisassemblyComment(unsigned int index); void disassembleNewAddress(DWORD_PTR address); + void initAddressCommentList(); + void addModuleAddressCommentEntry( DWORD_PTR address, DWORD moduleSize, const WCHAR * modulePath ); + void analyzeAddress( DWORD_PTR address, WCHAR * comment ); }; diff --git a/Scylla/DllInjection.cpp b/Scylla/DllInjection.cpp index c8f5fed..422d97c 100644 --- a/Scylla/DllInjection.cpp +++ b/Scylla/DllInjection.cpp @@ -1,246 +1,225 @@ #include "DllInjection.h" #include #include "Scylla.h" #include "NativeWinApi.h" +#include "ProcessAccessHelp.h" + +#pragma comment(lib, "Psapi.lib") //#define DEBUG_COMMENTS HMODULE DllInjection::dllInjection(HANDLE hProcess, const WCHAR * filename) { LPVOID remoteMemory = 0; SIZE_T memorySize = 0; HANDLE hThread = 0; HMODULE hModule = 0; memorySize = (wcslen(filename) + 1) * sizeof(WCHAR); if (memorySize < 7) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"dllInjection :: memorySize invalid"); #endif return 0; } remoteMemory = VirtualAllocEx(hProcess, NULL, memorySize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); if (remoteMemory == 0) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"dllInjection :: VirtualAllocEx failed 0x%X", GetLastError()); #endif return 0; } if (WriteProcessMemory(hProcess, remoteMemory, filename, memorySize, &memorySize)) { hThread = startRemoteThread(hProcess,LoadLibraryW,remoteMemory); if (hThread) { WaitForSingleObject(hThread, INFINITE); #ifdef _WIN64 hModule = getModuleHandleByFilename(hProcess, filename); #else //returns only 32 bit values -> design bug by microsoft if (!GetExitCodeThread(hThread, (LPDWORD) &hModule)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"dllInjection :: GetExitCodeThread failed 0x%X", GetLastError()); #endif hModule = 0; } #endif CloseHandle(hThread); } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"dllInjection :: CreateRemoteThread failed 0x%X", GetLastError()); #endif } } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"dllInjection :: WriteProcessMemory failed 0x%X", GetLastError()); #endif } VirtualFreeEx(hProcess, remoteMemory, 0, MEM_RELEASE); return hModule; } bool DllInjection::unloadDllInProcess(HANDLE hProcess, HMODULE hModule) { HANDLE hThread = 0; DWORD lpThreadId = 0; BOOL freeLibraryRet = 0; hThread = startRemoteThread(hProcess,FreeLibrary,hModule); if (hThread) { WaitForSingleObject(hThread, INFINITE); if (!GetExitCodeThread(hThread, (LPDWORD) &freeLibraryRet)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"unloadDllInProcess :: GetExitCodeThread failed 0x%X", GetLastError()); #endif freeLibraryRet = 0; } CloseHandle(hThread); } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"unloadDllInProcess :: CreateRemoteThread failed 0x%X", GetLastError()); #endif } return freeLibraryRet != 0; } HMODULE DllInjection::getModuleHandleByFilename( HANDLE hProcess, const WCHAR * filename ) { HMODULE * hMods = 0; HMODULE hModResult = 0; - DWORD count = 0; WCHAR target[MAX_PATH]; - DWORD cbNeeded = 0; - bool notEnough = true; - - count = 100; - hMods = new HMODULE[count]; - do + DWORD numHandles = ProcessAccessHelp::getModuleHandlesFromProcess(hProcess, &hMods); + if (numHandles == 0) { - if (!EnumProcessModules(hProcess, hMods, count * sizeof(HMODULE), &cbNeeded)) - { -#ifdef DEBUG_COMMENTS - Scylla::debugLog.log(L"DllInjection::getModuleHandle :: EnumProcessModules failed count %d", count); -#endif - delete [] hMods; - return 0; - } - - if ( (count * sizeof(HMODULE)) < cbNeeded ) - { - delete [] hMods; - count += 100; - hMods = new HMODULE[count]; - } - else - { - notEnough = false; - } - } while (notEnough); - + return 0; + } - for (DWORD i = 0; i < (cbNeeded / sizeof(HMODULE)); i++ ) + for (DWORD i = 0; i < numHandles; i++) { if (GetModuleFileNameExW(hProcess, hMods[i], target, _countof(target))) { - if (!_wcsicmp(target,filename)) + if (!_wcsicmp(target, filename)) { hModResult = hMods[i]; break; } } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"DllInjection::getModuleHandle :: GetModuleFileNameExW failed 0x%X", GetLastError()); #endif } } if (!hModResult) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"DllInjection::getModuleHandle :: Handle not found"); #endif } delete [] hMods; return hModResult; } void DllInjection::specialThreadSettings( HANDLE hThread ) { if (hThread) { if (!SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"specialThreadSettings :: SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL) failed 0x%X", GetLastError()); #endif } if (NativeWinApi::NtSetInformationThread) { if (NativeWinApi::NtSetInformationThread(hThread, ThreadHideFromDebugger, 0, 0) != STATUS_SUCCESS) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"specialThreadSettings :: NtSetInformationThread ThreadHideFromDebugger failed"); #endif } } } } HANDLE DllInjection::startRemoteThread(HANDLE hProcess, LPVOID lpStartAddress, LPVOID lpParameter) { HANDLE hThread = 0; hThread = customCreateRemoteThread(hProcess, lpStartAddress, lpParameter); if (hThread) { specialThreadSettings(hThread); ResumeThread(hThread); } return hThread; } HANDLE DllInjection::customCreateRemoteThread(HANDLE hProcess, LPVOID lpStartAddress, LPVOID lpParameter) { DWORD lpThreadId = 0; HANDLE hThread = 0; NTSTATUS ntStatus = 0; if (NativeWinApi::NtCreateThreadEx) { #define THREAD_ALL_ACCESS_VISTA_7 (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFFF) //for windows vista/7 ntStatus = NativeWinApi::NtCreateThreadEx(&hThread, THREAD_ALL_ACCESS_VISTA_7, 0, hProcess, (LPTHREAD_START_ROUTINE)lpStartAddress, (LPVOID)lpParameter, TRUE, 0, 0, 0, 0); if (NT_SUCCESS(ntStatus)) { return hThread; } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"customCreateRemoteThread :: NtCreateThreadEx failed 0x%X", NativeWinApi::RtlNtStatusToDosError(ntStatus)); #endif return 0; } } else { return CreateRemoteThread(hProcess,NULL,NULL,(LPTHREAD_START_ROUTINE)lpStartAddress,lpParameter,CREATE_SUSPENDED,&lpThreadId); } } diff --git a/Scylla/DumpMemoryGui.cpp b/Scylla/DumpMemoryGui.cpp index 39c8647..a05893b 100644 --- a/Scylla/DumpMemoryGui.cpp +++ b/Scylla/DumpMemoryGui.cpp @@ -1,573 +1,548 @@ #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; } memoryList.clear(); } 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 + DWORD numHandles = ProcessAccessHelp::getModuleHandlesFromProcess(ProcessAccessHelp::hProcess, &hMods); + if (numHandles == 0) { - 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); + return; + } - for (DWORD i = 0; i < (cbNeeded / sizeof(HMODULE)); i++ ) + for (DWORD i = 0; i < numHandles; 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, _countof(iter->peSection), sectionName); } else { wcscat_s((WCHAR *)iter->peSection, _countof(iter->peSection), L"|"); wcscat_s((WCHAR *)iter->peSection, _countof(iter->peSection), sectionName); } found = true; } } else { if ((sectionSize+sectionAddress) < iter->address) { break; } if (wcslen(iter->peSection) == 0) { wcscpy_s((WCHAR *)iter->peSection, _countof(iter->peSection), sectionName); } else { wcscat_s((WCHAR *)iter->peSection, _countof(iter->peSection), L"|"); wcscat_s((WCHAR *)iter->peSection, _countof(iter->peSection), 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(); for (WORD i = 0; i < peFile.getNumberOfSections(); i++) { peFile.getSectionNameUnicode(i, sectionNameW, _countof(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/MainGui.cpp b/Scylla/MainGui.cpp index 0c00987..6011d8e 100644 --- a/Scylla/MainGui.cpp +++ b/Scylla/MainGui.cpp @@ -1,1395 +1,1395 @@ #include "MainGui.h" #include "Architecture.h" //#include "PluginLoader.h" //#include "ConfigurationHolder.h" #include "PeParser.h" #include "DllInjectionPlugin.h" #include "DisassemblerGui.h" #include "PickApiGui.h" //#include "NativeWinApi.h" #include "ImportRebuilder.h" #include "SystemInformation.h" #include "Scylla.h" #include "AboutGui.h" #include "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::OnDisassembler(UINT uNotifyCode, int nID, CWindow wndCtl) { disassemblerActionHandler(); } void MainGui::OnIATAutoSearch(UINT uNotifyCode, int nID, CWindow wndCtl) { iatAutosearchActionHandler(); } void MainGui::OnGetImports(UINT uNotifyCode, int nID, CWindow wndCtl) { getImportsActionHandler(); } void MainGui::OnInvalidImports(UINT uNotifyCode, int nID, CWindow wndCtl) { showInvalidImportsActionHandler(); } void MainGui::OnSuspectImports(UINT uNotifyCode, int nID, CWindow wndCtl) { showSuspectImportsActionHandler(); } void MainGui::OnClearImports(UINT uNotifyCode, int nID, CWindow wndCtl) { clearImportsActionHandler(); } void MainGui::OnInvalidateSelected(UINT uNotifyCode, int nID, CWindow wndCtl) { invalidateSelectedImportsActionHandler(); } void MainGui::OnCutSelected(UINT uNotifyCode, int nID, CWindow wndCtl) { deleteSelectedImportsActionHandler(); } void MainGui::OnSaveTree(UINT uNotifyCode, int nID, CWindow wndCtl) { saveTreeActionHandler(); } void MainGui::OnLoadTree(UINT uNotifyCode, int nID, CWindow wndCtl) { loadTreeActionHandler(); } void MainGui::OnAutotrace(UINT uNotifyCode, int nID, CWindow wndCtl) { // TODO } void MainGui::OnExit(UINT uNotifyCode, int nID, CWindow wndCtl) { 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); + DisassemblerGui dlgDisassembler(address, &apiReader); dlgDisassembler.DoModal(); } } } void MainGui::processSelectedActionHandler(int index) { std::vector& processList = Scylla::processLister.getProcessList(); Process &process = processList.at(index); selectedProcess = 0; clearImportsActionHandler(); Scylla::windowLog.log(L"Analyzing %s", process.fullPath); if (ProcessAccessHelp::hProcess != 0) { ProcessAccessHelp::closeProcessHandle(); apiReader.clearAll(); } if (!ProcessAccessHelp::openProcessHandle(process.PID)) { enableDialogControls(FALSE); Scylla::windowLog.log(L"Error: Cannot open process handle."); updateStatusBar(); return; } ProcessAccessHelp::getProcessModules(process.PID, ProcessAccessHelp::moduleList); apiReader.readApisFromModuleList(); Scylla::windowLog.log(L"Loading modules done."); //TODO improve ProcessAccessHelp::selectedModule = 0; ProcessAccessHelp::targetSizeOfImage = process.imageSize; ProcessAccessHelp::targetImageBase = process.imageBase; ProcessAccessHelp::getSizeOfImageCurrentProcess(); process.imageSize = (DWORD)ProcessAccessHelp::targetSizeOfImage; Scylla::windowLog.log(L"Imagebase: " PRINTF_DWORD_PTR_FULL L" Size: %08X", process.imageBase, process.imageSize); process.entryPoint = ProcessAccessHelp::getEntryPointFromFile(process.fullPath); EditOEPAddress.SetValue(process.entryPoint + process.imageBase); selectedProcess = &process; enableDialogControls(TRUE); updateStatusBar(); } void MainGui::fillProcessListComboBox(CComboBox& hCombo) { hCombo.ResetContent(); std::vector& processList = Scylla::processLister.getProcessListSnapshot(); for (size_t i = 0; i < processList.size(); i++) { swprintf_s(stringBuffer, L"0x%04X - %s - %s", processList[i].PID, processList[i].filename, processList[i].fullPath); hCombo.AddString(stringBuffer); } } /* void MainGui::addTextToOutputLog(const WCHAR * text) { if (m_hWnd) { ListLog.SetCurSel(ListLog.AddString(text)); } } */ void MainGui::clearOutputLog() { if (m_hWnd) { ListLog.ResetContent(); } } bool MainGui::saveLogToFile(const WCHAR * file) { const BYTE BOM[] = {0xFF, 0xFE}; // UTF-16 little-endian const WCHAR newLine[] = L"\r\n"; bool success = true; HANDLE hFile = CreateFile(file, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); if(hFile != INVALID_HANDLE_VALUE) { ProcessAccessHelp::writeMemoryToFileEnd(hFile, sizeof(BOM), BOM); WCHAR * buffer = 0; size_t bufsize = 0; for(int i = 0; i < ListLog.GetCount(); i++) { size_t size = ListLog.GetTextLen(i); size += _countof(newLine)-1; if(size+1 > bufsize) { bufsize = size+1; delete[] buffer; try { buffer = new WCHAR[bufsize]; } catch(std::bad_alloc&) { buffer = 0; success = false; break; } } ListLog.GetText(i, buffer); wcscat_s(buffer, bufsize, newLine); ProcessAccessHelp::writeMemoryToFileEnd(hFile, (DWORD)(size * sizeof(WCHAR)), buffer); } delete[] buffer; CloseHandle(hFile); } return success; } void MainGui::showInvalidImportsActionHandler() { importsHandling.selectImports(true, false); GotoDlgCtrl(TreeImports); } void MainGui::showSuspectImportsActionHandler() { importsHandling.selectImports(false, true); GotoDlgCtrl(TreeImports); } void MainGui::deleteSelectedImportsActionHandler() { CTreeItem selected = TreeImports.GetFirstSelectedItem(); while(!selected.IsNull()) { if(importsHandling.isModule(selected)) { importsHandling.cutModule(selected); } else { importsHandling.cutImport(selected); } selected = TreeImports.GetNextSelectedItem(selected); } updateStatusBar(); } void MainGui::invalidateSelectedImportsActionHandler() { CTreeItem selected = TreeImports.GetFirstSelectedItem(); while(!selected.IsNull()) { if(importsHandling.isImport(selected)) { importsHandling.invalidateImport(selected); } selected = TreeImports.GetNextSelectedItem(selected); } updateStatusBar(); } void MainGui::loadTreeActionHandler() { if(!selectedProcess) return; WCHAR selectedFilePath[MAX_PATH]; getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if(showFileDialog(selectedFilePath, false, NULL, filterXml, NULL, stringBuffer)) { TreeImportExport treeIO(selectedFilePath); DWORD_PTR addrOEP = 0; DWORD_PTR addrIAT = 0; DWORD sizeIAT = 0; if(!treeIO.importTreeList(importsHandling.moduleList, &addrOEP, &addrIAT, &sizeIAT)) { Scylla::windowLog.log(L"Loading tree file failed %s", selectedFilePath); MessageBox(L"Loading tree file failed.", L"Failure", MB_ICONERROR); } else { EditOEPAddress.SetValue(addrOEP); EditIATAddress.SetValue(addrIAT); EditIATSize.SetValue(sizeIAT); importsHandling.displayAllImports(); updateStatusBar(); Scylla::windowLog.log(L"Loaded tree file %s", selectedFilePath); Scylla::windowLog.log(L"-> OEP: " PRINTF_DWORD_PTR_FULL, addrOEP); Scylla::windowLog.log(L"-> IAT: " PRINTF_DWORD_PTR_FULL L" Size: " PRINTF_DWORD_PTR, addrIAT, sizeIAT); } } } void MainGui::saveTreeActionHandler() { if(!selectedProcess) return; WCHAR selectedFilePath[MAX_PATH]; getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if(showFileDialog(selectedFilePath, true, NULL, filterXml, L"xml", stringBuffer)) { TreeImportExport treeIO(selectedFilePath); DWORD_PTR addrOEP = EditOEPAddress.GetValue(); DWORD_PTR addrIAT = EditIATAddress.GetValue(); DWORD sizeIAT = EditIATSize.GetValue(); if(!treeIO.exportTreeList(importsHandling.moduleList, selectedProcess, addrOEP, addrIAT, sizeIAT)) { Scylla::windowLog.log(L"Saving tree file failed %s", selectedFilePath); MessageBox(L"Saving tree file failed.", L"Failure", MB_ICONERROR); } else { Scylla::windowLog.log(L"Saved tree file %s", selectedFilePath); } } } void MainGui::iatAutosearchActionHandler() { DWORD_PTR searchAddress = 0; DWORD_PTR addressIAT = 0; DWORD sizeIAT = 0; IATSearch iatSearch; if(!selectedProcess) return; if(EditOEPAddress.GetWindowTextLength() > 0) { searchAddress = EditOEPAddress.GetValue(); if (searchAddress) { if (iatSearch.searchImportAddressTableInProcess(searchAddress, &addressIAT, &sizeIAT)) { Scylla::windowLog.log(L"IAT found at VA " PRINTF_DWORD_PTR_FULL L" RVA " PRINTF_DWORD_PTR_FULL L" Size 0x%04X (%d)", addressIAT, addressIAT - ProcessAccessHelp::targetImageBase, sizeIAT, sizeIAT); EditIATAddress.SetValue(addressIAT); EditIATSize.SetValue(sizeIAT); swprintf_s(stringBuffer, L"IAT found:\r\n\r\nStart: " PRINTF_DWORD_PTR_FULL L"\r\nSize: 0x%04X (%d) ", addressIAT, sizeIAT, sizeIAT); MessageBox(stringBuffer, L"IAT found", MB_ICONINFORMATION); } else { Scylla::windowLog.log(L"IAT not found at OEP " PRINTF_DWORD_PTR_FULL L"!", searchAddress); } } } } void MainGui::getImportsActionHandler() { if(!selectedProcess) return; DWORD_PTR addressIAT = EditIATAddress.GetValue(); DWORD sizeIAT = EditIATSize.GetValue(); if (addressIAT && sizeIAT) { apiReader.readAndParseIAT(addressIAT, sizeIAT, importsHandling.moduleList); importsHandling.displayAllImports(); updateStatusBar(); } } void MainGui::SetupImportsMenuItems(CTreeItem item) { bool isItem, isImport = false; isItem = !item.IsNull(); if(isItem) { isImport = importsHandling.isImport(item); } CMenuHandle hSub = hMenuImports.GetSubMenu(0); UINT itemOnly = isItem ? MF_ENABLED : MF_GRAYED; UINT importOnly = isImport ? MF_ENABLED : MF_GRAYED; hSub.EnableMenuItem(ID__INVALIDATE, itemOnly); hSub.EnableMenuItem(ID__DISASSEMBLE, importOnly); hSub.EnableMenuItem(ID__CUTTHUNK, importOnly); hSub.EnableMenuItem(ID__DELETETREENODE, itemOnly); } void MainGui::DisplayContextMenuImports(CWindow hwnd, CPoint pt) { if(TreeImports.GetCount() < 1) return; CTreeItem over, parent; if(pt.x == -1 && pt.y == -1) // invoked by keyboard { CRect pos; over = TreeImports.GetFocusItem(); if(over) { over.EnsureVisible(); over.GetRect(&pos, TRUE); TreeImports.ClientToScreen(&pos); } else { TreeImports.GetWindowRect(&pos); } pt = pos.TopLeft(); } else { // Get item under cursor over = findTreeItem(pt, true); } SetupImportsMenuItems(over); CMenuHandle hSub = hMenuImports.GetSubMenu(0); BOOL menuItem = hSub.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD, pt.x, pt.y, hwnd); if (menuItem) { if ((menuItem >= PLUGIN_MENU_BASE_ID) && (menuItem <= (int)(Scylla::plugins.getScyllaPluginList().size() + Scylla::plugins.getImprecPluginList().size() + PLUGIN_MENU_BASE_ID))) { //wsprintf(stringBuffer, L"%d %s\n",menuItem,pluginList[menuItem - PLUGIN_MENU_BASE_ID].pluginName); //MessageBox(stringBuffer, L"plugin selection"); pluginActionHandler(menuItem); return; } switch (menuItem) { case ID__INVALIDATE: if(importsHandling.isModule(over)) importsHandling.invalidateModule(over); else importsHandling.invalidateImport(over); break; case ID__DISASSEMBLE: startDisassemblerGui(over); break; case ID__EXPANDALLNODES: importsHandling.expandAllTreeNodes(); break; case ID__COLLAPSEALLNODES: importsHandling.collapseAllTreeNodes(); break; case ID__CUTTHUNK: importsHandling.cutImport(over); break; case ID__DELETETREENODE: importsHandling.cutModule(importsHandling.isImport(over) ? over.GetParent() : over); break; } } updateStatusBar(); } void MainGui::DisplayContextMenuLog(CWindow hwnd, CPoint pt) { if(pt.x == -1 && pt.y == -1) // invoked by keyboard { CRect pos; ListLog.GetWindowRect(&pos); pt = pos.TopLeft(); } CMenuHandle hSub = hMenuLog.GetSubMenu(0); BOOL menuItem = hSub.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD, pt.x, pt.y, hwnd); if (menuItem) { switch (menuItem) { case ID__SAVE: WCHAR selectedFilePath[MAX_PATH]; getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if(showFileDialog(selectedFilePath, true, NULL, filterTxt, L"txt", stringBuffer)) { saveLogToFile(selectedFilePath); } break; case ID__CLEAR: clearOutputLog(); break; } } } void MainGui::appendPluginListToMenu(CMenuHandle hMenu) { std::vector &scyllaPluginList = Scylla::plugins.getScyllaPluginList(); std::vector &imprecPluginList = Scylla::plugins.getImprecPluginList(); if (scyllaPluginList.size() > 0) { CMenuHandle newMenu; newMenu.CreatePopupMenu(); for (size_t i = 0; i < scyllaPluginList.size(); i++) { newMenu.AppendMenu(MF_STRING, i + PLUGIN_MENU_BASE_ID, scyllaPluginList[i].pluginName); } hMenu.AppendMenu(MF_MENUBARBREAK); hMenu.AppendMenu(MF_POPUP, newMenu, L"Scylla Plugins"); } if (imprecPluginList.size() > 0) { CMenuHandle newMenu; newMenu.CreatePopupMenu(); for (size_t i = 0; i < imprecPluginList.size(); i++) { newMenu.AppendMenu(MF_STRING, scyllaPluginList.size() + i + PLUGIN_MENU_BASE_ID, imprecPluginList[i].pluginName); } hMenu.AppendMenu(MF_MENUBARBREAK); hMenu.AppendMenu(MF_POPUP, newMenu, L"ImpREC Plugins"); } } void MainGui::dumpMemoryActionHandler() { WCHAR selectedFilePath[MAX_PATH]; DumpMemoryGui dlgDumpMemory; if(dlgDumpMemory.DoModal()) { getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if(showFileDialog(selectedFilePath, true, dlgDumpMemory.dumpFilename, filterMem, L"mem", stringBuffer)) { if (ProcessAccessHelp::writeMemoryToNewFile(selectedFilePath,dlgDumpMemory.dumpedMemorySize,dlgDumpMemory.dumpedMemory)) { Scylla::windowLog.log(L"Memory dump saved %s", selectedFilePath); } else { Scylla::windowLog.log(L"Error! Cannot write memory dump to disk"); } } } } void MainGui::dumpSectionActionHandler() { WCHAR selectedFilePath[MAX_PATH]; DumpSectionGui dlgDumpSection; const WCHAR * fileFilter; const WCHAR * defExtension; PeParser * peFile = 0; dlgDumpSection.entryPoint = EditOEPAddress.GetValue(); if (ProcessAccessHelp::selectedModule) { //dump DLL fileFilter = filterDll; defExtension = L"dll"; dlgDumpSection.imageBase = ProcessAccessHelp::selectedModule->modBaseAddr; //get it from gui wcscpy_s(dlgDumpSection.fullpath, ProcessAccessHelp::selectedModule->fullPath); } else { fileFilter = filterExe; defExtension = L"exe"; dlgDumpSection.imageBase = ProcessAccessHelp::targetImageBase; //get it from gui wcscpy_s(dlgDumpSection.fullpath, selectedProcess->fullPath); } if(dlgDumpSection.DoModal()) { getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if(showFileDialog(selectedFilePath, true, NULL, fileFilter, defExtension, stringBuffer)) { if (Scylla::config[USE_PE_HEADER_FROM_DISK].isTrue()) { peFile = new PeParser(dlgDumpSection.fullpath, true); } else { peFile = new PeParser(dlgDumpSection.imageBase, true); } std::vector & sectionList = dlgDumpSection.getSectionList(); if (peFile->dumpProcess(dlgDumpSection.imageBase, dlgDumpSection.entryPoint, selectedFilePath, sectionList)) { Scylla::windowLog.log(L"Dump success %s", selectedFilePath); } else { Scylla::windowLog.log(L"Error: Cannot dump image."); MessageBox(L"Cannot dump image.", L"Failure", MB_ICONERROR); } delete peFile; } } } void MainGui::dumpActionHandler() { if(!selectedProcess) return; WCHAR selectedFilePath[MAX_PATH]; const WCHAR * fileFilter; const WCHAR * defExtension; DWORD_PTR modBase = 0; DWORD_PTR entrypoint = 0; WCHAR * filename = 0; PeParser * peFile = 0; if (ProcessAccessHelp::selectedModule) { fileFilter = filterDll; defExtension = L"dll"; } else { fileFilter = filterExe; defExtension = L"exe"; } getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if(showFileDialog(selectedFilePath, true, NULL, fileFilter, defExtension, stringBuffer)) { entrypoint = EditOEPAddress.GetValue(); if (ProcessAccessHelp::selectedModule) { //dump DLL modBase = ProcessAccessHelp::selectedModule->modBaseAddr; filename = ProcessAccessHelp::selectedModule->fullPath; } else { //dump exe modBase = ProcessAccessHelp::targetImageBase; filename = selectedProcess->fullPath; } if (Scylla::config[USE_PE_HEADER_FROM_DISK].isTrue()) { peFile = new PeParser(filename, true); } else { peFile = new PeParser(modBase, true); } if (peFile->dumpProcess(modBase, entrypoint, selectedFilePath)) { Scylla::windowLog.log(L"Dump success %s", selectedFilePath); } else { Scylla::windowLog.log(L"Error: Cannot dump image."); MessageBox(L"Cannot dump image.", L"Failure", MB_ICONERROR); } delete peFile; } } void MainGui::peRebuildActionHandler() { DWORD newSize = 0; WCHAR selectedFilePath[MAX_PATH]; getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if(showFileDialog(selectedFilePath, false, NULL, filterExeDll, NULL, stringBuffer)) { if (Scylla::config[CREATE_BACKUP].isTrue()) { if (!ProcessAccessHelp::createBackupFile(selectedFilePath)) { Scylla::windowLog.log(L"Creating backup file failed %s", selectedFilePath); } } DWORD fileSize = (DWORD)ProcessAccessHelp::getFileSize(selectedFilePath); PeParser peFile(selectedFilePath, true); if (peFile.readPeSectionsFromFile()) { peFile.setDefaultFileAlignment(); if (Scylla::config[REMOVE_DOS_HEADER_STUB].isTrue()) { peFile.removeDosStub(); } peFile.alignAllSectionHeaders(); peFile.fixPeHeader(); if (peFile.savePeFileToDisk(selectedFilePath)) { newSize = (DWORD)ProcessAccessHelp::getFileSize(selectedFilePath); if (Scylla::config[UPDATE_HEADER_CHECKSUM].isTrue()) { Scylla::windowLog.log(L"Generating PE header checksum"); if (!PeParser::updatePeHeaderChecksum(selectedFilePath, newSize)) { Scylla::windowLog.log(L"Generating PE header checksum FAILED!"); } } Scylla::windowLog.log(L"Rebuild success %s", selectedFilePath); Scylla::windowLog.log(L"-> Old file size 0x%08X new file size 0x%08X (%d %%)", fileSize, newSize, ((newSize * 100) / fileSize) ); } else { Scylla::windowLog.log(L"Rebuild failed, cannot save file %s", selectedFilePath); MessageBox(L"Rebuild failed. Cannot save file.", L"Failure", MB_ICONERROR); } } else { Scylla::windowLog.log(L"Rebuild failed, cannot read file %s", selectedFilePath); MessageBox(L"Rebuild failed. Cannot read file.", L"Failure", MB_ICONERROR); } } } void MainGui::dumpFixActionHandler() { if(!selectedProcess) return; if (TreeImports.GetCount() < 2) { Scylla::windowLog.log(L"Nothing to rebuild"); return; } WCHAR newFilePath[MAX_PATH]; WCHAR selectedFilePath[MAX_PATH]; const WCHAR * fileFilter; DWORD_PTR modBase = 0; DWORD_PTR entrypoint = EditOEPAddress.GetValue(); if (ProcessAccessHelp::selectedModule) { modBase = ProcessAccessHelp::selectedModule->modBaseAddr; fileFilter = filterDll; } else { modBase = ProcessAccessHelp::targetImageBase; fileFilter = filterExe; } getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if (showFileDialog(selectedFilePath, false, NULL, fileFilter, NULL, stringBuffer)) { wcscpy_s(newFilePath, selectedFilePath); const WCHAR * extension = 0; WCHAR* dot = wcsrchr(newFilePath, L'.'); if (dot) { *dot = L'\0'; extension = selectedFilePath + (dot - newFilePath); //wcsrchr(selectedFilePath, L'.'); } wcscat_s(newFilePath, L"_SCY"); if(extension) { wcscat_s(newFilePath, extension); } ImportRebuilder importRebuild(selectedFilePath); if (Scylla::config[IAT_FIX_AND_OEP_FIX].isTrue()) { importRebuild.setEntryPointRva((DWORD)(entrypoint - modBase)); } if (importRebuild.rebuildImportTable(newFilePath, importsHandling.moduleList)) { Scylla::windowLog.log(L"Import Rebuild success %s", newFilePath); } else { Scylla::windowLog.log(L"Import Rebuild failed %s", selectedFilePath); MessageBox(L"Import Rebuild failed", L"Failure", MB_ICONERROR); } } } void MainGui::enableDialogControls(BOOL value) { BOOL valButton = value ? TRUE : FALSE; GetDlgItem(IDC_BTN_PICKDLL).EnableWindow(valButton); GetDlgItem(IDC_BTN_DUMP).EnableWindow(valButton); GetDlgItem(IDC_BTN_FIXDUMP).EnableWindow(valButton); GetDlgItem(IDC_BTN_IATAUTOSEARCH).EnableWindow(valButton); GetDlgItem(IDC_BTN_GETIMPORTS).EnableWindow(valButton); GetDlgItem(IDC_BTN_SUSPECTIMPORTS).EnableWindow(valButton); GetDlgItem(IDC_BTN_INVALIDIMPORTS).EnableWindow(valButton); GetDlgItem(IDC_BTN_CLEARIMPORTS).EnableWindow(valButton); CMenuHandle menu = GetMenu(); UINT valMenu = value ? MF_ENABLED : MF_GRAYED; menu.EnableMenuItem(ID_FILE_DUMP, valMenu); menu.EnableMenuItem(ID_FILE_DUMPMEMORY, valMenu); menu.EnableMenuItem(ID_FILE_DUMPSECTION, valMenu); menu.EnableMenuItem(ID_FILE_FIXDUMP, valMenu); menu.EnableMenuItem(ID_IMPORTS_INVALIDATESELECTED, valMenu); menu.EnableMenuItem(ID_IMPORTS_CUTSELECTED, valMenu); menu.EnableMenuItem(ID_IMPORTS_SAVETREE, valMenu); menu.EnableMenuItem(ID_IMPORTS_LOADTREE, valMenu); menu.EnableMenuItem(ID_MISC_DLLINJECTION, valMenu); menu.EnableMenuItem(ID_MISC_DISASSEMBLER, valMenu); menu.GetSubMenu(MenuImportsOffsetTrace).EnableMenuItem(MenuImportsTraceOffsetScylla, MF_BYPOSITION | valMenu); menu.GetSubMenu(MenuImportsOffsetTrace).EnableMenuItem(MenuImportsTraceOffsetImpRec, MF_BYPOSITION | valMenu); //not yet implemented GetDlgItem(IDC_BTN_AUTOTRACE).EnableWindow(FALSE); menu.EnableMenuItem(ID_TRACE_AUTOTRACE, MF_GRAYED); } CTreeItem MainGui::findTreeItem(CPoint pt, bool screenCoordinates) { if(screenCoordinates) { TreeImports.ScreenToClient(&pt); } UINT flags; CTreeItem over = TreeImports.HitTest(pt, &flags); if(over) { if(!(flags & TVHT_ONITEM)) { over.m_hTreeItem = NULL; } } return over; } void MainGui::showAboutDialog() { AboutGui dlgAbout; dlgAbout.DoModal(); } void MainGui::dllInjectActionHandler() { if(!selectedProcess) return; WCHAR selectedFilePath[MAX_PATH]; HMODULE hMod = 0; DllInjection dllInjection; getCurrentModulePath(stringBuffer, _countof(stringBuffer)); if (showFileDialog(selectedFilePath, false, NULL, filterDll, NULL, stringBuffer)) { hMod = dllInjection.dllInjection(ProcessAccessHelp::hProcess, selectedFilePath); if (hMod && Scylla::config[DLL_INJECTION_AUTO_UNLOAD].isTrue()) { if (!dllInjection.unloadDllInProcess(ProcessAccessHelp::hProcess, hMod)) { Scylla::windowLog.log(L"DLL unloading failed, target %s", selectedFilePath); } } if (hMod) { Scylla::windowLog.log(L"DLL Injection was successful, target %s", selectedFilePath); } else { Scylla::windowLog.log(L"DLL Injection failed, target %s", selectedFilePath); } } } void MainGui::disassemblerActionHandler() { DWORD_PTR oep = EditOEPAddress.GetValue(); - DisassemblerGui disGuiDlg(oep); + DisassemblerGui disGuiDlg(oep, &apiReader); disGuiDlg.DoModal(); } void MainGui::optionsActionHandler() { OptionsGui dlgOptions; dlgOptions.DoModal(); } void MainGui::clearImportsActionHandler() { importsHandling.clearAllImports(); updateStatusBar(); } void MainGui::pluginActionHandler( int menuItem ) { if(!selectedProcess) return; DllInjectionPlugin dllInjectionPlugin; std::vector &scyllaPluginList = Scylla::plugins.getScyllaPluginList(); std::vector &imprecPluginList = Scylla::plugins.getImprecPluginList(); menuItem -= PLUGIN_MENU_BASE_ID; dllInjectionPlugin.hProcess = ProcessAccessHelp::hProcess; dllInjectionPlugin.apiReader = &apiReader; if (menuItem < (int)scyllaPluginList.size()) { //scylla plugin dllInjectionPlugin.injectPlugin(scyllaPluginList[menuItem], importsHandling.moduleList,selectedProcess->imageBase, selectedProcess->imageSize); } else { #ifndef _WIN64 menuItem -= (int)scyllaPluginList.size(); //imprec plugin dllInjectionPlugin.injectImprecPlugin(imprecPluginList[menuItem], importsHandling.moduleList,selectedProcess->imageBase, selectedProcess->imageSize); #endif } importsHandling.scanAndFixModuleList(); importsHandling.displayAllImports(); updateStatusBar(); } bool MainGui::getCurrentModulePath(WCHAR * buffer, size_t bufferSize) { if(!selectedProcess) return false; if(ProcessAccessHelp::selectedModule) { wcscpy_s(buffer, bufferSize, ProcessAccessHelp::selectedModule->fullPath); } else { wcscpy_s(buffer, bufferSize, selectedProcess->fullPath); } WCHAR * slash = wcsrchr(buffer, L'\\'); if(slash) { *(slash+1) = L'\0'; } return true; } diff --git a/Scylla/PeParser.cpp b/Scylla/PeParser.cpp index 39d57f7..b361022 100644 --- a/Scylla/PeParser.cpp +++ b/Scylla/PeParser.cpp @@ -1,1233 +1,1210 @@ #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) +bool PeParser::readSectionFromProcess(const DWORD_PTR readOffset, PeFileSection & peFileSection) +{ + return readSectionFrom(readOffset, peFileSection, true); //process +} + +bool PeParser::readSectionFromFile(const DWORD readOffset, PeFileSection & peFileSection) +{ + return readSectionFrom(readOffset, peFileSection, false); //file +} + +bool PeParser::readSectionFrom(const DWORD_PTR readOffset, PeFileSection & peFileSection, const bool isProcess) { const DWORD maxReadSize = 100; + DWORD currentReadSize; BYTE data[maxReadSize]; - DWORD bytesRead = 0; bool retValue = true; DWORD valuesFound = 0; - DWORD currentOffset = 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 readPeSectionFromFile(readOffset, peFileSection); + if (isProcess) + { + return readPeSectionFromProcess(readOffset, peFileSection); + } + else + { + return readPeSectionFromFile((DWORD)readOffset, peFileSection); + } + } + + currentReadSize = readSize % maxReadSize; //alignment % + + if (!currentReadSize) + { + currentReadSize = maxReadSize; } + currentOffset = readOffset + readSize - currentReadSize; - currentOffset = readOffset + readSize - maxReadSize; while(currentOffset >= readOffset) //start from the end { - SetFilePointer(hFile, currentOffset, 0, FILE_BEGIN); + ZeroMemory(data, currentReadSize); - ZeroMemory(data, sizeof(data)); - if (!ReadFile(hFile, data, sizeof(data), &bytesRead, 0)) + if (isProcess) + { + retValue = ProcessAccessHelp::readMemoryPartlyFromProcess(currentOffset, currentReadSize, data); + } + else + { + retValue = ProcessAccessHelp::readMemoryFromFile(hFile, (LONG)currentOffset, currentReadSize, data); + } + + if (!retValue) { - retValue = false; break; } - valuesFound = isMemoryNotNull(data, sizeof(data)); + valuesFound = isMemoryNotNull(data, currentReadSize); if (valuesFound) { //found some real code currentOffset += valuesFound; if (readOffset < currentOffset) { //real size - peFileSection.dataSize = currentOffset - readOffset; + peFileSection.dataSize = (DWORD)(currentOffset - readOffset); } break; } - currentOffset -= maxReadSize; + currentReadSize = maxReadSize; + currentOffset -= currentReadSize; } if (peFileSection.dataSize) { - retValue = readPeSectionFromFile(readOffset, peFileSection); + if (isProcess) + { + retValue = readPeSectionFromProcess(readOffset, peFileSection); + } + else + { + retValue = readPeSectionFromFile((DWORD)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 329354b..b3dc055 100644 --- a/Scylla/PeParser.h +++ b/Scylla/PeParser.h @@ -1,132 +1,136 @@ #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 readSectionFromProcess(const DWORD_PTR readOffset, PeFileSection & peFileSection ); + bool readSectionFromFile(const DWORD readOffset, PeFileSection & peFileSection ); + bool readSectionFrom(const DWORD_PTR readOffset, PeFileSection & peFileSection, const bool isProcess); + + + 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/ProcessAccessHelp.cpp b/Scylla/ProcessAccessHelp.cpp index 91aee0d..0cc8123 100644 --- a/Scylla/ProcessAccessHelp.cpp +++ b/Scylla/ProcessAccessHelp.cpp @@ -1,785 +1,819 @@ #include "ProcessAccessHelp.h" #include "Scylla.h" #include "NativeWinApi.h" #include "PeParser.h" HANDLE ProcessAccessHelp::hProcess = 0; ModuleInfo * ProcessAccessHelp::selectedModule; DWORD_PTR ProcessAccessHelp::targetImageBase = 0; DWORD_PTR ProcessAccessHelp::targetSizeOfImage = 0; DWORD_PTR ProcessAccessHelp::maxValidAddress = 0; std::vector ProcessAccessHelp::moduleList; //target process module list std::vector ProcessAccessHelp::ownModuleList; //own module list _DInst ProcessAccessHelp::decomposerResult[MAX_INSTRUCTIONS]; unsigned int ProcessAccessHelp::decomposerInstructionsCount = 0; _CodeInfo ProcessAccessHelp::decomposerCi = {0}; _DecodedInst ProcessAccessHelp::decodedInstructions[MAX_INSTRUCTIONS]; unsigned int ProcessAccessHelp::decodedInstructionsCount = 0; BYTE ProcessAccessHelp::fileHeaderFromDisk[PE_HEADER_BYTES_COUNT]; //#define DEBUG_COMMENTS bool ProcessAccessHelp::openProcessHandle(DWORD dwPID) { if (dwPID > 0) { if (hProcess) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"openProcessHandle :: There is already a process handle, HANDLE %X", hProcess); #endif return false; } else { //hProcess = OpenProcess(PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_QUERY_INFORMATION|PROCESS_VM_READ|PROCESS_VM_WRITE, 0, dwPID); //if (!NT_SUCCESS(NativeWinApi::NtOpenProcess(&hProcess,PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_QUERY_INFORMATION|PROCESS_VM_READ|PROCESS_VM_WRITE,&ObjectAttributes, &cid))) hProcess = NativeOpenProcess(PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_QUERY_INFORMATION|PROCESS_VM_READ|PROCESS_VM_WRITE, dwPID); if (hProcess) { return true; } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"openProcessHandle :: Failed to open handle, PID %X", dwPID); #endif return false; } } } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"openProcessHandle :: Wrong PID, PID %X", dwPID); #endif return false; } } HANDLE ProcessAccessHelp::NativeOpenProcess(DWORD dwDesiredAccess, DWORD dwProcessId) { HANDLE hProcess = 0; CLIENT_ID cid = {0}; OBJECT_ATTRIBUTES ObjectAttributes; NTSTATUS ntStatus = 0; InitializeObjectAttributes(&ObjectAttributes, 0, 0, 0, 0); cid.UniqueProcess = (HANDLE)dwProcessId; ntStatus = NativeWinApi::NtOpenProcess(&hProcess,dwDesiredAccess,&ObjectAttributes, &cid); if (NT_SUCCESS(ntStatus)) { return hProcess; } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"NativeOpenProcess :: Failed to open handle, PID %X Error 0x%X", dwProcessId, NativeWinApi::RtlNtStatusToDosError(ntStatus)); #endif return 0; } } void ProcessAccessHelp::closeProcessHandle() { CloseHandle(hProcess); hProcess = 0; moduleList.clear(); targetImageBase = 0; selectedModule = 0; } bool ProcessAccessHelp::readMemoryPartlyFromProcess(DWORD_PTR address, SIZE_T size, LPVOID dataBuffer) { DWORD_PTR addressPart = 0; DWORD_PTR readBytes = 0; DWORD_PTR bytesToRead = 0; MEMORY_BASIC_INFORMATION memBasic = {0}; bool returnValue = false; if (!hProcess) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"readMemoryPartlyFromProcess :: hProcess == NULL"); #endif return returnValue; } if (!readMemoryFromProcess(address, size, dataBuffer)) { addressPart = address; do { if (!VirtualQueryEx(ProcessAccessHelp::hProcess,(LPCVOID)addressPart,&memBasic,sizeof(memBasic))) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"readMemoryPartlyFromProcess :: Error VirtualQueryEx %X %X err: %u", addressPart,size, GetLastError()); #endif break; } bytesToRead = memBasic.RegionSize; if ( (readBytes+bytesToRead) > size) { bytesToRead = size - readBytes; } if (memBasic.State == MEM_COMMIT) { if (!readMemoryFromProcess(addressPart, bytesToRead, (LPVOID)((DWORD_PTR)dataBuffer + readBytes))) { break; } } else { ZeroMemory((LPVOID)((DWORD_PTR)dataBuffer + readBytes),bytesToRead); } readBytes += bytesToRead; addressPart += memBasic.RegionSize; } while (readBytes < size); if (readBytes == size) { returnValue = true; } } else { returnValue = true; } return returnValue; } bool ProcessAccessHelp::readMemoryFromProcess(DWORD_PTR address, SIZE_T size, LPVOID dataBuffer) { SIZE_T lpNumberOfBytesRead = 0; DWORD dwProtect = 0; bool returnValue = false; if (!hProcess) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"readMemoryFromProcess :: hProcess == NULL"); #endif return returnValue; } if (!ReadProcessMemory(hProcess, (LPVOID)address, dataBuffer, size, &lpNumberOfBytesRead)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"readMemoryFromProcess :: Error ReadProcessMemory %X %X err: %u", address, size, GetLastError()); #endif if (!VirtualProtectEx(hProcess, (LPVOID)address, size, PAGE_READWRITE, &dwProtect)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"readMemoryFromProcess :: Error VirtualProtectEx %X %X err: %u", address,size, GetLastError()); #endif returnValue = false; } else { if (!ReadProcessMemory(hProcess, (LPVOID)address, dataBuffer, size, &lpNumberOfBytesRead)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"readMemoryFromProcess :: Error ReadProcessMemory %X %X err: %u", address, size, GetLastError()); #endif returnValue = false; } else { returnValue = true; } VirtualProtectEx(hProcess, (LPVOID)address, size, dwProtect, &dwProtect); } } else { returnValue = true; } if (returnValue) { if (size != lpNumberOfBytesRead) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"readMemoryFromProcess :: Error ReadProcessMemory read %d bytes requested %d bytes", lpNumberOfBytesRead, size); #endif returnValue = false; } else { returnValue = true; } } return returnValue; } bool ProcessAccessHelp::decomposeMemory(BYTE * dataBuffer, SIZE_T bufferSize, DWORD_PTR startAddress) { ZeroMemory(&decomposerCi, sizeof(_CodeInfo)); decomposerCi.code = dataBuffer; decomposerCi.codeLen = (int)bufferSize; decomposerCi.dt = dt; decomposerCi.codeOffset = startAddress; decomposerInstructionsCount = 0; if (distorm_decompose(&decomposerCi, decomposerResult, sizeof(decomposerResult)/sizeof(decomposerResult[0]), &decomposerInstructionsCount) == DECRES_INPUTERR) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"decomposeMemory :: distorm_decompose == DECRES_INPUTERR"); #endif return false; } else { return true; } } bool ProcessAccessHelp::disassembleMemory(BYTE * dataBuffer, SIZE_T bufferSize, DWORD_PTR startOffset) { // Holds the result of the decoding. _DecodeResult res; // next is used for instruction's offset synchronization. // decodedInstructionsCount holds the count of filled instructions' array by the decoder. decodedInstructionsCount = 0; _OffsetType offset = startOffset; res = distorm_decode(offset, dataBuffer, (int)bufferSize, dt, decodedInstructions, MAX_INSTRUCTIONS, &decodedInstructionsCount); /* for (unsigned int i = 0; i < decodedInstructionsCount; i++) { #ifdef SUPPORT_64BIT_OFFSET printf("%0*I64x (%02d) %-24s %s%s%s\n", dt != Decode64Bits ? 8 : 16, decodedInstructions[i].offset, decodedInstructions[i].size, (char*)decodedInstructions[i].instructionHex.p, (char*)decodedInstructions[i].mnemonic.p, decodedInstructions[i].operands.length != 0 ? " " : "", (char*)decodedInstructions[i].operands.p); #else printf("%08x (%02d) %-24s %s%s%s\n", decodedInstructions[i].offset, decodedInstructions[i].size, (char*)decodedInstructions[i].instructionHex.p, (char*)decodedInstructions[i].mnemonic.p, decodedInstructions[i].operands.length != 0 ? " " : "", (char*)decodedInstructions[i].operands.p); #endif }*/ if (res == DECRES_INPUTERR) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"disassembleMemory :: res == DECRES_INPUTERR"); #endif return false; } else if (res == DECRES_SUCCESS) { //printf("disassembleMemory :: res == DECRES_SUCCESS\n"); return true; } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"disassembleMemory :: res == %d", res); #endif return false; } } DWORD_PTR ProcessAccessHelp::findPattern(DWORD_PTR startOffset, DWORD size, BYTE * pattern, const char * mask) { DWORD pos = 0; size_t searchLen = strlen(mask) - 1; for(DWORD_PTR retAddress = startOffset; retAddress < startOffset + size; retAddress++) { if( *(BYTE*)retAddress == pattern[pos] || mask[pos] == '?' ) { if(mask[pos+1] == 0x00) { return (retAddress - searchLen); } pos++; } else { pos = 0; } } return 0; } bool ProcessAccessHelp::readHeaderFromCurrentFile(const WCHAR * filePath) { return readHeaderFromFile(fileHeaderFromDisk, sizeof(fileHeaderFromDisk), filePath); } LONGLONG ProcessAccessHelp::getFileSize(const WCHAR * filePath) { LONGLONG fileSize = 0; HANDLE hFile = CreateFile(filePath, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); if (hFile != INVALID_HANDLE_VALUE) { fileSize = getFileSize(hFile); CloseHandle(hFile); } return fileSize; } LONGLONG ProcessAccessHelp::getFileSize(HANDLE hFile) { LARGE_INTEGER lpFileSize = {0}; if ((hFile != INVALID_HANDLE_VALUE) && (hFile != 0)) { if (!GetFileSizeEx(hFile, &lpFileSize)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"ProcessAccessHelp::getFileSize :: GetFileSizeEx failed %u", GetLastError()); #endif return 0; } else { return lpFileSize.QuadPart; } } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"ProcessAccessHelp::getFileSize hFile invalid"); #endif return 0; } } bool ProcessAccessHelp::readMemoryFromFile(HANDLE hFile, LONG offset, DWORD size, LPVOID dataBuffer) { DWORD lpNumberOfBytesRead = 0; DWORD retValue = 0; DWORD dwError = 0; - if ((hFile != INVALID_HANDLE_VALUE) && (hFile != 0)) + if (hFile != INVALID_HANDLE_VALUE) { retValue = SetFilePointer(hFile, offset, NULL, FILE_BEGIN); dwError = GetLastError(); if ((retValue == INVALID_SET_FILE_POINTER) && (dwError != NO_ERROR)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"readMemoryFromFile :: SetFilePointer failed error %u", dwError); #endif return false; } else { if (ReadFile(hFile, dataBuffer, size, &lpNumberOfBytesRead, 0)) { return true; } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"readMemoryFromFile :: ReadFile failed - size %d - error %u", size, GetLastError()); #endif return false; } } } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"readMemoryFromFile :: hFile invalid"); #endif return false; } } bool ProcessAccessHelp::writeMemoryToNewFile(const WCHAR * file,DWORD size, LPCVOID dataBuffer) { HANDLE hFile = CreateFile(file, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0); if (hFile != INVALID_HANDLE_VALUE) { return writeMemoryToFile(hFile,0,size,dataBuffer); } else { return false; } } bool ProcessAccessHelp::writeMemoryToFile(HANDLE hFile, LONG offset, DWORD size, LPCVOID dataBuffer) { DWORD lpNumberOfBytesWritten = 0; DWORD retValue = 0; DWORD dwError = 0; - if ((hFile != INVALID_HANDLE_VALUE) && (hFile != 0)) + if ((hFile != INVALID_HANDLE_VALUE) && dataBuffer) { retValue = SetFilePointer(hFile, offset, NULL, FILE_BEGIN); dwError = GetLastError(); if ((retValue == INVALID_SET_FILE_POINTER) && (dwError != NO_ERROR)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"writeMemoryToFile :: SetFilePointer failed error %u", dwError); #endif return false; } else { if (WriteFile(hFile, dataBuffer, size, &lpNumberOfBytesWritten, 0)) { return true; } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"writeMemoryToFile :: WriteFile failed - size %d - error %u", size, GetLastError()); #endif return false; } } } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"writeMemoryToFile :: hFile invalid"); #endif return false; } } bool ProcessAccessHelp::writeMemoryToFileEnd(HANDLE hFile, DWORD size, LPCVOID dataBuffer) { DWORD lpNumberOfBytesWritten = 0; DWORD retValue = 0; if ((hFile != INVALID_HANDLE_VALUE) && (hFile != 0)) { SetFilePointer(hFile, 0, 0, FILE_END); if (WriteFile(hFile, dataBuffer, size, &lpNumberOfBytesWritten, 0)) { return true; } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"writeMemoryToFileEnd :: WriteFile failed - size %d - error %u", size, GetLastError()); #endif return false; } } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"writeMemoryToFileEnd :: hFile invalid"); #endif return false; } } bool ProcessAccessHelp::readHeaderFromFile(BYTE * buffer, DWORD bufferSize, const WCHAR * filePath) { DWORD lpNumberOfBytesRead = 0; LONGLONG fileSize = 0; DWORD dwSize = 0; bool returnValue = 0; HANDLE hFile = CreateFile(filePath, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); if( hFile == INVALID_HANDLE_VALUE ) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"readHeaderFromFile :: INVALID_HANDLE_VALUE %u", GetLastError()); #endif returnValue = false; } else { fileSize = getFileSize(hFile); if (fileSize > 0) { if (fileSize > bufferSize) { dwSize = bufferSize; } else { dwSize = (DWORD)(fileSize - 1); } returnValue = readMemoryFromFile(hFile, 0, dwSize, buffer); } CloseHandle(hFile); } return returnValue; } LPVOID ProcessAccessHelp::createFileMappingViewRead(const WCHAR * filePath) { return createFileMappingView(filePath, GENERIC_READ, PAGE_READONLY | SEC_IMAGE, FILE_MAP_READ); } LPVOID ProcessAccessHelp::createFileMappingViewFull(const WCHAR * filePath) { return createFileMappingView(filePath, GENERIC_ALL, PAGE_EXECUTE_READWRITE, FILE_MAP_ALL_ACCESS); } LPVOID ProcessAccessHelp::createFileMappingView(const WCHAR * filePath, DWORD accessFile, DWORD flProtect, DWORD accessMap) { HANDLE hFile = CreateFile(filePath, accessFile, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); if( hFile == INVALID_HANDLE_VALUE ) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"createFileMappingView :: INVALID_HANDLE_VALUE %u", GetLastError()); #endif return NULL; } HANDLE hMappedFile = CreateFileMapping(hFile, NULL, flProtect, 0, 0, NULL); CloseHandle(hFile); if( hMappedFile == NULL ) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"createFileMappingView :: hMappedFile == NULL"); #endif return NULL; } if (GetLastError() == ERROR_ALREADY_EXISTS) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"createFileMappingView :: GetLastError() == ERROR_ALREADY_EXISTS"); #endif return NULL; } LPVOID addrMappedDll = MapViewOfFile(hMappedFile, accessMap, 0, 0, 0); if( addrMappedDll == NULL ) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"createFileMappingView :: addrMappedDll == NULL"); #endif CloseHandle(hMappedFile); return NULL; } CloseHandle(hMappedFile); return addrMappedDll; } DWORD ProcessAccessHelp::getProcessByName(const WCHAR * processName) { DWORD dwPID = 0; HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); PROCESSENTRY32W pe32; pe32.dwSize = sizeof(PROCESSENTRY32W); if( !Process32FirstW( hProcessSnap, &pe32 ) ) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"getProcessByName :: Error getting first Process"); #endif CloseHandle( hProcessSnap ); return 0; } do { if(!_wcsicmp(pe32.szExeFile, processName)) { dwPID = pe32.th32ProcessID; break; } } while(Process32NextW(hProcessSnap, &pe32)); CloseHandle(hProcessSnap); return dwPID; } bool ProcessAccessHelp::getProcessModules(DWORD dwPID, std::vector &moduleList) { HANDLE hModuleSnap = INVALID_HANDLE_VALUE; MODULEENTRY32 me32; ModuleInfo module; // Take a snapshot of all modules in the specified process. hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, dwPID ); if( hModuleSnap == INVALID_HANDLE_VALUE ) { return false; } // Set the size of the structure before using it. me32.dwSize = sizeof( MODULEENTRY32 ); // Retrieve information about the first module, // and exit if unsuccessful if( !Module32First( hModuleSnap, &me32 ) ) { CloseHandle( hModuleSnap ); return false; } // Now walk the module list of the process, // and display information about each module //the first is always the .exe if (!Module32Next(hModuleSnap, &me32)) { CloseHandle( hModuleSnap ); return false; } moduleList.reserve(20); do { //printf(L"\n MODULE NAME: %s", me32.szModule); module.modBaseAddr = (DWORD_PTR)me32.modBaseAddr; module.modBaseSize = me32.modBaseSize; module.isAlreadyParsed = false; module.parsing = false; wcscpy_s(module.fullPath, me32.szExePath); moduleList.push_back(module); } while(Module32Next(hModuleSnap, &me32)); CloseHandle( hModuleSnap ); return true; } bool ProcessAccessHelp::getMemoryRegionFromAddress(DWORD_PTR address, DWORD_PTR * memoryRegionBase, SIZE_T * memoryRegionSize) { MEMORY_BASIC_INFORMATION memBasic; if (VirtualQueryEx(hProcess,(LPCVOID)address,&memBasic,sizeof(MEMORY_BASIC_INFORMATION)) != sizeof(MEMORY_BASIC_INFORMATION)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"getMemoryRegionFromAddress :: VirtualQueryEx error %u", GetLastError()); #endif return false; } else { *memoryRegionBase = (DWORD_PTR)memBasic.BaseAddress; *memoryRegionSize = memBasic.RegionSize; return true; } } bool ProcessAccessHelp::getSizeOfImageCurrentProcess() { DWORD_PTR newSizeOfImage = getSizeOfImageProcess(ProcessAccessHelp::hProcess, ProcessAccessHelp::targetImageBase); if (newSizeOfImage != 0) { ProcessAccessHelp::targetSizeOfImage = newSizeOfImage; return true; } else { return false; } } SIZE_T ProcessAccessHelp::getSizeOfImageProcess(HANDLE processHandle, DWORD_PTR moduleBase) { SIZE_T sizeOfImage = 0; MEMORY_BASIC_INFORMATION lpBuffer = {0}; SIZE_T dwLength = sizeof(MEMORY_BASIC_INFORMATION); do { moduleBase = (DWORD_PTR)((SIZE_T)moduleBase + lpBuffer.RegionSize); sizeOfImage += lpBuffer.RegionSize; //printf("Query 0x"PRINTF_DWORD_PTR_FULL" size 0x%08X\n",moduleBase,sizeOfImage); if (!VirtualQueryEx(processHandle, (LPCVOID)moduleBase, &lpBuffer, dwLength)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"getSizeOfImageProcess :: VirtualQuery failed %X", GetLastError()); #endif lpBuffer.Type = 0; sizeOfImage = 0; } /*else { printf("\nAllocationBase %X\n",lpBuffer.AllocationBase); printf("AllocationProtect %X\n",lpBuffer.AllocationProtect); printf("BaseAddress %X\n",lpBuffer.BaseAddress); printf("Protect %X\n",lpBuffer.Protect); printf("RegionSize %X\n",lpBuffer.RegionSize); printf("State %X\n",lpBuffer.State); printf("Type %X\n",lpBuffer.Type); }*/ } while (lpBuffer.Type == MEM_IMAGE); //printf("Real sizeOfImage %X\n",sizeOfImage); return sizeOfImage; } DWORD ProcessAccessHelp::getEntryPointFromFile(const WCHAR * filePath) { PeParser peFile(filePath, false); return peFile.getEntryPoint(); } bool ProcessAccessHelp::createBackupFile(const WCHAR * filePath) { size_t fileNameLength = wcslen(filePath) + 5; //.bak + null BOOL retValue = 0; WCHAR * backupFile = new WCHAR[fileNameLength]; wcscpy_s(backupFile, fileNameLength, filePath); wcscat_s(backupFile, fileNameLength, L".bak"); retValue = CopyFile(filePath, backupFile, FALSE); if (!retValue) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"createBackupFile :: CopyFile failed with error 0x%X", GetLastError()); #endif } delete [] backupFile; return retValue != 0; } + +DWORD ProcessAccessHelp::getModuleHandlesFromProcess(const HANDLE hProcess, HMODULE ** hMods) +{ + DWORD count = 30; + DWORD cbNeeded = 0; + bool notEnough = true; + + *hMods = new HMODULE[count]; + + do + { + if (!EnumProcessModules(hProcess, *hMods, count * sizeof(HMODULE), &cbNeeded)) + { +#ifdef DEBUG_COMMENTS + Scylla::debugLog.log(L"getModuleHandlesFromProcess :: EnumProcessModules failed count %d", count); +#endif + delete [] *hMods; + return 0; + } + + if ((count * sizeof(HMODULE)) < cbNeeded) + { + delete [] *hMods; + count = cbNeeded / sizeof(HMODULE); + *hMods = new HMODULE[count]; + } + else + { + notEnough = false; + } + } while (notEnough); + + return cbNeeded / sizeof(HMODULE); +} \ No newline at end of file diff --git a/Scylla/ProcessAccessHelp.h b/Scylla/ProcessAccessHelp.h index c5fc3c0..a2087e2 100644 --- a/Scylla/ProcessAccessHelp.h +++ b/Scylla/ProcessAccessHelp.h @@ -1,217 +1,219 @@ #pragma once #include #include #include /************************************************************************/ /* distorm */ /************************************************************************/ #include // The number of the array of instructions the decoder function will use to return the disassembled instructions. // Play with this value for performance... #define MAX_INSTRUCTIONS (200) /************************************************************************/ class ApiInfo; class ModuleInfo { public: WCHAR fullPath[MAX_PATH]; DWORD_PTR modBaseAddr; DWORD modBaseSize; bool isAlreadyParsed; bool parsing; /* for iat rebuilding with duplicate entries: ntdll = low priority kernelbase = low priority SHLWAPI = low priority kernel32 = high priority priority = 1 -> normal/high priority priority = 0 -> low priority */ int priority; std::vector apiList; ModuleInfo() { modBaseAddr = 0; modBaseSize = 0; priority = 1; isAlreadyParsed = false; parsing = false; } const WCHAR * getFilename() const { const WCHAR* slash = wcsrchr(fullPath, L'\\'); if(slash) { return slash+1; } return fullPath; } }; class ApiInfo { public: char name[MAX_PATH]; WORD hint; DWORD_PTR va; DWORD_PTR rva; WORD ordinal; bool isForwarded; ModuleInfo * module; }; class ProcessAccessHelp { public: static HANDLE hProcess; //OpenProcess handle to target process static DWORD_PTR targetImageBase; static DWORD_PTR targetSizeOfImage; static DWORD_PTR maxValidAddress; static ModuleInfo * selectedModule; static std::vector moduleList; //target process module list static std::vector ownModuleList; //own module list static const size_t PE_HEADER_BYTES_COUNT = 2000; static BYTE fileHeaderFromDisk[PE_HEADER_BYTES_COUNT]; //for decomposer static _DInst decomposerResult[MAX_INSTRUCTIONS]; static unsigned int decomposerInstructionsCount; static _CodeInfo decomposerCi; //distorm :: Decoded instruction information. static _DecodedInst decodedInstructions[MAX_INSTRUCTIONS]; static unsigned int decodedInstructionsCount; #ifdef _WIN64 static const _DecodeType dt = Decode64Bits; #else static const _DecodeType dt = Decode32Bits; #endif /* * Open a new process handle */ static bool openProcessHandle(DWORD dwPID); static HANDLE NativeOpenProcess(DWORD dwDesiredAccess, DWORD dwProcessId); static void closeProcessHandle(); /* * Get all modules from a process */ static bool getProcessModules(DWORD dwPID, std::vector &moduleList); /* * file mapping view with different access level */ static LPVOID createFileMappingViewRead(const WCHAR * filePath); static LPVOID createFileMappingViewFull(const WCHAR * filePath); /* * Create a file mapping view of a file */ static LPVOID createFileMappingView(const WCHAR * filePath, DWORD accessFile, DWORD flProtect, DWORD accessMap); /* * Read memory from target process */ static bool readMemoryFromProcess(DWORD_PTR address, SIZE_T size, LPVOID dataBuffer); /* * Read memory from target process and ignore no data pages */ static bool readMemoryPartlyFromProcess(DWORD_PTR address, SIZE_T size, LPVOID dataBuffer); /* * Read memory from file */ static bool readMemoryFromFile(HANDLE hFile, LONG offset, DWORD size, LPVOID dataBuffer); /* * Write memory to file */ static bool writeMemoryToFile(HANDLE hFile, LONG offset, DWORD size, LPCVOID dataBuffer); /* * Write memory to new file */ static bool writeMemoryToNewFile(const WCHAR * file,DWORD size, LPCVOID dataBuffer); /* * Write memory to file end */ static bool writeMemoryToFileEnd(HANDLE hFile, DWORD size, LPCVOID dataBuffer); /* * Disassemble Memory */ static bool disassembleMemory(BYTE * dataBuffer, SIZE_T bufferSize, DWORD_PTR startOffset); static bool decomposeMemory(BYTE * dataBuffer, SIZE_T bufferSize, DWORD_PTR startAddress); /* * Search for pattern */ static DWORD_PTR findPattern(DWORD_PTR startOffset, DWORD size, BYTE * pattern, const char * mask); /* * Get process ID by process name */ static DWORD getProcessByName(const WCHAR * processName); /* * Get memory region from address */ static bool getMemoryRegionFromAddress(DWORD_PTR address, DWORD_PTR * memoryRegionBase, SIZE_T * memoryRegionSize); /* * Read PE Header from file */ static bool readHeaderFromFile(BYTE * buffer, DWORD bufferSize, const WCHAR * filePath); static bool readHeaderFromCurrentFile(const WCHAR * filePath); /* * Get real sizeOfImage value */ static SIZE_T getSizeOfImageProcess(HANDLE processHandle, DWORD_PTR moduleBase); /* * Get real sizeOfImage value current process */ static bool getSizeOfImageCurrentProcess(); static LONGLONG getFileSize(HANDLE hFile); static LONGLONG getFileSize(const WCHAR * filePath); static DWORD getEntryPointFromFile(const WCHAR * filePath); static bool createBackupFile(const WCHAR * filePath); + + static DWORD getModuleHandlesFromProcess(const HANDLE hProcess, HMODULE ** hMods ); }; diff --git a/Scylla/Scylla.h b/Scylla/Scylla.h index 2e6a862..98fea0d 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 2" +#define APPVERSION_S "v0.7 Beta 4" #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[]; };