You have a byte array pointer (char* data
) then simply move pointer to offset you need data + PE_POINTER_OFFSET
, cast to pointer to integer (int*)(data + PE_POINTER_OFFSET)
and deference the pointer to get value:
int32_t head_addr = *reinterpret_cast<int32_t*>(data + PE_POINTER_OFFSET);
uint16_t machineUint = *reinterpret_cast<uint16_t*>(data + head_addr + macoffset);
EDIT 1: you're trying to read a PE so I may safely assume your environment is Windows. Both x86 and x64 supports unaligned memory access (of course you'll pay a price in performance for this but probably nothing you will ever note and you'll save memcpy
s).
Itanimum (if you have to support it) and (very old) ARM may be a problem: for first one just use __unaligned
for your char array and for second one (if you don't let compiler do the job for you) you can use __packed
.
Note also that this assumptions (plus endianness) are valid because you're working with PE files on Windows environment, if you had to write portable code or to read something else then this is not the right way to do it (in short you have to address single bytes and to copy them using a fixed order).
EDIT 2: according to updated code you're using problem is with *reinterpret_cast<int32_t*>(data, ptr_offset)
, note that you don't sum a pointer with an offset and also offset is invalid (it should be 60 - if I'm not wrong). What you're doing there is reading from absolute location with address 4096 and it'll cause an access violation. In code:
uint16_t GetAppCompiledMachineType(string fileName)
{
const int32_t PE_POINTER_OFFSET = 60;
const int32_t MACHINE_OFFSET = 4;
char data[4096];
fstream f;
f.open(fileName, ios::in | ios::binary);
f.read(data, sizeof(data));
int32_t pe_header_offset = *reinterpret_cast<int32_t*>(
data + PE_POINTER_OFFSET);
// assert(pe_header_offset + MACHINE_OFFSET < sizeof(data));
return *reinterpret_cast<std::uint16_t*>(
data + pe_header_offset + MACHINE_OFFSET);
}
This code is still far to be production quality but note few changes:
- Buffer
data
isn't dynamically allocated then you don't need to free that memory (you were not freeing allocated memory, Windows will free it for you when process exits but if you call that function many times you'll consume memory).
- With statically allocated array you can use
sizeof()
to determine buffer size (as input for read()
).
PE_POINTER_OFFSET
has now correct value (60 instead of 4096).
- Offset from
data
is now calculated correctly (as sum of data
with PE_POINTER_OFFSET
).
All these said we're still using a buffered approach but it's pretty useless here because fstream
will manage that for us. Let's simplify our code (with the side effect to also make it more robust, we're not assuming PE header fits our 4K buffer).
uint16_t GetAppCompiledMachineType(string fileName)
{
const int32_t PE_POINTER_OFFSET = 60;
const int32_t MACHINE_OFFSET = 4;
fstream f(fileName, ios::in | ios::binary);
int32_t pe_header_offset:
f.seekg(PE_POINTER_OFFSET); f >> pe_header_offset;
uint16_t machineType;
f.seekg(pe_header_offset + MACHINE_OFFSET); f >> machineType;
return machineType;
}
Now it works without casts and conversions (but still assuming PE and machine endianness match).