{"record":{"id":"b857386084ea32dd","repo":"t8y2/dbx","slug":"pe-import-name-is-not-ascii","errorCode":null,"errorMessage":"PE import name is not ASCII","messagePattern":"PE import name is not ASCII","errorType":"exception","errorClass":"PeFormatError","httpStatus":null,"severity":"error","filePath":"agents/scripts/validate_windows_pe_dependencies.py","lineNumber":33,"sourceCode":"    return struct.unpack_from(\"<H\", data, offset)[0]\n\n\ndef _read_u32(data: bytes, offset: int) -> int:\n    if offset < 0 or offset + 4 > len(data):\n        raise PeFormatError(\"unexpected end of PE file\")\n    return struct.unpack_from(\"<I\", data, offset)[0]\n\n\ndef _read_c_string(data: bytes, offset: int) -> str:\n    if offset < 0 or offset >= len(data):\n        raise PeFormatError(\"PE string offset is outside the file\")\n    end = data.find(b\"\\0\", offset)\n    if end < 0:\n        raise PeFormatError(\"unterminated PE string\")\n    try:\n        return data[offset:end].decode(\"ascii\")\n    except UnicodeDecodeError as error:\n        raise PeFormatError(\"PE import name is not ASCII\") from error\n\n\ndef imported_dlls(path: Path) -> list[str]:\n    data = path.read_bytes()\n    if len(data) < 64 or data[:2] != b\"MZ\":\n        raise PeFormatError(\"missing DOS header\")\n\n    pe_offset = _read_u32(data, 0x3C)\n    if data[pe_offset : pe_offset + 4] != b\"PE\\0\\0\":\n        raise PeFormatError(\"missing PE signature\")\n\n    section_count = _read_u16(data, pe_offset + 6)\n    optional_header_size = _read_u16(data, pe_offset + 20)\n    optional_header_offset = pe_offset + 24\n    optional_magic = _read_u16(data, optional_header_offset)\n    if optional_magic == 0x20B:\n        data_directories_offset = optional_header_offset + 112\n    elif optional_magic == 0x10B:","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/t8y2/dbx/blob/c0390bff16418b651f4728520d99adf8ce48829a/agents/scripts/validate_windows_pe_dependencies.py#L15-L51","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nimports = imported_dlls(binary)\nforbidden = forbidden_msvc_runtime_dlls(imports)\n// after\ntry:\n    forbidden = forbidden_msvc_runtime_dlls(imported_dlls(binary))\nexcept PeFormatError as error:\n    raise SystemExit(f\"reject {binary}: {error}\")","handlingStrategy":"try-catch","validationCode":"import pefile\npe = pefile.PE(str(path))\nnames = [e.dll.decode(\"ascii\", \"strict\") for e in pe.DIRECTORY_ENTRY_IMPORT]  # raises UnicodeDecodeError early if names are not ASCII","typeGuard":"def is_ascii(data: bytes) -> bool:\n    try:\n        data.decode(\"ascii\")\n        return True\n    except UnicodeDecodeError:\n        return False","tryCatchPattern":"try:\n    imports = imported_dlls(path)\nexcept PeFormatError as error:\n    if \"not ASCII\" in str(error):\n        print(f\"{path}: import table is packed, obfuscated, or corrupt\")\n    else:\n        raise","preventionTips":["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"],"tags":["pe","binary-parsing","encoding","ascii","malformed-input"],"backgroundTag":"pe-format-invalid","analyzedSha":"c0390bff16418b651f4728520d99adf8ce48829a","analyzedAt":"2026-09-05T23:05:10.900Z","contentChangedAt":"2026-09-05T23:05:10.900Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}