Sign in

    moon-pe-inspect

    Safe PE/COFF inspection, import/export extraction, and security metadata auditing for MoonBit.

    pe
    coff
    binary-analysis
    security
    windows
    Download zip
    Author
    Version
    0.2.0
    License
    Apache-2.0
    Last updated
    14 hours ago
    Downloads
    15

    #moon-pe-inspect

    A pure MoonBit PE/COFF inspector for build artifacts and security metadata.

    moon-pe-inspect parses Windows PE files without loading or executing them. It extracts PE32/PE32+ headers, sections, imports, exports, resources, relocations, delay imports, TLS, Debug/PDB metadata, Load Config, and exception tables. The core is a bounds-checked MoonBit library; the CLI adds text, JSON, and artifact diff output for CI and analysis workflows.

    #Why this project

    PE files are produced by Windows build pipelines, shipped as DLLs and EXEs, and examined during vulnerability triage. Existing generic binary readers stop at byte access. This project owns the domain logic:

    • validate DOS, PE, COFF, and optional-header structures;
    • map RVAs to section file offsets;
    • walk import descriptors and thunk tables;
    • resolve export names, ordinals, and forwarders;
    • traverse resource, relocation, delay-import, TLS, debug, load-config, and exception directories;
    • detect missing hardening flags and writable-executable sections;
    • compare build artifacts and report metadata changes;
    • return bounded errors instead of panicking on malformed input.

    #Features

    • PE32 and PE32+ support.
    • Machine, subsystem, image base, entry point, checksum, and image-size metadata.
    • Section table parsing with virtual/file ranges and characteristics.
    • Imported DLL and function extraction, including ordinal imports.
    • Export extraction with ordinal and forwarder resolution.
    • Resource trees, base relocations, delay imports, TLS callbacks, CodeView PDB metadata, Load Config, and exception entries.
    • Security diagnostics for ASLR, NX, CFG metadata, SafeSEH, security cookies, high-entropy VA, RWX sections, relocations, executable entry points, and certificate-table presence.
    • Artifact diffing for headers, sections, imports, exports, directories, and security findings.
    • CLI commands with human-readable and JSON output.
    • Reproducible synthetic PE fixtures for tests and demonstrations.

    #Quick start

    Install from mooncakes.io:

    moon add 404-32/moon-pe-inspect@0.2.0

    Package page: https://mooncakes.io/docs/404-32/moon-pe-inspect/0.2.0

    Build and test from source:

    git clone https://github.com/404-32/byc001.git cd byc001 moon test --target wasm

    Inspect the included PE32 fixture:

    moon run cmd/main -- inspect examples/minimal-pe32.exe

    List imports and exports:

    moon run cmd/main -- imports examples/minimal-pe32.exe moon run cmd/main -- exports examples/minimal-pe32.exe

    Produce JSON for CI:

    moon run cmd/main -- inspect examples/minimal-pe32plus.exe --json moon run cmd/main -- security examples/minimal-pe32plus.exe --json

    Inspect extended directories and compare two artifacts:

    moon run cmd/main -- directories examples/minimal-pe32.exe moon run cmd/main -- resources examples/minimal-pe32.exe moon run cmd/main -- delay-imports examples/minimal-pe32.exe moon run cmd/main -- load-config examples/minimal-pe32.exe moon run cmd/main -- diff examples/minimal-pe32.exe examples/minimal-pe32plus.exe

    Inspect a real Windows binary:

    moon run cmd/main -- sections C:\Windows\System32\notepad.exe

    #Library API

    ///|
    let image = @pe.PEImage::parse(file_bytes)

    ///|
    let sections = image.sections

    ///|
    let imports = image.imports()

    ///|
    let exports = image.exports()

    ///|
    let resources = image.resources()

    ///|
    let relocations = image.base_relocations()

    ///|
    let delay_imports = image.delay_imports()

    ///|
    let tls = image.tls()

    ///|
    let debug_entries = image.debug_entries()

    ///|
    let load_config = image.load_config()

    ///|
    let exceptions = image.exception_entries()

    ///|
    let diagnostics = image.security_diagnostics()

    ///|
    let offset = image.rva_to_offset(0x1000UL)

    Parsing is read-only. All binary reads are checked against the available byte range, and malformed files produce a PeError containing a file offset and message.

    #Security checks

    • pe.no-aslr: DYNAMIC_BASE is missing.
    • pe.no-nx: NX_COMPAT is missing.
    • pe.no-cfg: GUARD_CF is missing.
    • pe.cfg-metadata-missing: CFG is advertised without a guard function table.
    • pe.aslr-without-relocations: ASLR is advertised without base relocations.
    • pe.no-safeseh: 32-bit image has no SafeSEH metadata or NO_SEH.
    • pe.no-security-cookie: Load Config does not declare a /GS cookie.
    • pe.no-high-entropy-va: 64-bit image lacks high-entropy VA.
    • pe.rwx-section: a section is writable and executable.
    • pe.entrypoint-not-executable: entry point is outside executable sections.
    • pe.unsigned: no certificate table is present.
    • pe.certificate-table: certificate data exists, but the tool does not verify it.

    The last distinction is intentional: detecting an Authenticode certificate table is not the same as validating a signature.

    #Scope

    This project inspects static PE metadata. It does not load or execute images, perform disassembly, unpack compressed binaries, validate certificate chains, or parse every Windows-specific data directory. New formats and checks can be added without changing the safe binary-reader foundation.

    #Development

    python scripts/generate_fixtures.py moon check --target wasm --deny-warn moon test --target wasm --deny-warn moon fmt --check moon run cmd/main -- inspect examples/minimal-pe32.exe

    License: Apache-2.0.

    PeError

    pub(all) suberror PeError {
    PeError(Int, String)
    }

    DataDirectory

    pub(all) struct DataDirectory {
    index : Int
    name : String
    virtual_address : UInt64
    size : Int
    }

    DebugEntry

    pub(all) struct DebugEntry {
    debug_type : Int
    type_name : String
    timestamp : Int
    size_of_data : Int
    address_of_raw_data : UInt64
    pointer_to_raw_data : Int
    pdb_path : String?
    pdb_age : Int?
    pdb_guid : String?
    }

    DelayImportLibrary

    pub(all) struct DelayImportLibrary {
    name : String
    attributes : Int
    timestamp : Int
    symbols : Array[ImportSymbol]
    }

    Diagnostic

    pub(all) struct Diagnostic {
    severity : Severity
    code : String
    message : String
    }

    DiffItem

    pub(all) struct DiffItem {
    field : String
    before : String
    after : String
    }

    ExceptionEntry

    pub(all) struct ExceptionEntry {
    begin_rva : UInt64
    end_rva : UInt64
    unwind_info_rva : UInt64
    }

    ExportSymbol

    pub(all) struct ExportSymbol {
    name : String
    ordinal : Int
    rva : UInt64
    forwarder : String?
    }

    ImportLibrary

    pub(all) struct ImportLibrary {
    name : String
    symbols : Array[ImportSymbol]
    }

    ImportSymbol

    pub(all) struct ImportSymbol {
    name : String?
    ordinal : Int?
    hint : Int?
    }

    LoadConfigInfo

    pub(all) struct LoadConfigInfo {
    structure_size : Int
    timestamp : Int
    global_flags_clear : Int?
    global_flags_set : Int?
    security_cookie : UInt64?
    se_handler_table : UInt64?
    se_handler_count : Int?
    guard_cf_check_pointer : UInt64?
    guard_cf_dispatch_pointer : UInt64?
    guard_cf_function_table : UInt64?
    guard_cf_function_count : Int?
    guard_flags : Int?
    }

    PEFormat

    pub(all) enum PEFormat {
    PE32
    PE32Plus
    }

    PEImage

    pub(all) struct PEImage {
    data : Bytes
    pe_offset : Int
    format : PEFormat
    machine : Int
    number_of_sections : Int
    timestamp : UInt64
    symbol_table_pointer : UInt64
    number_of_symbols : UInt64
    size_of_optional_header : Int
    characteristics : Int
    entry_point : UInt64
    image_base : UInt64
    section_alignment : Int
    file_alignment : Int
    size_of_image : Int
    size_of_headers : Int
    checksum : UInt64
    subsystem : Int
    dll_characteristics : Int
    sections : Array[Section]
    directories : Array[DataDirectory]
    }

    PEImage::base_relocations

    fn PEImage::base_relocations(self : PEImage) -> Array[RelocationBlock] raise PeError

    PEImage::debug_entries

    fn PEImage::debug_entries(self : PEImage) -> Array[DebugEntry] raise PeError

    PEImage::delay_imports

    fn PEImage::delay_imports(self : PEImage) -> Array[DelayImportLibrary] raise PeError

    PEImage::diff

    fn PEImage::diff(self : PEImage, other : PEImage) -> Array[DiffItem]

    PEImage::directory

    fn PEImage::directory(self : PEImage, index : Int) -> DataDirectory?

    PEImage::exception_entries

    fn PEImage::exception_entries(self : PEImage) -> Array[ExceptionEntry] raise PeError

    PEImage::exports

    fn PEImage::exports(self : PEImage) -> Array[ExportSymbol] raise PeError

    PEImage::imports

    fn PEImage::imports(self : PEImage) -> Array[ImportLibrary] raise PeError

    PEImage::is_64_bit

    fn PEImage::is_64_bit(self : PEImage) -> Bool

    PEImage::load_config

    fn PEImage::load_config(self : PEImage) -> LoadConfigInfo? raise PeError

    PEImage::parse

    fn PEImage::parse(data : Bytes) -> PEImage raise PeError

    PEImage::read_c_string

    fn PEImage::read_c_string(self : PEImage, rva : UInt64, max_length : Int) -> String raise PeError

    PEImage::resources

    fn PEImage::resources(self : PEImage) -> Array[ResourceEntry] raise PeError

    PEImage::rva_to_offset

    fn PEImage::rva_to_offset(self : PEImage, rva : UInt64) -> Int raise PeError

    PEImage::section_by_name

    fn PEImage::section_by_name(self : PEImage, name : String) -> Section?

    PEImage::security_diagnostics

    fn PEImage::security_diagnostics(self : PEImage) -> Array[Diagnostic]

    PEImage::tls

    fn PEImage::tls(self : PEImage) -> TlsInfo? raise PeError

    PEImage::va_to_rva

    fn PEImage::va_to_rva(self : PEImage, va : UInt64) -> UInt64?

    RelocationBlock

    pub(all) struct RelocationBlock {
    page_rva : UInt64
    entries : Array[RelocationEntry]
    }

    RelocationEntry

    pub(all) struct RelocationEntry {
    relocation_type : Int
    offset : Int
    target_rva : UInt64
    }

    ResourceEntry

    pub(all) struct ResourceEntry {
    path : String
    type_id : Int?
    name_id : Int?
    language_id : Int?
    data_rva : UInt64
    file_offset : Int?
    size : Int
    code_page : Int
    }

    Section

    pub(all) struct Section {
    name : String
    virtual_size : Int
    virtual_address : UInt64
    raw_size : Int
    raw_offset : Int
    characteristics : UInt64
    }

    Severity

    pub(all) enum Severity {
    Info
    Warning
    Critical
    }

    TlsInfo

    pub(all) struct TlsInfo {
    raw_data_start : UInt64
    raw_data_end : UInt64
    index_address : UInt64
    callbacks_address : UInt64
    size_of_zero_fill : Int
    characteristics : Int
    callbacks : Array[UInt64]
    }

    architecture_name

    fn architecture_name(machine : Int) -> String

    relocation_type_name

    fn relocation_type_name(relocation_type : Int) -> String

    subsystem_name

    fn subsystem_name(subsystem : Int) -> String

    Powered by MoonBit

    Site sourceReport issuePackagesBuild queueSkillsStatistics

    © 2026 mooncakes.io