t8y2/dbx · error · PeFormatError
PE import name is not ASCII
Error message
PE import name is not ASCII
What it means
PeFormatError raised by _read_c_string when the bytes between offset and the NUL terminator fail .decode("ascii"); the original UnicodeDecodeError is chained via `from error`. Import DLL names in a PE must be ASCII, so non-ASCII bytes at a resolved import-name offset mean the offset points at the wrong data (bad RVA mapping) or the file is corrupt/hostile.
Source
Thrown at agents/scripts/validate_windows_pe_dependencies.py:33
return struct.unpack_from("<H", data, offset)[0]
def _read_u32(data: bytes, offset: int) -> int:
if offset < 0 or offset + 4 > len(data):
raise PeFormatError("unexpected end of PE file")
return struct.unpack_from("<I", data, offset)[0]
def _read_c_string(data: bytes, offset: int) -> str:
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:View on GitHub (pinned to c0390bff16)
Solutions
- Confirm with pefile or objdump that the binary's import directory is intact; if the import table is packed/encrypted, unpack the binary first.
- Re-check that the RVA-to-offset conversion uses the correct section (VirtualAddress vs PointerToRawData) — a wrong mapping commonly lands in non-string data.
- If you accept non-ASCII names, wrap imported_dlls in try/except PeFormatError and report the file as unparseable.
- Reject the binary in CI: this error from the validator means the PE cannot be proven free of dynamic VC++ runtime dependencies.
Example fix
// before
imports = imported_dlls(binary)
forbidden = forbidden_msvc_runtime_dlls(imports)
// after
try:
forbidden = forbidden_msvc_runtime_dlls(imported_dlls(binary))
except PeFormatError as error:
raise SystemExit(f"reject {binary}: {error}") Defensive patterns
Strategy: try-catch
Validate before calling
import pefile
pe = pefile.PE(str(path))
names = [e.dll.decode("ascii", "strict") for e in pe.DIRECTORY_ENTRY_IMPORT] # raises UnicodeDecodeError early if names are not ASCII Type guard
def is_ascii(data: bytes) -> bool:
try:
data.decode("ascii")
return True
except UnicodeDecodeError:
return False Try / catch
try:
imports = imported_dlls(path)
except PeFormatError as error:
if "not ASCII" in str(error):
print(f"{path}: import table is packed, obfuscated, or corrupt")
else:
raise Prevention
- Unpack/decrypt binaries before validating their import tables
- Validate that RVAs map into real section data with pefile before trusting your own parser
- Treat non-ASCII import names as a hard rejection — legitimate DLL names are ASCII
- Keep the UnicodeDecodeError chain (`raise ... from`) when logging so root cause is visible
When it happens
Trigger: imported_dlls() resolves a name_rva to an offset whose bytes up to the next \0 contain bytes >= 0x80 — e.g. the RVA actually lands in code or resource data rather than the import-name table, or a malware sample deliberately fills the name field with high-byte values.
Common situations: Analyzing packed or obfuscated binaries whose import tables were wiped/encrypted, offsets computed from a hand-rolled or buggy RVA translator, or reverse-engineering samples that intentionally poison import names to break parsing tools.
Related errors
- PE string offset is outside the file
- unterminated PE string
- unexpected end of PE file
- missing DOS header
- missing PE signature
AI-assisted analysis of t8y2/dbx@c0390bff16 (2026-09-05).
Data as JSON: /api/errors/b857386084ea32dd.
Report an issue: GitHub.