t8y2/dbx · error · PeFormatError

missing PE signature

Error message

missing PE signature

What it means

PeFormatError raised by imported_dlls when the 4-byte signature at the offset stored in the DOS header (epe_offset, read from 0x3C) is not b"PE\0\0". The file has a valid MZ stub but the DOS-header e_lfanew pointer does not lead to a PE signature, so it is not a parseable Windows PE (it may be an old DOS executable or a corrupted/patched file).

Source

Thrown at agents/scripts/validate_windows_pe_dependencies.py:43

    if offset < 0 or offset >= len(data):
        raise PeFormatError("PE string offset is outside the file")
    end = data.find(b"\0", offset)
    if end < 0:
        raise PeFormatError("unterminated PE string")
    try:
        return data[offset:end].decode("ascii")
    except UnicodeDecodeError as error:
        raise PeFormatError("PE import name is not ASCII") from error


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)

View on GitHub (pinned to c0390bff16)

Solutions

  1. Confirm the file is a real PE with `file binary.exe` — output should say 'PE32'/'PE32+', not 'MS-DOS executable'.
  2. Rebuild or re-obtain the binary; a broken e_lfanew usually means corruption or an incomplete build/pack step.
  3. If the file is intentionally DOS-only, exclude it from Windows PE dependency validation.
  4. Catch PeFormatError and fail gracefully in CI with a clear 'missing PE signature' message.

Example fix

// before
result = subprocess.run(["python", "validate_windows_pe_dependencies.py", binary])
// after
result = subprocess.run(["python", "validate_windows_pe_dependencies.py", binary])
if "missing PE signature" in result.stderr:
    raise SystemExit(f"{binary} is not a valid Windows PE (bad e_lfanew)")
Defensive patterns

Strategy: validation

Validate before calling

import struct
data = path.read_bytes()
if len(data) >= 64 and data[:2] == b"MZ":
    pe_offset = struct.unpack_from("<I", data, 0x3C)[0]
    if data[pe_offset:pe_offset + 4] != b"PE\0\0":
        raise SystemExit(f"{path}: DOS header present but no PE signature (e_lfanew=0x{pe_offset:x})")

Type guard

def has_pe_signature(data: bytes) -> bool:
    if len(data) < 64 or data[:2] != b"MZ":
        return False
    pe_offset = int.from_bytes(data[0x3C:0x40], "little")
    return pe_offset + 4 <= len(data) and data[pe_offset:pe_offset + 4] == b"PE\0\0"

Try / catch

try:
    imports = imported_dlls(path)
except PeFormatError as error:
    if "missing PE signature" in str(error):
        print(f"{path} is a DOS executable or corrupt PE; skipping")
    else:
        raise

Prevention

When it happens

Trigger: imported_dlls(path) reads _read_u32(data, 0x3C) and slices data[pe_offset:pe_offset+4] on a classic MS-DOS executable, a file whose e_lfanew was overwritten, a PE whose stub was modified by packers/protectors, or a text file that merely starts with 'MZ'.

Common situations: Validating genuine DOS-era .exe/.com files that lack a PE header, binaries mangled by a hex edit or bad patch, files processed by tools that rewrote e_lfanew incorrectly, or scripts that fabricate an MZ header without updating the PE pointer.

Related errors


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