Skip to content

Synthesis: minimal-PE string-coverage section can get RVA 0 and overlap .text/.smdaIAT #219

Description

@r0ny123

Summary

In the minimal-PE path, the synthetic string-coverage section is added with no overlap or lower-bound check (PeSynthesizer.py:~415-440):

str_vaddr = align_down(min_s, section_alignment)
str_size  = align_up(max_s, section_alignment) - str_vaddr
regions.append({"name": ".rdata", "vaddr": str_vaddr, ...})

The .smdaIAT path immediately above (:~397) does check overlaps before appending its region, so the asymmetry looks unintentional rather than deliberate.

Consequences when a string ref sits low in the image:

  • align_down of a low RVA (e.g. 0x200) yields RVA 0, which is below SizeOfHeaders. A section overlapping the headers is invalid per the PE spec and Windows rejects it.
  • The resulting range can fully contain .text and .smdaIAT, so strings planted under .text's range are silently lost on mapping.

With string refs at base+0x200 and base+0x50000, LIEF reports .rdata va=00000000 vs=00051000 containing both .text va=00001000 and .smdaIAT va=00003000.

Note on verification

Unlike the sibling issues I filed alongside this one, I confirmed this one by reading the code and by the asymmetry with the .smdaIAT overlap check rather than by re-running it end to end — my attempts to drive the minimal-PE path on the repo fixtures kept landing in the full-PE path, which has a different layout routine. Flagging that explicitly so you can weigh it accordingly; the mechanism is straightforward but I would not call it reproduced by me.

Suggested direction

Mirror the .smdaIAT overlap check, and clamp str_vaddr to at least SizeOfHeaders (or the first section's RVA) so the coverage section can never start at 0 or straddle an existing region.

Related, same subsystem

PeSynthesizer._buildOptionalHeader (:~296-316) copies the original optional header wholesale, so the export/resource/reloc/TLS/debug/IAT/delay-import directory RVAs survive while their targets are now zero-filled; only the IMPORT entry is rewritten. Parsers that follow those directories read zeroed structures instead of failing cleanly. Same subsystem, same "output parses but is not internally consistent" theme.


Found during a whole-repo audit of src/smda/**. Synthesis is documented as experimental, so filing rather than patching.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions