Command reference
disrobe <command> --help is authoritative for the binary you are running; the surface changes with optional build features. This page maps the public command surface: how commands are shaped, the command groups and integrations, then every command by ecosystem. Output paths and --emit support are command-specific; the global flags page covers the options parsed at the top level.
Recovery support varies by format, version and backend. The language guides list supported variants and limitations; chain reports identify unsupported constructs in your input.
Command shape
Ecosystem command families nest an action:
disrobe <pass> <action> <input> [--out <path>] [flags]
Other operations take their arguments directly, for example auto, scan, query, taint, extract, webview and report. Unambiguous prefixes resolve: disrobe dec ... works when only one subcommand starts with dec.
disrobe --help # every subcommand
disrobe <pass> --help # actions and flags for one pass, e.g. `disrobe py --help`
disrobe passes # direct recovery families plus auto-chain pass IDs
disrobe catalog [ecosystem] # supported families and recovery tiers
disrobe explain DR-CLI-0030 # look up any error code
The standard recovery loop:
disrobe auto input.bin --out recovered/ --capture-stages
disrobe context --out recovered/
Output formats
The CLI accepts these global output flags. A command can reject a format that does not fit its output contract:
| Flag | Output |
|---|---|
| (default) | Human-readable text |
--json | A single structured JSON document |
--ndjson | Newline-delimited JSON (streaming) |
--sarif | SARIF 2.1.0, for GitHub code scanning and other SARIF consumers |
disrobe scan firmware.bin --sarif > findings.sarif
detect also supports JSON, NDJSON and SARIF. Its structured output includes each matching detector, confidence score and signature markers. SARIF records use note severity and identify the input file; a format detection alone does not establish a vulnerability.
Command groups
| Group | Root commands | Detailed guide |
|---|---|---|
| Automatic recovery and provenance | auto, chain, context, status, report, diff, guard | chain, reading a result, reports |
| Static triage and reporting | scan, ioc, indicators, frisk, strings, behavior, identify, detect, catalog, capabilities, taint, vulnmatch | catalog, Frisk, forensics safety |
| Containers and webview assets | extract, webview | containers, webview |
| Python and packaging | py, pyarmor, pyinstaller, pyfreeze (experimental), nuitka | Python |
| JavaScript and WebAssembly | js, wasm | JavaScript, WebAssembly |
| Native analysis and recovery | native, macho, go, swift, as3, semdiff | native, decompile, unpack, Go, Swift, AS3 |
| JVM, .NET, and mobile | jvm, apk, dotnet, hermes, flutter, mobile | JVM and Android, .NET, mobile |
| Script and bytecode languages | lua, php, shell, ruby, beam, pickle | Lua, PHP, shell, Ruby, BEAM, pickle |
| Structured artifacts and query | envelope, verify, query, yara, annot, rename | envelopes, query |
| Project tooling and service | serve, plugin, init, config, passes, doctor, install, install-deps, self-update, completions, man, explain, bug-report | service, config, plugins, LLM sidecar |
| Public collection | prowl | forensics safety |
Public integrations
| Integration | Entry point | Detailed guide |
|---|---|---|
| Rust library | core types and the pass registry | Library APIs |
| Python bindings | import disrobe | Python bindings |
| MCP over stdio | disrobe-mcp or disrobe serve --mcp | MCP |
| HTTP, gRPC, and LSP | disrobe serve | service |
| GitHub Action | action.yml | GitHub Action |
| Editor plugins | VS Code, IDA, Ghidra, Binary Ninja | editor plugins |
| Browser playground | browser UI and compiled Wasm worker | playground |
| pre-commit hook | hook ID disrobe | pre-commit |
| LLM sidecar | disrobe init --ide | LLM sidecar |
Nested commands are listed by ecosystem below. For measurements and their limits, start with the evidence index.
Python
| Command | Purpose |
|---|---|
disrobe py decompile <pyc> | Decompile a .pyc to source. --backend native (the only supported value). --no-roundtrip skips the recompile-equivalence check. |
disrobe py disasm <pyc> | Per-instruction disassembly (3.8-3.15 + PyPy/MicroPython/Jython/IronPython/Brython). |
disrobe py deob <src> | Peel a source obfuscator. --cleanup runs a ruff-AST fold. |
disrobe py extract <archive> | Extract a wheel / sdist / egg / .whl / .zip / any archive. |
disrobe py sourcedefender <pye> | Decrypt a SourceDefender .pye envelope. |
disrobe pyarmor unpack <py> | Unpack PyArmor v6-v9-pro. --allow-dynamic permits the dynamic-hook fallback (trusted/sandboxed samples only). --dynamic-timeout <SECS>. --mode auto|standard|super. --target <PYVER>. --allow-bcc. --strict. --no-cextract / --cextract-only. --all-emits writes stubs for all 12 emit kinds. --cache <DIR>. |
disrobe pyinstaller extract <exe> | Extract a PyInstaller build (2.x-6.20+, AES decrypt). |
disrobe pyinstaller detect <exe> | Report cookie / Python version / TOC offsets without extracting. |
disrobe pyfreeze extract <exe> | Extract cx_Freeze / py2exe / shiv / pex / PyOxidizer (experimental, unvalidated) / Briefcase. |
disrobe pyfreeze detect <exe> | Identify the freezer without extracting. |
disrobe nuitka detect|extract|symbols|decompile|const <input> | Nuitka flavor detect, --onefile extract, symbol scan, constants decompile, single .const decode. |
JavaScript / WebAssembly
| Command | Purpose |
|---|---|
disrobe js deob <js> | Deobfuscate (obfuscator.io, JS-Confuser, Jscrambler, esoteric encoders). |
disrobe js unbundle <js> | Split a bundle into per-module sources; the unbundler routes 11 catalogued bundler families. |
disrobe js v8 <blob> | Inspect V8 .jsc / Node SEA / nexe / nw.js / Electron .asar. |
disrobe webview <binary> | Statically recover Electron ASAR or embedded Tauri/Wails HTML, JavaScript, CSS, and assets to --out <DIR>. The standard CLI also routes supported Electron and Tauri inputs through webview.carve in auto; Wails uses go.classify. See Webview desktop frontends. |
disrobe wasm decompile <wasm> | Lift to --target json|rust|ts|wat|c. |
disrobe wasm deob <wasm> | Reverse Wasm obfuscator families. |
disrobe wasm component <wasm> | Parse a Component Model envelope. |
disrobe wasm types <wasm> | Recover the GC type graph. |
disrobe wasm lift-gc <wasm> | Lift the recovered GC type graph to typed Rust + TypeScript struct / array source. |
JVM / Android / .NET
| Command | Purpose |
|---|---|
disrobe jvm decompile <class|jar|dex|apk> | Run the in-house classfile, jar, DEX, or APK recovery path, and an installed external decompiler only when --backend cfr|vineflower|procyon|jd|krakatau|jadx|dex2-jar names it. Every input emits in-house source by default. A named backend that is missing or does not fit the input format fails. For a standalone DEX, --format ghidra|ida|json also writes its class, method, and field identifiers through the shared symbol exporter. The script formats find each original owner, member name, and descriptor in the loaded DEX database before applying the replacement name. IDAPython class renames require IDA 9.4 or later; method and field renames use older DEX record APIs. |
disrobe jvm dex2-jar <dex> | Translate a standalone DEX to deterministic .class files and classes.jar with Disrobe's in-house translator. This command does not invoke d2j-dex2jar; disrobe jvm decompile <dex> --backend dex2-jar remains the separate external-backend route. |
disrobe jvm extract <jar|apk> | Extract container + dump classfile inventory. |
disrobe jvm backends | Report JVM/Android backends on PATH. |
disrobe jvm retrace | Retrace an obfuscated stack frame back to class/method/line through a ProGuard/R8 mapping.txt (--mapping, --class, --method, --line). |
disrobe jvm jni <class|jar|dex|apk|aab|aar|apks|oat> | Link declared native methods across the DEX/classfile <-> .so/.dll/.dylib JNI boundary: static Java_ symbol matching, RegisterNatives triple recovery, and C prototype emission. --native <LIB> supplies a native library, or a split .apk/.apks, for a bare class/jar/dex/oat (repeatable); a self-contained apk/aab/aar/apks carries its own. An .aar scans jni/<abi>/*.so and its nested classes.jar. A raw .oat file locates its single embedded dex through the OAT header; a multi-dex .oat is refused rather than guessed. --json for machine output. |
disrobe apk <apk> | Decode the binary AndroidManifest.xml, map resource ids to names, dump each signer certificate's SHA-256, and link the embedded DEX against its embedded native libraries (the same JNI surface jvm jni prints). --out <DIR> writes the decoded manifest and resource table to disk. |
disrobe dotnet decompile <dll|exe> | Run the in-house CIL decompiler, and an installed external decompiler only when --backend ilspy|dnspy|dnspy-ex|de4dot names it. A named backend that is not installed fails. --language csharp|fsharp|vbnet selects the in-house surface language. |
disrobe dotnet deobfuscate|peel <dll|exe> | Detect the .NET protector and peel it: decrypt resources, recover constants/strings, classify renamable identifiers, strip watermarks. --protector <name> forces one. |
disrobe dotnet analyze <dll> | PE/CLR metadata, protector detection, R2R + NativeAOT probe. |
disrobe dotnet native-aot <image> | Recover NativeAOT names, types, method boundaries and managed signatures. Takes a PE, ELF or Mach-O image, not a managed assembly. |
disrobe dotnet backends | Report .NET backends on PATH. |
Native
| Command | Purpose |
|---|---|
disrobe native decompile <bin> | In-tree x86-64 -> C/Rust decompile and AArch64, ARM32 and MIPS32 -> pseudo-C decompile, default (--backend native --format c|rust). The manifest names the architecture it routed to in its architecture field. Only AArch64 has a whole-program engine and an image-leaf engine; ARM32 and MIPS32 recover each function through the p-code lift alone, so their functions_whole_program and functions_image_leaf counts stay zero. AArch64 whole-program call resolution is limited to linked ELF inputs; relocatable objects fail before output on every p-code architecture. --format rust and the types.json sidecar are x86-64 only. C output is graded against real gcc/clang and x86-64 Rust output against rustc. On the AArch64 path a symbolic devirtualizer folds proven-dead conditional arms before structuring (on by default; --no-devirt disables it). --backend ghidra drives ghidra-headless instead: --emit source,disasm,ast,cfg,ir,manifest,sourcemap,symbols,strings,imports,signatures,report. Every function recovered through the p-code lifter carries a decode object in the JSON result, and the run as a whole carries the same shape as decode_coverage. Both give decoded_instructions, the machine instructions the decoder split the code into; modelled_instructions, how many of those the lifter gave semantics to; unmodelled_instructions, the remainder; matched_instructions with matched_percent, counting every instruction the decoder recognised, which is the sum of the supported, callother and unsupported statuses; semantic_percent, the share that is supported alone; instructions_emitting_callother with its percent, counting instructions whose lifted body contains a callother operation, which is a different measure from the callother status and can differ from it in both directions; by_status, one entry per decode status with an instruction count and a percent of decoded, always listing all seven statuses so one that never occurs reads as zero rather than being absent; and unlifted_mnemonics, a map from mnemonic to occurrence count. matched_percent and semantic_percent do not sum to one hundred, and counts_note restates why in the output itself. A high matched figure beside a low semantic figure means the decoder recognised the instructions but the recovered source describes less of the function than its length suggests. The whole-run block adds lowest_covered_functions, the functions whose semantic share falls below the whole-run figure, worst first and tied names in alphabetical order, capped at ten with lowest_covered_functions_omitted counting any the cap dropped, so a high whole-binary figure cannot hide one badly covered function. Every percent is a string carrying exactly two fractional digits, so the human and JSON output agree digit for digit and no float printer can reformat them. |
disrobe native symbols <bin> | Dump symbols, sections, segments, imports, and debug info. |
disrobe native identify <bin> | Fingerprint compiler / packer / protector / installer, each routed to its pass. |
disrobe native unpack [bin] | Detect + unpack the 12 Implemented-tier families (Donut, sRDI, UPX, ASPack, Petite, MPRESS, FSG, PECompact, Yoda's Crypter, NSPack, MEW, kkrunchy) via in-house decoders + x86 stub emulator. Input is optional; --list shows all supported packers (the full detect catalog is 27 packers and protectors; Yoda's Protector needs the original image for a diff-based carve, and the commercial protector tier is reported without static recovery). When the image matches a known layering, such as UPX repacked inside ASPack, the command says so before it unpacks, names the layers in order with the confidence of the match, and prints why that combination is used. The notice appears even when the unpack itself cannot finish, which is the case where knowing the image is double-packed matters most. After a successful unpack it names the layers still present, because one pass removes one layer; run the command again on the recovered image to take the next one. |
disrobe native devirt <bin> | Devirtualize the bytecode-VM tier: recover the handler table, lift to a re-executable IR + pseudo-code. |
disrobe native export <bin> | Unpack, recover symbols, and export a backend-ready bundle: a rebuilt loadable PE + a Ghidra post-script / IDAPython / JSON symbol map. --format ghidra|ida|json (default ghidra). |
disrobe native disasm <bin> | Per-function listing / --emit cfg-dot CFG / --emit json / --raw linear sweep (--syntax nasm|intel|att|masm). Accepts a .dr envelope. |
disrobe native callgraph <bin> | Whole-program call graph as Graphviz DOT. |
disrobe native patch <bin> | Rewrite bytes at a VA (or nop a span) and revalidate the image. |
disrobe native sigmaker <bin> | Wildcarded byte signature from a function, uniqueness-tested. |
disrobe native diff <a> <b> | Match functions across two builds by content and CFG fingerprint. Native images only; for other languages use disrobe semdiff. Text output lists at most 25 added, removed, and changed rows by default. --limit <N> sets that shared listing limit for text, JSON, NDJSON, and SARIF; --limit 0 preserves the exact totals while withholding every row. Machine output remains complete when --limit is omitted. The listing object records the effective limit plus the exact shown and withheld counts. |
disrobe native match <a> <b> | Name the counterpart of every function across two stripped binaries: anchor on shared data references, then on a control-flow fingerprint, then propagate along the call graph. Each pair carries the stage and the evidence that produced it, and a refusal is reported with its candidates. --out <FILE>, or -o, writes the report as JSON. --limit <N> bounds the text listing, 25 by default, and also bounds the report when you give it; --limit 0 prints the counts and withholds every row. --stage data-reference|control-flow|propagation|refused selects one stage; without it the listing shows every matched row from A and the ambiguous rows from B, and the report keeps every verdict. --function <ADDRESS> prints one function's correspondences from both sides with their full evidence; it accepts decimal or 0x hex, cannot be combined with --stage, ignores --limit, and fails with DR-NATIVE-0208 when neither input carries that address. Every report row names the side it came from, and the listing block records the selection in force with the number of rows shown and withheld. This command is reachable only as a subcommand and is deliberately absent from disrobe auto: it answers a pairwise question about two inputs, while auto drives a chain over one sample, so there is no input for a second binary to arrive through. Use disrobe semdiff when the two builds are of the same program and you want correspondence by what each function computes. |
disrobe native entropy <bin> | 4KB sliding-window Shannon entropy; ASCII heat-strip + byte histogram + packed-region runs. --format text|json|svg (default text), --svg <out> for a dark-theme entropy map with section overlays. |
disrobe native signatures <bin> | Crypto-constant fingerprints (AES, SHA, ChaCha20). --flirt <sig> to match a FLIRT DB. |
disrobe native fingerprint <bin> | Aggregate crypto-constant + FLIRT + string-xref sidecar at .disrobe/fingerprints/<stem>.json. --flirt <sig>. |
disrobe native sbom <bin> | Emit a CycloneDX 1.5 SBOM from embedded cargo-auditable metadata. Pass --format spdx --timestamp YYYY-MM-DDTHH:MM:SSZ for SPDX 2.3 JSON. Both formats use the same component discovery result. SPDX output records the application and Cargo packages, their checksums and package URLs, and CONTAINS relationships. Unknown supplier and licence fields are omitted. |
disrobe native graph <bin> | Import/export table as Graphviz DOT. |
disrobe native pdb <pdb> | Read build provenance out of a Windows PDB: DBI stream version, GUID and age, and for every module the compiler records the linker wrote, with language, target machine, frontend and backend version, and the security-check, hot-patch and profile-guided optimization flags. Also lists the tool path, working directory, source path, command line, object path and environment strings each module recorded, keeping the raw bytes beside the text so a non-UTF-8 value is still readable. Writes <out>/<stem>.pdb.json. |
disrobe query <bin|.dr> <q...> | Queryable IR: functions, calls-to <sym>, xrefs-to <sym>, string-decoders, complexity-over <n>, capability <network|crypto|filesystem|process>. Accepts a raw binary or a Disasm- or Mir-rung .dr envelope. |
disrobe capabilities <bin|.dr> | Rule engine over the IR, mapping behaviors to MITRE ATT&CK + MBC with per-match evidence. |
disrobe taint <input> | Track a value from source calls to sink calls across the normalized IR (native / wasm / JVM / Dalvik / CIL / ABC / Ruby / Lua / BEAM / .pyc / .dr). --source <SYM> / --sink <SYM> override the built-in source/sink sets (repeatable). With --cfg, --dfg or a pack that names them it also writes the control-flow and data-flow metadata categories; see metadata sidecar. |
disrobe semdiff <base> <other> | Pair the functions of two builds by what they compute, not by name. Lifts both inputs to the normalized IR, matches leaf functions on an exact structural signature, then on a symbolic summary, then propagates along the call graph. Reports each pair with the tier that produced it and each refusal with a typed reason: no-candidate, ambiguous, round-budget-exhausted, function-count-cap-exceeded, duplicate-address, source-language-mismatch. Accepts every input the lifters accept (native / wasm / JVM / Dalvik / CIL / ABC / Ruby / Lua / BEAM / .pyc / .dr), which is the difference from native diff and native match: those read native images only. Inputs that lift to different source languages are refused per function with source-language-mismatch. Every native image lifts under one source language whatever its architecture, so that per-function guard cannot separate them; two native images of different machine architectures are instead refused up front with DR-CLI-0874. Pass --lineage with two or more OTHER builds to track each base function across all of them at once: the report groups correspondences into families, one per base function, each carrying a verdict for every variant, and says how many families are present in every variant. Without --lineage exactly one OTHER is allowed and a second is refused with DR-CLI-0872 rather than ignored; --lineage accepts at most 32 variants and refuses more with DR-CLI-0873 rather than dropping any. --limit <N> bounds the rows listed per section, 40 by default; totals stay exact. Inputs over 256 MiB are refused with DR-CLI-0871. |
disrobe vulnmatch <input> | Match reachability-aware vulnerability rules against a PE, ELF, Mach-O, COFF, or Disasm/Mir-rung .dr envelope while preserving reachable, reachability-unknown, present, and confirmed states. Pass --openvex --author <IDENTITY> --timestamp YYYY-MM-DDTHH:MM:SSZ to emit OpenVEX 0.2.0 JSON. Reachable and confirmed findings map to affected; a proven unreachable finding maps to not_affected; all unresolved states map to under_investigation. The command never emits fixed because static reachability analysis does not prove remediation. |
Other languages
| Command | Purpose |
|---|---|
disrobe go recover|info <bin> | Go symbol recovery / build fingerprint. |
disrobe lua decompile|deobfuscate|detect <chunk> | Lua decompile / obfuscator peel / dialect detect. |
disrobe php decode|deobfuscate|extract <input> | Encoder decode / eval-chain peel / Phar extract. |
disrobe shell deob|detect <input> | PowerShell / Bash / Batch / VBA deobfuscate (Invoke-Obfuscation, Invoke-Stealth, Bashfuscator, ...) and dialect / family detect. |
disrobe ruby decompile|detect <input> | Ruby artifact analysis / flavor detection. |
disrobe beam parse|lift|disasm <beam> | BEAM chunk parse / Core Erlang lift / Code disasm. |
disrobe pickle disasm|decompile|safety|trace|polyglot|ml-detect <input> | Pickle static analysis suite. |
disrobe swift classdump|shield-undo|xor-decrypt <input> | Swift/ObjC class-dump, SwiftShield mapping parser, explicit-key XOR blob decode. |
disrobe macho dump|classdump|fat <input> | Mach-O dump including .ipa; raw thin/fat Mach-O class-dump and slice inspection. |
disrobe as3 disasm|tags <swf> | AS3 DoABC disasm / SWF tag list. |
disrobe hermes decompile|disasm|info <bundle> | Hermes JS-surface lift / disasm / header. |
disrobe flutter dump|decompile|kernel|disasm|map|inventory|inventory-standalone <input> | Flutter Dart AOT + kernel inspection. flutter dump --format ghidra|ida|json emits recovered function names through the shared symbol exporter. --engine-symbol-map <path> adds externally supplied engine names only after the map's GNU build ID and bounded addresses match the ELF input. inventory and inventory-standalone recover the full library/class/method/field declaration graph on a pinned Dart snapshot version. |
disrobe mobile detect|extract|hermes|flutter|recon <input> | Mobile runtime pipeline. |
Chain, envelope, and forensics
| Command | Purpose |
|---|---|
disrobe extract <input> | Carve and extract a container or firmware image: detect every known format at any offset, recurse into nested archives, split unknown and padding regions, and report per-chunk entropy. --out <dir> names the directory for carved members, --recursive re-scans every extracted file up to --max-depth, and --luks1-raw-volume-key-file opens LUKS1 volumes. |
disrobe detect <input> | Run every obfuscator/packer catalog detector against a file and report each hit (pass, obfuscator, confidence, markers). |
disrobe identify <input> | Fingerprint the compiler / linker / packer / protector / installer of a PE / ELF / Mach-O with structural evidence and the pass that handles each (top-level shortcut for native identify; alias die). --coverage adds a byte-accounting map of the file. |
disrobe identify <input> --coverage | Account for every byte of a PE / ELF / Mach-O against the structures its format declares. Reports claimed_bytes (bytes a declared structure covers), slack_bytes (alignment padding between structures), unclaimed_bytes (bytes no structure covers, which is where an appended overlay shows up), truncated_bytes (bytes a structure declares past the end of the file), and coverage_ratio, which is claimed_bytes over the file length. complete is false when any byte is unclaimed or missing. The regions list tiles the whole file, so the region lengths sum to the file length. overlaps names each pair of structures that claim the same bytes. unbacked names a structure that declares a size the file does not store, and truncated names one whose declared end is past the end of the file. |
disrobe catalog [ecosystem] | List the supported obfuscator, packer, protector, freezer, and bundler registry by ecosystem. The default full build's live binary reports 169 families across 15 ecosystems. Builds that include the chain feature report the registry compiled into that binary. Filter with python, js, jvm, dotnet, native, go, wasm, ruby, lua, php, beam, as3, mobile, swift, or shell. --json emits { family_count, ecosystem_count, ecosystems[] }. |
disrobe auto <input> | Auto-detect + chain. --max-depth <N> (default 8), --capture-stages, --emit recovery, --dry-run, --redact, --timings. A run writes chain.json, recovery.json, anti-analysis.json, and report.json, the citable forensic summary that disrobe report <out-dir> renders; none of them records a duration, the worker count, or a clock. --timings also writes run.json with the start and end clocks, the worker count, and each node's duration. For a standalone DEX root, --format ghidra|ida|json adds exports/dalvik/symbols.ghidra.java, symbols.ida.py, or symbols.json without counting that presentation file as a recovered chain artifact. The request fails if the successful Dalvik node belongs to a nested container instead of the original input. --dry-run creates no export. --redact scrubs detected secrets from machine output and report files without changing recovered artifacts. A directory input is batch-processed recursively (--include <GLOB>, --exclude <GLOB>, --batch-max-depth <N>, --jobs <N>) into an aggregate manifest.json, and each per-file out directory holds its own report.json. |
disrobe chain <input> | Explicit pipeline. --chain 'auto:8' or 'pyarmor.unpack,py.decompile', with --capture-stages and --timings available. --chain-pin <pass-prefix> requires --chain auto[:N] and runs that prefix before automatic selection; it does not pin package versions. |
disrobe diff <left> <right> | Structurally diff two chain.json documents (passes, stage BLAKE3 hashes, sizes, verdicts). |
disrobe guard verify <subject> --reference <ref> | Verify a subject chain.json's per-stage output hashes against a committed reference. |
disrobe guard check <path> [--root <subtree>...] | Deny writes to ground-truth stage paths (out/**/stages, out/**/final, .disrobe-stage-lock). --root adds extra protected subtrees (repeatable). |
disrobe envelope create|inspect|verify|diff|migrate-check <dr> | .dr envelope operations; migrate-check takes source and target envelopes. |
disrobe verify <dr> | Alias for disrobe envelope verify. |
disrobe scan <path> | Scan one file for secret values. --redact replaces detected values in text, JSON, NDJSON, and SARIF output. Raw values remain the default. |
disrobe frisk <path> [--format text|json|sarif] | Scan files, directories, APKs, and recovered source for secrets, endpoints, buckets, manifest exposure, and IOCs. Rule packs use --pattern <FILE>, suppressions use --suppress <SUBSTR>, and baselines use --emit-baseline / --baseline <FILE>. --redact replaces detected secret values after suppression and baseline filtering. |
disrobe report <target> | Render text, JSON, Markdown, HTML, or SARIF from a chain or batch result. --redact scrubs detected secrets throughout the rendered document. |
disrobe prowl [target...] | Harvest URLs and IOCs from public archives and threat-intel feeds. Inputs can come from arguments, --targets-file, --stdin, or --recon-input. Sources are wayback, commoncrawl, otx, urlscan, crtsh, urlhaus, threatfox, and virustotal (vt alias). Filters include --subs, --blacklist, --from, --to, --mc, --fc, --mt, --ft, --ioc, --fp, and --no-iocs. Network controls include --proxy, --timeout, --concurrency, --per-host-rps, --max-pages, --max-urls, --max-iocs, and --retries. Keys resolve from --api-key provider=key, provider env vars, a permissions-checked TOML file, or disrobe prowl keyring set|get|rm|list <provider>. |
disrobe ioc <path> [--format text|json|sarif] [--defang] | Extract indicators of compromise (URLs, IPs, domains, emails, paths, registry keys, wallets, crypto constants); decodes one base64/hex layer. |
disrobe indicators <json...> [--targets-only] [--format text|json] | Merge frisk, ioc, and prowl JSON artifacts into disrobe.indicators/v0, deduplicate by class and value, retain source provenance, or print only network targets for prowl --targets-file. |
disrobe strings <path> [--min-len N] [--no-decode] | Cross-format string extraction: ASCII + UTF-16LE, with single-byte XOR / base64 / ROT-n / stack-string deobfuscation. |
disrobe behavior <path> | Behavior / capability summary across 7 categories, tagged with MITRE ATT&CK technique ids. --effects adds a per-effect instruction census. |
disrobe hermes disasm <input> --function <index-or-name> | Print the instructions of one function by its zero-based index or exact name, decoded through the opcode table for the bundle's own bytecode version. Add --json for the same instruction list as a structured document. Duplicate names require an index. Without --function, the command keeps writing the whole-bundle summary document. An index past the end is refused with the number of functions the bundle declares. |
disrobe behavior <path> --effects | Lift the input to the intermediate representation and report, for each hard effect, how many instructions carry it. Covers memory reads and writes, stack and register and flag writes, syscalls, import calls, indirect calls and jumps, returns, exception raise and catch, atomic read-modify-write, fences, and privileged instructions. Each count is paired with the evidence that assigned it: encoding when the instruction itself says so, resolved-import or resolved-syscall when a resolved target says so, and unknown when nothing did. instructions and functions give the denominators, effect_free counts instructions with no hard effect, and unmodelled counts instructions the effect model does not cover, so a low unmodelled is what makes the other counts meaningful. Accepts any input the intermediate representation accepts, which today is WebAssembly, JVM class files, Dalvik, .NET, ActionScript, Ruby, Lua, BEAM and Python bytecode. An input that does not lift is refused with an error rather than reported as having no effects. |
disrobe yara parse <path> | Parse a YARA ruleset into a typed AST (read-only, no matching). |
disrobe yara generate <input> [--name N] [--sha256 H] [--date D] | Generate a candidate YARA rule from an artifact; output round-trips through the parser. |
disrobe status | Summarize ./out/: per-stage counts, sizes, manifests. |
disrobe context --out <dir> | Summarize a recovery report (status, confidence, verdict, provenance), and the run's run.json timings when the directory holds one. |
disrobe context --out <dir> --fail-on <threshold> | Grade the worst chain verdict under the directory and exit non-zero when it reaches never, incomplete, failed or any. |
disrobe report <dir-or-input> [--format text|json|markdown|html|sarif] | Consolidate a completed run (or raw input) into a forensic summary: identity, topology, per-stage verdicts/scores, artifact inventory, the layers that stopped short with the input each one lacks, a cited byte range and blake3 digest for every artifact, and the steps to re-check them. --format html emits a self-contained, offline, dark-theme report (inline SVG bars, IOC + ATT&CK tables, XSS-escaped). --format sarif emits the same content as a SARIF 2.1.0 log that validates against the published schema: run.artifacts carries each digest, every result region cites a start offset plus a length in the artifact it indexes, and run.properties carries the disrobe document, a STIX 2.1 bundle when SOURCE_DATE_EPOCH is set, MAEC 5.0 behavior objects, the capability report, and the aggregated indicators. Every format, sarif included, is byte-identical across runs over one target: the render carries no clock unless SOURCE_DATE_EPOCH is set, and then every timestamp holds that date. |
Workspace and meta
| Command | Purpose |
|---|---|
disrobe init [--ide <flavor>] [--force] | Scaffold a .disrobe/ workspace and optional editor settings. It refuses, naming the files and writing nothing, when any file it would write already exists; --force overwrites them. Always: .disrobe/AGENTS.md, .disrobe/manifest.json. --ide claude adds .claude/settings.json, .claude/commands/disrobe-{verify,status,rename,diff}.md, .disrobe/skills/<pack>/SKILL.md for verify-decompilation, recover-symbol-names, reconstruct-imports, confidence-audit, escalate-to-dynamic, diff-against-pypi and patch-and-roundtrip, and .cursorrules, .windsurfrules and CLAUDE.md linked to .disrobe/AGENTS.md. --ide cursor, windsurf and aider add .cursorrules, .windsurfrules or .aider.conf.yml. |
disrobe config [show] | Print the resolved .disrobe.toml config (honors --json). See project configuration. |
disrobe config init [--out <path>] [--force] | Write a documented .disrobe.toml template. |
disrobe annot refresh|regenerate | Rebuild a symbol annotation file. |
disrobe rename <old> <new> [--note] | Record an append-only rename. |
disrobe passes | Print direct recovery-family summaries followed by the pass IDs reachable from disrobe auto in this build. |
disrobe plugin run <component> --trusted-key <pubkey> --out <file> [--input <file>] [--fuel N] [--wall-deadline-ms MS] [--memory-cap-bytes N] [--format text|json] | Verify and run a signed WebAssembly component plugin under the disrobe-plugin-host sandbox (fuel, wall-clock, and memory caps; deny-all imports). Reads input from stdin when --input is omitted. CLI-only: a plugin names an explicit local path an operator supplies, not a chain pass reachable from disrobe auto. |
disrobe plugin verify <component> --trusted-key <pubkey> [--format text|json] | Verify a signed WebAssembly component plugin's signature and capability manifest without running it. |
disrobe plugin list <dir> [--trusted-key <pubkey>] [--format text|json] | List plugin bundles (a <name>.wasm component beside its <name>.wasm.minisig signature and <name>.toml manifest) in a directory; verifies each bundle when --trusted-key is given. |
disrobe explain <code> | Look up a DR-* error code and print its description and common fixes. |
disrobe doctor [--auto-install] [-y] | Probe 46 to 51 optional external tools depending on the platform; report installed, missing, or stale. --auto-install installs every missing tool with a known install action and records every other missing tool as a skip with a typed reason (commercial-or-license-gated, ships-with-another-tool, platform-exclusive, preinstalled-by-the-operating-system, no-manager-models-its-install-path, or no-package-on-any-manager), in both text and --json output. |
disrobe install <tool> [--list] [-y] [--dry-run] | Install one optional tool via the native package manager. |
disrobe install-deps [<dep>] [--all] [--dry-run] | Install heavyweight deps (Ghidra) from upstream releases. |
disrobe serve [--bind <ADDR>] [--stdio|--mcp|--grpc] | Run the daemon. See the daemon. |
disrobe completions <shell> [--install] [--rc-file <PATH>] | Generate shell completions (bash, zsh, fish, PowerShell, elvish). |
disrobe man [--out <dir>] | Generate man pages (one .1 per subcommand). |
disrobe bug-report [--out <PATH|->] | Collect environment, manifests, and tooling versions into a markdown bug report. |
disrobe self-update [--check-only] [--dry-run] | Print update guidance: download the release archive from GitHub Releases (no network by default). |
Run the examples
Watch the chaptered CLI walkthrough and read its command transcript. The recording shows native unpacking, indicator extraction, automatic recovery, Lua, WebAssembly, and recovered source.
The feature capture records twelve commands and their output. It extracts three known indicators with their byte offsets, round-trips two ZIP members, recovers all 73,160 original code bytes from a UPX-packed greeting, decodes an APK manifest, compares a recovered Lua greeting with its baseline, and verifies an envelope before and after a one-byte payload change.
From the repository root, reproduce it with a full CLI build, Python 3.14 and Lua 5.1:
node docs/demo/capture-features.mjs --binary /path/to/disrobe --python /path/to/python --lua /path/to/lua
The Wasm quickstart, Python project example, and service examples cover automatic recovery, project briefs and the MCP, HTTP, gRPC and LSP interfaces. Each record names its inputs and binary so results can be compared across builds.
The public-collection example retrieves four archived example.org URLs from the Common Crawl index. It queries one archive, caps output at ten URLs, and makes no requests to the archived pages.