I'm trying to read a .exe PE file into memory and access NT headers. I can already access DOS headers but can't resolve NT headers from it.
Here's what I have so far:
static constexpr uint16_t DOS_HDR_MAGIC = 0x5A4D; // "MZ"
static constexpr uint32_t NT_HDR_MAGIC = 0x00004550; // "PE\x0\x0"
struct nt_headers_t
{
uint32_t signature;
file_header_t file_header;
optional_header_x64_t optional_header;
};
struct dos_header_t
{
uint16_t e_magic;
uint16_t e_cblp;
uint16_t e_cp;
uint16_t e_crlc;
uint16_t e_cparhdr;
uint16_t e_minalloc;
uint16_t e_maxalloc;
uint16_t e_ss;
uint16_t e_sp;
uint16_t e_csum;
uint16_t e_ip;
uint16_t e_cs;
uint16_t e_lfarlc;
uint16_t e_ovno;
uint16_t e_res[ 4 ];
uint16_t e_oemid;
uint16_t e_oeminfo;
uint16_t e_res2[ 10 ];
uint32_t e_lfanew;
};
int main(void) {
std::ifstream input("./stuff.exe", std::ios::in | std::ios::binary );
input.seekg(0, std::ios::end);
int file_size = input.tellg();
input.seekg(0, std::ios::beg);
std::byte *file = new std::byte[file_size];
input.read((char *)file, file_size);
struct dos_header_t *dos_header = (struct dos_header_t *)file;
assert(dos_header->e_magic == DOS_HDR_MAGIC);
struct nt_headers_t *nt_headers = (struct nt_headers_t *)file + dos_header->e_lfanew;
assert(nt_headers->signature == NT_HDR_MAGIC);
}
e_lfanew
should contain address to the start of NT headers. I simply add this value to file start: (struct nt_headers_t *)file + dos_header->e_lfanew;
Am I doing that wrong? Attached picture says that e_lfanew
contains the NT headers offset in reverse order. How should I reverse it?
I simply add this value to file start:
(struct nt_headers_t *)file + dos_header->e_lfanew;
Am I doing that wrong?
Yes, but for a "boring reason" that has nothing to do with PE headers: since you've done the cast before the addition, the offset is scaled by the size of nt_headers_t
. The offset needs to be added unscaled, so add it first, and cast afterwards.
Attached picture says that e_lfanew contains the NT headers offset in reverse order. How should I reverse it?
It's in little-endian byte order, you're probably running the code on a little-endian machine (that's most of them nowadays) so you don't need to do anything, just reading the value will interpret it correctly.