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

  1. Confirm with pefile or objdump that the binary's import directory is intact; if the import table is packed/encrypted, unpack the binary first.
  2. Re-check that the RVA-to-offset conversion uses the correct section (VirtualAddress vs PointerToRawData) — a wrong mapping commonly lands in non-string data.
  3. If you accept non-ASCII names, wrap imported_dlls in try/except PeFormatError and report the file as unparseable.
  4. 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

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


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