diff --git a/Scylla/DumpMemoryGui.cpp b/Scylla/DumpMemoryGui.cpp index 8e492cd..11c9cf3 100644 --- a/Scylla/DumpMemoryGui.cpp +++ b/Scylla/DumpMemoryGui.cpp @@ -1,605 +1,571 @@ #include "DumpMemoryGui.h" #include "Architecture.h" #include "ProcessAccessHelp.h" #include +#include "PeParser.h" WCHAR DumpMemoryGui::protectionString[100]; const WCHAR DumpMemoryGui::MemoryUndefined[] = L"UNDEF"; const WCHAR DumpMemoryGui::MemoryUnknown[] = L"UNKNOWN"; const WCHAR * DumpMemoryGui::MemoryStateValues[] = {L"COMMIT",L"FREE",L"RESERVE"}; const WCHAR * DumpMemoryGui::MemoryTypeValues[] = {L"IMAGE",L"MAPPED",L"PRIVATE"}; const WCHAR * DumpMemoryGui::MemoryProtectionValues[] = {L"EXECUTE",L"EXECUTE_READ",L"EXECUTE_READWRITE",L"EXECUTE_WRITECOPY",L"NOACCESS",L"READONLY",L"READWRITE",L"WRITECOPY",L"GUARD",L"NOCACHE",L"WRITECOMBINE"}; DumpMemoryGui::DumpMemoryGui() { dumpedMemory = 0; dumpedMemorySize = 0; deviceNameResolver = new DeviceNameResolver(); } DumpMemoryGui::~DumpMemoryGui() { if (dumpedMemory) { delete [] dumpedMemory; } if (deviceNameResolver) { delete deviceNameResolver; } } BOOL DumpMemoryGui::OnInitDialog(CWindow wndFocus, LPARAM lInitParam) { DoDataExchange(); // attach controls DlgResize_Init(true, true); addColumnsToMemoryList(ListMemorySelect); displayMemoryList(ListMemorySelect); forceDump = false; DoDataExchange(DDX_LOAD); EditMemoryAddress.SetValue(ProcessAccessHelp::targetImageBase); EditMemorySize.SetValue((DWORD)ProcessAccessHelp::targetSizeOfImage); CenterWindow(); return TRUE; } void DumpMemoryGui::addColumnsToMemoryList(CListViewCtrl& list) { list.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT); list.InsertColumn(COL_ADDRESS, L"Address", LVCFMT_CENTER); list.InsertColumn(COL_SIZE, L"Size", LVCFMT_CENTER); list.InsertColumn(COL_FILENAME, L"File", LVCFMT_LEFT); list.InsertColumn(COL_PESECTION, L"PE Section", LVCFMT_LEFT); list.InsertColumn(COL_TYPE, L"Type", LVCFMT_CENTER); list.InsertColumn(COL_PROTECTION, L"Protection", LVCFMT_CENTER); list.InsertColumn(COL_STATE, L"State", LVCFMT_CENTER); list.InsertColumn(COL_MAPPED_FILE, L"Mapped File", LVCFMT_LEFT); } void DumpMemoryGui::displayMemoryList(CListViewCtrl& list) { int count = 0; WCHAR temp[20]; list.DeleteAllItems(); getMemoryList(); std::vector::const_iterator iter; for( iter = memoryList.begin(); iter != memoryList.end(); iter++ , count++) { swprintf_s(temp, PRINTF_DWORD_PTR_FULL, iter->address); list.InsertItem(count,temp); swprintf_s(temp, L"%08X", iter->size); list.SetItemText(count, COL_SIZE, temp); list.SetItemText(count, COL_FILENAME, iter->filename); list.SetItemText(count, COL_PESECTION, iter->peSection); if (iter->state == MEM_FREE) { list.SetItemText(count, COL_TYPE, MemoryUndefined); } else { list.SetItemText(count, COL_TYPE, getMemoryTypeString(iter->type)); } if ( (iter->state == MEM_RESERVE) || (iter->state == MEM_FREE) ) { list.SetItemText(count, COL_PROTECTION, MemoryUndefined); } else { list.SetItemText(count, COL_PROTECTION, getMemoryProtectionString(iter->protect)); } list.SetItemText(count, COL_STATE, getMemoryStateString(iter->state)); list.SetItemText(count, COL_MAPPED_FILE, iter->mappedFilename); list.SetItemData(count, (DWORD_PTR)&(*iter)); } list.SetColumnWidth(COL_ADDRESS, LVSCW_AUTOSIZE_USEHEADER); list.SetColumnWidth(COL_SIZE, LVSCW_AUTOSIZE_USEHEADER); list.SetColumnWidth(COL_FILENAME, LVSCW_AUTOSIZE_USEHEADER); list.SetColumnWidth(COL_PESECTION, LVSCW_AUTOSIZE_USEHEADER); list.SetColumnWidth(COL_TYPE, LVSCW_AUTOSIZE_USEHEADER); list.SetColumnWidth(COL_PROTECTION, LVSCW_AUTOSIZE_USEHEADER); list.SetColumnWidth(COL_STATE, LVSCW_AUTOSIZE_USEHEADER); list.SetColumnWidth(COL_MAPPED_FILE, LVSCW_AUTOSIZE_USEHEADER); } const WCHAR * DumpMemoryGui::getMemoryTypeString(DWORD value) { switch(value) { case MEM_IMAGE: return MemoryTypeValues[TYPE_IMAGE]; case MEM_MAPPED: return MemoryTypeValues[TYPE_MAPPED]; case MEM_PRIVATE: return MemoryTypeValues[TYPE_PRIVATE]; default: return MemoryUnknown; } } const WCHAR * DumpMemoryGui::getMemoryStateString(DWORD value) { switch(value) { case MEM_COMMIT: return MemoryStateValues[STATE_COMMIT]; case MEM_FREE: return MemoryStateValues[STATE_FREE]; case MEM_RESERVE: return MemoryStateValues[STATE_RESERVE]; default: return MemoryUnknown; } } WCHAR * DumpMemoryGui::getMemoryProtectionString(DWORD value) { protectionString[0] = 0; if (value & PAGE_GUARD) { wcscpy_s(protectionString, MemoryProtectionValues[PROT_GUARD]); wcscat_s(protectionString, L" | "); value ^= PAGE_GUARD; } if (value & PAGE_NOCACHE) { wcscpy_s(protectionString, MemoryProtectionValues[PROT_NOCACHE]); wcscat_s(protectionString, L" | "); value ^= PAGE_NOCACHE; } if (value & PAGE_WRITECOMBINE) { wcscpy_s(protectionString, MemoryProtectionValues[PROT_WRITECOMBINE]); wcscat_s(protectionString, L" | "); value ^= PAGE_WRITECOMBINE; } switch(value) { case PAGE_EXECUTE: { wcscat_s(protectionString, MemoryProtectionValues[PROT_EXECUTE]); break; } case PAGE_EXECUTE_READ: { wcscat_s(protectionString, MemoryProtectionValues[PROT_EXECUTE_READ]); break; } case PAGE_EXECUTE_READWRITE: { wcscat_s(protectionString, MemoryProtectionValues[PROT_EXECUTE_READWRITE]); break; } case PAGE_EXECUTE_WRITECOPY: { wcscat_s(protectionString, MemoryProtectionValues[PROT_EXECUTE_WRITECOPY]); break; } case PAGE_NOACCESS: { wcscat_s(protectionString, MemoryProtectionValues[PROT_NOACCESS]); break; } case PAGE_READONLY: { wcscat_s(protectionString, MemoryProtectionValues[PROT_READONLY]); break; } case PAGE_READWRITE: { wcscat_s(protectionString, MemoryProtectionValues[PROT_READWRITE]); break; } case PAGE_WRITECOPY: { wcscat_s(protectionString, MemoryProtectionValues[PROT_WRITECOPY]); break; } default: { wcscat_s(protectionString, MemoryUnknown); } } return protectionString; } LRESULT DumpMemoryGui::OnListMemoryColumnClicked(NMHDR* pnmh) { NMLISTVIEW* list = (NMLISTVIEW*)pnmh; int column = list->iSubItem; if(column == prevColumn) { ascending = !ascending; } else { prevColumn = column; ascending = true; } // lo-byte: column, hi-byte: sort-order ListMemorySelect.SortItems(&listviewCompareFunc, MAKEWORD(column, ascending)); return 0; } LRESULT DumpMemoryGui::OnListMemoryClick(NMHDR* pnmh) { int index = ListMemorySelect.GetSelectionMark(); if (index != -1) { selectedMemory = (Memory *)ListMemorySelect.GetItemData(index); if (selectedMemory) { updateAddressAndSize(selectedMemory); } } return 0; } void DumpMemoryGui::OnOK(UINT uNotifyCode, int nID, CWindow wndCtl) { DoDataExchange(DDX_SAVE); if (EditMemoryAddress.GetValue() == 0 || EditMemorySize.GetValue() == 0) { wndCtl.MessageBoxW(L"Textbox is empty!",L"Error",MB_ICONERROR); } else { if (dumpMemory()) { EndDialog(1); } else { wndCtl.MessageBoxW(L"Reading memory from process failed",L"Error",MB_ICONERROR); } } } void DumpMemoryGui::OnCancel(UINT uNotifyCode, int nID, CWindow wndCtl) { EndDialog(0); } void DumpMemoryGui::updateAddressAndSize( Memory * selectedMemory ) { EditMemoryAddress.SetValue(selectedMemory->address); EditMemorySize.SetValue(selectedMemory->size); } int DumpMemoryGui::listviewCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { const Memory * module1 = (Memory *)lParam1; const Memory * module2 = (Memory *)lParam2; int column = LOBYTE(lParamSort); bool ascending = (HIBYTE(lParamSort) == TRUE); int diff = 0; switch(column) { case COL_ADDRESS: diff = module1->address < module2->address ? -1 : 1; break; case COL_SIZE: diff = module1->size < module2->size ? -1 : 1; break; case COL_FILENAME: diff = _wcsicmp(module1->filename, module2->filename); break; case COL_PESECTION: diff = _wcsicmp(module1->peSection, module2->peSection); break; case COL_TYPE: diff = module1->type < module2->type ? -1 : 1; break; case COL_PROTECTION: diff = module1->protect < module2->protect ? -1 : 1; break; case COL_STATE: diff = _wcsicmp(getMemoryStateString(module1->state), getMemoryStateString(module2->state)); //diff = module1->state < module2->state ? -1 : 1; break; case COL_MAPPED_FILE: diff = _wcsicmp(module1->mappedFilename, module2->mappedFilename); break; } return ascending ? diff : -diff; } void DumpMemoryGui::getMemoryList() { DWORD count = 0; DWORD_PTR address = 0; MEMORY_BASIC_INFORMATION memBasic = {0}; Memory memory; HMODULE * hMods = 0; DWORD cbNeeded = 0; bool notEnough = true; WCHAR target[MAX_PATH]; count = 100; hMods = new HMODULE[count]; if (memoryList.empty()) { memoryList.reserve(20); } else { memoryList.clear(); } memory.filename[0] = 0; memory.peSection[0] = 0; memory.mappedFilename[0] = 0; while(VirtualQueryEx(ProcessAccessHelp::hProcess,(LPCVOID)address,&memBasic,sizeof(memBasic))) { memory.address = (DWORD_PTR)memBasic.BaseAddress; memory.type = memBasic.Type; memory.state = memBasic.State; memory.size = (DWORD)memBasic.RegionSize; memory.protect = memBasic.Protect; if (memory.type == MEM_MAPPED) { if (!getMappedFilename(&memory)) { memory.mappedFilename[0] = 0; } } memoryList.push_back(memory); memory.mappedFilename[0] = 0; address += memBasic.RegionSize; } do { if (!EnumProcessModules(ProcessAccessHelp::hProcess, hMods, count * sizeof(HMODULE), &cbNeeded)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"getMemoryList :: EnumProcessModules failed count %d", count); #endif delete [] hMods; return; } if ( (count * sizeof(HMODULE)) < cbNeeded ) { delete [] hMods; count += 100; hMods = new HMODULE[count]; } else { notEnough = false; } } while (notEnough); for (DWORD i = 0; i < (cbNeeded / sizeof(HMODULE)); i++ ) { if (GetModuleFileNameExW(ProcessAccessHelp::hProcess, hMods[i], target, _countof(target))) { setModuleName((DWORD_PTR)hMods[i],target); setAllSectionNames((DWORD_PTR)hMods[i],target); } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"getMemoryList :: GetModuleFileNameExW failed 0x%X", GetLastError()); #endif } } delete [] hMods; } void DumpMemoryGui::setSectionName(DWORD_PTR sectionAddress, DWORD sectionSize, const WCHAR * sectionName) { bool found = false; std::vector::const_iterator iter; for( iter = memoryList.begin(); iter != memoryList.end(); iter++) { if (!found) { if ( (iter->address <= sectionAddress) && (sectionAddress < (iter->address + iter->size)) ) { if (wcslen(iter->peSection) == 0) { wcscpy_s((WCHAR *)iter->peSection, IMAGE_SIZEOF_SHORT_NAME * 4, sectionName); } else { wcscat_s((WCHAR *)iter->peSection, IMAGE_SIZEOF_SHORT_NAME * 4, L"|"); wcscat_s((WCHAR *)iter->peSection, IMAGE_SIZEOF_SHORT_NAME * 4, sectionName); } found = true; } } else { if ((sectionSize+sectionAddress) < iter->address) { break; } if (wcslen(iter->peSection) == 0) { wcscpy_s((WCHAR *)iter->peSection, IMAGE_SIZEOF_SHORT_NAME * 4, sectionName); } else { wcscat_s((WCHAR *)iter->peSection, IMAGE_SIZEOF_SHORT_NAME * 4, L"|"); wcscat_s((WCHAR *)iter->peSection, IMAGE_SIZEOF_SHORT_NAME * 4, sectionName); } } } } void DumpMemoryGui::setModuleName(DWORD_PTR moduleBase, const WCHAR * moduleName) { bool found = false; std::vector::const_iterator iter; //get filename const WCHAR* slash = wcsrchr(moduleName, L'\\'); if(slash) { moduleName = slash+1; } for( iter = memoryList.begin(); iter != memoryList.end(); iter++) { if (iter->address == moduleBase) { found = true; } if (found) { if (iter->type == MEM_IMAGE) { wcscpy_s((WCHAR *)iter->filename, MAX_PATH, moduleName); } else { break; } } } } void DumpMemoryGui::setAllSectionNames( DWORD_PTR moduleBase, WCHAR * moduleName ) { - WORD numSections = 0; - PIMAGE_DOS_HEADER pDos = 0; - PIMAGE_NT_HEADERS pNT = 0; - PIMAGE_SECTION_HEADER pSec = 0; - DWORD size = sizeof(IMAGE_DOS_HEADER) + sizeof(IMAGE_NT_HEADERS) + 200; - DWORD correctSize = 0; WCHAR sectionNameW[IMAGE_SIZEOF_SHORT_NAME + 1] = {0}; - CHAR sectionNameA[IMAGE_SIZEOF_SHORT_NAME + 1] = {0}; - BYTE * buffer = new BYTE[size]; + PeParser peFile(moduleName); - if (ProcessAccessHelp::readMemoryFromProcess(moduleBase,size,buffer)) + if (peFile.isValidPeFile()) { - pDos = (PIMAGE_DOS_HEADER)buffer; + std::vector & listSectionHeader = peFile.getSectionHeaderList(); - if (pDos->e_magic == IMAGE_DOS_SIGNATURE) + for (WORD i = 0; i < peFile.getNumberOfSections(); i++) { - pNT = (PIMAGE_NT_HEADERS)((DWORD_PTR)pDos + pDos->e_lfanew); - if (pNT->Signature == IMAGE_NT_SIGNATURE) - { - numSections = pNT->FileHeader.NumberOfSections; - correctSize = (numSections*sizeof(IMAGE_SECTION_HEADER)) + sizeof(IMAGE_NT_HEADERS) + pDos->e_lfanew; - - if (size < correctSize) - { - size = correctSize; - delete [] buffer; - buffer = new BYTE[size]; - if (!ProcessAccessHelp::readMemoryFromProcess(moduleBase,size,buffer)) - { - delete [] buffer; - return; - } - - pDos = (PIMAGE_DOS_HEADER)buffer; - pNT = (PIMAGE_NT_HEADERS)((DWORD_PTR)pDos + pDos->e_lfanew); - } - - pSec = IMAGE_FIRST_SECTION(pNT); - - for (WORD i = 0; i < numSections; i++) - { - ZeroMemory(sectionNameA, sizeof(sectionNameA)); - memcpy(sectionNameA,pSec->Name,8); - swprintf_s(sectionNameW,L"%S",sectionNameA); + peFile.getSectionNameUnicode(i, sectionNameW, _countof(sectionNameW)); - setSectionName(moduleBase + pSec->VirtualAddress, pSec->Misc.VirtualSize,sectionNameW); - pSec++; - } - - } + setSectionName(moduleBase + listSectionHeader[i].VirtualAddress, listSectionHeader[i].Misc.VirtualSize, sectionNameW); } } + else + { + MessageBox(moduleName,L"Not a valid PE -> This should never happen",MB_ICONERROR); + } - delete [] buffer; } bool DumpMemoryGui::dumpMemory() { DWORD_PTR address = EditMemoryAddress.GetValue(); dumpedMemorySize = EditMemorySize.GetValue(); swprintf_s(dumpFilename,TEXT("MEM_")TEXT(PRINTF_DWORD_PTR_FULL_S)TEXT("_")TEXT("%08X"),address,dumpedMemorySize); dumpedMemory = new BYTE[dumpedMemorySize]; if (dumpedMemory) { if (forceDump) { return ProcessAccessHelp::readMemoryPartlyFromProcess(address,dumpedMemorySize,dumpedMemory); } else { return ProcessAccessHelp::readMemoryFromProcess(address,dumpedMemorySize,dumpedMemory); } } else { return false; } } bool DumpMemoryGui::getMappedFilename( Memory* memory ) { WCHAR filename[MAX_PATH] = {0}; //TODO replace with Nt direct syscall if (GetMappedFileNameW(ProcessAccessHelp::hProcess, (LPVOID)memory->address, filename, _countof(filename)) > 0) { return deviceNameResolver->resolveDeviceLongNameToShort(filename, memory->mappedFilename); } return false; } diff --git a/Scylla/DumpSectionGui.cpp b/Scylla/DumpSectionGui.cpp index a985ce1..6a044b2 100644 --- a/Scylla/DumpSectionGui.cpp +++ b/Scylla/DumpSectionGui.cpp @@ -1,391 +1,355 @@ #include "DumpSectionGui.h" #include "Architecture.h" #include "ProcessAccessHelp.h" +#include "PeParser.h" bool PeSection::highlightVirtualSize() { //highlight big virtual sizes -> anti-dump protection - if (virtualSize > 0x2000000) - { - return true; - } - else - { - return false; - } + return (virtualSize > 0x2000000); } std::vector & DumpSectionGui::getSectionList() { return sectionList; } BOOL DumpSectionGui::OnInitDialog(CWindow wndFocus, LPARAM lInitParam) { DoDataExchange(); // attach controls DlgResize_Init(true, true); addColumnsToSectionList(ListSectionSelect); displaySectionList(ListSectionSelect); selectOrDeselectAll(); isEditing = false; selectedSection = 0; CenterWindow(); return TRUE; } LRESULT DumpSectionGui::OnListSectionColumnClicked(NMHDR* pnmh) { NMLISTVIEW* list = (NMLISTVIEW*)pnmh; int column = list->iSubItem; if(column == prevColumn) { ascending = !ascending; } else { prevColumn = column; ascending = true; } // lo-byte: column, hi-byte: sort-order ListSectionSelect.SortItems(&listviewCompareFunc, MAKEWORD(column, ascending)); return 0; } LRESULT DumpSectionGui::OnListSectionClick(NMHDR* pnmh) { //int index = ListSectionSelect.GetSelectionMark(); //if (index != -1) //{ //} return 0; } LRESULT DumpSectionGui::OnListDoubleClick(NMHDR* pnmh) { RECT rect; RECT rect1,rect2; NMITEMACTIVATE* ia = (NMITEMACTIVATE*)pnmh; if (ia->iSubItem != COL_VSize) { return 0; } LVHITTESTINFO hti; hti.pt = ia->ptAction; int clicked = ListSectionSelect.HitTest(&hti); if(clicked != -1) { selectedSection = (PeSection *)ListSectionSelect.GetItemData(clicked); } ListSectionSelect.GetSubItemRect(ia->iItem,ia->iSubItem,LVIR_BOUNDS,&rect); //Get the Rectange of the listControl ListSectionSelect.GetWindowRect(&rect1); //Get the Rectange of the Dialog GetWindowRect(&rect2); int x = rect1.left - rect2.left; int y = rect1.top - rect2.top; isEditing = true; EditListControl.SetWindowPos(HWND_TOP,rect.left + 7, rect.top + 7, rect.right - rect.left, rect.bottom - rect.top, NULL); EditListControl.ShowWindow(SW_SHOW); EditListControl.SetFocus(); //Draw a Rectangle around the SubItem //Rectangle(ListSectionSelect.GetDC(),rect.left,rect.top-1,rect.right,rect.bottom); //Set the listItem text in the EditBox EditListControl.SetValue(selectedSection->virtualSize); return 0; } void DumpSectionGui::OnSectionSelectAll(UINT uNotifyCode, int nID, CWindow wndCtl) { selectOrDeselectAll(); } void DumpSectionGui::OnEditList(UINT uNotifyCode, int nID, CWindow wndCtl) { switch (uNotifyCode) { case EN_KILLFOCUS: { isEditing = false; updateEditedItem(); EditListControl.ShowWindow(SW_HIDE); } break; } } void DumpSectionGui::OnOK(UINT uNotifyCode, int nID, CWindow wndCtl) { if (isEditing) //EN_KILLFOCUS not sent? { updateEditedItem(); } updateCheckState(); EndDialog(1); } void DumpSectionGui::OnCancel(UINT uNotifyCode, int nID, CWindow wndCtl) { EndDialog(0); } int DumpSectionGui::listviewCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { const PeSection * module1 = (PeSection *)lParam1; const PeSection * module2 = (PeSection *)lParam2; int column = LOBYTE(lParamSort); bool ascending = (HIBYTE(lParamSort) == TRUE); int diff = 0; switch(column) { case COL_NAME: diff = _wcsicmp(module1->name, module2->name); break; case COL_VA: diff = module1->virtualAddress < module2->virtualAddress ? -1 : 1; break; case COL_VSize: diff = module1->virtualSize < module2->virtualSize ? -1 : 1; break; case COL_RVA: diff = module1->rawAddress < module2->rawAddress ? -1 : 1; break; case COL_RSize: diff = module1->rawSize < module2->rawSize ? -1 : 1; break; case COL_Characteristics: diff = module1->characteristics < module2->characteristics ? -1 : 1; break; } return ascending ? diff : -diff; } void DumpSectionGui::addColumnsToSectionList(CListViewCtrl& list) { list.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT|LVS_EX_CHECKBOXES|LVS_EX_GRIDLINES, LVS_EX_FULLROWSELECT|LVS_EX_CHECKBOXES|LVS_EX_GRIDLINES); list.InsertColumn(COL_NAME, L"Name", LVCFMT_CENTER); list.InsertColumn(COL_VA, L"Virtual Address", LVCFMT_CENTER); list.InsertColumn(COL_VSize, L"Virtual Size", LVCFMT_CENTER); list.InsertColumn(COL_RVA, L"Raw Address", LVCFMT_CENTER); list.InsertColumn(COL_RSize, L"Raw Size", LVCFMT_CENTER); list.InsertColumn(COL_Characteristics, L"Characteristics", LVCFMT_CENTER); } void DumpSectionGui::displaySectionList(CListViewCtrl& list) { int count = 0; WCHAR temp[20]; list.DeleteAllItems(); if (sectionList.empty()) { getAllSectionsFromFile(); } std::vector::const_iterator iter; for( iter = sectionList.begin(); iter != sectionList.end(); iter++ , count++) { list.InsertItem(count, iter->name); swprintf_s(temp, PRINTF_DWORD_PTR_FULL, iter->virtualAddress); list.SetItemText(count, COL_VA, temp); swprintf_s(temp, L"%08X", iter->virtualSize); list.SetItemText(count, COL_VSize, temp); swprintf_s(temp, L"%08X", iter->rawAddress); list.SetItemText(count, COL_RVA, temp); swprintf_s(temp, L"%08X", iter->rawSize); list.SetItemText(count, COL_RSize, temp); swprintf_s(temp, L"%08X", iter->characteristics); list.SetItemText(count, COL_Characteristics, temp); list.SetItemData(count, (DWORD_PTR)&(*iter)); } list.SetColumnWidth(COL_NAME, LVSCW_AUTOSIZE_USEHEADER); list.SetColumnWidth(COL_VA, LVSCW_AUTOSIZE_USEHEADER); list.SetColumnWidth(COL_VSize, LVSCW_AUTOSIZE_USEHEADER); list.SetColumnWidth(COL_RVA, LVSCW_AUTOSIZE_USEHEADER); list.SetColumnWidth(COL_RSize, LVSCW_AUTOSIZE_USEHEADER); list.SetColumnWidth(COL_Characteristics, LVSCW_AUTOSIZE_USEHEADER); } LRESULT DumpSectionGui::OnNMCustomdraw(NMHDR* pnmh) { LRESULT pResult = 0; unsigned int vectorIndex = 0; LPNMLVCUSTOMDRAW lpLVCustomDraw = (LPNMLVCUSTOMDRAW)(pnmh); switch(lpLVCustomDraw->nmcd.dwDrawStage) { case CDDS_ITEMPREPAINT: case CDDS_ITEMPREPAINT | CDDS_SUBITEM: { vectorIndex = (unsigned int)lpLVCustomDraw->nmcd.dwItemSpec; if (lpLVCustomDraw->iSubItem == COL_VSize) { if (sectionList[vectorIndex].highlightVirtualSize()) { lpLVCustomDraw->clrText = RGB(255,255,255); // white text lpLVCustomDraw->clrTextBk = RGB(255,0,0); // red background } } else { lpLVCustomDraw->clrText = CLR_DEFAULT; lpLVCustomDraw->clrTextBk = CLR_DEFAULT; } } break; default: break; } pResult |= CDRF_NOTIFYPOSTPAINT; pResult |= CDRF_NOTIFYITEMDRAW; pResult |= CDRF_NOTIFYSUBITEMDRAW; return pResult; } void DumpSectionGui::getAllSectionsFromFile() { - PIMAGE_DOS_HEADER pDos = 0; - PIMAGE_SECTION_HEADER pSec = 0; - PIMAGE_NT_HEADERS pNT = 0; - DWORD size = sizeof(IMAGE_DOS_HEADER) + sizeof(IMAGE_NT_HEADERS) + 200; - DWORD correctSize = 0; - CHAR sectionNameA[IMAGE_SIZEOF_SHORT_NAME + 1] = {0}; PeSection peSection; if (sectionList.empty()) { sectionList.reserve(3); } else { sectionList.clear(); } - BYTE * buffer = new BYTE[size]; + PeParser peFile(fullpath); - if (ProcessAccessHelp::readHeaderFromFile(buffer,size,fullpath)) + if (peFile.isValidPeFile()) { - pDos = (PIMAGE_DOS_HEADER)buffer; + std::vector & listSectionHeader = peFile.getSectionHeaderList(); - if (pDos->e_magic == IMAGE_DOS_SIGNATURE) + for (WORD i = 0; i < peFile.getNumberOfSections(); i++) { - pNT = (PIMAGE_NT_HEADERS)((DWORD_PTR)pDos + pDos->e_lfanew); - if (pNT->Signature == IMAGE_NT_SIGNATURE) - { - correctSize = (pNT->FileHeader.NumberOfSections*sizeof(IMAGE_SECTION_HEADER)) + sizeof(IMAGE_NT_HEADERS) + pDos->e_lfanew + 50; - - if (size < correctSize) - { - size = correctSize; - delete [] buffer; - buffer = new BYTE[size]; - if (!ProcessAccessHelp::readHeaderFromFile(buffer,size,fullpath)) - { - delete [] buffer; - return; - } - - pDos = (PIMAGE_DOS_HEADER)buffer; - pNT = (PIMAGE_NT_HEADERS)((DWORD_PTR)pDos + pDos->e_lfanew); - } - - pSec = IMAGE_FIRST_SECTION(pNT); - - for (WORD i = 0; i < pNT->FileHeader.NumberOfSections; i++) - { - ZeroMemory(sectionNameA, sizeof(sectionNameA)); - memcpy(sectionNameA,pSec->Name,8); - swprintf_s(peSection.name,L"%S",sectionNameA); - - - peSection.virtualAddress = imageBase + pSec->VirtualAddress; - peSection.virtualSize = pSec->Misc.VirtualSize; - peSection.rawAddress = pSec->PointerToRawData; - peSection.rawSize = pSec->SizeOfRawData; - peSection.characteristics = pSec->Characteristics; - peSection.isDumped = true; + peFile.getSectionNameUnicode(i, peSection.name, _countof(peSection.name)); - sectionList.push_back(peSection); + peSection.virtualAddress = imageBase + listSectionHeader[i].VirtualAddress; + peSection.virtualSize = listSectionHeader[i].Misc.VirtualSize; + peSection.rawAddress = listSectionHeader[i].PointerToRawData; + peSection.rawSize = listSectionHeader[i].SizeOfRawData; + peSection.characteristics = listSectionHeader[i].Characteristics; + peSection.isDumped = true; - pSec++; - } - - } + sectionList.push_back(peSection); } } + else + { + MessageBox(fullpath, L"Not a valid PE -> This should never happen", MB_ICONERROR); + } - delete [] buffer; } void DumpSectionGui::updateEditedItem() { if (selectedSection) { - selectedSection->virtualSize = EditListControl.GetValue(); + DWORD newValue = EditListControl.GetValue(); - displaySectionList(ListSectionSelect); + if (selectedSection->virtualSize != newValue) + { + selectedSection->virtualSize = newValue; + displaySectionList(ListSectionSelect); + selectOrDeselectAll(); + } } } void DumpSectionGui::updateCheckState() { PeSection * pesection; for (size_t i = 0; i < sectionList.size(); i++) { pesection = (PeSection *)ListSectionSelect.GetItemData((int)i); pesection->isDumped = ListSectionSelect.GetCheckState((int)i) == TRUE; } } void DumpSectionGui::selectOrDeselectAll() { BOOL checkState = ListSectionSelect.GetCheckState((int)0) ? FALSE : TRUE; for (size_t i = 0; i < sectionList.size(); i++) { ListSectionSelect.SetCheckState((int)i, checkState); } } diff --git a/Scylla/PeDump.cpp b/Scylla/PeDump.cpp index 86d9fb7..41fca1f 100644 --- a/Scylla/PeDump.cpp +++ b/Scylla/PeDump.cpp @@ -1,437 +1,437 @@ #include "PeDump.h" #include "ProcessAccessHelp.h" #include "Scylla.h" #include "Architecture.h" bool PeDump::useHeaderFromDisk = true; bool PeDump::appendOverlayData = true; //#define DEBUG_COMMENTS bool PeDump::fillPeHeaderStructs(bool fromDisk) { DWORD dwSize = ProcessAccessHelp::PE_HEADER_BYTES_COUNT; if (dwSize > sizeOfImage) { dwSize = (DWORD)sizeOfImage; } headerData = new BYTE[dwSize]; if (!headerData) return false; if (fromDisk) { //from disk if (!ProcessAccessHelp::readHeaderFromFile(headerData, dwSize, fullpath)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"fillPeHeaderStructs -> ProcessAccessHelp::readHeaderFromFile failed - %X %s", dwSize, fullpath); #endif return false; } } else { //from memory - if (!ProcessAccessHelp::readMemoryFromProcess(imageBase, dwSize, headerData)) + if (!ProcessAccessHelp::readMemoryPartlyFromProcess(imageBase, dwSize, headerData)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"fillPeHeaderStructs -> ProcessAccessHelp::readMemoryFromProcess failed - " PRINTF_DWORD_PTR_FULL L" %X " PRINTF_DWORD_PTR_FULL, imageBase, dwSize, headerData); #endif return false; } } pDOSHeader = (PIMAGE_DOS_HEADER)headerData; pNTHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)headerData + (DWORD_PTR)pDOSHeader->e_lfanew); pSectionHeader = IMAGE_FIRST_SECTION(pNTHeader); return true; } bool PeDump::validateHeaders() { if ((pDOSHeader != 0) && (pDOSHeader->e_magic == IMAGE_DOS_SIGNATURE) && (pNTHeader->Signature == IMAGE_NT_SIGNATURE)) { #ifdef _WIN64 if (pNTHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) #else if (pNTHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) #endif { return true; } else { return false; } } else { return false; } } bool PeDump::dumpCompleteProcessToDisk(const WCHAR * dumpFilePath) { if (!fillPeHeaderStructs(useHeaderFromDisk)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"dumpCompleteProcessToDisk -> fillPeHeaderStructs failed"); #endif return false; } if (!validateHeaders()) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"dumpCompleteProcessToDisk -> validateHeaders failed"); #endif return false; } dumpData = new BYTE[sizeOfImage]; if (dumpData) { if (!ProcessAccessHelp::readMemoryPartlyFromProcess(imageBase,sizeOfImage,dumpData)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"dumpCompleteProcessToDisk -> readMemoryFromProcess failed"); #endif return false; } else { fixDump(dumpData); if (saveDumpToDisk(dumpFilePath, dumpData, (DWORD)sizeOfImage)) { if (appendOverlayData) { appendOverlayDataToDump(dumpFilePath); } //printf("dump success\n"); return true; } else { return false; } } } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"dumpCompleteProcessToDisk -> new BYTE[sizeOfImage] failed %X", sizeOfImage); #endif return false; } } bool PeDump::appendOverlayDataToDump(const WCHAR *dumpFilePath) { DWORD_PTR offset = 0; DWORD size = 0; if (getOverlayData(fullpath,&offset,&size)) { if (offset == 0) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"appendOverlayDataToDump :: No overlay exists"); #endif return true; } else { if (copyFileDataFromOffset(fullpath, dumpFilePath, offset, size)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"appendOverlayDataToDump :: appending overlay success"); #endif return true; } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"appendOverlayDataToDump :: appending overlay failed"); #endif return false; } } } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"appendOverlayDataToDump :: getOverlayData failed"); #endif return false; } } bool PeDump::copyFileDataFromOffset(const WCHAR * sourceFile, const WCHAR * destFile, DWORD_PTR fileOffset, DWORD dwSize) { HANDLE hSourceFile, hDestFile; BYTE * dataBuffer = 0; bool retValue = false; hSourceFile = CreateFile(sourceFile, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); if(hSourceFile == INVALID_HANDLE_VALUE) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"copyFileDataFromOffset :: failed to open source file"); #endif return false; } hDestFile = CreateFile(destFile, GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0); if(hSourceFile == INVALID_HANDLE_VALUE) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"copyFileDataFromOffset :: failed to open destination file"); #endif CloseHandle(hSourceFile); return false; } dataBuffer = new BYTE[dwSize]; if (ProcessAccessHelp::readMemoryFromFile(hSourceFile, (LONG)fileOffset, dwSize, dataBuffer)) { if (ProcessAccessHelp::writeMemoryToFileEnd(hDestFile,dwSize,dataBuffer)) { retValue = true; } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"copyFileDataFromOffset :: writeMemoryToFileEnd failed"); #endif retValue = false; } } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"copyFileDataFromOffset :: readMemoryFromFile failed to read from source file"); #endif retValue = false; } delete [] dataBuffer; CloseHandle(hSourceFile); CloseHandle(hDestFile); return retValue; } void PeDump::fixDump(BYTE * dumpBuffer) { int counter = 0; PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)dumpBuffer; PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)((DWORD_PTR)dumpBuffer + pDos->e_lfanew); PIMAGE_SECTION_HEADER pSec = IMAGE_FIRST_SECTION(pNt); fixNtHeaderForDump(pNt, pNTHeader); do { fixSectionHeaderForDump(pSec, pSectionHeader); pSectionHeader++; pSec++; counter++; } while (counter < pNt->FileHeader.NumberOfSections); } void PeDump::fixBadNtHeaderValues(PIMAGE_NT_HEADERS pNtHead) { //maybe imagebase in process is not real imagebase pNtHead->OptionalHeader.ImageBase = imageBase; pNtHead->OptionalHeader.AddressOfEntryPoint = (DWORD)(entryPoint - imageBase); pNtHead->OptionalHeader.SizeOfImage = sizeOfImage; } void PeDump::fixSectionHeaderForDump(PIMAGE_SECTION_HEADER oldSecHead, PIMAGE_SECTION_HEADER newSecHead) { memcpy_s(oldSecHead->Name, IMAGE_SIZEOF_SHORT_NAME, newSecHead->Name, IMAGE_SIZEOF_SHORT_NAME); oldSecHead->Characteristics = newSecHead->Characteristics; oldSecHead->Misc.VirtualSize = newSecHead->Misc.VirtualSize; oldSecHead->VirtualAddress = newSecHead->VirtualAddress; oldSecHead->SizeOfRawData = newSecHead->Misc.VirtualSize; oldSecHead->PointerToRawData = newSecHead->VirtualAddress; } void PeDump::fixNtHeaderForDump(PIMAGE_NT_HEADERS oldNtHead, PIMAGE_NT_HEADERS newNtHead) { //some special fixBadNtHeaderValues(newNtHead); //fix FileHeader oldNtHead->FileHeader.NumberOfSections = newNtHead->FileHeader.NumberOfSections; //fix OptionalHeader oldNtHead->OptionalHeader.ImageBase = newNtHead->OptionalHeader.ImageBase; oldNtHead->OptionalHeader.SizeOfImage = newNtHead->OptionalHeader.SizeOfImage; oldNtHead->OptionalHeader.BaseOfCode = newNtHead->OptionalHeader.BaseOfCode; oldNtHead->OptionalHeader.AddressOfEntryPoint = newNtHead->OptionalHeader.AddressOfEntryPoint; oldNtHead->OptionalHeader.SectionAlignment = newNtHead->OptionalHeader.SectionAlignment; oldNtHead->OptionalHeader.FileAlignment = newNtHead->OptionalHeader.SectionAlignment; //deleted in x64 PE #ifndef _WIN64 oldNtHead->OptionalHeader.BaseOfData = newNtHead->OptionalHeader.BaseOfData; #endif } bool PeDump::saveDumpToDisk(const WCHAR * dumpFilePath, BYTE *dumpBuffer, DWORD dumpSize) { DWORD lpNumberOfBytesWritten = 0; bool retValue = false; HANDLE hFile = CreateFile(dumpFilePath, GENERIC_WRITE, FILE_SHARE_WRITE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); if(hFile == INVALID_HANDLE_VALUE) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"saveDumpToDisk :: INVALID_HANDLE_VALUE %u", GetLastError()); #endif retValue = false; } else { if (WriteFile(hFile, dumpBuffer, dumpSize, &lpNumberOfBytesWritten, 0)) { if (lpNumberOfBytesWritten != dumpSize) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"saveDumpToDisk :: lpNumberOfBytesWritten != dumpSize %d %d", lpNumberOfBytesWritten,dumpSize); #endif retValue = false; } else { retValue = true; } } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"saveDumpToDisk :: WriteFile failed %u",GetLastError()); #endif retValue = false; } CloseHandle(hFile); } return retValue; } bool PeDump::getOverlayData(const WCHAR * filepath, DWORD_PTR * overlayFileOffset, DWORD * overlaySize) { LONGLONG fileSize = 0; DWORD dwSize = 0; DWORD bufferSize = 1000; BYTE *buffer = 0; bool returnValue = 0; PIMAGE_DOS_HEADER pDOSh = 0; PIMAGE_NT_HEADERS pNTh = 0; PIMAGE_SECTION_HEADER pSech = 0; int counter = 0; DWORD calcSize = 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"getOverlayData :: INVALID_HANDLE_VALUE %u", GetLastError()); #endif returnValue = false; } else { fileSize = ProcessAccessHelp::getFileSize(hFile); if (fileSize > 0) { if (fileSize > bufferSize) { dwSize = bufferSize; } else { dwSize = (DWORD)(fileSize - 1); } buffer = new BYTE[dwSize]; if (ProcessAccessHelp::readMemoryFromFile(hFile, 0, dwSize, buffer)) { pDOSh = (PIMAGE_DOS_HEADER)buffer; pNTh = (PIMAGE_NT_HEADERS)((DWORD_PTR)buffer + pDOSh->e_lfanew); //first section pSech = IMAGE_FIRST_SECTION(pNTh); counter = 1; //get last section while(counter < pNTh->FileHeader.NumberOfSections) { counter++; pSech++; } //printf("PointerToRawData %X\nSizeOfRawData %X\nfile size %X\n",pSech->PointerToRawData,pSech->SizeOfRawData,pSech->PointerToRawData+pSech->SizeOfRawData); calcSize = pSech->PointerToRawData + pSech->SizeOfRawData; if (calcSize < fileSize) { //overlay found *overlayFileOffset = calcSize; *overlaySize = (DWORD)(fileSize - calcSize); } else { *overlayFileOffset = 0; *overlaySize = 0; } returnValue = true; } else { returnValue = false; } delete [] buffer; } else { returnValue = false; } CloseHandle(hFile); } return returnValue; } \ No newline at end of file diff --git a/Scylla/PeParser.cpp b/Scylla/PeParser.cpp new file mode 100644 index 0000000..180d542 --- /dev/null +++ b/Scylla/PeParser.cpp @@ -0,0 +1,298 @@ + +#include "PeParser.h" + + +PeParser::PeParser(const WCHAR * file, bool readSectionHeaders) +{ + fileMemory = 0; + headerMemory = 0; + pDosHeader = 0; + pNTHeader32 = 0; + pNTHeader64 = 0; + + filename = file; + + if (wcslen(filename) > 3) + { + readPeHeader(readSectionHeaders); + + if (readSectionHeaders) + { + if (isValidPeFile()) + { + getSectionHeaders(); + } + } + } +} + +PeParser::~PeParser() +{ + if (headerMemory) + { + delete [] headerMemory; + } + if (fileMemory) + { + delete [] fileMemory; + } + + listSectionHeaders.clear(); +} + +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::readPeHeader(bool readSectionHeaders) +{ + bool retValue = false; + DWORD readSize = sizeof(IMAGE_DOS_HEADER) + 200 + sizeof(IMAGE_NT_HEADERS64); + DWORD correctSize = 0; + DWORD numberOfBytesRead = 0; + + if (readSectionHeaders) + { + readSize += (10 * sizeof(IMAGE_SECTION_HEADER)); + } + + headerMemory = new BYTE[readSize]; + + HANDLE hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); + + if (hFile != INVALID_HANDLE_VALUE) + { + if (ReadFile(hFile, headerMemory, readSize, &numberOfBytesRead, 0)) + { + retValue = true; + pDosHeader = (PIMAGE_DOS_HEADER)headerMemory; + + if (pDosHeader->e_lfanew > 0 && pDosHeader->e_lfanew < (LONG)readSize) //malformed PE + { + pNTHeader32 = (PIMAGE_NT_HEADERS32)((DWORD_PTR)pDosHeader + pDosHeader->e_lfanew); + pNTHeader64 = (PIMAGE_NT_HEADERS64)((DWORD_PTR)pDosHeader + pDosHeader->e_lfanew); + } + + if (isValidPeFile()) + { + 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 valid pe + } + + if (readSize < correctSize) + { + readSize = correctSize; + delete [] headerMemory; + headerMemory = new BYTE[readSize]; + + SetFilePointer(hFile, 0, 0, FILE_BEGIN); + + if (ReadFile(hFile,headerMemory,readSize,&numberOfBytesRead,0)) + { + pDosHeader = (PIMAGE_DOS_HEADER)headerMemory; + if (pDosHeader->e_lfanew > 0 && pDosHeader->e_lfanew < (LONG)readSize) //malformed PE + { + pNTHeader32 = (PIMAGE_NT_HEADERS32)((DWORD_PTR)pDosHeader + pDosHeader->e_lfanew); + pNTHeader64 = (PIMAGE_NT_HEADERS64)((DWORD_PTR)pDosHeader + pDosHeader->e_lfanew); + } + } + } + } + } + + CloseHandle(hFile); + } + + return retValue; +} + +bool PeParser::readFileToMemory() +{ + bool retValue = false; + DWORD numberOfBytesRead = 0; + LARGE_INTEGER largeInt = {0}; + const DWORD MaxFileSize = 500 * 1024 * 1024; // GB * MB * KB * B -> 500 MB + + HANDLE hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); + + if (hFile != INVALID_HANDLE_VALUE) + { + if (GetFileSizeEx(hFile, &largeInt)) + { + if (largeInt.QuadPart > MaxFileSize) + { + //TODO handle big files + retValue = false; + } + else + { + fileMemory = new BYTE[largeInt.LowPart]; + + if (ReadFile(hFile,fileMemory,largeInt.LowPart,&numberOfBytesRead,0)) + { + retValue = true; + } + else + { + delete [] fileMemory; + fileMemory = 0; + } + } + } + + CloseHandle(hFile); + } + + return retValue; +} + +bool PeParser::getSectionHeaders() +{ + PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNTHeader32); + + listSectionHeaders.clear(); + listSectionHeaders.reserve(getNumberOfSections()); + + for (WORD i = 0; i < getNumberOfSections(); i++) + { + listSectionHeaders.push_back(*pSection); + pSection++; + } + + return true; +} + +bool PeParser::getSectionNameUnicode(const int sectionIndex, WCHAR * output, int outputLen) +{ + CHAR sectionNameA[IMAGE_SIZEOF_SHORT_NAME + 1] = {0}; + + output[0] = 0; + + memcpy(sectionNameA, listSectionHeaders[sectionIndex].Name, IMAGE_SIZEOF_SHORT_NAME); + + return (swprintf_s(output, outputLen, L"%S", sectionNameA) != -1); +} + +WORD PeParser::getNumberOfSections() +{ + return pNTHeader32->FileHeader.NumberOfSections; +} + +std::vector & PeParser::getSectionHeaderList() +{ + return listSectionHeaders; +} + diff --git a/Scylla/PeParser.h b/Scylla/PeParser.h new file mode 100644 index 0000000..86b5c12 --- /dev/null +++ b/Scylla/PeParser.h @@ -0,0 +1,50 @@ +#pragma once + +#include +#include + +class PeParser +{ +public: + PeParser(const WCHAR * file, bool readSectionHeaders = true); + //PeParser(HANDLE hProcess, 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(); + + DWORD getEntryPoint(); + + bool getSectionNameUnicode(const int sectionIndex, WCHAR * output, int outputLen); + +private: + const WCHAR * filename; + + PIMAGE_DOS_HEADER pDosHeader; + PIMAGE_NT_HEADERS32 pNTHeader32; + PIMAGE_NT_HEADERS64 pNTHeader64; + + std::vector listSectionHeaders; + + BYTE * fileMemory; + BYTE * headerMemory; + + bool readPeHeader(bool readSectionHeaders); + bool readFileToMemory(); + + bool hasDirectory(const int directoryIndex); + bool getSectionHeaders(); + bool readPeHeaderFromProcess( HANDLE hProcess, DWORD_PTR moduleBase ); +}; + diff --git a/Scylla/PluginLoader.cpp b/Scylla/PluginLoader.cpp index 4c8a168..ac0c3aa 100644 --- a/Scylla/PluginLoader.cpp +++ b/Scylla/PluginLoader.cpp @@ -1,353 +1,326 @@ #include "PluginLoader.h" #include "Logger.h" #include "ProcessAccessHelp.h" #include "StringConversion.h" #include +#include "PeParser.h" + const WCHAR PluginLoader::PLUGIN_DIR[] = L"Plugins\\"; const WCHAR PluginLoader::PLUGIN_SEARCH_STRING[] = L"*.dll"; const WCHAR PluginLoader::PLUGIN_IMPREC_DIR[] = L"ImpRec_Plugins\\"; const WCHAR PluginLoader::PLUGIN_IMPREC_WRAPPER_DLL[] = L"Imprec_Wrapper_DLL.dll"; //#define DEBUG_COMMENTS std::vector & PluginLoader::getScyllaPluginList() { return scyllaPluginList; } std::vector & PluginLoader::getImprecPluginList() { return imprecPluginList; } bool PluginLoader::findAllPlugins() { if (!scyllaPluginList.empty()) { scyllaPluginList.clear(); } if (!imprecPluginList.empty()) { imprecPluginList.clear(); } if (!buildSearchString()) { return false; } if (!searchForPlugin(scyllaPluginList, dirSearchString, true)) { return false; } #ifndef _WIN64 if (!buildSearchStringImprecPlugins()) { return false; } if (!searchForPlugin(imprecPluginList, dirSearchString, false)) { return false; } #endif return true; } bool PluginLoader::searchForPlugin(std::vector & newPluginList, const WCHAR * searchPath, bool isScyllaPlugin) { WIN32_FIND_DATA ffd; HANDLE hFind = 0; DWORD dwError = 0; Plugin pluginData; hFind = FindFirstFile(searchPath, &ffd); dwError = GetLastError(); if (dwError == ERROR_FILE_NOT_FOUND) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"findAllPlugins :: No files found"); #endif return true; } if (hFind == INVALID_HANDLE_VALUE) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"findAllPlugins :: FindFirstFile failed %d", dwError); #endif return false; } do { if ( !(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) { if ((ffd.nFileSizeHigh != 0) || (ffd.nFileSizeLow < 200)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"findAllPlugins :: Plugin invalid file size: %s", ffd.cFileName); #endif } else { pluginData.fileSize = ffd.nFileSizeLow; wcscpy_s(pluginData.fullpath, baseDirPath); wcscat_s(pluginData.fullpath, ffd.cFileName); #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"findAllPlugins :: Plugin %s", pluginData.fullpath); #endif if (isValidDllFile(pluginData.fullpath)) { if (isScyllaPlugin) { if (getScyllaPluginName(&pluginData)) { //add valid plugin newPluginList.push_back(pluginData); } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"Cannot get scylla plugin name %s", pluginData.fullpath); #endif } } else { if (isValidImprecPlugin(pluginData.fullpath)) { wcscpy_s(pluginData.pluginName, ffd.cFileName); newPluginList.push_back(pluginData); } } } } } } while (FindNextFile(hFind, &ffd) != 0); dwError = GetLastError(); FindClose(hFind); if (dwError == ERROR_NO_MORE_FILES) { return true; } else { return false; } } bool PluginLoader::getScyllaPluginName(Plugin * pluginData) { bool retValue = false; char * pluginName = 0; def_ScyllaPluginNameW ScyllaPluginNameW = 0; def_ScyllaPluginNameA ScyllaPluginNameA = 0; HMODULE hModule = LoadLibraryEx(pluginData->fullpath, 0, DONT_RESOLVE_DLL_REFERENCES); //do not call DllMain if (hModule) { ScyllaPluginNameW = (def_ScyllaPluginNameW)GetProcAddress(hModule, "ScyllaPluginNameW"); if (ScyllaPluginNameW) { wcscpy_s(pluginData->pluginName, ScyllaPluginNameW()); #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"getPluginName :: Plugin name %s", pluginData->pluginName); #endif retValue = true; } else { ScyllaPluginNameA = (def_ScyllaPluginNameA)GetProcAddress(hModule, "ScyllaPluginNameA"); if (ScyllaPluginNameA) { pluginName = ScyllaPluginNameA(); StringConversion::ToUTF16(pluginName, pluginData->pluginName, _countof(pluginData->pluginName)); #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"getPluginName :: Plugin name mbstowcs_s %s", pluginData->pluginName); #endif if (wcslen(pluginData->pluginName) > 1) { retValue = true; } else { retValue = false; } } else { retValue = false; } } FreeLibrary(hModule); return retValue; } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"getPluginName :: LoadLibraryEx failed %s", pluginData->fullpath); #endif return false; } } bool PluginLoader::buildSearchString() { ZeroMemory(dirSearchString, sizeof(dirSearchString)); ZeroMemory(baseDirPath, sizeof(baseDirPath)); if (!GetModuleFileName(0, dirSearchString, _countof(dirSearchString))) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"buildSearchString :: GetModuleFileName failed %d", GetLastError()); #endif return false; } //wprintf(L"dirSearchString 1 %s\n\n", dirSearchString); PathRemoveFileSpec(dirSearchString); //wprintf(L"dirSearchString 2 %s\n\n", dirSearchString); PathAppend(dirSearchString, PLUGIN_DIR); wcscpy_s(baseDirPath, dirSearchString); wcscat_s(dirSearchString, PLUGIN_SEARCH_STRING); //wprintf(L"dirSearchString 3 %s\n\n", dirSearchString); #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"dirSearchString final %s", dirSearchString); #endif return true; } bool PluginLoader::isValidDllFile( const WCHAR * fullpath ) { - BYTE * data = 0; - DWORD lpNumberOfBytesRead = 0; - PIMAGE_DOS_HEADER pDos = 0; - PIMAGE_NT_HEADERS pNT = 0; - bool retValue = false; - - HANDLE hFile = CreateFile(fullpath, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); + PeParser peFile(fullpath,false); - if (hFile != INVALID_HANDLE_VALUE) + if (peFile.isTargetFileSamePeFormat() && peFile.hasExportDirectory()) { - data = new BYTE[sizeof(IMAGE_DOS_HEADER) + sizeof(IMAGE_NT_HEADERS) + 0x100]; - - if (ReadFile(hFile, data, sizeof(IMAGE_DOS_HEADER) + sizeof(IMAGE_NT_HEADERS) + 0x100, &lpNumberOfBytesRead, 0)) - { - pDos = (PIMAGE_DOS_HEADER)data; - - if (pDos->e_magic == IMAGE_DOS_SIGNATURE) - { - pNT = (PIMAGE_NT_HEADERS)((DWORD_PTR)pDos + pDos->e_lfanew); - - if (pNT->Signature == IMAGE_NT_SIGNATURE) - { -#ifdef _WIN64 - if (pNT->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) -#else - if (pNT->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) -#endif - { - retValue = true; - } - } - } - } - - delete [] data; - CloseHandle(hFile); + return true; + } + else + { + return false; } - - return retValue; } bool PluginLoader::isValidImprecPlugin(const WCHAR * fullpath) { def_Imprec_Trace Imprec_Trace = 0; bool retValue = false; HMODULE hModule = LoadLibraryEx(fullpath, 0, DONT_RESOLVE_DLL_REFERENCES); //do not call DllMain if (hModule) { Imprec_Trace = (def_Imprec_Trace)GetProcAddress(hModule, "Trace"); if (Imprec_Trace) { retValue = true; } else { retValue = false; } FreeLibrary(hModule); return retValue; } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"isValidImprecPlugin :: LoadLibraryEx failed %s", pluginData->fullpath); #endif return false; } } bool PluginLoader::buildSearchStringImprecPlugins() { wcscpy_s(dirSearchString, baseDirPath); wcscat_s(dirSearchString, PLUGIN_IMPREC_DIR); wcscpy_s(baseDirPath, dirSearchString); //build imprec wrapper dll path wcscpy_s(imprecWrapperDllPath, dirSearchString); wcscat_s(imprecWrapperDllPath, PLUGIN_IMPREC_WRAPPER_DLL); if (!fileExists(imprecWrapperDllPath)) { return false; } wcscat_s(dirSearchString, PLUGIN_SEARCH_STRING); return true; } bool PluginLoader::fileExists(const WCHAR * fileName) { return (GetFileAttributesW(fileName) != INVALID_FILE_ATTRIBUTES); } diff --git a/Scylla/ProcessAccessHelp.cpp b/Scylla/ProcessAccessHelp.cpp index 86324b9..f7867f7 100644 --- a/Scylla/ProcessAccessHelp.cpp +++ b/Scylla/ProcessAccessHelp.cpp @@ -1,802 +1,786 @@ #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); hFile = 0; } 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)) { 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)) { 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) { - PIMAGE_NT_HEADERS pNtHeader = 0; - PIMAGE_DOS_HEADER pDosHeader = 0; + PeParser peFile(filePath, false); - readHeaderFromCurrentFile(filePath); - - pDosHeader = (PIMAGE_DOS_HEADER)fileHeaderFromDisk; - - if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) - { - return 0; - } - - pNtHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)fileHeaderFromDisk + (DWORD_PTR)(pDosHeader->e_lfanew)); - - if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) - { - return 0; - } - - return pNtHeader->OptionalHeader.AddressOfEntryPoint; + 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; } diff --git a/Scylla/Scylla.h b/Scylla/Scylla.h index 8bb0893..6163ba5 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.6 Beta 3" +#define APPVERSION_S "v0.6 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[]; }; diff --git a/Scylla/Scylla.vcxproj b/Scylla/Scylla.vcxproj index c22bab0..8397a2f 100644 --- a/Scylla/Scylla.vcxproj +++ b/Scylla/Scylla.vcxproj @@ -1,252 +1,252 @@  Debug Win32 Debug x64 Release Win32 Release x64 {710434C9-FC4B-4F1D-B318-E10ADC78499F} Win32Proj Scylla Application true Unicode v90 Application true Unicode - v90 Application false true Unicode v90 Application false true Unicode - v90 true $(SolutionDir)$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ $(SolutionDir)WTL81_9127_Include;$(IncludePath) true $(SolutionDir)WTL81_9127_Include;$(IncludePath) false $(SolutionDir)$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ $(SolutionDir)WTL81_9127_Include;$(IncludePath) false $(SolutionDir)WTL81_9127_Include;$(IncludePath) Level3 Disabled WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) $(SolutionDir)tinyxml;$(SolutionDir)diStorm\include;%(AdditionalIncludeDirectories) Windows true - $(SolutionDir)$(Platform)\$(Configuration)\diStorm.lib;$(SolutionDir)$(Platform)\$(Configuration)\tinyxml.lib;psapi.lib;dbghelp.lib;imagehlp.lib;%(AdditionalDependencies) + $(SolutionDir)$(Platform)\$(Configuration)\diStorm.lib;$(SolutionDir)$(Platform)\$(Configuration)\tinyxml.lib;%(AdditionalDependencies) type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' true $(TargetDir)$(TargetName).map Level3 Disabled WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) $(SolutionDir)tinyxml;$(SolutionDir)diStorm\include;%(AdditionalIncludeDirectories) Windows true - $(SolutionDir)$(Platform)\$(Configuration)\diStorm.lib;$(SolutionDir)$(Platform)\$(Configuration)\tinyxml.lib;psapi.lib;dbghelp.lib;imagehlp.lib;%(AdditionalDependencies) + $(SolutionDir)$(Platform)\$(Configuration)\diStorm.lib;$(SolutionDir)$(Platform)\$(Configuration)\tinyxml.lib;%(AdditionalDependencies) type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' Level3 MaxSpeed true true WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) MultiThreaded $(SolutionDir)tinyxml;$(SolutionDir)diStorm\include;%(AdditionalIncludeDirectories) true Speed Windows false true true - $(SolutionDir)$(Platform)\$(Configuration)\diStorm.lib;$(SolutionDir)$(Platform)\$(Configuration)\tinyxml.lib;psapi.lib;dbghelp.lib;imagehlp.lib;%(AdditionalDependencies) + $(SolutionDir)$(Platform)\$(Configuration)\diStorm.lib;$(SolutionDir)$(Platform)\$(Configuration)\tinyxml.lib;%(AdditionalDependencies) type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' Level3 MaxSpeed true true WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) MultiThreaded $(SolutionDir)tinyxml;$(SolutionDir)diStorm\include;%(AdditionalIncludeDirectories) true Windows false true true - $(SolutionDir)$(Platform)\$(Configuration)\diStorm.lib;$(SolutionDir)$(Platform)\$(Configuration)\tinyxml.lib;psapi.lib;dbghelp.lib;imagehlp.lib;%(AdditionalDependencies) + $(SolutionDir)$(Platform)\$(Configuration)\diStorm.lib;$(SolutionDir)$(Platform)\$(Configuration)\tinyxml.lib;%(AdditionalDependencies) type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' + + \ No newline at end of file