Static.Pe is now working with corkami's mini.exe and reports specific error messages.

This commit is contained in:
mrexodia 2015-12-29 00:04:42 +01:00
parent 0b527f1985
commit c56f2daebd
4 changed files with 157 additions and 53 deletions

View File

@ -20,7 +20,7 @@ namespace GleeBug
_sectionHeaders = Region<IMAGE_SECTION_HEADER>(); _sectionHeaders = Region<IMAGE_SECTION_HEADER>();
} }
bool Pe::ParseHeaders() Pe::Error Pe::ParseHeaders()
{ {
//clear all current data //clear all current data
Clear(); Clear();
@ -28,58 +28,89 @@ namespace GleeBug
//read the DOS header //read the DOS header
_dosHeader = readRegion<IMAGE_DOS_HEADER>(); _dosHeader = readRegion<IMAGE_DOS_HEADER>();
if (!_dosHeader) if (!_dosHeader)
return false; return ErrorDosHeaderRead;
//verify the DOS header //verify the DOS header
if (_dosHeader()->e_magic != IMAGE_DOS_SIGNATURE) if (_dosHeader->e_magic != IMAGE_DOS_SIGNATURE)
return false; return ErrorDosHeaderMagic;
//get the NT headers offset //get the NT headers offset
auto newOffset = uint32(_dosHeader()->e_lfanew); auto newOffset = uint32(_dosHeader->e_lfanew);
//verify the new offset //verify the new offset
if (newOffset < 0 || newOffset < _offset || newOffset >= _file.GetSize()) if (newOffset < 0 || newOffset < _offset || newOffset >= _file.GetSize())
return false; return ErrorDosHeaderNtHeaderOffset;
//read the data between the DOS header and the NT headers //read & verify the data between the DOS header and the NT headers
auto offsetDiff = newOffset - _offset; auto afterDosCount = newOffset - _offset;
_afterDosData = readRegion<uint8>(offsetDiff); _afterDosData = readRegion<uint8>(afterDosCount);
if (!_afterDosData)
return ErrorAfterDosHeaderData;
//read & verify the signature //read & verify the signature
auto signature = readRegion<DWORD>(); auto signature = readRegion<DWORD>();
if (!signature || *(signature()) != IMAGE_NT_SIGNATURE) if (!signature)
return false; return ErrorNtSignatureRead;
if (*(signature()) != IMAGE_NT_SIGNATURE)
return ErrorNtSignatureMagic;
//read the file header //read the file header
auto ifh = readRegion<IMAGE_FILE_HEADER>(); auto ifh = readRegion<IMAGE_FILE_HEADER>();
if (!ifh) if (!ifh)
return false; return ErrorNtFileHeaderRead;
switch (ifh()->Machine)
//read the optional header
uint32 realSizeOfIoh;
switch (ifh->Machine)
{ {
case IMAGE_FILE_MACHINE_I386: 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 //read & verify the optional header
return false; realSizeOfIoh = uint32(sizeof(IMAGE_OPTIONAL_HEADER32));
if (!_ntHeaders32) //validate we read the entire NT headers region auto ioh = readRegion<IMAGE_OPTIONAL_HEADER32>();
return false; if (!ioh)
return ErrorNtOptionalHeaderRead;
if (ioh->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)
return ErrorNtOptionalHeaderMagic;
//construct & verify the NT headers region
_ntHeaders32 = Region<IMAGE_NT_HEADERS32>(&_data, signature.Offset());
if (!_ntHeaders32)
return ErrorNtHeadersRegionSize;
}
break; break;
case IMAGE_FILE_MACHINE_AMD64: 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 //read & verify the optional header
return false; realSizeOfIoh = uint32(sizeof(IMAGE_OPTIONAL_HEADER64));
if (!_ntHeaders64) //validate we read the entire NT headers region auto ioh = readRegion<IMAGE_OPTIONAL_HEADER64>();
return false; if (!ioh)
return ErrorNtOptionalHeaderRead;
if (ioh->Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC)
return ErrorNtOptionalHeaderMagic;
//construct & verify the NT headers region
_ntHeaders64 = Region<IMAGE_NT_HEADERS64>(&_data, signature.Offset());
if (!_ntHeaders64)
return ErrorNtHeadersRegionSize;
}
break; break;
default: //unsupported machine default: //unsupported machine
return false; return ErrorNtFileHeaderUnsupportedMachine;
} }
#define IMAGE_FIRST_SECTION123( ntheader ) ((PIMAGE_SECTION_HEADER) \ //read data after the optional header
((ULONG_PTR)(ntheader) + \ auto sizeOfIoh = ifh->SizeOfOptionalHeader; //this field can be zero
FIELD_OFFSET( IMAGE_NT_HEADERS, OptionalHeader ) + \ uint32 afterOptionalCount = sizeOfIoh > realSizeOfIoh ? sizeOfIoh - realSizeOfIoh : 0;
((ntheader))->FileHeader.SizeOfOptionalHeader \ _afterOptionalData = readRegion<uint8>(afterOptionalCount);
))
return true; //read the section headers
auto sectionCount = ifh->NumberOfSections;
_sectionHeaders = readRegion<IMAGE_SECTION_HEADER>(sectionCount);
return ErrorOk;
} }
uint32 Pe::readData(uint32 size) uint32 Pe::readData(uint32 size)
@ -97,11 +128,11 @@ namespace GleeBug
bool Pe::IsValidPe() const bool Pe::IsValidPe() const
{ {
return false; return _sectionHeaders.Valid();
} }
bool Pe::IsPe64() const bool Pe::IsPe64() const
{ {
return false; return IsValidPe() ? _ntHeaders64.Valid() : false;
} }
}; };

View File

@ -9,10 +9,26 @@ namespace GleeBug
class Pe class Pe
{ {
public: public:
enum Error
{
ErrorOk,
ErrorDosHeaderRead,
ErrorDosHeaderMagic,
ErrorDosHeaderNtHeaderOffset,
ErrorAfterDosHeaderData,
ErrorNtSignatureRead,
ErrorNtSignatureMagic,
ErrorNtFileHeaderRead,
ErrorNtFileHeaderUnsupportedMachine,
ErrorNtOptionalHeaderRead,
ErrorNtOptionalHeaderMagic,
ErrorNtHeadersRegionSize
};
explicit Pe(File & file); explicit Pe(File & file);
void Clear(); void Clear();
bool ParseHeaders(); Error ParseHeaders();
bool IsValidPe() const; bool IsValidPe() const;
bool IsPe64() const; bool IsPe64() const;
@ -20,6 +36,7 @@ namespace GleeBug
const Region<uint8> & GetAfterDosData() const { return _afterDosData; } const Region<uint8> & GetAfterDosData() const { return _afterDosData; }
const Region<IMAGE_NT_HEADERS32> & GetNtHeaders32() const { return _ntHeaders32; } const Region<IMAGE_NT_HEADERS32> & GetNtHeaders32() const { return _ntHeaders32; }
const Region<IMAGE_NT_HEADERS64> & GetNtHeaders64() const { return _ntHeaders64; } const Region<IMAGE_NT_HEADERS64> & GetNtHeaders64() const { return _ntHeaders64; }
const Region<uint8> & GetAfterOptionalData() const { return _afterOptionalData; }
const Region<IMAGE_SECTION_HEADER> & GetSectionHeaders() const { return _sectionHeaders; } const Region<IMAGE_SECTION_HEADER> & GetSectionHeaders() const { return _sectionHeaders; }
private: private:
@ -40,6 +57,7 @@ namespace GleeBug
Region<uint8> _afterDosData; Region<uint8> _afterDosData;
Region<IMAGE_NT_HEADERS32> _ntHeaders32; Region<IMAGE_NT_HEADERS32> _ntHeaders32;
Region<IMAGE_NT_HEADERS64> _ntHeaders64; Region<IMAGE_NT_HEADERS64> _ntHeaders64;
Region<uint8> _afterOptionalData;
Region<IMAGE_SECTION_HEADER> _sectionHeaders; Region<IMAGE_SECTION_HEADER> _sectionHeaders;
}; };
}; };

View File

@ -80,6 +80,14 @@ namespace GleeBug
_offset + _count * sizeof(T) <= _data->size(); _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(). \brief Returns Valid().
*/ */
@ -96,6 +104,11 @@ namespace GleeBug
return Data(); return Data();
} }
T* operator ->() const
{
return Data();
}
private: private:
std::vector<uint8>* _data; std::vector<uint8>* _data;
uint32 _offset; uint32 _offset;

View File

@ -3,14 +3,13 @@
#include "GleeBug/Static.File.h" #include "GleeBug/Static.File.h"
#include "GleeBug/Static.Pe.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() 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 szCommandLine[256] = L"";
wchar_t szCurrentDir[256] = L"c:\\"; wchar_t szCurrentDir[256] = L"c:\\";
MyDebugger dbg; MyDebugger dbg;
@ -26,36 +25,79 @@ static void testDebugger()
} }
} }
template<typename T>
static void printRegion(const char* str, Region<T> 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() 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; using namespace GleeBug;
File file(szFilePath, File::ReadOnly); File file(szFilePath, File::ReadOnly);
if (file.Open()) if (file.Open())
{ {
Pe pe(file); Pe pe(file);
if (pe.ParseHeaders()) if (pe.ParseHeaders() == Pe::ErrorOk)
{ {
PIMAGE_DOS_HEADER idh = pe.GetDosHeader().Data(); auto idh = pe.GetDosHeader();
puts("DOS Header:"); printRegion("DOS Header:", idh);
printf(" e_magic: %02X\n", idh->e_magic); printf(" e_magic: %02X\n", idh->e_magic);
printf(" e_lfanew: %08X\n", idh->e_lfanew); printf(" e_lfanew: %08X\n", idh->e_lfanew);
auto afterDosData = pe.GetAfterDosData();
printRegion("After DOS Data", afterDosData);
#ifdef _WIN64 #ifdef _WIN64
PIMAGE_NT_HEADERS64 inth = pe.GetNtHeaders64().Data(); auto inth = pe.GetNtHeaders64();
#else //x32 #else //x32
PIMAGE_NT_HEADERS32 inth = pe.GetNtHeaders32().Data(); auto inth = pe.GetNtHeaders32();
#endif //_WIN64 #endif //_WIN64
puts("\nNT Headers:"); printRegion("NT Headers:", inth);
printf(" Signature: %08X\n", inth->Signature); printf(" Signature: %08X\n", inth->Signature);
PIMAGE_FILE_HEADER ifh = &inth->FileHeader; PIMAGE_FILE_HEADER ifh = &inth->FileHeader;
puts("\n File Header:"); puts("\n File Header:");
printf(" Machine : %02X\n", ifh->Machine); printf(" Machine : %04X\n", ifh->Machine);
printf(" TimeDateStamp: %08X\n", ifh->TimeDateStamp); printf(" NumberOfSections: %04X\n", ifh->NumberOfSections);
printf(" TimeDateStamp : %08X\n", ifh->TimeDateStamp);
PIMAGE_OPTIONAL_HEADER ioh = &inth->OptionalHeader; PIMAGE_OPTIONAL_HEADER ioh = &inth->OptionalHeader;
puts("\n Optional Header:"); puts("\n Optional Header:");
printf(" Magic : %04X\n", ioh->Magic); printf(" Magic : %04X\n", ioh->Magic);
printf(" ImageBase: %p\n", ioh->ImageBase); printf(" EntryPoint: %08X\n", ioh->AddressOfEntryPoint);
printf(" Subsystem: %04X\n", ioh->Subsystem); printf(" ImageBase : %p\n", ioh->ImageBase);
puts("\n Section Headers:"); 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 else
puts("Pe::ParseHeaders failed!"); puts("Pe::ParseHeaders failed!");