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
- 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.
- Re-obtain the binary from a trusted build artifact (rebuild/re-download); the header is likely corrupt.
- If you must support another PE variant, extend the script's magic dispatch to compute the correct data_directories_offset for it.
- 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
- Only run the validator on artifacts produced by a known PE toolchain (MSVC/MinGW).
- Verify file hashes against build outputs to catch corrupted/truncated copies.
- Pre-screen with pefile.PE(path) which gives clearer diagnostics for header problems.
- Exclude non-image PE variants (COFF objects, .lib) from validation.
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
- PE RVA 0x{rva:x} is not backed by file data
- PE import descriptor has no DLL name
- unexpected end of PE file
- truncated PE import descriptor
- PE import descriptor table is not terminated
AI-assisted analysis of t8y2/dbx@c0390bff16 (2026-09-05).
Data as JSON: /api/errors/d5be941d42fbf5d2.
Report an issue: GitHub.