郭玉龙
郭玉龙

Reputation: 61

C# Pointer issues

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

Answers (1)

antiduh
antiduh

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

Related Questions