How to properly construct the NtHeader
when calling PIMAGE_NT_HEADERS64
Microsoft docs does not seem to have much remarks on this function, the problem is that casting from void*
to DWORD
fails
int runPE64(void* Image)
{
/*
non relevant code
*/
char CurrentFilePath[1024];
DOSHeader = PIMAGE_DOS_HEADER(Image); // Initialize Variable
NtHeader = PIMAGE_NT_HEADERS64( DWORD(Image) DOSHeader->e_lfanew); // Initialize
GetModuleFileNameA(0, CurrentFilePath, 1024); // path to current executable
return 0;
}
int main()
{
unsigned char data[] = {0x4D,0x5A,0x00}; // this is dummy data
runPE64(data);
return 0;
}
Error when compiling
$ g runPE64.cpp
runPE64.cpp: In function 'int runPE64(void*)':
runPE64.cpp:31:41: error: cast from 'void*' to 'DWORD' {aka 'long unsigned int'} loses precision [-fpermissive]
31 | NtHeader = PIMAGE_NT_HEADERS64( DWORD(Image) DOSHeader->e_lfanew); // Initialize
| ^~~~~~~~~~~~
runPE64.cpp:31:20: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
31 | NtHeader = PIMAGE_NT_HEADERS64( DWORD(Image) DOSHeader->e_lfanew); // Initialize
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Is there another way to do this or is there any good explanation of what to pass PIMAGE_NT_HEADERS64
CodePudding user response:
DWORD
is 32 bits (4 bytes) in size, in both 32-bit and 64-bit systems.
The compiler is warning you that the size of DWORD
is different than the size of a void*
pointer in your compilation, so you will lose bits. This means you must be compiling a 64-bit executable, where pointers are 64 bits (8 bytes) in size.
You need to typecast to DWORD_PTR
instead, which is the same size as a pointer, whether you compile for 32-bit or 64-bit.
NtHeader = PIMAGE_NT_HEADERS64( DWORD_PTR(Image) DOSHeader->e_lfanew);
Alternatively, you can use pointer arithmetic instead of integer arithmetic:
NtHeader = PIMAGE_NT_HEADERS64( LPBYTE(Image) DOSHeader->e_lfanew); // Initialize