v0.7.5 — Structural validator expansion
Substantial expansion of IOCX's PE structural analysis capabilities. Four new parser/validator pairs, 24 new reason codes, security-relevant metadata enrichment. 1370 tests at 100% coverage; end-to-end binary verification on real-world binaries.
Highlights
- Four new structural validators covering exports, delay-load imports, VS_VERSIONINFO, and resource hierarchy enforcement
- 24 new reason codes with priority-resolved sub-reason taxonomies
- Enriched public metadata for Optional Header, header decoding, and per-resource fields
- Deterministic byte-level extraction on all new parsers (never raises, tombstone-tagged sub-structure failures)
- 1370 tests, 100% coverage on new modules; delay-load parser verified byte-exact against dumpbin output on mspaint.exe
What's new
Structural validators
-
Exports validator decodes the 40-byte IMAGE_EXPORT_DIRECTORY, EAT, ENPT, and EOT purely from bytes. Emits ten new reason codes covering directory, name-pointer, and function-entry anomalies. Forwarder detection follows the PE-spec rule.
-
Delay-load imports validator decodes the 32-byte IMAGE_DELAY_IMPORT_DESCRIPTOR, INT, and IAT purely from bytes. Emits eight new reason codes. Handles PE32+/PE32 thunk sizing, v1/v0 attribute modes, and bound state detection explicitly rather than through pefile interpretation.
-
VS_VERSIONINFO validator decodes the envelope, VS_FIXEDFILEINFO, StringFileInfo, and VarFileInfo purely from bytes. Emits four new reason codes. Deterministic leaf selection across multiple RT_VERSION entries.
-
Resource hierarchy enforcement now tracks tree depth and enforces the PE spec's Type → Name → Language layering. Two new reason codes for hierarchy violations.
Public metadata enrichment
-
Optional Header gains nine new fields: dll_characteristics (raw + decoded flags + unknown bits), win32_version_value, loader_flags, and stack/heap sizing (stack_reserve_size, stack_commit_size, heap_reserve_size, heap_commit_size).
-
Header gains subsystem_name (decoded from IMAGE_SUBSYSTEM_) and machine_name (decoded from IMAGE_FILE_MACHINE_; supporting table covers all 29 documented machine types).
-
Resources now expose a structured ResourceEntry per resource covering type, name, language, language_name, codepage, size, entropy, rva, raw_offset, and per-entry errors. Entropy rounded to 4 decimal places for snapshot stability. Resources with unreadable data are now emitted with error tags rather than silently dropped.
Breaking changes
-
Consumers checking
language_name == "unknown"must update tolanguage_name is None. The magic-string sentinel was replaced with None from every "cannot decode" path, allowing consumers to distinguish structurally-invalid from unmapped-primary from not-provided. -
Extended metadata no longer emits
subsystem_humanandmachine_human. The parser layer is now the single source of truth for both. Consumers should use subsystem_name (uppercase-underscore form: WINDOWS_CUI) and machine_name (added this release). Migration is a string-conversion exercise if display-friendly forms are needed. -
Snapshot refresh required for fixtures with resources, optional header, or extended metadata. Mechanical via existing fixture regeneration tooling. See CHANGELOG for the full list of affected fields.
Fixes
- Resource validator no longer silently returns when a directory's own RVA falls outside .rsrc.
- Resource entropy now computed over the correct byte range (previously sliced get_memory_mapped_image() with raw file offset; caught before snapshot stamping).
- pe.get_offset_from_rva failures now produce a -1 sentinel rather than propagating exceptions.
Architectural notes
Producer-facing structural metadata (export_struct, delay_import_struct, Load Config) is kept internal by design — it feeds validators and heuristics, not the public IOC schema. Consumers needing structural information should rely on validator reason codes and the existing consumer-facing metadata fields (exports, delayed_imports, etc.).
Public schema promotion of version_info_struct (containing consumer-facing metadata like CompanyName, ProductVersion, OriginalFilename) is deferred to a future release with corresponding fixture corpus refresh.
Scheduled for next release
- TLS Directory parser and validator (originally deferred; queued for next release)
- ~25 single-anomaly fixtures targeting the new reason codes, including negative-control fixtures demonstrating validator precision
- Cross-tool divergence study using the new fixtures, particularly for delay-load's three spec-interpretation questions (v0/v1 mode, INT/IAT mirror vs bound assumption, declared-size vs walk-to-terminator)
- SUBLANG table refinement for multilingual LCID edge cases
- Heuristic work items filed: CFG declaration consistency, implausibility framework, intra-field DllCharacteristics flag dependencies
Under the hood
- 100% line and branch coverage on all new modules
- ~650 new tests bringing suite total to 1370 tests
- Defensive-path coverage via monkeypatched struct.error injection
- Delay-load parser cross-checked against dumpbin /imports on mspaint.exe: 107 imports from gdiplus.dll with byte-exact agreement on names, hints, IAT addresses, ordering, and bound state
- New TypedDicts for all new structural data; iocx.parsers.pe_constants module houses PE-spec lookup tables
Documentation
- Reason-codes reference gains sections for Resource Hierarchy, VS_VERSIONINFO, Export, and Delay-Load Import anomalies, each with sub-reason taxonomies
- Validator documentation sections 2.5 (VS_VERSIONINFO), 2.6 (exports), and 2.7 (delay-load imports) with explicit determinism rationale
- Schema reference documents new Optional Header fields, mixed-default convention, and _decode_langid semantics