t8y2/dbx · error · PeFormatError

PE import descriptor has no DLL name

Error message

PE import descriptor has no DLL name

What it means

Each non-terminal import descriptor must carry a valid Name RVA (offset +12) pointing to the ASCII DLL name string. This error is raised when that Name field is 0 in a descriptor that is not the all-zero terminator — a structure the PE spec forbids. The library throws it because it cannot record which DLL the descriptor refers to.

Source

Thrown at agents/scripts/validate_windows_pe_dependencies.py:97

            span = max(virtual_size, raw_size)
            if virtual_address <= rva < virtual_address + span:
                delta = rva - virtual_address
                if delta >= raw_size:
                    break
                return raw_offset + delta
        raise PeFormatError(f"PE RVA 0x{rva:x} is not backed by file data")

    descriptor_offset = rva_to_offset(import_directory_rva)
    imports = []
    for _ in range(4096):
        if descriptor_offset + 20 > len(data):
            raise PeFormatError("truncated PE import descriptor")
        descriptor = data[descriptor_offset : descriptor_offset + 20]
        if descriptor == b"\0" * 20:
            return sorted(set(imports), key=str.casefold)
        name_rva = _read_u32(data, descriptor_offset + 12)
        if name_rva == 0:
            raise PeFormatError("PE import descriptor has no DLL name")
        imports.append(_read_c_string(data, rva_to_offset(name_rva)))
        descriptor_offset += 20

    raise PeFormatError("PE import descriptor table is not terminated")


def forbidden_msvc_runtime_dlls(imports: list[str]) -> list[str]:
    return sorted(
        {name for name in imports if name.casefold().startswith(("msvcp", "vcruntime"))},
        key=str.casefold,
    )


def main() -> int:
    parser = argparse.ArgumentParser(description="Reject Windows PE files that require the Visual C++ runtime")
    parser.add_argument("binary", type=Path)
    args = parser.parse_args()

View on GitHub (pinned to c0390bff16)

Solutions

  1. Open the binary with pefile / dumpbin /imports to confirm the import directory contains a descriptor with a zero Name field.
  2. Rebuild the binary from source with a standard toolchain so the import table is emitted correctly.
  3. If the malformed descriptor is intentional (import obfuscation), parse imports from a memory dump of the unpacked process instead.
  4. Catch PeFormatError around imported_dlls and fail the check with a clear 'malformed import table' message for that artifact.

Example fix

// before
imports = imported_dlls(Path(binary_path))
// after
try:
    imports = imported_dlls(Path(binary_path))
except PeFormatError as err:
    print(f"{binary_path}: malformed PE import table ({err})")
    imports = []
Defensive patterns

Strategy: validation

Validate before calling

import pefile

def import_names_present(path) -> bool:
    pe = pefile.PE(path)
    for entry in getattr(pe, "DIRECTORY_ENTRY_IMPORT", []):
        if not entry.dll:
            return False
    return True

Try / catch

try:
    imports = imported_dlls(path)
except PeFormatError as err:
    if "no DLL name" in str(err):
        report_malformed_import_table(path, err)
    else:
        raise

Prevention

When it happens

Trigger: imported_dlls(path) on a PE whose import descriptor array contains an entry with a zero Name RVA but non-zero other fields — caused by hand-edited headers, incomplete zeroing of a removed import, or fuzzed binaries.

Common situations: Import-stripping or import-hiding tools that blanked the Name field incorrectly; malware samples crafted to break parsers; a linker or post-processing tool bug that emitted a malformed descriptor; corrupt memory-mapped file edits.

Related errors


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