Summary
Both ElfSynthesizer (:~318) and MachoSynthesizer (:~539) place the first segment with
file_cursor = align_up(file_cursor, PAGE_SIZE) + va_start % PAGE_SIZE
That is page-congruent, but it starts the first segment after the header page rather than mapping the header at the image base, which is what the ELF and Mach-O conventions expect. SMDA's own loaders derive the base address from min(section.va - section.offset), so they read back a base that is off by a page or entirely wrong.
Reproduction
tests/mirai_x64_xored on master (4.4.1), unmodified, round-tripped through ELF synthesis:
original: 151 functions, base 0x400000
re-loaded: 174 functions, base 0x3fe000
The base comes back 0x2000 low, and every derived RVA in the re-disassembled report shifts with it.
For Mach-O, every synthesized segment ends up with vmaddr - fileoff == 0xFFFFF000, so MachoFileLoader._calculate_base_address returns 0xFFFFF000 instead of 0x100000000. (Note that on current master a negative/again-wrong base is now filtered by the loader, but the synthesized layout is still not what the format requires.)
The Mach-O output is additionally not dyld-valid: __TEXT must start at file offset 0 and cover the mach header.
Related, same subsystem
While looking at this I also noticed MachoSynthesizer writes its LC_SYMTAB/LC_DYSYMTAB payloads past the last segment — inside no segment at all — and emits no __LINKEDIT (nor __PAGEZERO). LIEF parses it, but dyld and any consumer that resolves the symbol table through segment mapping will see nothing. Mentioning it here rather than as a separate issue since it is the same "output parses but is not format-valid" theme.
Found during a whole-repo audit of src/smda/** and re-verified against master before filing. Synthesis is documented as experimental, so filing rather than patching.
Summary
Both
ElfSynthesizer(:~318) andMachoSynthesizer(:~539) place the first segment withThat is page-congruent, but it starts the first segment after the header page rather than mapping the header at the image base, which is what the ELF and Mach-O conventions expect. SMDA's own loaders derive the base address from
min(section.va - section.offset), so they read back a base that is off by a page or entirely wrong.Reproduction
tests/mirai_x64_xoredonmaster(4.4.1), unmodified, round-tripped through ELF synthesis:The base comes back 0x2000 low, and every derived RVA in the re-disassembled report shifts with it.
For Mach-O, every synthesized segment ends up with
vmaddr - fileoff == 0xFFFFF000, soMachoFileLoader._calculate_base_addressreturns0xFFFFF000instead of0x100000000. (Note that on currentmastera negative/again-wrong base is now filtered by the loader, but the synthesized layout is still not what the format requires.)The Mach-O output is additionally not dyld-valid:
__TEXTmust start at file offset 0 and cover the mach header.Related, same subsystem
While looking at this I also noticed
MachoSynthesizerwrites its LC_SYMTAB/LC_DYSYMTAB payloads past the last segment — inside no segment at all — and emits no__LINKEDIT(nor__PAGEZERO). LIEF parses it, but dyld and any consumer that resolves the symbol table through segment mapping will see nothing. Mentioning it here rather than as a separate issue since it is the same "output parses but is not format-valid" theme.Found during a whole-repo audit of
src/smda/**and re-verified againstmasterbefore filing. Synthesis is documented as experimental, so filing rather than patching.