Reputation: 61
I have tried to use a pointer with a struct in C#, but some strange calculation occurs when I add an offset to the pointer:
p_FILE_HEADER = (IMAGE_FILE_HEADER*)(p_DOS_HEADER + p_DOS_HEADER->e_lfanew);
0000018a mov eax,dword ptr [ebp-3Ch]
0000018d mov eax,dword ptr [eax+14h]
00000190 mov edx,dword ptr [ebp-3Ch]
00000193 mov edx,dword ptr [edx+14h]
00000196 mov edx,dword ptr [edx+3Ch]
00000199 xor ecx,ecx
0000019b shl edx,6 //strange
0000019e add eax,edx
000001a0 mov edx,dword ptr [ebp-3Ch]
000001a3 mov dword ptr [edx+0Ch],eax
Everything seems okay except the shift instruction, I don't get it why it would be here.
Can anyone tell me the reason?
Here is the struct definition (yes it's part of the PE header)
[StructLayout(LayoutKind.Sequential,Pack=1) ]
public unsafe struct IMAGE_DOS_HEADER
{ // DOS .EXE header
public ushort e_magic; //0x0 // Magic number
public ushort e_cblp; //0x2 // Bytes on last page of file
public ushort e_cp; //0x4 // Pages in file
public ushort e_crlc; //0x6 // Relocations
public ushort e_cparhdr; //0x8 // Size of header in paragraphs
public ushort e_minalloc; //0xA // Minimum extra paragraphs needed
public ushort e_maxalloc; //0xC // Maximum extra paragraphs needed
public ushort e_ss; //;0xE // Initial (relative) SS value
public ushort e_sp; //0x10 // Initial SP value
public ushort e_csum; //0x12 // Checksum
public ushort e_ip; //0x14 // Initial IP value
public ushort e_cs; //0x16 // Initial (relative) CS value
public ushort e_lfarlc; //0x18 // File address of relocation table
public ushort e_ovno; //0x1A // Overlay number
// [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 4)]
public fixed ushort e_res[4]; //0x1C // Reserved words
public ushort e_oemid; //0x24 // OEM identifier (for e_oeminfo)
public ushort e_oeminfo; //0x26 // OEM information; e_oemid specific
// [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 10)]
public fixed ushort e_res2 [10]; //0x28 // Reserved words
public uint e_lfanew; //0x3C // File address of new exe header
}
Upvotes: 1
Views: 165
Reputation: 12435
So lets walk through this for just a second.
p_FILE_HEADER = (IMAGE_FILE_HEADER*)(p_DOS_HEADER + p_DOS_HEADER->e_lfanew);
So you have some variable p_DOS_HEADER
that is presumably an instance of IMAGE_DOS_HEADER
. You load your PE image into memory and lay this structure on top of it. So p_DOS_HEADER.e_lfanew
tells you, how far from the start of the file, in bytes, is the 'new exe header'. p_DOS_HEADER
tells you where in memory your 'file' starts.
In C#, pointer arithmetic works based off the size of the pointed-to type. int* thing = ...; thing++
will cause thing to jump ahead four bytes (the size of int
), not one byte. This is the same convention that most other pointer-capable languages support, like C++ or C.
However, the field you're reading - e_lfanew
stores the offset in bytes. Thus, you want byte arithmetic.
You want something like this:
p_FILE_HEADER = (IMAGE_FILE_HEADER*)( (byte*)p_DOS_HEADER + p_DOS_HEADER->e_lfanew);
Upvotes: 3