t8y2/dbx · error · PeFormatError
PE string offset is outside the file
Error message
PE string offset is outside the file
What it means
PeFormatError raised by _read_c_string when the offset it is asked to read a NUL-terminated string from is negative or at/after the end of the file bytes. The library throws it instead of letting Python raise IndexError/struct errors, so callers get a uniform PE-format exception while walking the import name table. It almost always means the RVA-to-file-offset mapping produced an out-of-bounds offset, i.e. the file is malformed, truncated, or not a real PE.
Source
Thrown at agents/scripts/validate_windows_pe_dependencies.py:26
class PeFormatError(ValueError):
pass
def _read_u16(data: bytes, offset: int) -> int:
if offset < 0 or offset + 2 > len(data):
raise PeFormatError("unexpected end of PE file")
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")
View on GitHub (pinned to c0390bff16)
Solutions
- Verify the file is intact and a genuine PE (size matches expected bytes, valid section table) with a tool like `objdump -x` or pefile before re-running.
- Re-obtain the binary from a trusted source / re-download or rebuild it; a truncated file is the most common cause.
- If the file is intentionally malformed, catch PeFormatError around imported_dlls and treat it as 'cannot validate' rather than letting it propagate.
- If you are parsing an unpacked/modified PE, fix the section headers or Name RVAs so import names resolve inside the mapped file data.
Example fix
// before
imports = imported_dlls(Path("app.exe")) # raises PeFormatError
// after
try:
imports = imported_dlls(Path("app.exe"))
except PeFormatError as error:
print(f"cannot validate {path}: {error}") # treat as unparseable PE Defensive patterns
Strategy: try-catch
Validate before calling
data = path.read_bytes()
if len(data) < 64 or data[:2] != b"MZ":
raise SystemExit("not a PE")
# cheap sanity: import name offsets must lie inside the file;
# prefer a real check with pefile if available
import pefile
pe = pefile.PE(data=data)
assert all(entry.dll for entry in pe.DIRECTORY_ENTRY_IMPORT) Type guard
def is_parseable_pe(data: bytes) -> bool:
return len(data) >= 64 and data[:2] == b"MZ" and 0 < len(data) - 4 Try / catch
try:
imports = imported_dlls(path)
except PeFormatError as error:
print(f"unparseable PE ({path}): {error}")
imports = None # or fail the check Prevention
- Validate the whole file exists and its size matches the build manifest before parsing
- Run `objdump -x` or pefile over binaries once at build time to catch malformed PEs early
- Do not feed truncated downloads into the validator; verify checksums
- Treat any PeFormatError as 'cannot prove compliance' and fail closed in CI
When it happens
Trigger: imported_dlls() resolves an import-descriptor name_rva via rva_to_offset() and passes the result to _read_c_string; the offset lands outside data. Concretely: a crafted/corrupt PE whose import directory or name RVAs point beyond the mapped sections, a section table whose raw_offset/raw_size values overshoot the file, or a name_rva that maps to exactly EOF.
Common situations: Inspecting a truncated or partially-downloaded .exe/.dll, feeding a non-PE binary that still passes the MZ/PE checks (e.g. an SFX stub or .NET single-file bundle with odd sections), analyzing malware samples with deliberately corrupted import tables, or a self-modified binary where the section headers were patched.
Related errors
- unterminated PE string
- PE import name is not ASCII
- 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/2b5b4dbb55e55677.
Report an issue: GitHub.