Unsafe Relocation Fixup Exploitation
A skill for analyzing and exploiting unsafe relocation fixup vulnerabilities in asset loaders and binary parsers.
Overview
Unsafe relocation fixups occur when asset loaders blindly trust attacker-controlled metadata to patch pointers within loaded data. This creates arbitrary read/write primitives that can be weaponized for RCE.
Vulnerability Pattern
The classic unsafe relocation handler:
int *GrannyGRNFixUp_0(DWORD RelocationCount,
Relocation *PointerFixupArray,
int *SectionArray,
char *destination)
{
while (RelocationCount--) {
int target_base = SectionArray[PointerFixupArray->SectionNumber]; // UNCHECKED
int *patch_site = (int *)(destination + PointerFixupArray->SectionOffset); // UNCHECKED
*patch_site = target_base;
if (target_base)
*patch_site = target_base + PointerFixupArray->Offset;
++PointerFixupArray;
}
return SectionArray;
}
Critical flaws:
SectionNumberindex is never bounds-checkedSectionOffsetis never validated against section size- Negative offsets allow walking backwards into allocator metadata
- Oversized indices allow walking outside the section array
Exploitation Methodology
Stage 1: Write Backwards into Loader Metadata
Goal: Use negative offsets to corrupt the section pointer array itself.
Key insight: Custom allocators prepend headers to allocations. By calculating the exact distance between:
- Start of first section buffer
- Section pointer array (stored before first section)
You can craft relocations that write into the pointer array.
Calculation example:
0x20 (header) + 0x20 (section descriptors)
+ n * 1 (section types) + n * 1 (flags)
+ n * 4 (pointer table) = 0x4000
Solving for n gives the number of sections needed to position metadata at a specific offset.
Stage 2: Deterministic Heap Layout
Windows 10 NT Heap behavior:
- Allocations ≤ 0x4000 → randomized LFH (Large Free Heap)
- Allocations > 0x4000 → deterministic backend allocator
Strategy:
- Inflate metadata (many empty sections) until allocation > 0x4000
- Preload malicious assets to "prime" heap layout
- Force predictable placement of:
- Allocation #1: metadata + section pointer arrays
- Allocation #2: section 0 contents
- Allocation #3: section 1 contents
Stage 3: Convert to RCE
- Corrupt SectionContentArray[1] using negative offset relocation
- Recycle the corrupted pointer - Section 1's relocation table now uses your injected pointer
- Hit reliable dispatchers - Overwrite function pointers that fire during normal operation:
- Allocator callbacks (Malloc/Free)
- Virtual tables
- Animation dispatchers
- Rendering callbacks
Analysis Checklist
When investigating potential unsafe relocation vulnerabilities:
- Identify asset loaders that maintain SectionArray/relocation tables
- Diff relocation handlers for missing bounds on indices/offsets
- Measure allocator headers from both game wrapper and OS heap
- Calculate backwards offsets precisely
- Force deterministic placement by inflating metadata
- Identify reliable targets - function pointers that will fire
Defensive Considerations
- Always bounds-check relocation indices
- Validate offsets against section sizes
- Use safe integer arithmetic
- Consider ASLR/DEP hardening
- Validate asset metadata before processing