How are PE Base Relocations build up?

executable, portability, relocation

Solution

Neither options you indicated entirely correct/true.

This excellent tutorial on How to inject code in a PE file shows that the actual `IMAGE_BASE_RELOCATION` structure is:

typedef struct _IMAGE_BASE_RELOCATION {
  DWORD   VirtualAddress;
  DWORD   SizeOfBlock;
} IMAGE_BASE_RELOCATION, *PIMAGE_BASE_RELOCATION;

Section 5.2 of this Microsoft Portable Executable and Common Object File Format Specification describe the structure. The `SizeOfBlock-8` actually indicates how many `WORD TypeOffset` follow after the `VirtualAddress` and `SizeOfBlock`.

I think you would also be interested in Table 7 of the tutorial, which shows the structure of the blocks from the relocation table. I'll copy-paste the table here for quick-reference.

Problem

I'm currently having trouble understanding how PE Base Relocations are build up. I understand there can be more then one relocation, I understand also why and how this is done, but I just don't understand it programmatically: Which of the following is true (IMAGE_BASE_RELOCATION in WinNT.h)? ``` // Base relocation #1 DWORD VirtualAddress; DWORD SizeOfBlock; // size of current relocation WORD TypeOffset[1]; // Base relocation #2 DWORD VirtualAddress; DWORD SizeOfBlock; // size of current relocation WORD TypeOffset[1]; // Base relocation #3 DWORD VirtualAddress; DWORD SizeOfBlock; // size of current relocation WORD TypeOffset[1]; ``` Or ``` DWORD VirtualAddress; DWORD SizeOfBlock; // size of all relocations WORD TypeOffset[1]; // relocation #1 WORD TypeOffset[1]; // relocation #2 WORD TypeOffset[1]; // relocation #3 ``` Or are both incorrect? How must I loop through all base relocations programmatically? Currently I have this code, seems to be incorrect somewhere: ``` DWORD baseRelocationSize = imageNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; unsigned int baseRelocationCount = baseRelocationSize / sizeof(IMAGE_BASE_RELOCATION); DWORD baseDelta = (DWORD_PTR)moduleBase - (DWORD_PTR)imageNtHeaders->OptionalHeader.ImageBase; IMAGE_BASE_RELOCATION* baseRelocation = (IMAGE_BASE_RELOCATION*)((DWORD_PTR)moduleBase + (DWORD_PTR)imageNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress); for(unsigned int i = 0; i != baseRelocationCount; ++i) { unsigned int entryCount = (baseRelocation->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD); for(unsigned int j = 0; j != entryCount; ++j) { WORD* entry = (WORD*)((DWORD_PTR)baseRelocation + (DWORD_PTR)sizeof(IMAGE_BASE_RELOCATION)); if((*entry >> 12) & IMAGE_REL_BASED_HIGHLOW) { DWORD* pdw = (PDWORD)((DWORD_PTR)moduleBase + (DWORD_PTR)baseRelocation->VirtualAddress + ((*entry) & 0xfff)); (*pdw) += baseDelta; } entry++; } baseRelocation += baseRelocation->SizeOfBlock; } ```

Original source