diff --git a/GleeBug/GleeBug.vcxproj b/GleeBug/GleeBug.vcxproj index 1d5a1ef..578546d 100644 --- a/GleeBug/GleeBug.vcxproj +++ b/GleeBug/GleeBug.vcxproj @@ -164,6 +164,7 @@ + @@ -177,6 +178,9 @@ + + + diff --git a/GleeBug/GleeBug.vcxproj.filters b/GleeBug/GleeBug.vcxproj.filters index b04db63..8fd3aba 100644 --- a/GleeBug/GleeBug.vcxproj.filters +++ b/GleeBug/GleeBug.vcxproj.filters @@ -65,6 +65,9 @@ Source Files + + Source Files + @@ -100,5 +103,14 @@ Header Files + + Header Files + + + Header Files + + + Header Files + \ No newline at end of file diff --git a/GleeBug/Static.Pe.cpp b/GleeBug/Static.Pe.cpp new file mode 100644 index 0000000..ce6f0a6 --- /dev/null +++ b/GleeBug/Static.Pe.cpp @@ -0,0 +1,107 @@ +#include "Static.Pe.h" + +namespace GleeBug +{ + Pe::Pe(File & file) + : _file(file) + { + Clear(); + } + + void Pe::Clear() + { + _fileSize = 0; + _data.clear(); + _offset = 0; + _dosHeader = Region(); + _afterDosData = Region(); + _ntHeaders32 = Region(); + _ntHeaders64 = Region(); + _sectionHeaders = Region(); + } + + bool Pe::ParseHeaders() + { + //clear all current data + Clear(); + + //read the DOS header + _dosHeader = readRegion(); + if (!_dosHeader) + return false; + + //verify the DOS header + if (_dosHeader()->e_magic != IMAGE_DOS_SIGNATURE) + return false; + + //get the NT headers offset + auto newOffset = uint32(_dosHeader()->e_lfanew); + + //verify the new offset + if (newOffset < 0 || newOffset < _offset || newOffset >= _file.GetSize()) + return false; + + //read the data between the DOS header and the NT headers + auto offsetDiff = newOffset - _offset; + _afterDosData = readRegion(offsetDiff); + + //read & verify the signature + auto signature = readRegion(); + if (!signature || *(signature()) != IMAGE_NT_SIGNATURE) + return false; + + //read the file header + auto ifh = readRegion(); + if (!ifh) + return false; + 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; + 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; + default: //unsupported machine + return false; + } + +#define IMAGE_FIRST_SECTION123( ntheader ) ((PIMAGE_SECTION_HEADER) \ + ((ULONG_PTR)(ntheader) + \ + FIELD_OFFSET( IMAGE_NT_HEADERS, OptionalHeader ) + \ + ((ntheader))->FileHeader.SizeOfOptionalHeader \ + )) + return true; + } + + uint32 Pe::readData(uint32 size) + { + std::vector temp(size); + + if (!_file.Read(_offset, temp.data(), size)) + return INVALID_VALUE; + + auto result = _offset; + _offset += size; + _data.insert(_data.end(), temp.begin(), temp.end()); + return result; + } + + bool Pe::IsValidPe() const + { + return false; + } + + bool Pe::IsPe64() const + { + return false; + } +}; \ No newline at end of file diff --git a/GleeBug/Static.Pe.h b/GleeBug/Static.Pe.h new file mode 100644 index 0000000..c52ba46 --- /dev/null +++ b/GleeBug/Static.Pe.h @@ -0,0 +1,47 @@ +#ifndef _STATIC_PE_H +#define _STATIC_PE_H + +#include "Static.File.h" +#include "Static.Region.h" + +namespace GleeBug +{ + class Pe + { + public: + explicit Pe(File & file); + + void Clear(); + bool ParseHeaders(); + bool IsValidPe() const; + bool IsPe64() const; + + const Region & GetDosHeader() const { return _dosHeader; } + const Region & GetAfterDosData() const { return _afterDosData; } + const Region & GetNtHeaders32() const { return _ntHeaders32; } + const Region & GetNtHeaders64() const { return _ntHeaders64; } + const Region & GetSectionHeaders() const { return _sectionHeaders; } + + private: + uint32 readData(uint32 size); + + template + inline Region readRegion(uint32 count = 1) + { + return Region(&_data, readData(sizeof(T) * count), count); + } + + File & _file; + uint32 _fileSize; + std::vector _data; + uint32 _offset; + + Region _dosHeader; + Region _afterDosData; + Region _ntHeaders32; + Region _ntHeaders64; + Region _sectionHeaders; + }; +}; + +#endif //_STATIC_PE_H \ No newline at end of file diff --git a/GleeBug/Static.Region.h b/GleeBug/Static.Region.h new file mode 100644 index 0000000..af37887 --- /dev/null +++ b/GleeBug/Static.Region.h @@ -0,0 +1,106 @@ +#ifndef _STATIC_REGION_H +#define _STATIC_REGION_H + +#include "Static.Global.h" + +namespace GleeBug +{ + /** + \brief An immutable region object. Used to indicate a region of data in a vector. + \tparam T Type of the data in the region. + */ + template + class Region + { + public: + /** + \brief Default constructor (constructs an invalid region). + */ + explicit Region() + : Region(nullptr, INVALID_VALUE, INVALID_VALUE) + { + } + + /** + \brief Constructor (constructs a valid region). + \param [in] data Pointer to the vector that holds the actual data. Use nullptr to create an invalid region. + \param offset The offset. Use INVALID_VALUE to create an invalid region. + \param count (Optional) Number of Ts in the region. Use INVALID_VALUE to create an invalid region. + */ + explicit Region(std::vector* data, uint32 offset, uint32 count = 1) + : _data(data), + _offset(offset), + _count(count) + { + } + + /** + \brief Returns a pointer inside the data to the start of this region. + \return nullptr if the region is invalid, a pointer to the data otherwise. + */ + T* Data() const + { + if (!Valid()) + return nullptr; + return (T*)(_data->data() + _offset); + } + + /** + \brief Gets the offset in the data of this region. + */ + uint32 Offset() const + { + return _offset; + } + + /** + \brief Gets the number of Ts in this region. + */ + uint32 Count() const + { + return _count; + } + + /** + \brief Gets the size of this region in bytes. Basically: sizeof(T) * Count(). + */ + uint32 Size() const + { + return Valid() ? _count * sizeof(T) : INVALID_VALUE; + } + + /** + \brief Returns if this region is valid. + */ + bool Valid() const + { + return _offset != INVALID_VALUE && + _count != INVALID_VALUE && + _data && _data->data() && + _offset + _count * sizeof(T) <= _data->size(); + } + + /** + \brief Returns Valid(). + */ + operator bool() const + { + return Valid(); + } + + /** + \brief Returns Data(). + */ + T* operator ()() const + { + return Data(); + } + + private: + std::vector* _data; + uint32 _offset; + uint32 _count; + }; +}; + +#endif //_STATIC_REGION_H \ No newline at end of file diff --git a/MyDebugger/main.cpp b/MyDebugger/main.cpp index 93abbae..836f74c 100644 --- a/MyDebugger/main.cpp +++ b/MyDebugger/main.cpp @@ -1,13 +1,16 @@ #include #include "MyDebugger.h" +#include "GleeBug/Static.File.h" +#include "GleeBug/Static.Pe.h" -int main() -{ #ifdef _WIN64 - wchar_t szFilePath[256] = L"c:\\test64.exe"; +wchar_t szFilePath[256] = L"c:\\test64.exe"; #else //x86 - wchar_t szFilePath[256] = L"c:\\test32.exe"; +wchar_t szFilePath[256] = L"c:\\test32.exe"; #endif //_WIN64 + +static void testDebugger() +{ wchar_t szCommandLine[256] = L""; wchar_t szCurrentDir[256] = L"c:\\"; MyDebugger dbg; @@ -21,6 +24,51 @@ int main() { puts("Debugger::Init failed!"); } +} + +static void testStatic() +{ + using namespace GleeBug; + File file(szFilePath, File::ReadOnly); + if (file.Open()) + { + Pe pe(file); + if (pe.ParseHeaders()) + { + PIMAGE_DOS_HEADER idh = pe.GetDosHeader().Data(); + puts("DOS Header:"); + printf(" e_magic: %02X\n", idh->e_magic); + printf(" e_lfanew: %08X\n", idh->e_lfanew); +#ifdef _WIN64 + PIMAGE_NT_HEADERS64 inth = pe.GetNtHeaders64().Data(); +#else //x32 + PIMAGE_NT_HEADERS32 inth = pe.GetNtHeaders32().Data(); +#endif //_WIN64 + puts("\nNT Headers:"); + 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); + 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:"); + } + else + puts("Pe::ParseHeaders failed!"); + } + else + { + puts("File::Open failed!"); + } +} + +int main() +{ + testStatic(); system("pause"); return 0; } \ No newline at end of file