Skip to main content
Glama

re-lief

MCP server exposing LIEF (Library to Instrument Executable Formats) for cross-format binary analysis. Handles PE, ELF, MachO, COFF, DEX, ART, OAT in a single, normalized API.

Why

LIEF is the Python successor to pefile — same data for PE, plus ELF, MachO, DEX, ART, and OAT. It also handles DWARF/PDB debug info, ObjC metadata, the Dyld Shared Cache, and (optionally) has a built-in disassembler/assembler.

This server is the foundation of the RE-AI plugin: it works without any system tools installed (no rizin, no gdb, no anything), is pure Python, and runs in-process.

Related MCP server: re-rizin

Tools

Tool

What it does

check_lief

Health check — return LIEF version, supported formats

parse_binary

Auto-detect format and return normalized header + high-level structure

get_sections

Section list with permissions (R/W/X), virtual vs raw size, entropy

get_imports_exports

Symbol-level import/export tables (per format)

get_authenticode

PE signature details (Win)

get_overlay

Appended data after the last section

list_dex_classes

Android DEX class list

list_dex_methods

Methods of a DEX class

list_oat_art

Android OAT/ART method list

disasm_capstone

Capstone disassembly (works for any LIEF-parsed binary)

extract_strings

ASCII + UTF-16LE string extraction with section awareness

categorize_strings

ASCII + UTF-16LE string extraction, section-aware, bucketed into keyword categories from data/drm-indicators.yaml::string_categories. Superset of extract_strings.

get_imphash

PE import hash (MD5 of normalized import table)

normalize_for_diff

Produce a structural snapshot suitable for diffing two binaries

Install

This server is part of the RE-AI plugin. The plugin's install.sh / install.bat installs it as part of the standard flow.

To install standalone:

pip install -e ./servers/re-lief

Run

re-lief                          # stdio transport (default for MCP)
python -m re_lief                # equivalent

Format support

LIEF auto-detects the format and exposes a polyglot API. Most tools return results shaped by format:

  • PE (.exe, .dll, .sys): full sections, imports/exports, imphash, Authenticode, resources, exceptions, TLS, debug info (PDB path)

  • ELF (Linux binaries, .so, kernel modules): sections, segments (program headers), dynamic symbols, RELRO, BIND_NOW, NX, PIE, RPATH/RUNPATH, SONAME, dynamic libs

  • MachO (macOS/iOS binaries, .dylib, frameworks): load commands, segments, LC_BUILD_VERSION, code signature, dyld info, ObjC metadata

  • DEX (Android Dalvik): class list with FQN, method list per class, string pool

  • OAT/ART (Android runtime): method list with class/method indices, vdex references

  • COFF (Windows object files, EFI): sections, symbols, relocations

Deprecation of pefile

If you're familiar with the v1 re-ai repo, this server supersedes the old pefile-based code. The string-extraction algorithm (ASCII + UTF-16LE) and imphash logic were ported from backend/analysis/native.py; the rest of the API is LIEF-native and works for all formats.

Categorization vocabulary

categorize_strings reads its 11 keyword categories from data/drm-indicators.yaml::string_categories at MCP-server load time. The anti_debug and hwid categories inherit their keyword lists from drm-indicators.yaml::anti_debug_indicators.checks[].name and hwid_apis.high_signal[].api via a seed_from: YAML pointer — when a future agent adds a new HWID API to hwid_apis.high_signal, the categorizer picks it up automatically on next reload. The other 9 categories have their keyword lists inline in the YAML under string_categories.categories[].keywords.

This makes the categorizer idempotent with the catalog: the YAML is the single source of truth for both the indicator set that re-drm-fingerprint reads and the keyword set that the categorizer reads. Both the static analysis and the string analysis will give consistent answers.

On large binaries (>100 MB, e.g. a Unity IL2CPP GameAssembly.dll wrapped by an encrypted-VM bytecode interpreter), pass skip_sections=[".idata", ".xtls", ".xpdata", ".udata", ".xdata", ".didata", ".ecode", ".00cfg"] to skip the encrypted-VM bytecode regions. Note: on the bundled IL2CPP target sample, the import-table strings live inside those sections, so skipping them blinds the categorizer to the imports. Use skip_sections for memory-bound runs; use the full section walk for completeness.

Available Tools

17 tools
categorize_stringsA

Extract strings from path and bucket them into semantic categories.

The categorization vocabulary is loaded from data/drm-indicators.yaml::string_categories at MCP-server load time. Two categories (anti_debug, hwid) inherit their keyword lists from the existing catalog sections via a seed_from pointer; the rest have inline keyword lists. When a future agent adds a new HWID API to hwid_apis.high_signal, the hwid category picks it up on next MCP-server reload with zero Python change.

The return shape is a strict superset of extract_strings:

::

{
  "path": "...",
  "min_length": 5,
  "totals":   {"ascii_extracted": N, "utf16le_extracted": N,
               "deduplicated": N, "categorized": N},
  "truncated": {"input": bool, "per_category": bool,
                "per_encoding": bool},
  "by_category": {
    "anti_debug": {"count": N, "samples": [{"string":..., "section":...}, ...]},
    "hwid":       {"count": N, "samples": [...]},
    "crypto":     {"count": N, "samples": [...]},
    "network":    {"count": N, "samples": [...]},
    "registry":   {"count": N, "samples": [...]},
    "process":    {"count": N, "samples": [...]},
    "file":       {"count": N, "samples": [...]},
    "fingerprint": {"count": N, "samples": [...]},
    "activation":  {"count": N, "samples": [...]},
    "obfuscation": {"count": N, "samples": [...]},
    "misc":        {"count": N, "samples": [...]}
  },
  "ascii_capped": [...],          # backward-compat with extract_strings
  "utf16le_capped": [...],
  "uncategorized_sample": [...]   # 50 misc strings (helps spot missing categories)
}

On large binaries (e.g. a 500+ MB Unity IL2CPP GameAssembly.dll wrapped by an encrypted-VM bytecode interpreter), pass skip_sections=[".idata", ".xtls", ".xpdata", ".udata", ".xdata", ".didata", ".ecode", ".00cfg"] to skip the encrypted-VM bytecode regions. Those sections contain no readable strings; the categorization result is the same and the memory footprint drops dramatically.

Categories are descriptive — they describe observable string content, not specific commercial products.

Inputs: path (required), min_length, categories, include_misc, +3 more.

check_liefA

Return LIEF version, supported formats, and a green/yellow status.

Returns a JSON-serializable dict suitable for scripts/check_deps.py.

Inputs: no named parameters.

classify_native_protectionA

Classify a native binary's protection class (category-only).

Combines get_sections + get_imports_exports + the vendored native_packer_signatures regex catalog

  • entropy heuristics to label a binary's likely protection class. Returns one of:

  • "plain-pe" — no protection observed.

  • "packer-stub-wrapped" — UPX / ASPack / MPRESS / Petite / kkrunchy style (single non-standard section name).

  • "vm-bytecoded-pe" — single .vmp0 / .vmp1 style section set.

  • "encrypted-vm-bytecode-interpreter" — the proprietary-engine section family (.arch / .xcode / .xtext / .sbss / .link / .xtls / .xpdata).

  • "il2cpp-runtime" — large .idata + tiny .text + GameAssembly.dll sibling.

  • "anti-debug-wrapped" — bare anti-debug surface but no packer.

  • "unpacked-debug-pe" — debug build (PDB section + lots of stdio / conio / assert symbols).

Args: path: file to classify

Returns::

{
  "path": "...",
  "protection_class": "...",
  "evidence": [{"category": "...", "indicator": "...",
                "section": "..."}, ...]
}

Inputs: path (required).

disasm_capstoneA

Disassemble size bytes of section section_name starting at offset.

Returns a JSON list of instructions (address, mnemonic, operands, bytes). Truncates to max_insns (default 500) — call again with a different offset to see more.

Inputs: path (required), section_name (required), offset, size, +1 more.

extract_stringsA

Extract printable ASCII and UTF-16LE strings from path.

Returns {"ascii": [...], "utf16le": [...], "totals": {...}, "truncated": bool}. Each string has string, offset, and section fields.

.. note:: This is the v2.4 shape, kept stable for backward compatibility. New code should call categorize_strings (below), which returns the same ascii / utf16le arrays plus a keyword-bucketed by_category block.

Inputs: path (required), min_length.

get_authenticodeC

Return Authenticode signature details for PE binaries.

Inputs: path (required).

get_debug_directoryA

Return the PE debug directory entries (incl. IMAGE_DEBUG_TYPE_POGO).

The POGO entry (type 10) is the third-party-ATD layer's trigger-arming metadata (per ANTI-TAMPER-TAXONOMY.md Pattern A-DW). Surfaced with kind: "POGO" in the response dict. The CODEVIEW entry (type 2) is the PDB pointer; the canonical vendor-tag signal lives in the RSDS CodeView stream (resolved by re-pdb parse_pdb rather than this read-path).

The skill-side fallback references/pogo_debug_check.py in skills/re-drm-fingerprint/ mirrors this same shape for hosts that don't have the new MCP tool installed.

See See the RE-AI output directory per-target/p3r/stage5-pogo-debug-check.md for the canonical Pattern A-DW detection pattern.

Inputs: path (required).

get_imphashA

Return the PE import hash (imphash) for path.

Imphash is the MD5 of the normalized import table — used for malware variant identification. Returns an empty string for non-PE formats.

Inputs: path (required).

get_imports_exportsA

Return symbol-level import and export tables for path.

Args: path: PE / ELF / MachO to analyze. max_imports: cap the returned imports list to this many entries. 0 = no cap (the v2.9.0 default). max_exports: same cap for the exports list. library_filter: optional substring filter against the library name (pipe-separated for OR). e.g. "kernel32|user32" to keep only those two.

Added in v2.9.1+ to fix Gap 27 (the response-size ceiling on the 4 large VM-protected targets). The response includes a truncated flag + original_count / returned_count when the caps fire. The v2.9.0 callers (no kwargs) are unaffected.

Inputs: path (required), max_imports, max_exports, library_filter.

get_overlayB

Return appended data after the last section (PE overlay).

Inputs: path (required).

get_sectionsA

Return section list with permissions, virtual vs raw size, and entropy.

Works for PE (.text/.rdata/.data/.rsrc), ELF (.text/.rodata/.data), and MachO (__TEXT/__DATA/__LINKEDIT).

Inputs: path (required). Returns: result

list_dex_classesB

List all classes in a Dalvik DEX file.

Returns FQN, access flags, and method/field counts.

Inputs: path (required). Returns: result

list_dex_methodsC

List all methods of a DEX class identified by FQN (e.g. Lcom/foo/Bar;).

Inputs: path (required), class_fqn (required). Returns: result

list_oat_artC

List all methods in an OAT/ART Android runtime file.

Inputs: path (required). Returns: result

normalize_for_diffA

Return a structural snapshot suitable for diffing two binaries.

Strips variable-length fields (hashes, timestamps) and keeps the parts that should match between two builds of the same source.

Inputs: path (required).

parse_binaryA

Auto-detect the format of path and return a normalized header dict.

Returns hashes, format name, architecture, entrypoint, and format-specific fields (imphash for PE, PIE/NX/RELRO for ELF, code signature for MachO, etc.).

Inputs: path (required).

scan_anti_analysis_primitivesA

Scan a binary for anti-analysis primitives (defender side).

Walks the string table + the IAT + (best-effort) the section table and matches the content against the vendored data/anti-analysis-catalog.json. Returns category-only labels (anti_debug, anti_vm, anti_emulator, anti_sandbox, process_introspection, memory_integrity, code_integrity). Never names a specific commercial product.

The byte-sequence evidence (RDTSC = 0F 31, INT 2D = CD 2D, INT 3 = CC, CPUID = 0F A2) is not checked here — that requires a disasm pass via re-rizin.search_bytes. re-anti-analysis is the cross-tool orchestrator that does both the string-table pass and the disasm pass.

Args: path: file to scan max_per_category: per-category cap (default 100)

Returns::

{
  "path": "...",
  "matches": [{"primitive": "...", "category": "...",
               "evidence_kind": "...", "offset": N,
               "section": "..."}, ...],
  "by_category": {"anti_debug": 4, "anti_vm": 2, ...},
  "truncated": bool
}

Inputs: path (required), max_per_category.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.7/5.0

    Scored across 17 tools

    Disambiguation4/5

    Most tools have distinct purposes, but there is minor overlap between extract_strings and categorize_strings, as the latter is a superset retained for backward compatibility. Otherwise, each tool targets a specific analysis task.

    Naming Consistency5/5

    All tool names follow a consistent snake_case verb_noun pattern (e.g., classify_native_protection, get_sections), making them predictable and easy for an agent to understand.

    Tool Count5/5

    With 17 tools covering binary analysis across multiple formats (PE, ELF, MachO, DEX, OAT), the count is well-scoped for the domain without being excessive or sparse.

    Completeness4/5

    The tool set covers a wide range of binary analysis operations, including headers, sections, imports/exports, disassembly, strings, and protection classification. Minor gaps exist (e.g., no relocation or resource tools), but core workflows are supported.

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      A
      quality
      C
      maintenance
      A multi-backend MCP server that exposes binary analysis capabilities from IDA Pro and Ghidra, allowing LLMs to directly drive reverse-engineering tools via natural language.
      11
      177
      Apache 2.0
    • A
      license
      Not graded
      quality
      F
      maintenance
      MCP server for reverse engineering Windows executables and related binary formats, offering static analysis, Ghidra-assisted function recovery, plugin-driven tooling, and optional isolated Windows runtime execution.
      10 npm
      239
      MIT
    • A
      license
      Not graded
      quality
      D
      maintenance
      MCP server for analyzing Android APK, DEX, or JAR files via a headless jadx engine, enabling LLM agents to query decompiled code, symbols, call graphs, and more.
      2
      GPL 3.0