Lion Cipher Lab
Decode the PE Rich header for build-toolchain attribution (and spot a false flag)
- Threat Intel Analyst
- Advanced
- ~70 min
- Free · no account required
Why it matters
When a threat-intel analyst wants to know WHO built a Windows binary, one of the strongest cheap signals is not in the code at all -- it is in the Rich header, an undocumented blob the Microsoft linker (link.exe) stamps between the DOS stub and the PE header. For every object file that goes into a binary, link.exe records a comp.id (the exact build tool plus its build/version number) and a COUNT of how many objects of that toolchain were linked. That is a fingerprint of the precise build environment: which Visual Studio, which service pack, which mix of C/C++/assembler/resource objects. Two…
What you'll learn
- where the Rich header physically lives in a PE file: after the DOS stub and before the PE (NT) header pointed at by e_lfanew, unmentioned by the official PE format spec
- the Rich header's exact byte layout: the clear 'DanS' start marker, three padding DWORDs, then (comp.id, count) DWORD pairs, then the clear 'Rich' end marker followed by the 4-byte XOR key
- recovering the 4-byte XOR key that trails the 'Rich' marker and using it to decode the array backwards until the 'DanS' anchor appears
- reading a comp.id: product id in the high 16 bits, build/version number in the low 16 bits, paired with a COUNT of how many object files of that toolchain were linked in
- computing a Rich hash (md5 over the XOR-decoded array) and using it to cluster two binaries built with the SAME toolchain even when their XOR keys and file sizes differ
- recognizing when there is NO Rich header at all -- GCC/Clang/MinGW binaries never carry one, and an attacker can strip it -- and reading that absence as its own signal
- the Olympic Destroyer false-flag lesson: because the Rich header fingerprints a build environment, it can be COPIED to misdirect attribution, so it is triage/lead, not proof
- applying estimative language and the Pyramid of Pain: corroborate a Rich-header lead with code, imphash, and infrastructure before asserting attribution
Steps in this lab
- What the Rich header is, and where it hides
- The byte layout, and why it is XOR-encoded
- Set up a benign, self-contained scratch folder
- Create the generator: make_pe_with_rich.py
- Create the decoder: decode_rich.py, and decode synthetic_rich.bin
- Cluster by Rich hash -- and see the no-header case
- OPTIONAL: cross-check with pefile
- The judgment: a lead, not proof (Olympic Destroyer)