mirror of https://github.com/x64dbg/GleeBug
basics of the PE parser are working now
This commit is contained in:
parent
c2fe70969f
commit
82c542bd62
|
|
@ -164,6 +164,7 @@
|
||||||
<ClCompile Include="Debugger.Thread.Registers.cpp" />
|
<ClCompile Include="Debugger.Thread.Registers.cpp" />
|
||||||
<ClCompile Include="Debugger.Thread.Registers.GetSet.cpp" />
|
<ClCompile Include="Debugger.Thread.Registers.GetSet.cpp" />
|
||||||
<ClCompile Include="Static.File.cpp" />
|
<ClCompile Include="Static.File.cpp" />
|
||||||
|
<ClCompile Include="Static.Pe.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="Debugger.Breakpoint.h" />
|
<ClInclude Include="Debugger.Breakpoint.h" />
|
||||||
|
|
@ -177,6 +178,9 @@
|
||||||
<ClInclude Include="Debugger.Thread.Registers.Register.h" />
|
<ClInclude Include="Debugger.Thread.Registers.Register.h" />
|
||||||
<ClInclude Include="GleeBug.h" />
|
<ClInclude Include="GleeBug.h" />
|
||||||
<ClInclude Include="Static.File.h" />
|
<ClInclude Include="Static.File.h" />
|
||||||
|
<ClInclude Include="Static.Global.h" />
|
||||||
|
<ClInclude Include="Static.Pe.h" />
|
||||||
|
<ClInclude Include="Static.Region.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,9 @@
|
||||||
<ClCompile Include="Static.File.cpp">
|
<ClCompile Include="Static.File.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="Static.Pe.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="Debugger.h">
|
<ClInclude Include="Debugger.h">
|
||||||
|
|
@ -100,5 +103,14 @@
|
||||||
<ClInclude Include="Static.File.h">
|
<ClInclude Include="Static.File.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="Static.Pe.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Static.Region.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Static.Global.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
@ -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<IMAGE_DOS_HEADER>();
|
||||||
|
_afterDosData = Region<uint8>();
|
||||||
|
_ntHeaders32 = Region<IMAGE_NT_HEADERS32>();
|
||||||
|
_ntHeaders64 = Region<IMAGE_NT_HEADERS64>();
|
||||||
|
_sectionHeaders = Region<IMAGE_SECTION_HEADER>();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Pe::ParseHeaders()
|
||||||
|
{
|
||||||
|
//clear all current data
|
||||||
|
Clear();
|
||||||
|
|
||||||
|
//read the DOS header
|
||||||
|
_dosHeader = readRegion<IMAGE_DOS_HEADER>();
|
||||||
|
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<uint8>(offsetDiff);
|
||||||
|
|
||||||
|
//read & verify the signature
|
||||||
|
auto signature = readRegion<DWORD>();
|
||||||
|
if (!signature || *(signature()) != IMAGE_NT_SIGNATURE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
//read the file header
|
||||||
|
auto ifh = readRegion<IMAGE_FILE_HEADER>();
|
||||||
|
if (!ifh)
|
||||||
|
return false;
|
||||||
|
switch (ifh()->Machine)
|
||||||
|
{
|
||||||
|
case IMAGE_FILE_MACHINE_I386:
|
||||||
|
_ntHeaders32 = Region<IMAGE_NT_HEADERS32>(&_data, signature.Offset()); //this region is not valid at this point
|
||||||
|
if (!readRegion<IMAGE_OPTIONAL_HEADER32>()) //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<IMAGE_NT_HEADERS64>(&_data, signature.Offset()); //this region is not valid at this point
|
||||||
|
if (!readRegion<IMAGE_OPTIONAL_HEADER64>()) //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<uint8> 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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -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<IMAGE_DOS_HEADER> & GetDosHeader() const { return _dosHeader; }
|
||||||
|
const Region<uint8> & GetAfterDosData() const { return _afterDosData; }
|
||||||
|
const Region<IMAGE_NT_HEADERS32> & GetNtHeaders32() const { return _ntHeaders32; }
|
||||||
|
const Region<IMAGE_NT_HEADERS64> & GetNtHeaders64() const { return _ntHeaders64; }
|
||||||
|
const Region<IMAGE_SECTION_HEADER> & GetSectionHeaders() const { return _sectionHeaders; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32 readData(uint32 size);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline Region<T> readRegion(uint32 count = 1)
|
||||||
|
{
|
||||||
|
return Region<T>(&_data, readData(sizeof(T) * count), count);
|
||||||
|
}
|
||||||
|
|
||||||
|
File & _file;
|
||||||
|
uint32 _fileSize;
|
||||||
|
std::vector<uint8> _data;
|
||||||
|
uint32 _offset;
|
||||||
|
|
||||||
|
Region<IMAGE_DOS_HEADER> _dosHeader;
|
||||||
|
Region<uint8> _afterDosData;
|
||||||
|
Region<IMAGE_NT_HEADERS32> _ntHeaders32;
|
||||||
|
Region<IMAGE_NT_HEADERS64> _ntHeaders64;
|
||||||
|
Region<IMAGE_SECTION_HEADER> _sectionHeaders;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //_STATIC_PE_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<typename T>
|
||||||
|
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<uint8>* 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<uint8>* _data;
|
||||||
|
uint32 _offset;
|
||||||
|
uint32 _count;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //_STATIC_REGION_H
|
||||||
|
|
@ -1,13 +1,16 @@
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include "MyDebugger.h"
|
#include "MyDebugger.h"
|
||||||
|
#include "GleeBug/Static.File.h"
|
||||||
|
#include "GleeBug/Static.Pe.h"
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
wchar_t szFilePath[256] = L"c:\\test64.exe";
|
wchar_t szFilePath[256] = L"c:\\test64.exe";
|
||||||
#else //x86
|
#else //x86
|
||||||
wchar_t szFilePath[256] = L"c:\\test32.exe";
|
wchar_t szFilePath[256] = L"c:\\test32.exe";
|
||||||
#endif //_WIN64
|
#endif //_WIN64
|
||||||
|
|
||||||
|
static void testDebugger()
|
||||||
|
{
|
||||||
wchar_t szCommandLine[256] = L"";
|
wchar_t szCommandLine[256] = L"";
|
||||||
wchar_t szCurrentDir[256] = L"c:\\";
|
wchar_t szCurrentDir[256] = L"c:\\";
|
||||||
MyDebugger dbg;
|
MyDebugger dbg;
|
||||||
|
|
@ -21,6 +24,51 @@ int main()
|
||||||
{
|
{
|
||||||
puts("Debugger::Init failed!");
|
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");
|
system("pause");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue