t8y2/dbx · error · PeFormatError

unsupported PE optional header magic: 0x{optional_magic:04x}

Error message

unsupported PE optional header magic: 0x{optional_magic:04x}

What it means

imported_dlls() parses a Windows PE file to list its imported DLLs. After locating the optional header it reads the 16-bit magic that distinguishes PE32+ (0x20B) from PE32 (0x10B); only those two layouts are implemented. This error is raised when the file declares any other optional-header magic, so the parser cannot know where the data directories (and therefore the import table) live.

Source

Thrown at agents/scripts/validate_windows_pe_dependencies.py:54

def imported_dlls(path: Path) -> list[str]:
    data = path.read_bytes()
    if len(data) < 64 or data[:2] != b"MZ":
        raise PeFormatError("missing DOS header")

    pe_offset = _read_u32(data, 0x3C)
    if data[pe_offset : pe_offset + 4] != b"PE\0\0":
        raise PeFormatError("missing PE signature")

    section_count = _read_u16(data, pe_offset + 6)
    optional_header_size = _read_u16(data, pe_offset + 20)
    optional_header_offset = pe_offset + 24
    optional_magic = _read_u16(data, optional_header_offset)
    if optional_magic == 0x20B:
        data_directories_offset = optional_header_offset + 112
    elif optional_magic == 0x10B:
        data_directories_offset = optional_header_offset + 96
    else:
        raise PeFormatError(f"unsupported PE optional header magic: 0x{optional_magic:04x}")

    import_directory_rva = _read_u32(data, data_directories_offset + 8)
    import_directory_size = _read_u32(data, data_directories_offset + 12)
    if import_directory_rva == 0 or import_directory_size == 0:
        return []

    size_of_headers = _read_u32(data, optional_header_offset + 60)
    section_table_offset = optional_header_offset + optional_header_size
    sections = []
    for index in range(section_count):
        section_offset = section_table_offset + index * 40
        sections.append(
            (
                _read_u32(data, section_offset + 12),
                _read_u32(data, section_offset + 8),
                _read_u32(data, section_offset + 20),
                _read_u32(data, section_offset + 16),
            )

View on GitHub (pinned to c0390bff16)

Solutions

  1. Verify the input is a real Windows PE: check that data[0x3C] points to a 'PE\0\0' signature and that the optional header magic is 0x10B or 0x20B before validating.
  2. Re-obtain the binary from a trusted build artifact (rebuild/re-download); the header is likely corrupt.
  3. If you must support another PE variant, extend the script's magic dispatch to compute the correct data_directories_offset for it.
  4. Exclude the file from validation or guard the script invocation so only genuine .exe/.dll artifacts are passed in.

Example fix

// before
imports = imported_dlls(Path(binary_path))
// after
try:
    imports = imported_dlls(Path(binary_path))
except PeFormatError as err:
    print(f"skipping {binary_path}: {err}")
    imports = []
Defensive patterns

Strategy: validation

Validate before calling

import struct
from pathlib import Path

def has_supported_pe_optional_header(path: Path) -> bool:
    data = path.read_bytes()
    if len(data) < 64 or data[:2] != b"MZ":
        return False
    pe = struct.unpack_from("<I", data, 0x3C)[0]
    if data[pe:pe+4] != b"PE\x00\x00":
        return False
    magic = struct.unpack_from("<H", data, pe + 24)[0]
    return magic in (0x10B, 0x20B)

Type guard

def is_valid_pe_bytes(data: bytes) -> bool:
    return len(data) >= 64 and data[:2] == b"MZ"

Try / catch

try:
    imports = imported_dlls(path)
except PeFormatError as err:
    log.warning("unsupported or malformed PE %s: %s", path, err)
    imports = []

Prevention

When it happens

Trigger: Calling imported_dlls(path) on a file whose PE optional header magic is neither 0x10B nor 0x20B — e.g. corrupted pe_offset pointing into random bytes, a ROM/EFI or old PE image variant, a hand-crafted or fuzzed header, or a truncated file whose 0x3C pointer lands on non-header data.

Common situations: Validating a corrupt or tampered binary; pointing the validator at a non-PE file that happens to start with 'MZ' (some self-extractors, .NET single-file bundles, DOS stubs); a repo checkout where binary files were mangled by text-mode conversion; fuzz-tested inputs in CI.

Related errors


AI-assisted analysis of t8y2/dbx@c0390bff16 (2026-09-05). Data as JSON: /api/errors/d5be941d42fbf5d2. Report an issue: GitHub.