Technical Details
The Reproducibility Problem
MSVC++ builds are not reproducible even with /Brepro because:
COFF Header Timestamp - Build timestamp in PE header
Debug Directory Timestamps - 4 separate timestamps
CODEVIEW GUID - Random GUID linking .exe to .pdb
CODEVIEW Age - Incremental counter
REPRO Hash - Contains GUID and timestamps
This makes binary verification impossible in CI.
PE File Format
Structure Overview
DOS Header (offset 0x00)
PE Signature (offset varies)
COFF Header (after PE signature)
Optional Header (after COFF)
Section Table (after optional header)
Debug Directory (RVA in optional header)
Fields Patched
COFF Header TimeDateStamp (4 bytes at COFF+4)
Debug CODEVIEW Timestamp (4 bytes)
Debug CODEVIEW GUID (16 bytes)
Debug CODEVIEW Age (4 bytes)
Debug VC_FEATURE Timestamp (4 bytes)
Debug POGO Timestamp (4 bytes)
Debug REPRO Timestamp (4 bytes)
Debug REPRO Hash (36 bytes)
Algorithm
High-Level Flow
Read entire PE file into memory
Find PE signature offset from DOS header
Verify PE signature
Patch COFF header timestamp
Find debug directory (RVA to file offset)
Iterate debug entries, patch timestamps
For CODEVIEW: patch GUID and Age
For REPRO: patch entire hash
Write modified file back
Offset Calculations
DOS Header[0x3C:0x40] -> PE offset
PE offset + 0 -> "PE\0\0" signature
PE offset + 4 -> COFF header start
COFF offset + 4 -> TimeDateStamp
COFF offset + 20 -> Optional header start
Optional offset + 112 -> Data directories (PE32+)
Data directory[6] -> Debug directory RVA
Convert RVA to file offset via section table
Debug directory entries: 28 bytes each
Entry offset + 4 -> Timestamp
Entry offset + 12 -> Type
Entry offset + 24 -> Pointer to data
Comparison with Alternatives
ducible
❌ Unmaintained (last update 2018)
❌ Only patches COFF timestamp
❌ Misses debug directory fields
clang-cl + lld-link
✅ Fully reproducible (including PDBs)
✅ Supports
/TIMESTAMP:flag❌ Requires switching from MSVC toolchain
msvcpp-normalize-pe
✅ Works with native MSVC
✅ Patches all 8 fields
✅ Zero dependencies
❌ PDB files remain non-deterministic
Limitations
What This Fixes
✅ PE executables (.exe, .dll)
✅ Works with any MSVC version
✅ Preserves debugging capability
What This Cannot Fix
❌ PDB files (~11% content varies)
❌ Stripped binaries (no debug directory)