diff --git a/GleeBug/Static.Pe.cpp b/GleeBug/Static.Pe.cpp index ce6f0a6..d440666 100644 --- a/GleeBug/Static.Pe.cpp +++ b/GleeBug/Static.Pe.cpp @@ -20,7 +20,7 @@ namespace GleeBug _sectionHeaders = Region(); } - bool Pe::ParseHeaders() + Pe::Error Pe::ParseHeaders() { //clear all current data Clear(); @@ -28,58 +28,89 @@ namespace GleeBug //read the DOS header _dosHeader = readRegion(); if (!_dosHeader) - return false; + return ErrorDosHeaderRead; //verify the DOS header - if (_dosHeader()->e_magic != IMAGE_DOS_SIGNATURE) - return false; + if (_dosHeader->e_magic != IMAGE_DOS_SIGNATURE) + return ErrorDosHeaderMagic; //get the NT headers offset - auto newOffset = uint32(_dosHeader()->e_lfanew); + auto newOffset = uint32(_dosHeader->e_lfanew); //verify the new offset if (newOffset < 0 || newOffset < _offset || newOffset >= _file.GetSize()) - return false; + return ErrorDosHeaderNtHeaderOffset; - //read the data between the DOS header and the NT headers - auto offsetDiff = newOffset - _offset; - _afterDosData = readRegion(offsetDiff); + //read & verify the data between the DOS header and the NT headers + auto afterDosCount = newOffset - _offset; + _afterDosData = readRegion(afterDosCount); + if (!_afterDosData) + return ErrorAfterDosHeaderData; //read & verify the signature auto signature = readRegion(); - if (!signature || *(signature()) != IMAGE_NT_SIGNATURE) - return false; + if (!signature) + return ErrorNtSignatureRead; + if (*(signature()) != IMAGE_NT_SIGNATURE) + return ErrorNtSignatureMagic; //read the file header auto ifh = readRegion(); if (!ifh) - return false; - switch (ifh()->Machine) + return ErrorNtFileHeaderRead; + + //read the optional header + uint32 realSizeOfIoh; + switch (ifh->Machine) { case IMAGE_FILE_MACHINE_I386: - _ntHeaders32 = Region(&_data, signature.Offset()); //this region is not valid at this point - if (!readRegion()) //read the optional header data - return false; - if (!_ntHeaders32) //validate we read the entire NT headers region - return false; - break; + { + //read & verify the optional header + realSizeOfIoh = uint32(sizeof(IMAGE_OPTIONAL_HEADER32)); + auto ioh = readRegion(); + if (!ioh) + return ErrorNtOptionalHeaderRead; + if (ioh->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) + return ErrorNtOptionalHeaderMagic; + + //construct & verify the NT headers region + _ntHeaders32 = Region(&_data, signature.Offset()); + if (!_ntHeaders32) + return ErrorNtHeadersRegionSize; + } + break; + case IMAGE_FILE_MACHINE_AMD64: - _ntHeaders64 = Region(&_data, signature.Offset()); //this region is not valid at this point - if (!readRegion()) //read the optional header data - return false; - if (!_ntHeaders64) //validate we read the entire NT headers region - return false; - break; + { + //read & verify the optional header + realSizeOfIoh = uint32(sizeof(IMAGE_OPTIONAL_HEADER64)); + auto ioh = readRegion(); + if (!ioh) + return ErrorNtOptionalHeaderRead; + if (ioh->Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) + return ErrorNtOptionalHeaderMagic; + + //construct & verify the NT headers region + _ntHeaders64 = Region(&_data, signature.Offset()); + if (!_ntHeaders64) + return ErrorNtHeadersRegionSize; + } + break; + default: //unsupported machine - return false; + return ErrorNtFileHeaderUnsupportedMachine; } -#define IMAGE_FIRST_SECTION123( ntheader ) ((PIMAGE_SECTION_HEADER) \ - ((ULONG_PTR)(ntheader) + \ - FIELD_OFFSET( IMAGE_NT_HEADERS, OptionalHeader ) + \ - ((ntheader))->FileHeader.SizeOfOptionalHeader \ - )) - return true; + //read data after the optional header + auto sizeOfIoh = ifh->SizeOfOptionalHeader; //this field can be zero + uint32 afterOptionalCount = sizeOfIoh > realSizeOfIoh ? sizeOfIoh - realSizeOfIoh : 0; + _afterOptionalData = readRegion(afterOptionalCount); + + //read the section headers + auto sectionCount = ifh->NumberOfSections; + _sectionHeaders = readRegion(sectionCount); + + return ErrorOk; } uint32 Pe::readData(uint32 size) @@ -97,11 +128,11 @@ namespace GleeBug bool Pe::IsValidPe() const { - return false; + return _sectionHeaders.Valid(); } bool Pe::IsPe64() const { - return false; + return IsValidPe() ? _ntHeaders64.Valid() : false; } }; \ No newline at end of file diff --git a/GleeBug/Static.Pe.h b/GleeBug/Static.Pe.h index c52ba46..028e413 100644 --- a/GleeBug/Static.Pe.h +++ b/GleeBug/Static.Pe.h @@ -9,10 +9,26 @@ namespace GleeBug class Pe { public: + enum Error + { + ErrorOk, + ErrorDosHeaderRead, + ErrorDosHeaderMagic, + ErrorDosHeaderNtHeaderOffset, + ErrorAfterDosHeaderData, + ErrorNtSignatureRead, + ErrorNtSignatureMagic, + ErrorNtFileHeaderRead, + ErrorNtFileHeaderUnsupportedMachine, + ErrorNtOptionalHeaderRead, + ErrorNtOptionalHeaderMagic, + ErrorNtHeadersRegionSize + }; + explicit Pe(File & file); void Clear(); - bool ParseHeaders(); + Error ParseHeaders(); bool IsValidPe() const; bool IsPe64() const; @@ -20,6 +36,7 @@ namespace GleeBug const Region & GetAfterDosData() const { return _afterDosData; } const Region & GetNtHeaders32() const { return _ntHeaders32; } const Region & GetNtHeaders64() const { return _ntHeaders64; } + const Region & GetAfterOptionalData() const { return _afterOptionalData; } const Region & GetSectionHeaders() const { return _sectionHeaders; } private: @@ -40,6 +57,7 @@ namespace GleeBug Region _afterDosData; Region _ntHeaders32; Region _ntHeaders64; + Region _afterOptionalData; Region _sectionHeaders; }; }; diff --git a/GleeBug/Static.Region.h b/GleeBug/Static.Region.h index af37887..7955679 100644 --- a/GleeBug/Static.Region.h +++ b/GleeBug/Static.Region.h @@ -80,6 +80,14 @@ namespace GleeBug _offset + _count * sizeof(T) <= _data->size(); } + /** + \brief Returns if this region is empty (has no data). + */ + bool Empty() const + { + return Size() == 0; + } + /** \brief Returns Valid(). */ @@ -96,6 +104,11 @@ namespace GleeBug return Data(); } + T* operator ->() const + { + return Data(); + } + private: std::vector* _data; uint32 _offset; diff --git a/MyDebugger/main.cpp b/MyDebugger/main.cpp index 836f74c..eab78ff 100644 --- a/MyDebugger/main.cpp +++ b/MyDebugger/main.cpp @@ -3,14 +3,13 @@ #include "GleeBug/Static.File.h" #include "GleeBug/Static.Pe.h" -#ifdef _WIN64 -wchar_t szFilePath[256] = L"c:\\test64.exe"; -#else //x86 -wchar_t szFilePath[256] = L"c:\\test32.exe"; -#endif //_WIN64 - static void testDebugger() { +#ifdef _WIN64 + wchar_t szFilePath[256] = L"c:\\test64.exe"; +#else //x86 + wchar_t szFilePath[256] = L"c:\\test32.exe"; +#endif //_WIN64 wchar_t szCommandLine[256] = L""; wchar_t szCurrentDir[256] = L"c:\\"; MyDebugger dbg; @@ -26,36 +25,79 @@ static void testDebugger() } } +template +static void printRegion(const char* str, Region region) +{ + printf("\n%s (offset: 0x%X, size: 0x%X, v: %s, e: %s)\n", + str, + region.Offset(), + region.Size(), + region.Valid() ? "true" : "false", + region.Empty() ? "true" : "false"); +} + static void testStatic() { +#ifdef _WIN64 + wchar_t szFilePath[256] = L"c:\\test64.exe"; +#else //x86 + wchar_t szFilePath[256] = L"c:\\!exclude\\pe\\mini.exe"; +#endif //_WIN64 using namespace GleeBug; File file(szFilePath, File::ReadOnly); if (file.Open()) { Pe pe(file); - if (pe.ParseHeaders()) + if (pe.ParseHeaders() == Pe::ErrorOk) { - PIMAGE_DOS_HEADER idh = pe.GetDosHeader().Data(); - puts("DOS Header:"); + auto idh = pe.GetDosHeader(); + printRegion("DOS Header:", idh); printf(" e_magic: %02X\n", idh->e_magic); printf(" e_lfanew: %08X\n", idh->e_lfanew); + + auto afterDosData = pe.GetAfterDosData(); + printRegion("After DOS Data", afterDosData); + #ifdef _WIN64 - PIMAGE_NT_HEADERS64 inth = pe.GetNtHeaders64().Data(); + auto inth = pe.GetNtHeaders64(); #else //x32 - PIMAGE_NT_HEADERS32 inth = pe.GetNtHeaders32().Data(); + auto inth = pe.GetNtHeaders32(); #endif //_WIN64 - puts("\nNT Headers:"); + printRegion("NT Headers:", inth); printf(" Signature: %08X\n", inth->Signature); + PIMAGE_FILE_HEADER ifh = &inth->FileHeader; puts("\n File Header:"); - printf(" Machine : %02X\n", ifh->Machine); - printf(" TimeDateStamp: %08X\n", ifh->TimeDateStamp); + printf(" Machine : %04X\n", ifh->Machine); + printf(" NumberOfSections: %04X\n", ifh->NumberOfSections); + printf(" TimeDateStamp : %08X\n", ifh->TimeDateStamp); + PIMAGE_OPTIONAL_HEADER ioh = &inth->OptionalHeader; puts("\n Optional Header:"); - printf(" Magic : %04X\n", ioh->Magic); - printf(" ImageBase: %p\n", ioh->ImageBase); - printf(" Subsystem: %04X\n", ioh->Subsystem); - puts("\n Section Headers:"); + printf(" Magic : %04X\n", ioh->Magic); + printf(" EntryPoint: %08X\n", ioh->AddressOfEntryPoint); + printf(" ImageBase : %p\n", ioh->ImageBase); + printf(" Subsystem : %04X\n", ioh->Subsystem); + + auto afterOptionalData = pe.GetAfterOptionalData(); + printRegion("After Optional Data", afterOptionalData); + + auto ish = pe.GetSectionHeaders(); + printRegion("Section Headers:", ish); + for (auto i = 0; i < ifh->NumberOfSections; i++) + { + if (i) + puts(""); + auto cur = ish.Data() + i; + printf(" Section %d:\n", i + 1); + char name[9] = ""; + memcpy(name, cur->Name, sizeof(cur->Name)); + printf(" Name : %s\n", name); + printf(" VSize: %08X\n", cur->Misc.VirtualSize); + printf(" VAddr: %08X\n", cur->VirtualAddress); + printf(" RSize: %08X\n", cur->SizeOfRawData); + printf(" RAddr: %08X\n", cur->PointerToRawData); + } } else puts("Pe::ParseHeaders failed!");