Unsafe Relocation Fixups in Asset Loaders
Tip
Μάθετε & εξασκηθείτε στο AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Μάθετε & εξασκηθείτε στο Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Υποστηρίξτε το HackTricks
- Ελέγξτε τα σχέδια συνδρομής!
- Εγγραφείτε στην 💬 ομάδα Discord ή στην ομάδα telegram ή ακολουθήστε μας στο Twitter 🐦 @hacktricks_live.
- Μοιραστείτε κόλπα hacking υποβάλλοντας PRs στα HackTricks και HackTricks Cloud github repos.
Γιατί οι asset relocations έχουν σημασία
Πολλές legacy game engines (Granny 3D, Gamebryo, κ.λπ.) φορτώνουν σύνθετα assets με τα εξής βήματα:
- Ανάλυση του header και του section table.
- Δέσμευση ενός heap buffer για κάθε section.
- Δημιουργία του
SectionArrayπου αποθηκεύει το base pointer κάθε section. - Εφαρμογή relocation tables ώστε οι pointers που είναι ενσωματωμένοι στα δεδομένα του section να διορθώνονται στο σωστό target section + offset.
Όταν ο relocation handler εμπιστεύεται τυφλά attacker-controlled metadata, κάθε relocation γίνεται πιθανό arbitrary read/write primitive. Στο Anno 1404: Venice, το granny2.dll περιλαμβάνει τον ακόλουθο helper:
`GrannyGRNFixUp_0` (trimmed)
```c int *__cdecl GrannyGRNFixUp_0(DWORD RelocationCount, Relocation *PointerFixupArray, int *SectionArray, char *destination) { while (RelocationCount--) { int target_base = SectionArray[PointerFixupArray->SectionNumber]; // unchecked index int *patch_site = (int *)(destination + PointerFixupArray->SectionOffset); // unchecked offset *patch_site = target_base ; if (target_base) *patch_site = target_base + PointerFixupArray->Offset; ++PointerFixupArray; } return SectionArray; } ```SectionNumber is never range-checked and SectionOffset is never validated against the current section size. Crafting relocation entries with negative offsets or oversized indices lets you walk outside the section you control and stomp allocator metadata such as the section pointer array itself.
Στάδιο 1 – Εγγραφή προς τα πίσω στα metadata του loader
Ο στόχος είναι να κάνει τον relocation table του section 0 να υπεργράψει εγγραφές του SectionContentArray (που αντικατοπτρίζει το SectionArray και αποθηκεύεται ακριβώς πριν από το πρώτο section buffer). Επειδή ο custom allocator του Granny προσθέτει προκέφαλο 0x1F bytes και το NT heap προσθέτει το δικό του header 0x10 bytes συν ευθυγράμμιση, ένας επιτιθέμενος μπορεί να προκαταλάβει την απόσταση μεταξύ της αρχής του πρώτου section (destination) και του section-pointer array.
Στο δοκιμασμένο build, αναγκάζοντας τον loader να δεσμεύσει μια δομή GrannyFile που έχει ακριβώς 0x4000 bytes κάνει τους section-pointer arrays να τοποθετηθούν ακριβώς πριν από το πρώτο section buffer. Λύνοντας
0x20 (header) + 0x20 (section descriptors)
+ n * 1 (section types) + n * 1 (flags)
+ n * 4 (pointer table) = 0x4000
παρέχει n = 2720 sections. Μια εγγραφή relocation με SectionOffset = -0x3FF0 ( 0x4000 - 0x20 - 0x20 + 0x30 ) τώρα επιλύεται σε SectionContentArray[1] αν και η προοριζόμενη section νομίζει ότι κάνει patch εσωτερικών δεικτών.
Stage 2 – Ντετερμινιστική διάταξη heap σε Windows 10
Το Windows 10 NT Heap δρομολογεί allocations ≤ RtlpLargestLfhBlock (0x4000) στο randomized LFH και τα μεγαλύτερα στο deterministic backend allocator. Κρατώντας τα metadata του GrannyFile ελαφρώς πάνω από αυτό το όριο (χρησιμοποιώντας το κόλπο με τις 2720 sections) και προφορτώνοντας αρκετά malicious .gr2 assets, μπορείτε να κάνετε:
- Allocation #1 (metadata + section pointer arrays) να καταλήξει σε ένα backend chunk >0x4000.
- Allocation #2 (section 0 contents) να καταλήξει αμέσως μετά την allocation #1.
- Allocation #3 (section 1 contents) να καταλήξει αμέσως μετά την allocation #2, δίνοντάς σας έναν προβλέψιμο στόχο για επακόλουθες relocations.
Το Process Monitor επιβεβαίωσε ότι τα assets stream-άρονται κατά απαίτηση, οπότε η επαναλαμβανόμενη αίτηση crafted units/buildings είναι αρκετή για να “προετοιμάσει” τη διάταξη του heap χωρίς να αγγίξετε το executable image.
Stage 3 – Μετατροπή του primitive σε RCE
- Corrupt
SectionContentArray[1]. Ο relocation table της section 0 το υπεργράφει χρησιμοποιώντας το offset-0x3FF0. Κατευθύνετέ το σε οποιαδήποτε writable περιοχή ελέγχετε (π.χ., δεδομένα μεταγενέστερης section). - Recycle the corrupted pointer. Ο relocation table της section 1 τώρα θεωρεί ότι
SectionNumber = 1είναι όποιος pointer έχετε εγχύσει. Ο handler γράφειSectionArray[1] + Offsetστοdestination + SectionOffset, δίνοντάς σας ένα arbitrary 4-byte write για κάθε εγγραφή relocation. - Hit reliable dispatchers. Στο Anno 1404 ο προτιμώμενος στόχος ήταν τα
granny2.dllallocator callbacks (no ASLR, DEP disabled). Η υπεγραφή του function pointer που χρησιμοποιεί τοgranny2.dllγια την επόμενη κλήσηMalloc/Freeαμέσως αποκλίνει την εκτέλεση σε κώδικα υπό τον έλεγχο του attacker που φορτώθηκε από το trojanized asset.
Εφόσον τόσο το granny2.dll όσο και τα εγχυμένα .gr2 buffers κατοικοεδρεύουν σε σταθερές διευθύνσεις όταν ASLR/DEP είναι απενεργοποιημένα, η επίθεση μειώνεται στο να κατασκευάσετε ένα μικρό ROP chain ή raw shellcode και να δείξετε το callback σε αυτό.
Practical checklist
- Αναζητήστε asset loaders που διατηρούν
SectionArray/ relocation tables. - Κάντε diff στους relocation handlers για έλλειψη bounds σε indices/offsets.
- Μετρήστε τα allocator headers που προστίθενται τόσο από τον allocator wrapper του παιχνιδιού όσο και από το underlying OS heap για να υπολογίσετε με ακρίβεια τα backwards offsets.
- Εξαναγκάστε ντετερμινιστική τοποθέτηση με:
- φουσκώνοντας τα metadata (πολλές empty sections) μέχρι το allocation size >
RtlpLargestLfhBlock; - επαναλαμβανόμενη φόρτωση του malicious asset για να γεμίσετε τα backend holes.
- φουσκώνοντας τα metadata (πολλές empty sections) μέχρι το allocation size >
- Χρησιμοποιήστε έναν two-stage relocation table (πρώτο για retarget
SectionArray, δεύτερο για spray writes) και υπεγράψτε function pointers που θα ενεργοποιηθούν κατά το normal rendering (allocator callbacks, virtual tables, animation dispatchers, κ.λπ.).
Μόλις αποκτήσετε arbitrary file write (π.χ. μέσω του path traversal στο multiplayer save transfer), το repackaging των RDA archives με το crafted .gr2 σας δίνει έναν καθαρό delivery vector που αποσυμπιέζεται αυτόματα από remote clients.
References
Tip
Μάθετε & εξασκηθείτε στο AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Μάθετε & εξασκηθείτε στο Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Υποστηρίξτε το HackTricks
- Ελέγξτε τα σχέδια συνδρομής!
- Εγγραφείτε στην 💬 ομάδα Discord ή στην ομάδα telegram ή ακολουθήστε μας στο Twitter 🐦 @hacktricks_live.
- Μοιραστείτε κόλπα hacking υποβάλλοντας PRs στα HackTricks και HackTricks Cloud github repos.


