# Reverse Engineering — full corpus # LLM Wiki An open-source template for building LLM-powered knowledge bases, following [Andrej Karpathy's "LLM Wiki" pattern](https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f). You provide raw sources. The LLM reads them, writes structured wiki pages, cross-links everything, and maintains it over time. You never edit the wiki directly — you curate sources and ask questions. ## How It Works The system has three layers: ``` raw/ Sources you collect (articles, transcripts, notes, PDFs) wiki/ LLM-written & maintained pages (summaries, concepts, entities, syntheses) CLAUDE.md Schema that tells the LLM how to structure everything ``` Three operations drive the workflow: | Operation | Trigger | What happens | |-----------|---------|--------------| | **Ingest** | "ingest raw/my-source.txt" | LLM reads the source, creates a summary page, creates/updates concept and entity pages, adds cross-links, updates the index and log | | **Query** | Ask any question | LLM searches the wiki, synthesizes an answer with citations, optionally creates a synthesis page for novel insights | | **Lint** | "lint" or "health check" | LLM audits all pages for orphans, contradictions, missing links, incomplete sections, and low-confidence claims — fixes what it can, reports the rest | ## Quick Start 1. **Clone this repo** ```bash git clone https://github.com/YOUR_USERNAME/llm-wiki.git my-knowledge-base cd my-knowledge-base ``` 2. **Customize CLAUDE.md** for your domain - Update the Purpose section with your topic - Replace the placeholder tagging taxonomy with your own categories - Adjust confidence level descriptions if needed - Everything else (workflows, page formats, linking rules) works as-is 3. **Drop sources into `raw/`** - Text files, transcripts, articles, notes — any plain text - These are immutable once added; the LLM never modifies them 4. **Tell the LLM to ingest** ``` ingest raw/my-first-source.txt ``` The LLM will create summary pages, concept pages, entity pages, cross-links, and update the index. 5. **Ask questions** ``` What are the key differences between X and Y? ``` The LLM answers from the wiki, citing specific pages. 6. **Run health checks** ``` lint ``` The LLM audits the wiki and fixes issues. ## Directory Structure ``` . ├── CLAUDE.md # Schema — the LLM's instructions ├── raw/ # Your source documents (immutable) └── wiki/ ├── index.md # Master catalog of all pages ├── log.md # Append-only activity log ├── dashboard.md # Dataview dashboard (Obsidian) ├── analytics.md # Charts View analytics (Obsidian) ├── flashcards.md # Spaced repetition cards ├── summaries/ # One page per source document ├── concepts/ # Concept and framework pages ├── entities/ # People, tools, organizations, etc. ├── syntheses/ # Cross-cutting analyses and comparisons ├── journal/ # Research/session journal entries │ └── template.md # Journal entry template └── presentations/ # Marp slide decks ``` ## Enhancements This template includes several extras beyond the core wiki pattern: ### Dataview Dashboard (`wiki/dashboard.md`) Live queries that surface low-confidence pages, recent updates, concepts by tag, and pages with the most sources. Requires the [Dataview](https://github.com/blacksmithgu/obsidian-dataview) Obsidian plugin. ### Charts View Analytics (`wiki/analytics.md`) Visual analytics with pie charts, bar charts, and word clouds. Requires the [Charts View](https://github.com/caronchen/obsidian-chartsview-plugin) Obsidian plugin. ### Mermaid Diagrams Use Mermaid code blocks in any wiki page to create flowcharts, sequence diagrams, or concept maps. Native support in Obsidian and GitHub. ### Marp Slides (`wiki/presentations/`) Create slide decks from markdown using [Marp](https://marp.app/). Drop presentation files in this directory. ### Research Journal (`wiki/journal/`) Track your research sessions, experiments, or applied work with the included template. The LLM can reference journal entries when answering queries. ### Spaced Repetition (`wiki/flashcards.md`) Flashcards in the format used by the [Spaced Repetition](https://github.com/st3v3nmw/obsidian-spaced-repetition) Obsidian plugin. Ask the LLM to generate flashcards from any wiki page. ### MCP Server This repo works with Claude Code's MCP server capabilities. Point an MCP-compatible client at this repo and the LLM can read/write the wiki programmatically. ## Customizing for Your Domain The schema in `CLAUDE.md` is domain-agnostic. To adapt it: 1. **Purpose** — Describe your knowledge domain in one paragraph 2. **Tagging taxonomy** — Replace placeholder categories with your own (e.g., for a cooking KB: `cuisine`, `technique`, `ingredient`, `equipment`) 3. **Confidence levels** — Adjust the descriptions to match your domain's evidence standards 4. **Entity types** — Update the entity page description to match what entities mean in your domain (people, tools, companies, etc.) 5. **Journal template** — Customize `wiki/journal/template.md` for your workflow Everything else — page format, linking conventions, workflows, rules — is universal and works across domains. ## Example Domains This template works for any knowledge-intensive topic: - **Research notes** — papers, experiments, methodologies - **Book analysis** — themes, characters, author techniques - **Competitive analysis** — companies, products, market trends - **Course notes** — lectures, readings, key concepts - **Personal development** — frameworks, habits, book summaries - **Technical documentation** — APIs, architectures, design patterns - **Hobby deep-dives** — any subject you want to master ## License MIT --- title: "Reverse Engineering KB — Master Index" type: index updated: 2026-10-16 rea_version: "6.5.0" ghidra_version: "12.1.4" ida_version: "9.4sp1" rizin_version: "0.9.1" cutter_version: "2.5.0" frida_version: "17.24.0" jadx_version: "1.5.6" apktool_version: "3.0.3" capa_version: "10.0.0" yara_x_version: "1.21.0" confidence: high sources: ["raw/github_release-rea-agents-v6-5-0.md", "raw/github_release-ghidra-12-1-4.md", "raw/github_release-rizin-v0-9-1.md", "raw/github_release-cutter-v2-5-0.md", "raw/github_release-frida-17-24-0.md", "raw/github_release-1-5-6.md", "raw/github_release-v3-0-3.md", "raw/github_release-v10-0-0.md", "raw/github_release-v1-21-0.md", "raw/web_community-9-4sp1-md.md"] --- # Reverse Engineering KB — Master Index **Domain:** software reverse engineering for legitimate analysis: triaging unknown binaries and suspicious samples, static analysis and decompilation, debugging and instrumentation, platform-specific targets, network captures, and driving RE tools from AI agents over MCP. Anchored on REA (`rea-agents` 6.5.0) and each tool's own documentation. **Scope:** interoperability, security and vulnerability research, malware analysis and defence, CTF/education, and software you are authorized to examine. No DRM/licence cracking, anti-cheat bypass, piracy, malware development or evasion. See [[concepts/legal-and-ethics]]. **Pages:** 24 (7 concepts · 6 entities · 11 syntheses) Start at [[syntheses/overview]] if you are new; it maps "I have X" to the right page. ## Concepts - [[concepts/legal-and-ethics]] — authorized-use boundaries, 17 USC 1201(f)/(j), UK CDPA s50B, what this wiki will not cover - [[concepts/executable-formats]] — ELF, PE/COFF, Mach-O (fat binaries, app bundles) and DEX at a working level - [[concepts/decompilation-concepts]] — how decompilers recover code, why output goes wrong, and how annotations fix it - [[concepts/dotnet-and-nativeaot]] — IL decompilation with ILSpy/dnSpyEx, and why NativeAOT needs Ghidra plus ghidra-nativeaot - [[concepts/go-rust-and-dart-binaries]] — Go pclntab and ABI (GoReSym), Rust v0 mangling, Flutter/Dart AOT (blutter) - [[concepts/webassembly]] — module structure, WABT round-trips, decompiling wasm - [[concepts/evm-bytecode]] — selectors and ABI recovery with EVMole, opcodes, Solidity metadata, JEB's EVM decompiler ## Entities - [[entities/ghidra]] — Ghidra 12.1.4: projects, import, auto-analysis, decompiler, data types, version tracking - [[entities/ida-pro]] — IDA 9.4sp1: disassembler, Hex-Rays decompiler, FLIRT, Lumina, IDAPython, idalib, official MCP - [[entities/rizin-and-cutter]] — Rizin 0.9.1 CLI model and rz-* tools, Cutter 2.5.0 GUI, rz-pipe scripting - [[entities/gdb-and-pwndbg]] — GDB for understanding behaviour, plus pwndbg's inspection views - [[entities/frida]] — Frida 17 modes, CLI tools, Gadget, Android and iOS setup for apps you may analyze - [[entities/rea]] — REA (`rea-agents` 6.5.0): setup, providers it drives, evidence model, platform limits ## Syntheses - [[syntheses/overview]] — what reverse engineering covers, the intent map, and the tool landscape - [[syntheses/triage-an-unknown-binary]] — the first 15 minutes: format, architecture, packing, strings, symbols, next tool - [[syntheses/malware-triage]] — safe handling, then DIE → FLOSS → capa → YARA/YARA-X, then hand-off - [[syntheses/choosing-a-disassembler]] — Ghidra vs IDA vs JEB vs Hopper vs Rizin/Cutter vs objdump - [[syntheses/dynamic-analysis-workflow]] — debugger vs instrumentation vs tracing vs record/replay, sandboxing, evidence - [[syntheses/android-apk-analysis]] — APK anatomy, JADX, apktool decode, ADB acquisition, Frida and traffic inspection on a test device - [[syntheses/javascript-and-electron-apps]] — ASAR extraction, source maps, wakaru, Electron fuses, CDP observation - [[syntheses/firmware-analysis]] — binwalk v3 and unblob extraction, entropy, loading raw images in Ghidra - [[syntheses/network-captures-and-protocols]] — Wireshark/tshark filters, TLS key logging, mitmproxy modes, HTTP/3 - [[syntheses/re-with-ai-agents-mcp]] — REA vs IDA MCP vs JEB MCP vs GhidraMCP and others: evidence, limits, safety - [[syntheses/troubleshooting]] — symptom-first fixes for Ghidra, IDA, Frida, JADX, apktool, capa, YARA-X and REA ## XL Edition (Pro) The gated XL layer adds 8 curated reference pages: Ghidra scripting, headless analysis, debugger and BSim; Ghidra processor and p-code notes; IDA scripting and idalib; Rizin and GDB/pwndbg command references; the Frida JavaScript API; the Android toolchain (jadx, apktool, adb, dex); and the full REA MCP/CLI/provider reference. --- title: "Decompilation Concepts" type: concept tags: [decompiler, p-code, microcode, ghidra, ida-pro, hex-rays, type-recovery, ssa, static-analysis] created: 2026-10-16 updated: 2026-10-16 confidence: high sources: ["raw/github_doc-ghidra-features-decompiler-src-main-help-help-topics-decompi-3.md", "raw/github_doc-ghidra-features-decompiler-src-main-help-help-topics-decompi-2.md", "raw/github_doc-ghidra-features-decompiler-src-main-help-help-topics-decompi.md", "raw/github_doc-ghidra-features-decompiler-src-main-help-help-topics-decompi-4.md", "raw/web_community-introduction-to-decompilation-vs-disassembly-md.md", "raw/web_community-tricks-md.md", "raw/web_community-failures-md.md", "raw/web_community-get-started-md.md", "raw/web_community-ctree-view-md.md", "raw/web_community-microcode-view-md.md", "raw/github_doc-ghidradocs-ghidraclass-beginner-introduction-to-ghidra-stude.md"] --- # Decompilation Concepts ## Definition A decompiler turns the machine code of one function into C-like pseudocode. A disassembler maps each instruction to a mnemonic; a decompiler goes further, running data-flow analysis across the whole function so it can rebuild expressions, variables, parameters and structured control flow (`if`, `switch`, loops). Hex-Rays puts the practical gain at output five to ten times shorter than the equivalent disassembly. The pseudocode is meant to be read, not recompiled: the Hex-Rays documentation says outright that it is deliberately not 100% compilable. Two decompilers anchor this wiki: Ghidra's Decompiler (see [[entities/ghidra]]) and the Hex-Rays decompiler in IDA (see [[entities/ida-pro]]). They differ in detail but share one model. Lift the instructions into an intermediate representation (IR), analyse that IR, then print it as C. Most bad output comes from wrong *inputs* to that pipeline, such as prototypes, function boundaries, memory attributes and types, so the fix is usually an annotation rather than a different tool. ## How It Works ### 1. Lifting to an IR - **Ghidra: p-code.** Every instruction is translated into p-code, Ghidra's IR, and all later analysis runs on p-code. The translation comes from the processor's SLEIGH specification (`*.slaspec`/`*.sinc` source, compiled to `*.sla`), chosen by the program's Language ID. A Language ID has five colon-separated fields (processor, endianness, address size, variant, compiler), for example `x86:LE:32:default:windows` or `MIPS:BE:32:micro:default`. All state (RAM, registers, temporaries, constants) lives in named *address spaces* such as `ram`, `register`, `unique`, `stack` and `constant`. A value is a *varnode*, the triple `(address space, offset, size)`. - **IDA: microcode.** Hex-Rays lifts to microcode, which moves through a series of *maturity levels* before it becomes a C-level tree, the **ctree**. You can watch this happen. The Microcode view (`Ctrl+Shift+F8`) steps through the maturity levels with `>` and `<`, and the newer CTree view (`Ctrl+F6`, which Hex-Rays says is still settling and may change) shows the final syntax tree node by node. The ctree only exists once local variables have been allocated (maturity `MMAT_LVARS` or higher). Processor behaviour that the model doesn't capture shows up as an opaque operation. In Ghidra that is a `CALLOTHER`, which the decompiler treats as a black box and prints as a named function call. Ghidra lets a *callother-fixup* supply the missing semantics. ### 2. Control flow and the function body Decompilation starts at the function's **entry point** and traces flow through jumps and fall-throughs until it reaches return-like instructions. It does not follow calls; a call is assumed to fall through. Ghidra re-derives the body from the entry point every time and ignores the stored "formal" body. That is why a body created by hand from a selection can make the Decompiler window jump to an unexpected function. ### 3. Data flow (SSA), variables and merging Ghidra converts p-code into Static Single Assignment form, where every write creates a new varnode with its own scope. A *HighVariable* is a set of non-overlapping varnodes that together form one source-level variable. Deciding which varnodes to group is called *merging*. Merging is forced when storage meets across control-flow joins and speculative otherwise. Speculative merges only happen between varnodes of the same data type. Data flow is also what lets a decompiler collapse a 20–30 instruction signed-division idiom back into `x = y / 2;` and find a call's arguments even when they were set up far from the call. ### 4. Parameters and calling conventions A **prototype model** (Ghidra's name for a calling convention such as `__stdcall` or `__thiscall`) says which registers and stack slots can hold parameters and return values. It also lists *unaffected* (callee-saved) locations and *killed-by-call* locations. Without explicit annotations, the decompiler uses the model to guess the prototype. Hidden *auto-parameters* such as `this` and `__return_storage_ptr__` are shown explicitly because analysts need to see them. ### 5. Type propagation Types flow from annotated sources (parameters, globals, library signatures) through the data flow to unlabeled variables and constants. Ghidra's decompiler does **not** invent structures, unions, typedefs or bitfields on its own. It only propagates ones you or an importer applied, though *Auto Create Structure* builds a structure from how a pointer is used. In IDA, the Hex-Rays getting-started primer shows the same thing. A function full of casts cleans up as soon as you declare a struct in Local Types (`Shift-F1`) and set the argument's type with `Y`. ### 6. Structuring and printing Finally, the control-flow graph is reduced to `if`/`while`/`do`/`switch`. Edges that can't be structured become `goto`. IDA's Microcode view has a *Structural analysis* action that draws each reduction step. ## Key Parameters These are the inputs that change pseudocode most. Each is an annotation you can set. | Lever | What it tells the decompiler | Ghidra | IDA | |---|---|---|---| | Function prototype | Parameter and return types and storage | Edit signature. Any Signature Source other than `DEFAULT` (`IMPORTED`, `USER_DEFINED`, `ANALYSIS`, `AI`) forces the whole prototype | `Y` on the function (Edit, Functions, Set function type) | | No-return | Calls to this function never come back | Function "no return" property | Mark the callee non-returning | | In-line / call-fixup | Fold a helper's effect into callers | In-line property, or a named call-fixup from the compiler spec | n/a in these sources | | Read-only memory | Values are constants and can be folded | Mutability `Constant`, or the read-only block flag with "Respect read-only flags" on | Segment without write permission, segment type CODE, or names such as `.rodata`/`.got` | | Volatile memory | Every access matters | Mutability `Volatile` | Segment named `IO`, `IOPORTS`, `PORTS` or `VOLATILE` (case-insensitive) | | Register values | A register holds a known constant | Set Register Values. Only applies if the range covers the entry point | n/a in these sources | | Flow overrides | Reinterpret a branch as a call, return or jump | `BRANCH`, `CALL`, `CALL_RETURN`, `RETURN` overrides | n/a in these sources | | Indirect-call target | Prototype at a computed call site | Function-pointer types | Set operand type, structure offset (`T`), or Change the callee address (`Alt-F11`, x86 only) | The Ghidra Decompiler options that most often matter are listed below. Several of them silently change what you see. | Option | Effect | |---|---| | Decompiler Timeout (seconds) | Per-function limit. Not enforced in the Decompiler window; applies to the switch analyzer, `analyzeHeadless`, scripts and other plug-ins | | Max Instructions per Function | Stops runaway tracing into zero-filled or data regions | | Max Entries per Jumptable | Sanity cap on recovered switch tables | | Eliminate unreachable code | Turn it off to see branches pruned by constant propagation (shown as `if (false)`) | | Respect read-only flags | Pulls read-only initial values into data flow as constants | | Prototype Evaluation | Calling convention assumed for functions marked `unknown` | ## When To Use - **Read pseudocode first** for logic: what a function returns, which strings and APIs it touches, how arguments flow. Decompilers answer "where is this set?" and "is this used?" at once. - **Drop to disassembly or IR** when the pseudocode contradicts itself, a value seems to vanish, or you need exact instruction semantics (anti-analysis tricks, unusual calling conventions, timing). IDA's Microcode view and Ghidra's p-code are the ground truth that the C is printed from. - **Iterate.** Analysis is a loop: fix a prototype or type, re-decompile, repeat. Both tools re-decompile automatically when annotations change. ## Risks & Pitfalls **Why pseudocode is wrong, and the usual fix:** | Symptom | Likely cause | Fix | |---|---|---| | Missing or garbage arguments, "call analysis failed" (IDA) | Wrong callee prototype, wrong stack pointer, or an unknown variadic count | Set callee types (`Y`); check the stack-pointer column (Options, General, Stack pointer) and correct it with `Alt-K`. One wrong `__stdcall` arity can break a neighbouring call | | Code after a call disappears, or the function runs into the next one | Callee not marked no-return | Mark it no-return (IDA suggests "noret"); in Ghidra run `FixupNoReturnFunction.java` | | `switch` shown as an indirect jump, "switch analysis failed" | Jump-table idiom not recognised | IDA: Edit, Other, Specify switch idiom. Ghidra: Decompiler Switch Analysis one-shot, Max Entries per Jumptable | | Polling loop decompiles to `while (1);` | Device memory assumed stable | Mark the region volatile | | `*off_XXXX` where a symbol was expected | Pointer table not known to be constant | Mark it read-only/constant | | "positive sp value has been found" | Stack pointer tracking went wrong | Fix stack-pointer values (`Alt-K`) | | Variables in red (IDA) | Local variable allocation failed, so variables overlap | Check prototypes and stack variables; reset with Edit, Other, Reset decompiler information | | `CONCAT31`, `SUB41`, `ZEXT14`, `CARRY4` (Ghidra) | Partial-register or carry operations with no C equivalent | Often a sign that a variable has the wrong size; retype it. The digits are operand sizes in bytes (`SUB41`: 4-byte input, 1-byte output; `CONCAT31`: 3- and 1-byte inputs; `CARRY4`: 4-byte inputs) | | `x._8_2_` style field tokens | An access spans several fields or elements | Correct the structure or array layout | | Worse output after you retype something | Annotations are *forcing*: a wrong type overrides analysis | Use `undefined1/2/4/8` when only the size is known, so propagation can fill in the type | More cautions: - **Annotations override analysis.** In Ghidra a typed variable annotation is fixed and won't be changed by propagation. A forcing Signature Source fixes the exact number of parameters, and with no parameters it forces `void`. Retyping is powerful and also the most common way to make output worse. - **Unreachable-block pruning hides comments.** Comments attached to blocks the decompiler drops are not shown. - **Context registers** (for example the ARM/Thumb T bit) change how bytes decode. Changing one after disassembly needs a clear and re-disassemble to take effect. - **Hex-Rays limits:** no 16-bit functions; functions whose unaliased stack exceeds 1 MB are refused; Hex-Rays' troubleshooting page says IDA64 decompiles only 64-bit functions and to use IDA32 for 32-bit (IDA 9.x ships a single unified binary, so check this against your install); `sizeof(int)` and `sizeof(enum)` must both be 4 in the compiler settings. After an internal error ("interr"), reload the database or restart IDA. - **Don't edit SLEIGH or spec files in place.** Ghidra warns that a program saved from a modified install can corrupt when reopened on a stock one. Use Specification Extensions instead. ## Related Concepts - [[concepts/executable-formats]]: headers, sections and debug info that feed the initial prototypes and types. - [[entities/ghidra]] and [[entities/ida-pro]]: the two decompilers described here. [[syntheses/choosing-a-disassembler]] compares them with JEB, Hopper and Rizin/Cutter. - [[concepts/go-rust-and-dart-binaries]] and [[concepts/dotnet-and-nativeaot]]: runtimes whose calling conventions and metadata break naive decompilation. - [[syntheses/troubleshooting]]: symptom-first fixes across tools. ## Sources - `raw/github_doc-ghidra-features-decompiler-src-main-help-help-topics-decompi-3.md` - `raw/github_doc-ghidra-features-decompiler-src-main-help-help-topics-decompi-2.md` - `raw/github_doc-ghidra-features-decompiler-src-main-help-help-topics-decompi.md` - `raw/github_doc-ghidra-features-decompiler-src-main-help-help-topics-decompi-4.md` - `raw/web_community-introduction-to-decompilation-vs-disassembly-md.md` - `raw/web_community-tricks-md.md` - `raw/web_community-failures-md.md` - `raw/web_community-get-started-md.md` - `raw/web_community-ctree-view-md.md` - `raw/web_community-microcode-view-md.md` - `raw/github_doc-ghidradocs-ghidraclass-beginner-introduction-to-ghidra-stude.md` --- title: ".NET Assemblies and NativeAOT" type: concept tags: [dotnet, cil, ilspy, dnspyex, nativeaot, readytorun, ghidra, managed-code] created: 2026-10-16 updated: 2026-10-16 confidence: medium sources: ["raw/web_community-assemblies-in-net-net-microsoft-learn.md", "raw/web_community-native-aot-deployment-overview-net-microsoft-learn.md", "raw/github_doc-readme-md-7.md", "raw/web_community-getting-started-with-icsharpcode-decompiler-md.md", "raw/github_doc-readme-md-8.md", "raw/github_doc-readme-md-9.md", "raw/github_doc-docs-managed-code-analysis-md.md", "raw/github_doc-docs-ghidra-nativeaot-md.md"] --- # .NET Assemblies and NativeAOT The first question with any .NET target is which kind of build you have. An ordinary assembly still carries CIL (Common Intermediate Language) and metadata, so an IL decompiler such as ILSpy can turn it back into readable C#. A NativeAOT build has been compiled to machine code ahead of time, so there are no CIL method bodies left to decompile. It has to be treated as a native binary in Ghidra (or Hopper), with the ghidra-nativeaot extension recovering the type information the runtime still needs. ## Definition - **Assembly.** Microsoft describes the assembly as the fundamental unit of deployment, version control, reuse, activation scoping and security permissions for .NET. It ships as an `.exe` or `.dll` PE file containing CIL code, type metadata and an **assembly manifest**. CIL in a PE file is not executed unless a manifest goes with it. Type identity includes the assembly name, so a `MyType` in one assembly is a different type from a `MyType` in another. - **ReadyToRun (R2R).** A managed assembly that also carries precompiled native code. It is still a PE/CLI assembly. ILSpy lists ReadyToRun binary support for .NET Core, and REA reads a ReadyToRun signature as one of the markers that identify a runtime family. - **NativeAOT.** Publishing with `true` produces a self-contained app compiled to native code at publish time. It runs without a JIT and bundles a stripped-down coreclr runtime. Each build targets one runtime identifier (RID), for example `win-x64` or `linux-arm64`. ## How It Works ### Managed assemblies: decompile the IL Because CIL and metadata survive compilation, decompilers can rebuild types, signatures and method bodies with high fidelity. | Tool | What it is for | Notes from its docs | |---|---|---| | **ILSpy** | Browsing and decompiling assemblies to C# | MIT-licensed, cross-platform desktop UI (Avalonia) on Windows, Linux and macOS. Whole-project decompilation, type/method search, a metadata explorer, BAML-to-XAML, ReadyToRun support, plugins. Also ships as the `ilspycmd` dotnet tool, a VS Code extension, PowerShell cmdlets, and the `ICSharpCode.Decompiler` / `ICSharpCode.ILSpyX` NuGet packages. Visual Studio 2022/2026 use its engine for F12 decompilation. The README says it uses no APM service to collect telemetry or metrics. | | **dnSpyEx** | Debugging and editing assemblies without source | An unofficial continuation of dnSpy, GPLv3. Debugs .NET Framework, .NET and Unity assemblies: breakpoints in any assembly, locals/watch windows, tracepoints, break on module load. Edits metadata, C#/VB method bodies and raw IL. Its hex editor jumps by metadata token, RVA or `#US`/`#Blob` heap offset. It uses ILSpy's decompiler engine and dnlib, which can read obfuscated assemblies. | dnSpyEx documents two useful debugger behaviours. When an assembly decrypts itself at runtime, dnSpyEx can debug the in-memory image, and you can force it to always use in-memory images. Dynamic modules can be debugged, but dynamic methods cannot because of CLR limitations. To script decompilation, add the `ICSharpCode.Decompiler` package and construct `new CSharpDecompiler(fileName, new DecompilerSettings())`. `DecompileTypeAsString(new FullTypeName("Demo.ConsoleApp.Test+NestedClassTest"))` returns one type as C#. Note the reflection-style `+` for nested types. Member tokens come from the type system (`typeInfo.Methods.First().MetadataToken`) and can be passed to `DecompileAsString`. ### NativeAOT: the IL is gone NativeAOT compiles IL to native code during `dotnet publish`, for example `dotnet publish -r win-x64 -c Release` or `dotnet publish -r linux-arm64 -c Release`. Several consequences matter for analysis: - **No CIL bodies.** A CIL decompiler cannot produce C# for the methods. Decompiling the native code gives pseudocode plus your own inferences, not original source. - **Not just Windows `.exe`.** Output may be a PE, ELF or Mach-O image, and shared-library builds (PE DLL, ELF `.so`, Mach-O `.dylib`) export chosen entry points explicitly. Identify the format from bytes and loader metadata, not the file extension (see [[concepts/executable-formats]]). - **Debug info is usually split off.** Publishing writes symbols to a separate file by default: `.dbg` on Linux, `.pdb` on Windows, a `.dSYM` folder on macOS. On Unix-like platforms, `false` embeds them in the binary instead. If you can get the matching sidecar, check that its identity matches before you trust it. - **Bigger, flatter code.** Every generic instantiation over a struct type gets its own pregenerated code. Generic virtual methods get one instantiation per implementing type. Expect lots of near-duplicate functions. - **Language features that can't exist.** NativeAOT rules out dynamic loading (`Assembly.LoadFile`), runtime code generation (`System.Reflection.Emit`) and C++/CLI, and on Windows it has no built-in COM. It requires trimming and implies single-file compilation. Don't go looking for these mechanisms in a confirmed NativeAOT binary. ### Recovering NativeAOT metadata in Ghidra The runtime still needs MethodTables (type descriptors with vtables), frozen objects such as string literals, and a ReadyToRun directory that roots all of it. **ghidra-nativeaot** (Washi1337, MIT) is a Ghidra analyzer and UI plugin for .NET 8+ NativeAOT binaries that rebuilds this layer. It reconstructs the full type hierarchy, annotates frozen objects (strings), detects vtable redirection, and adds a metadata browser and a refactoring engine for virtual methods. Build and install: ```sh gradle # assumes Ghidra under /opt/ghidra gradle -PGHIDRA_INSTALL_DIR=/path/to/ghidra ``` Gradle writes a plugin ZIP to `dist/`. Install it from **File > Install Extensions** in the Ghidra project window. Then open the binary in the CodeBrowser, run the **Native AOT Analyzer** (one-shot or as part of auto-analysis), and open the **Native AOT Metadata Browser** from the Windows menu. General Ghidra workflow is covered in [[entities/ghidra]]. **Finding the ReadyToRun header** is the step most likely to need manual help on stripped binaries. The plugin first looks for the symbol `__ReadyToRunHeader` or the pair `__modules_a` / `__modules_z`. If neither exists, it scans non-executable memory for the `RTR\0` signature plus plausible header fields. When that finds nothing, or finds too many candidates, use the fallback from the README. In `wmain`, the RTR directory list is the **second argument** to `S_P_CoreLib_Internal_Runtime_CompilerHelpers_StartupCodeHelpers__InitializeModules`. To locate that call in a stripped binary, compile a Hello World with symbols, compare the two in Ghidra's Version Tracking tool, follow the pointer array to data that starts with `RTR\0`, and label it `__ReadyToRunHeader`. Then rerun the analyzer. The README's worked example is Flare-On 11's `fullspeed.exe`. ### REA's managed and NativeAOT routes [[entities/rea]] (rea-agents) splits the two cases cleanly. - **Managed assemblies.** `rea inspect-managed-artifact /absolute/path/Assembly.dll --json` identifies the assembly and its metadata coverage. `rea inspect-managed-members /absolute/path/Assembly.dll --type Example.Parser` decodes types, signatures, CIL bodies, call edges and `ldstr` literals for selected types. Neither loads nor executes the assembly. Separately, REA's `verify:managed` verification script runs an optional real-ILSpy comparison when `REA_ILSPY_CMD_PATH` points at an absolute `ilspycmd`; ordinary inspection needs no ILSpy. - **NativeAOT.** A built-in read-only parser handles **x64 PE with .NET 8 RTR 9.1** metadata. It recovers MethodTables, base types, interfaces, virtual slots and frozen strings, and it also runs on REA's experimental Windows Ghidra route (checked manually with Ghidra 12.1.4 and JDK 21). Broader recovery that writes annotations into the Ghidra database needs the optional Linux headless adapter. You build it locally from the pinned ghidra-nativeaot commit and point `REA_GHIDRA_NATIVEAOT_JAR` at the JAR. Typical calls: ```sh rea inspect-native-load-image ./NativeAotFixture --provider ghidra --json rea inspect-native-data-type ./NativeAotFixture --address 0xMETHODTABLE_ADDRESS --provider ghidra --json rea function ./NativeAotFixture 0xADDRESS --provider ghidra --json ``` ## Key Parameters | Item | Value / meaning | |---|---| | `true` | MSBuild property that turns on NativeAOT publishing | | `dotnet publish -r ` | Publishes for one runtime identifier | | `false` | Unix: embed debug info instead of a sidecar | | NativeAOT targets (.NET 8) | Windows, Linux and macOS on x64 and Arm64. iOS, tvOS, MacCatalyst and Android are experimental. The .NET 9+ table adds x86 for Windows and Arm for Linux | | `RTR\0` | Signature at the start of the ReadyToRun directory | | `__ReadyToRunHeader`, `__modules_a`/`__modules_z` | Symbols ghidra-nativeaot uses to find RTR metadata | | `0x70xxxxxx` | User-string (`ldstr`) tokens. `0x70000000` is the empty `#US` entry | | `0x06xxxxxx` | MethodDef tokens. Only meaningful inside one build (module version ID, MVID) | | `REA_ILSPY_CMD_PATH`, `REA_GHIDRA_NATIVEAOT_JAR` | REA's optional ILSpy check and NativeAOT adapter | ## When To Use - **CIL present** (the CLI header and metadata parse, method bodies exist): start with ILSpy for reading, dnSpyEx when you need to debug or step through the code, and REA when you need structured facts or cross-build member comparison. - **Native image, .NET suspected** (no CLI metadata, but an `RTR\0` directory is present, or symbolized builds show `S_P_CoreLib_...` startup helpers): treat it as NativeAOT. Use Ghidra with ghidra-nativeaot, or REA's parser for x64 PE. - **Single-file bundles and IL2CPP** are separate formats. REA explicitly does not unpack .NET single-file hosts or decode IL2CPP metadata, and it won't infer NativeAOT from an ordinary native PE. Extract the components first and inspect each one on its own. ## Risks & Pitfalls - **Tokens are not identities.** Metadata tokens and RVAs are build-local. You can't carry `0x06001234` into a different MVID and assume it names the same method. Match members across builds by signature and body structure. - **Names are not proof.** Linking a NativeAOT native function to a specific managed method needs verified evidence. Similar names or vtables alone don't establish it. ghidra-nativeaot-derived names are generated, so original class and member names and custom field layouts stay unknown. - **Prototypes are guesses.** REA notes that the upstream plugin's blanket `__thiscall` assignment is not authoritative for the x64 ABI. Check parameters against instructions and call sites (see [[concepts/decompilation-concepts]]). - **Frozen strings live outside Ghidra's string list** in REA's parser route. Read them from `metadata_recovery.frozen_strings`, not `search_strings`. - **P/Invoke matches are declarations.** A module and entry-point match between managed imports and native exports shows a declared link, not that the call ever ran. A missing import doesn't rule out dynamic resolution. - **Debugging executes the target.** dnSpyEx debugging runs the assembly. Do it in an isolated VM for untrusted samples (see [[syntheses/malware-triage]]), and only on software you're authorized to examine ([[concepts/legal-and-ethics]]). ## Related Concepts - [[concepts/executable-formats]]: PE, ELF and Mach-O containers that hold both managed and NativeAOT output - [[concepts/decompilation-concepts]]: why native pseudocode differs from IL decompilation - [[entities/ghidra]]: the host for ghidra-nativeaot - [[entities/rea]]: managed inspection and NativeAOT parser routes - [[concepts/go-rust-and-dart-binaries]]: the same metadata-recovery mindset for other compiled runtimes - [[syntheses/triage-an-unknown-binary]]: telling managed, R2R and NativeAOT apart in the first minutes - [[syntheses/choosing-a-disassembler]] ## Sources - `raw/web_community-assemblies-in-net-net-microsoft-learn.md` - `raw/web_community-native-aot-deployment-overview-net-microsoft-learn.md` - `raw/github_doc-readme-md-7.md` - `raw/web_community-getting-started-with-icsharpcode-decompiler-md.md` - `raw/github_doc-readme-md-8.md` - `raw/github_doc-readme-md-9.md` - `raw/github_doc-docs-managed-code-analysis-md.md` - `raw/github_doc-docs-ghidra-nativeaot-md.md` --- title: "EVM Bytecode Analysis" type: concept tags: [evm, ethereum, smart-contracts, selectors, abi, evmole, cbor-metadata, solidity, jeb, opcodes] created: 2026-10-16 updated: 2026-10-16 confidence: medium sources: ["raw/web_community-ethereum-virtual-machine-evm-ethereum-org.md", "raw/web_community-opcodes-for-the-evm-ethereum-org.md", "raw/web_community-contract-metadata-solidity-0-8-38-develop-documentation.md", "raw/github_doc-readme-md-17.md", "raw/github_doc-agent-skills-evm-bytecode-analysis-skill-md.md", "raw/github_doc-agent-skills-evm-bytecode-analysis-references-cli-md.md", "raw/github_doc-agent-skills-evm-bytecode-analysis-references-interpretation.md", "raw/github_doc-agent-mcp-readme-md.md", "raw/web_community-ethereum-analysis-jeb-decompiler.md", "raw/github_doc-docs-evm-bytecode-md.md", "raw/web_community-decompiling-jeb-decompiler.md"] --- # EVM Bytecode Analysis Reversing a smart contract without verified source starts from its **deployed runtime bytecode**. The questions are nearly always the same. Which functions does it expose (selectors and their likely argument types)? Does it read or write state, or accept value? Which storage slots does it touch? What compiler metadata does it carry? EVMole answers the interface and storage questions statically. The CBOR trailer gives compiler hints. JEB Pro decompiles the whole contract to Solidity-like code when you need the logic. ## Definition - **EVM.** A deterministic virtual machine that every Ethereum node runs. Per ethereum.org it is a **stack machine with a depth of 1024 items**, and each item is a **256-bit word**. During execution it also has **memory**, a byte array that does not persist between transactions. Each contract account has **storage**, a persistent word-addressed store that is part of global state. **Transient storage** (`TSTORE`/`TLOAD`) lasts across internal calls within one transaction and is cleared when the transaction ends. - **Creation vs runtime bytecode.** A contract-creation transaction runs constructor (creation) code, which may copy, transform or return the runtime code. The runtime code is what's stored at the address and executed on every call. EVMole and REA analyse runtime bytecode only. They don't run constructors or dig the runtime out of creation code. - **Selector.** A 4-byte function identifier that the dispatcher compares against the start of calldata. Static analysis finds selector values, not names. - **CBOR metadata.** A trailer the Solidity compiler appends by default. It encodes a metadata hash (IPFS, or Swarm `bzzr1`/`bzzr0`) and the `solc` version. ## How It Works ### Reading a dispatcher by hand The contract entry point is at offset 0 and is generally the dispatcher. JEB names it `start()`. The opening bytes of EVMole's README example show the usual Solidity pattern (opcode values from the ethereum.org table): | Bytes | Opcode | Meaning | |---|---|---| | `6080 6040 52` | PUSH1 0x80, PUSH1 0x40, MSTORE | Store 0x80 at memory offset 0x40 | | `34 80 15 600e 57` | CALLVALUE, DUP1, ISZERO, PUSH1, JUMPI | Value check: continue only if no ether was sent | | `5f 80 fd` | PUSH0, DUP1, REVERT | Revert path | | `6004 36 10 6030 57` | PUSH1 4, CALLDATASIZE, LT, PUSH1, JUMPI | Jump to the revert block at 0x30 if calldata is shorter than 4 bytes | | `5f 35 60e0 1c` | PUSH0, CALLDATALOAD, PUSH1 0xe0, SHR | Load the first word and shift right 224 bits, leaving the top 4 bytes | | `80 63 2125b65b 14 6034 57` | DUP1, PUSH4, EQ, PUSH1 0x34, JUMPI | If the selector is `0x2125b65b`, jump to offset 0x34 (52) | EVMole reports exactly that: selector `2125b65b` at `bytecodeOffset: 52`, arguments `uint32,address,uint224`, mutability `pure`. Opcodes worth recognizing on sight: | Hex | Opcode | Why it matters | |---|---|---| | `35` | CALLDATALOAD | Reads calldata: selector and arguments | | `34` | CALLVALUE | Payability checks | | `54` / `55` | SLOAD / SSTORE | Persistent storage reads/writes | | `5C` / `5D` | TLOAD / TSTORE | Transient storage | | `56` / `57` / `5B` | JUMP / JUMPI / JUMPDEST | Control flow and jump targets | | `F1` / `F4` / `FA` | CALL / DELEGATECALL / STATICCALL | External calls | | `39` | CODECOPY | Copies the running code into memory | | `F3` / `FD` / `FE` | RETURN / REVERT / INVALID | Exits | | `5F` | PUSH0 | Pushes the constant 0 | ### EVMole: interface, storage and metadata EVMole extracts selectors, arguments, state mutability, persistent and transient storage layouts, and CBOR metadata from bytecode, including unverified contracts. It ships JavaScript, Rust, Python and Go bindings. The README says it has been tested on Solidity and Vyper output, and it distinguishes normal ABI dispatch from selectors handled by fallback logic. ```bash npx -y evmole@latest analyze --bytecode 0x6001600055 npx -y evmole@latest analyze --file runtime.hex --include selectors,arguments,stateMutability,storage echo '0x6001600055' | npx -y evmole@latest analyze ``` | Option | Meaning | |---|---| | `--include` | Any of `selectors`, `arguments`, `stateMutability`, `storage`, `transientStorage`, `metadata`, `disassembly`, `basicBlocks`, `controlFlowGraph` | | default set | Selectors, arguments, mutability, both storage kinds, metadata. Disassembly and CFG are opt-in | | `--offset` / `--limit` | Paginate list sections (limit default 1,000, max 5,000) | | `--pretty` | Human-readable JSON | | `evmole schema` | Print the version 1 request/response/error schemas | The CLI needs Node.js 22 or newer and writes one JSON document to stdout. Exit codes: `0` success, `2` bad CLI syntax or ambiguous input, `3` invalid bytecode or request, `4` a size/output limit was exceeded, `1` internal failure. Check every requested section's `pagination.truncated` and the `warnings` before drawing conclusions. From code: `contractInfo(code, {selectors:true, arguments:true, stateMutability:true})` in JavaScript, or `contract_info(code, selectors=True, arguments=True, state_mutability=True)` in Python. Foundry's `cast selectors $(cast code
)` uses EVMole's Rust implementation. Note that `cast code` fetches the code over RPC, and `cast selectors --resolve` adds guessed names to the output. For agents, `npx -y evmole-mcp@latest` starts a stdio MCP server with one tool, `analyze_evm_bytecode`, which takes hex `bytecode`, optional `include`, `offset` and `limit`. It makes no network requests and fetches no addresses. The portable skill installs with `npx skills add cdump/evmole --skill evm-bytecode-analysis -g`. See [[syntheses/re-with-ai-agents-mcp]]. ### Compiler metadata trailer solc appends a CBOR map to the end of the deployed bytecode. The **last two bytes give the CBOR length**, so decode backwards from the end. Possible keys are `ipfs`, `bzzr1`, `bzzr0` (older), `experimental` and `solc`. Release builds encode the version in 3 bytes (major, minor, patch). Pre-release builds embed a full version string with commit and date. The Solidity docs warn against matching on a fixed prefix such as `0xa264`: the map can hold other keys, so use a real CBOR parser. Developers can suppress the trailer with `--no-cbor-metadata` or `settings.metadata.appendCBOR: false`, so its absence proves nothing. JEB's docs say the same about metadata in general: it's indicative and shouldn't be trusted. ### JEB Pro: Solidity-like decompilation JEB's EVM analyzer finds public and private methods and tries to name methods and events without an ABI, using a hash dictionary of more than 340,000 entries for public method names. Its decompiler emits Solidity-like code and recognizes ERC20, ERC721 and MultiSigWallet implementations, storage variables, mutability, payability, event emission, `send`/`transfer` and precompile calls. Input files need a `.evm-bytecode` extension (binary or hex), or `.runtime` / `.bin-runtime` (hex, as solc produces). JEB can also download a contract by address from supported networks. In the GUI, Tab switches between assembly and decompiled view, Space shows a routine's CFG, N renames, X lists cross-references, and B cycles number base and rendering. The output deliberately contains constructs that aren't legal Solidity (raw EVM statements, memory accesses, occasionally `goto`), so don't expect it to recompile. Comparison with other tools is in [[syntheses/choosing-a-disassembler]]. ### REA's offline route `rea inspect-evm-interface ./runtime.hex hex --json` (or `./runtime.bin raw`) runs a bundled, unchanged EVMole 0.9.3 in a resource-limited worker. It needs util-linux `prlimit`, with `REA_EVM_PRLIMIT_COMMAND` as an override, and real verification covers flat legacy bytecode on Linux x64. It returns selectors with decoded-byte offsets and independently decodes the terminal CBOR map into `bytecode.metadata`. EOF-style `EF00` containers are rejected as unsupported. REA reports a SHA-256 of the file and of the decoded bytes. Neither is the Ethereum Keccak code hash. See [[entities/rea]]. ## Key Parameters | Item | Value | |---|---| | Stack | 1024 items of 256 bits | | Selector size | 4 bytes | | Selector extraction idiom | `PUSH0 CALLDATALOAD PUSH1 0xe0 SHR` | | CBOR length | Last 2 bytes of the bytecode | | Metadata keys | `ipfs`, `bzzr1`, `bzzr0`, `experimental`, `solc` | | EVMole list limit | default 1,000, max 5,000 | | EVMole runtime | Node.js 22+ | | REA bundled EVMole | 0.9.3 | ## When To Use - **"What can I call on this contract?"** Run EVMole with `selectors,arguments,stateMutability`. - **"Does it touch slot X / use transient storage?"** Request `storage` / `transientStorage`. - **"What compiled it?"** Decode the CBOR trailer (EVMole `metadata` or REA), and treat the result as a claim. - **"What does function 0x… actually do?"** Use JEB's decompiler, or EVMole's `disassembly` / `controlFlowGraph` and read by hand. ## Risks & Pitfalls - **Inference, not ABI.** Arguments, mutability and storage types are inferred from bytecode. Optimization, assembly, proxies or unreachable paths can make them incomplete or wrong. Say "EVMole infers `view`", not "the function is `view`". - **Selectors are not names.** Don't present a guessed name (from a signature database or JEB's dictionary) as fact. EVMole's guidance is to resolve names only through a separately authorized signature source. - **Creation code in, garbage out.** Passing constructor bytecode, or an address instead of bytecode, gives misleading or invalid results. - **Empty results don't prove absence.** No candidates doesn't mean no callable interface, and a missing trailer doesn't mean the contract wasn't built with Solidity. - **Stay offline unless you mean not to.** Both EVMole and REA avoid RPC and explorer lookups. Fetching code, resolving names or interacting with a live contract are separate, deliberate steps. Keep analysis within authorized audit, research or CTF scope ([[concepts/legal-and-ethics]]). ## Related Concepts - [[concepts/webassembly]]: another stack-machine bytecode - [[concepts/decompilation-concepts]]: why decompiled output needs verification - [[syntheses/choosing-a-disassembler]]: JEB's EVM support among the options - [[syntheses/re-with-ai-agents-mcp]]: evmole MCP and REA for agent workflows - [[entities/rea]] ## Sources - `raw/web_community-ethereum-virtual-machine-evm-ethereum-org.md` - `raw/web_community-opcodes-for-the-evm-ethereum-org.md` - `raw/web_community-contract-metadata-solidity-0-8-38-develop-documentation.md` - `raw/github_doc-readme-md-17.md` - `raw/github_doc-agent-skills-evm-bytecode-analysis-skill-md.md` - `raw/github_doc-agent-skills-evm-bytecode-analysis-references-cli-md.md` - `raw/github_doc-agent-skills-evm-bytecode-analysis-references-interpretation.md` - `raw/github_doc-agent-mcp-readme-md.md` - `raw/web_community-ethereum-analysis-jeb-decompiler.md` - `raw/github_doc-docs-evm-bytecode-md.md` - `raw/web_community-decompiling-jeb-decompiler.md` --- title: "Executable Formats: ELF, PE, Mach-O and DEX" type: concept tags: [elf, pe, coff, mach-o, fat-binary, universal-binary, dex, dalvik, app-bundle, ipa, headers, sections, segments, imports, relocations, debug-info] created: 2026-10-16 updated: 2026-10-16 confidence: high sources: ["raw/web_community-elf-5-linux-manual-page.md", "raw/web_community-pe-format-win32-apps-microsoft-learn.md", "raw/web_community-loader-h.md", "raw/web_community-dalvik-executable-format-android-os-core-topics-android-open.md", "raw/github_doc-docs-binary-diagnostics-md.md", "raw/github_doc-docs-apple-application-analysis-md.md", "raw/github_doc-docs-native-investigation-md.md", "raw/web_community-readelf-gnu-binary-utilities.md", "raw/github_doc-src-tools-rz-bin-intro-md.md", "raw/web_community-objdump-gnu-binary-utilities.md", "raw/github_doc-readme-md-21.md"] --- # Executable Formats: ELF, PE, Mach-O and DEX ## Definition An executable format is the on-disk layout that tells a loader (or a disassembler) where code and data are, how to map them into memory, what external libraries and symbols are needed, and where relocation and debug information lives. Reverse engineers meet four formats constantly: | Format | Platforms | Magic at offset 0 | Typical tools | |---|---|---|---| | **ELF** | Linux, Android native libs, most Unix, much firmware | `0x7f 'E' 'L' 'F'` | `readelf`, `objdump`, `nm`, `rz-bin` | | **PE/COFF** | Windows (EXE, DLL), .NET assemblies | `MZ` (MS-DOS stub), then `PE\0\0` at the offset stored at `0x3c` | `objdump -p`, `rz-bin`, DiE | | **Mach-O** | macOS, iOS | `0xfeedface` (32-bit) / `0xfeedfacf` (64-bit), or byte-swapped `0xcefaedfe` / `0xcffaedfe` | `rz-bin`, `otool`, [[entities/rea]] Mach-O tools | | **DEX** | Android (Dalvik/ART bytecode) | `dex\n` + 3-digit version + `\0`, e.g. `dex\n039\0` | JADX, apktool, `rz-bin` | ## How It Works ### ELF An ELF file starts with the ELF header, which is always at offset zero. It is followed by a **program header table** (segments, used by the loader), a **section header table** (sections, used by linkers and analysts), or both. - **Header (`ElfN_Ehdr`).** `e_ident` holds the magic, the class (`ELFCLASS32`/`ELFCLASS64`), data encoding (`ELFDATA2LSB`/`ELFDATA2MSB`), and OS/ABI. `e_type` is `ET_REL`, `ET_EXEC`, `ET_DYN` (shared object, which also covers PIE executables) or `ET_CORE`. `e_machine` gives the architecture and `e_entry` the entry point. - **Segments.** `PT_LOAD` segments are mapped into memory. If `p_memsz` > `p_filesz`, the extra bytes are zero-filled, which is how `.bss` works. `PT_INTERP` names the dynamic loader. `PT_DYNAMIC` points at dynamic-linking info. `PT_NOTE` holds notes. `PT_GNU_STACK` flags control whether the stack is executable. - **Sections that matter in RE.** Code is in `.text`. Read-only data such as strings and constants is in `.rodata`. `.data` is initialized data and `.bss` is zero-initialized data (`SHT_NOBITS`, no file bytes). The full symbol table is `.symtab`/`.strtab`, and `.dynsym`/`.dynstr` is the runtime subset. Dynamic linking uses `.dynamic`, `.plt` (procedure linkage table) and `.got` (global offset table). Relocations are in `.rel*`/`.rela*`, notes in `.note*`, and debug info in `.debug*` (DWARF). - **Imports.** ELF has no import table as such. Needed libraries are `DT_NEEDED` entries in `.dynamic`, and imported functions are undefined dynamic symbols resolved through the PLT/GOT. When a binary is stripped, `.symtab` is gone. Look at `.dynsym` instead: whatever the dynamic linker needs to resolve is still listed there. ### PE/COFF A PE image starts with an **MS-DOS stub** (the "This program cannot be run in DOS mode" program). At `0x3c` is the file offset of the 4-byte signature `PE\0\0`. After the signature come the **COFF file header** (machine type such as `IMAGE_FILE_MACHINE_AMD64` or `IMAGE_FILE_MACHINE_ARM64`, number of sections, characteristics), the **optional header**, and the section table. - **PE32 vs PE32+.** The optional-header magic is `0x10b` for PE32 and `0x20b` for PE32+ (64-bit address space, image size still limited to 2 GB). - **RVAs.** Most addresses in a PE are **relative virtual addresses**: the address after loading minus the image base. An RVA almost never equals the file offset. Convert between them through the section table. - **Data directories** in the optional header locate the export table (`.edata`), the import table (`.idata`), resources (`.rsrc`), exception data (`.pdata`), base relocations (`.reloc`), the TLS table, the debug directory, the **Import Address Table (IAT)**, delay-load imports, and the **CLR runtime header**, which marks the file as a .NET assembly. - **Imports.** The import directory table has one entry per DLL, each pointing to an import lookup table of names or ordinals and to the IAT. The loader fills the IAT with real addresses, and code calls through it. - **Certificates.** The attribute certificate table (Authenticode) is not mapped into memory, so its directory entry holds a **file pointer**, not an RVA. Certificates and debug data must sit at the end of the image file. - **Debug info.** The debug directory says what kind of debug data exists and where. CodeView/PDB references are the usual source of leaked build paths. ### Mach-O - **Header.** The magic is `MH_MAGIC` (`0xfeedface`) or `MH_MAGIC_64` (`0xfeedfacf`). The CIGAM forms mean the other byte order. File types include `MH_EXECUTE` (0x2), `MH_DYLIB` (0x6), `MH_BUNDLE` (0x8), `MH_DSYM` (0xa, debug companion only), and `MH_FILESET` (0xc). The `MH_PIE` flag (main executables only) tells the OS to load the program at a random address. - **Load commands** follow the header and describe everything else: | Load command | Purpose | |---|---| | `LC_SEGMENT_64` | maps a segment (`__PAGEZERO`, `__TEXT` with `__text`, `__DATA`, `__LINKEDIT`) | | `LC_MAIN` | entry point (replaces `LC_UNIXTHREAD`) | | `LC_LOAD_DYLIB` / `LC_LOAD_WEAK_DYLIB` | needed libraries | | `LC_RPATH` | run-path entries used by `@rpath` | | `LC_SYMTAB` / `LC_DYSYMTAB` | symbol tables | | `LC_DYLD_INFO_ONLY` / `LC_DYLD_CHAINED_FIXUPS` | binding and rebasing info | | `LC_FUNCTION_STARTS` | compressed function-start table, handy on stripped binaries | | `LC_UUID`, `LC_BUILD_VERSION` | identity, platform and minimum OS | | `LC_CODE_SIGNATURE` | code signature location | | `LC_ENCRYPTION_INFO(_64)` | encrypted range: `cryptoff`, `cryptsize`, `cryptid` (0 = not encrypted) | - **Universal (FAT) binaries** wrap several Mach-O slices, one per architecture. Every analysis has to pick a slice. Offsets inside a slice are relative to that slice, so add the slice's container offset to get a position in the original file. REA reports this as `selected_architecture` plus `container_file_offset`. - **Library resolution** follows dyld rules. `@executable_path` is the main executable's directory. `@loader_path` is the directory of the image that holds the load command. `@rpath` tries each `LC_RPATH` of the loading image, then those of its loaders. REA's `trace_dylib_resolution` reproduces this statically, off macOS, without executing anything. **App bundles.** An iOS IPA holds `Payload/.app`, a shallow bundle with `Info.plist` at its root. A macOS `.app` has `Contents/` with executables in `Contents/MacOS/`. Inside a bundle, look for nested code: `*.appex` app extensions, `*.xpc` services, `*.framework` (versioned with `Versions/`), login items in `Contents/Library/LoginItems/`, privileged helpers in `Contents/Library/LaunchServices/`, and launchd plists in `Contents/Library/LaunchAgents/` or `LaunchDaemons/`. **Each executable is its own process root**, with its own `@executable_path`. ### DEX A `.dex` file holds Dalvik bytecode for a whole set of classes. After the header come sorted, de-duplicated ID tables: `string_ids`, `type_ids`, `proto_ids`, `field_ids`, `method_ids`, then `class_defs` (superclasses and interfaces listed before the classes that use them), `call_site_ids`, `method_handles` (unsorted, duplicates allowed), the data area (which holds the `map_list`), and `link_data`. `endian_tag` is `ENDIAN_CONSTANT` `0x12345678`. **Versions**: `039` came with Android 9.0 (adds `const-method-handle`/`const-method-type`), `040` with Android 10 (wider `SimpleName` characters), and `041` is experimental in Android 16 for the container format and is not meant for production code. APK packaging and decompilation are covered in [[syntheses/android-apk-analysis]]. ## Key Parameters | Need | ELF | PE | Mach-O | |---|---|---|---| | Architecture | `e_machine` | COFF `Machine` | `cputype` (per slice) | | Entry | `e_entry` | `AddressOfEntryPoint` (RVA) | `LC_MAIN` | | Needed libraries | `DT_NEEDED` | import directory | `LC_LOAD_DYLIB` | | Load-time fixups | `.rel(a).*`, RELR | `.reloc` base relocations | `LC_DYLD_CHAINED_FIXUPS` / dyld info | | Debug info | `.debug_*` (DWARF) | debug directory → PDB | `MH_DSYM` companion | | Address model | virtual addresses in `p_vaddr` | RVAs + image base | segment `vmaddr` | Commands: `readelf -h -l -S -d -s f` (ELF header, segments, sections, dynamic, symbols), `objdump -p f` (format-specific headers, including PE data directories), `rz-bin -H f` (header fields), `rz-bin -SSS f` (section-to-segment map), `rz-bin -A f` (list the arch slices in a FAT binary), `rz-bin -R f` (relocations). ## When To Use - **Triage**: identify the format and architecture before choosing tools ([[syntheses/triage-an-unknown-binary]]). - **Fixing a bad load**: wrong base, wrong slice, missing segments, or a raw blob with no header ([[syntheses/firmware-analysis]]). - **Interpreting decompiler output**: knowing PLT/GOT and IAT thunks explains the indirect calls you see ([[concepts/decompilation-concepts]]). - **Malware work**: section anomalies, overlays, and certificate placement are classic signals ([[syntheses/malware-triage]]). ## Risks & Pitfalls - **Linked address ≠ runtime address.** PIE and ASLR relocate images. REA keeps the runtime load base null in static results for exactly this reason. - **RVA vs file offset confusion** in PE. Patching or carving at an RVA without converting it corrupts the wrong bytes. - **`ET_DYN` is ambiguous.** It can be a shared library or a PIE executable. Check for `PT_INTERP` and a non-zero entry point, but neither is conclusive: elf(5) notes `PT_INTERP` may also occur in shared objects. - **Section headers can be missing or damaged.** An ELF file only needs a program header table *or* a section header table, and segments are what get mapped. A file with no section table can still run. A missing symbol or relocation section doesn't mean the runtime tables are absent, and RELRO or canary heuristics that depend on sections become incomplete. DiE's format-integrity checks flag damaged PE structures the same way. - **Names aren't paths.** `DT_NEEDED`, `PT_INTERP`, and `LC_LOAD_DYLIB` give names to resolve, not resolved files. - **FAT slice offsets** are container-relative for the slice table and slice-relative inside it. Mixing them up misplaces every address. - **Encrypted Mach-O** (`cryptid` ≠ 0): the encrypted range is unreadable statically. This wiki does not cover decrypting App Store binaries. - **Absent canary symbol** doesn't prove every function lacks a stack protector. ## Related Concepts - [[syntheses/triage-an-unknown-binary]]: commands that read these structures - [[concepts/dotnet-and-nativeaot]]: what the CLR header means for analysis - [[syntheses/android-apk-analysis]]: DEX in its APK context - [[entities/frida]]: iOS and macOS runtime work on Mach-O targets - [[concepts/decompilation-concepts]]: how disassemblers use these tables ## Sources - `raw/web_community-elf-5-linux-manual-page.md` - `raw/web_community-pe-format-win32-apps-microsoft-learn.md` - `raw/web_community-loader-h.md` - `raw/web_community-dalvik-executable-format-android-os-core-topics-android-open.md` - `raw/github_doc-docs-binary-diagnostics-md.md` - `raw/github_doc-docs-apple-application-analysis-md.md` - `raw/github_doc-docs-native-investigation-md.md` - `raw/web_community-readelf-gnu-binary-utilities.md` - `raw/github_doc-src-tools-rz-bin-intro-md.md` - `raw/web_community-objdump-gnu-binary-utilities.md` - `raw/github_doc-readme-md-21.md` --- title: "Go, Rust and Flutter/Dart Binaries" type: concept tags: [go, golang, pclntab, goresym, rust, symbol-mangling, cargo-auditable, flutter, dart, blutter, pwndbg] created: 2026-10-16 updated: 2026-10-16 confidence: medium sources: ["raw/web_community-abi-internal-md.md", "raw/github_doc-readme-md-10.md", "raw/github_doc-docs-go-binaries-md.md", "raw/github_doc-docs-tutorials-go-debugging-md.md", "raw/web_community-symbol-mangling-the-rustc-book.md", "raw/web_community-v0-symbol-format-the-rustc-book.md", "raw/github_doc-docs-rust-binaries-md.md", "raw/github_doc-readme-md-11.md", "raw/github_doc-docs-flutter-analysis-md.md"] --- # Go, Rust and Flutter/Dart Binaries Go, Rust and Flutter (Dart AOT) binaries are native code, but each toolchain leaves its own structured metadata behind. Recover that metadata first, before you start reading disassembly. A "stripped" Go binary usually still has its function table and types. A Rust binary may carry its full crate dependency list. A Flutter app's snapshot hash tells you which Dart SDK built it, and the SDK version decides which tools can parse it. ## Definition | Runtime | Metadata worth recovering | Main tools | |---|---|---| | **Go** | `pclntab` (function names, entry/end addresses, file and line tables), `moduledata` (types, typelinks, itablinks), embedded build info (compiler version, modules, build settings) | GoReSym, REA (rea-agents, see [[entities/rea]]) `inspect-go-binary`, pwndbg `go-dump`/`go-type` | | **Rust** | Mangled symbols (v0 scheme, `_R` prefix), optional cargo-auditable `.dep-v0` dependency section, `/rustc//` paths in read-only data | `rustfilt`, gdb/lldb demangling, REA `inspect-rust-binary` | | **Flutter/Dart** | `libapp.so` AOT snapshot (hash, object pool, `package:` URIs), `libflutter.so` engine build ID | blutter, REA `identify-flutter-build` / `inspect-dart-aot` | ## How It Works ### Go: pclntab, moduledata and the register ABI The Go runtime needs function and type metadata for stack traces, garbage collection and reflection, so the linker keeps it even when symbols are stripped. **GoReSym** (Mandiant, MIT) is built from the Go compiler's own `debug/gosym` and runtime code. It extends that code to handle stripped binaries, malformed UPX-unpacked binaries, data ranges split across sections, and locating `moduledata`. It reads ELF, PE and Mach-O on x86/x64 and ARM64 in either byte order. ``` GoReSym.exe -t -d -p /path/to/input.exe ``` | Flag | Effect | |---|---| | `-t` | Recover Go type names | | `-d` | Include standard-library packages as well as user packages | | `-p` | Print file paths embedded in the `pclntab` | | `-strings` | Pull Go strings via the string internment table | | `-m ` | Recursively dump the `RTYPE` structure at that address | | `-v ` | Override automatic version detection (needed for some stripped binaries) | | `-human` | Flat text instead of JSON | The JSON output includes `Version`, `BuildId`, `Arch`, `TabMeta` (pclntab virtual address, layout version, pointer size), `ModuleMeta`, and arrays of `Types`, `Files`, `Strings`, `UserFunctions` and `StdFunctions`. To apply the results in IDA, run the repository's `IDAPython/goresym_rename.py` against the JSON (see [[entities/ida-pro]]). GoReSym parses `pclntab` from Go 1.2 onward, and types from Go 1.5 onward because `moduledata` didn't exist before 1.5. It handles the pre-1.2, 1.2, 1.16, 1.18 and 1.20 layouts and has added Go 1.24 parsing. The pclntab layout version never exceeds the runtime version: a Go 1.19 binary uses the 1.18 layout. When someone has tampered with the pclntab magic, GoReSym can locate the table through a `runtime_modulesinit` signature and repair the magic. For supply-chain questions without a disassembler, `rea inspect-go-binary /absolute/path/to/application --json` reads the embedded build info: compiler version string, main module, dependencies with versions and checksums, replacements, and settings such as `GOOS`, `GOARCH` and `vcs.revision`. It covers ELF, PE and thin Mach-O, never runs the file, and doesn't need Go installed. Function names and types are outside its scope. **Why Go decompiles badly.** Go functions use **ABIInternal**, a register-based convention the Go docs describe as unstable between Go versions. It is not the platform C ABI, so a decompiler that assumes System V or Microsoft x64 gets the parameters wrong. Hand-written assembly uses the stable stack-based **ABI0**, and wrappers bridge the two. | | amd64 | arm64 | |---|---|---| | Integer args/results | RAX, RBX, RCX, RDI, RSI, R8, R9, R10, R11 | R0–R15 | | Float args/results | X0–X14 | F0–F15 | | Current goroutine | R14 | R28 | | Closure context | RDX | R26 | | Fixed zero | X15 (except Plan 9) | ZR | | Frame pointer | RBP | R29 (link register R30) | Each argument or result travels entirely in registers or entirely on the stack. Values that don't fit the remaining registers, or that contain non-trivial arrays, go on the stack. The caller also reserves (but doesn't fill) spill space for register arguments. Composite layouts follow from that: a `string` is pointer + length, a slice is pointer + `len` + `cap`, and an interface is a type or itab pointer plus a data pointer. That's why one Go `string` parameter shows up as two register arguments in pseudocode. Retyping prototypes is covered in [[concepts/decompilation-concepts]]. **At runtime**, pwndbg can dump Go values with Go syntax ([[entities/gdb-and-pwndbg]]): ``` pwndbg> go-dump map[string]int 0xc0000b20f0 pwndbg> go-dump struct(24){0:a:int;8:b:string} 0xc000108120 pwndbg> go-type 0x49fbc0 ``` Structs are written as `struct(SIZE){OFFSET:NAME:TYPE;...}`. `-p` pretty-prints and `-x` shows integers in hex. Interface values (`any`, `interface`) dump without extra type info because the compiler emits a type object for every type the program uses. To find a type pointer for a non-interface value, look at what's passed to allocators such as `runtime.newobject` or `runtime.makeslice`, then pass that address to `go-type` or straight to `go-dump`. ### Rust: demangling and embedded dependencies rustc mangles symbol names, and `-C symbol-mangling-version` selects the scheme. According to the rustc book (fetched 2026-10-16), **v0** is the one stable scheme, and switching back to the legacy scheme needs a nightly toolchain. v0 symbols start with `_R`, can be restricted to `A-Z`, `a-z`, `0-9` and `_` (Unicode is optional), and encode generic parameters in a way that can be decoded. The format is not a stable ABI, and the book defines no single canonical demangled form, so different tools may print the same symbol differently. - Recent gdb and lldb demangle Rust symbols natively. - `rustfilt` demangles on the command line: `rustfilt _RNvCskwGfYPst2Cb_3foo16example_function` prints `foo::example_function`. - The `rustc-demangle` crate does it programmatically. - Items marked `#[no_mangle]` or `#[export_name]`, and items declared in `extern` blocks, keep plain names. These are often FFI or export boundaries worth looking at first. When a binary was built with cargo-auditable, it carries a zlib-compressed JSON dependency graph in `.dep-v0` (ELF and PE) or `__DATA,.dep-v0` (thin Mach-O). `rea inspect-rust-binary /absolute/path/to/application --json` decodes the crate names, versions, sources, root package and dependency edges. It also reports a `rustc_commit` when it finds a `/rustc/<40-hex>/` path in read-only data. That commit is an inference, not proof of which compiler built the file. ### Flutter/Dart: identify the SDK, then parse In an Android Flutter APK, app code is an AOT snapshot in `lib//libapp.so` and the engine is `libflutter.so`. Snapshot data sections start with the magic `f5 f5 dc dc`. The **snapshot hash** sits 20 bytes after that magic and identifies the Dart SDK build. Mapping the hash to an SDK release needs an external dataset, such as the one reFlutter maintains. This matters because the snapshot layout changes with each release, so typed class and function recovery needs a parser built for that exact SDK. Triage with REA, which parses the APK without running anything: ```sh rea identify-flutter-build /targets/Example.apk rea inspect-dart-aot /targets/Example.apk rea inspect-dart-aot /targets/Example.apk --abi armeabi-v7a ``` The default ABI preference is arm64-v8a, then x86_64, x86, armeabi-v7a. The output includes the snapshot hash, per-ABI engine SHA-256 and GNU build IDs, the four `_kDart*Snapshot*` exported symbols, and a bounded string-pool projection. That projection lists `package:` URIs (effectively a dependency inventory) and `dart:` SDK URIs. Release engines often strip the `Dart VM version` string, and REA reports that as `null` rather than guessing. REA does not do the hash-to-SDK lookup itself. **blutter** goes further by compiling the Dart AOT runtime for the detected version and using it to read the snapshot. Its limits are significant: Android `libapp.so` only, **arm64 only**, recent Dart versions only. It needs a C++20 compiler (g++>=13 or Clang>=16), and the author tests on Debian sid/trixie. ``` python3 blutter.py path/to/app/lib/arm64-v8a out_dir python3 blutter.py path/to/app/lib/arm64-v8a out_dir --rebuild ``` Extract the APK's `lib` directory first. The script detects the Dart version from the engine and, if no matching blutter executable exists, checks out the Dart source and builds one. `--rebuild` forces a rebuild after `git pull`. Outputs are `asm/*` (libapp assembly with symbols), `pp.txt` (all Dart objects in the object pool), `objs.txt` (a nested object dump) and `blutter_frida.js` (a Frida script template for the app, see [[entities/frida]]). The author's TODO list says obfuscated apps still miss many functions, iOS binaries aren't supported, and APK or IPA input isn't supported yet. ## Key Parameters | Item | Value | |---|---| | Go pclntab support (GoReSym) | Go 1.2 and later. Types from Go 1.5 | | Go amd64 goroutine register | R14 | | Rust v0 prefix | `_R` | | Rust mangling flag | `-C symbol-mangling-version` | | cargo-auditable section | `.dep-v0` / `__DATA,.dep-v0` | | Dart snapshot magic | `f5 f5 dc dc` (hash at +20 bytes) | | blutter target | Android arm64 `libapp.so`, recent Dart | | blutter toolchain | g++>=13 or Clang>=16 | ## When To Use - **Any Go binary:** run GoReSym before opening a disassembler, then import the names. If type parsing fails on a stripped binary, find the real Go version (for example from build info) and pass it with `-v`. - **Go supply-chain or provenance questions:** read build info (`inspect-go-binary`) instead of reversing code. - **Rust:** demangle everything first. Check for `.dep-v0` to get an exact crate list before you try to identify library code by hand. - **Flutter:** identify the snapshot hash and engine first. Use blutter for arm64 Android with a recent Dart. For other cases (other ABIs, iOS, older SDKs), fall back to native analysis of `libapp.so` or JEB's Dart support (see [[syntheses/choosing-a-disassembler]]). APK handling itself is covered in [[syntheses/android-apk-analysis]]. ## Risks & Pitfalls - **Wrong Go version, wrong types.** GoReSym warns that type parsing fails when the `-v` version is inaccurate. - **Absence proves little.** REA treats `build_info: null` as "no record found", not "not Go", and a missing `.dep-v0` doesn't mean the binary has no dependencies. Stripping, old toolchains and deliberate removal all erase metadata. - **Embedded metadata is unauthenticated.** Compiler strings, module versions and crate lists are just file content. They don't authenticate the compiler, the dependencies or the commit. - **Fat Mach-O.** REA's Go and Rust readers need a thin slice. Universal binaries aren't interpreted as one architecture, so extract a slice first ([[concepts/executable-formats]]). - **Platform-ABI assumptions** produce misleading Go pseudocode. Fix calling conventions before trusting argument counts. - **Dart class-like tokens are byte patterns**, not deserialized classes. Treat REA's `class_like_tokens` as hints. - **blutter's Frida template is for apps you're permitted to test.** Instrumentation runs the target (see [[concepts/legal-and-ethics]]). ## Related Concepts - [[concepts/dotnet-and-nativeaot]]: metadata recovery for another AOT-compiled runtime - [[concepts/decompilation-concepts]]: fixing prototypes and calling conventions - [[entities/gdb-and-pwndbg]]: pwndbg's Go commands - [[entities/ida-pro]] and [[entities/ghidra]]: where recovered symbols get applied - [[syntheses/android-apk-analysis]]: getting `lib//` out of an APK - [[entities/rea]]: build-info, cargo-auditable and Flutter triage tools - [[syntheses/triage-an-unknown-binary]] ## Sources - `raw/web_community-abi-internal-md.md` - `raw/github_doc-readme-md-10.md` - `raw/github_doc-docs-go-binaries-md.md` - `raw/github_doc-docs-tutorials-go-debugging-md.md` - `raw/web_community-symbol-mangling-the-rustc-book.md` - `raw/web_community-v0-symbol-format-the-rustc-book.md` - `raw/github_doc-docs-rust-binaries-md.md` - `raw/github_doc-readme-md-11.md` - `raw/github_doc-docs-flutter-analysis-md.md` --- title: "Legal and Ethical Boundaries of Reverse Engineering" type: concept tags: [legal, ethics, dmca, 1201, cdpa, interoperability, security-research, scope, authorization] created: 2026-10-16 updated: 2026-10-16 confidence: medium sources: ["raw/github_doc-disclaimer-md.md", "raw/github_doc-security-md.md", "raw/web_community-17-u-s-code-1201-circumvention-of-copyright-protection-syste.md", "raw/web_community-rulemaking-proceedings-under-section-1201-of-title-17-u-s-co.md", "raw/web_community-copyright-designs-and-patents-act-1988.md", "raw/web_community-faq-jeb-decompiler.md", "raw/github_doc-doc-faq-md.md", "raw/github_doc-readme-md-21.md"] --- # Legal and Ethical Boundaries of Reverse Engineering > **Not legal advice.** This page explains the statutory hooks that practitioners cite and the boundaries this wiki keeps. Whether a particular project is lawful depends on your jurisdiction, the licence you accepted, and the facts. If the answer matters, ask a lawyer. ## Definition Reverse engineering (RE) is recovering how software works from its compiled form: reading headers, disassembling, decompiling, tracing at runtime, or capturing traffic. Most of it is ordinary engineering work. Legal risk shows up in three places: 1. **Copyright.** Decompiling makes copies and derived representations of someone else's code. 2. **Anti-circumvention law.** In the US this is 17 U.S.C. § 1201 (the DMCA). Getting past a technical protection measure can be unlawful on its own, even when no copyright infringement follows. 3. **Contracts and access law.** Licence terms, terms of service, and computer-misuse statutes control what you may run, attach to, or intercept. This wiki covers **legitimate analysis only**: interoperability, security and vulnerability research, malware analysis and defence, CTFs and education, software preservation, and auditing software you own or are authorized to examine. The REA project draws the same line in its responsible-use statement. ## How It Works ### US: 17 U.S.C. § 1201 Section 1201(a)(1)(A) forbids circumventing a technological measure that effectively controls access to a copyrighted work. Two statutory exceptions matter most to RE: | Subsection | Who it covers | Conditions (paraphrased) | |---|---|---| | **1201(f) Reverse engineering** | Someone who has lawfully obtained the right to use a copy of a program | You may circumvent only to identify and analyse the elements needed for **interoperability** of an *independently created* program, only where that information was not already readily available to you, and only as far as the acts are not infringement. (f)(2) allows building the tools needed for this. (f)(3) allows sharing the results only to enable interoperability. (f)(4) defines interoperability as programs exchanging information and using what was exchanged. | | **1201(j) Security testing** | Someone testing a computer, system or network | "Security testing" means access **with the authorization of the owner or operator**, solely for good-faith testing, investigating or correcting a security flaw. The act must not infringe copyright or break other law, and the statute names 18 U.S.C. § 1030 (the CFAA). Factors: whether findings were used only to improve the owner's security or shared directly with the developer, and whether they were handled in a way that does not enable infringement, privacy violations or security breaches. | Two practical consequences: - **1201(f) is narrow.** It covers interoperability, not "understanding the app" in general, and it does not apply once the information is readily available, for example in public documentation or an SDK. - **1201(j) depends on authorization.** Without the owner's or operator's permission there is no security-testing exemption. **Temporary exemptions.** Section 1201(a)(1)(B)–(C) has the Librarian of Congress, on the Register of Copyrights' recommendation, grant class-based exemptions in three-year cycles. The Copyright Office is running the **tenth triennial** proceeding now. Renewed exemptions will run **October 2027 to October 2030**, and past final rules go back to 2000. This page does not reproduce the current exemptions, so check copyright.gov/1201 for what applies today. ### UK: Copyright, Designs and Patents Act 1988, s50B (Decompilation) Section 50B lets a **lawful user** of a program written in a low-level language convert it to a higher-level form, and make incidental copies while doing so, only when: - decompiling is **necessary** to get the information needed to create an independent program that can operate with the decompiled program or another program (the "permitted objective"), and - the information is not used for anything else. The conditions are **not** met if you: - already had the information readily available, - decompile more than you need for the objective, - give the information to people who don't need it for the objective, or - use it to build a program substantially similar in expression to the original, or to do any other act restricted by copyright. Under s50B(4), contract terms that try to prohibit a permitted decompilation are **void** (via s296A). The section was inserted with effect from 1 January 1993. ### Authorization is per operation REA's disclaimer makes a point that applies to any toolchain. Permission to inspect an artifact does not automatically extend to **executing** it, **intercepting** its traffic, **changing a device**, or **interacting with another party's system**. Having a public download, a file on disk, or an open debugging port does not by itself give you permission for every operation. Static reading, runtime instrumentation, and network capture are separate questions, and each can need its own authorization. You are also responsible for credentials, personal data, and captured traffic you collect. ## Key Parameters Questions to answer before you start: | Question | Why it matters | |---|---| | Did you lawfully obtain the copy and accept its licence? | Both 1201(f) and s50B start from a *lawful user* | | What is the objective: interoperability, security fix, malware defence, education? | The exceptions are purpose-bound | | Is the information already available (docs, SDK, spec)? | Ready availability defeats both 1201(f) and s50B | | Do you have the owner's or operator's authorization for testing? | Required for 1201(j). Also needed for runtime, network, and device work | | Who will see the results? | s50B limits recipients to those who need the information; 1201(f)(3) limits sharing to enabling interoperability | | Are you using commercial tools within their licence? | See "Tool licences" below | ### Tool licences Commercial analysis tools have their own terms. Non-OEM JEB licences, for example, are subscription-based, with keys derived from machine identifiers. An expired licence still opens existing projects but cannot create new ones, and floating and OEM licences have their own rules. REA states that IDA Pro and the Hex-Rays decompilers, Hopper, JEB and other proprietary tools must be obtained legally. An open-source bridge or API does **not** grant extra user, machine, automation, hosting, or output-sharing rights. Cracked copies, stolen keys, and unauthorized key sharing are out of bounds. Getting source-like output from a decompiler also does not give you rights to the original program or to the output. ## When To Use Read this page: - before analysing third-party software for interoperability or vulnerability research, - before any runtime, interception, or device step. Static authorization may not cover these. See [[syntheses/dynamic-analysis-workflow]], [[syntheses/network-captures-and-protocols]], and [[syntheses/android-apk-analysis]], - before handling live malware. See [[syntheses/malware-triage]], - before publishing findings, decompiled code, or tools. ### What this wiki deliberately does not cover These topics are out of scope on every page, whatever the stated purpose: - circumventing DRM, licence checks, activation, or other technical protection measures, - anti-cheat bypass, game cheats, or tampering with online services, - piracy, or reproducing proprietary code and assets, - malware development, AV/EDR evasion, or packer and crypter authoring, - certificate-pinning bypass recipes, - getting around authentication, bot protection, or access controls on systems outside your testing authorization. Dual-use techniques such as Frida hooking, apktool rebuilds, and TLS interception appear only in the context of an app or device you are permitted to test. Tools that *detect* protections (for example DiE, which reports DRM and licensing markers) are described for triage only. ## Risks & Pitfalls - **Assuming 1201(f) covers curiosity.** It covers interoperability of an independently created program, nothing broader. - **Testing without authorization.** 1201(j) requires the owner's or operator's permission and does not override the CFAA or other law. - **Over-sharing.** s50B bars giving the information to anyone who does not need it for the permitted objective, and 1201(f)(3) allows sharing only to enable interoperability. Publishing decompiled code goes well beyond them. - **Treating local work as risk-free.** Running a target can still affect accounts, devices, and services. REA notes that local operation does not guarantee executed targets or third-party tools have no external effects. - **Treating analysis tooling as a sandbox.** REA's security policy says its authenticated Ghidra and Hopper bridges are **not a sandbox**: opening an untrusted binary hands parsing to the provider with your user's permissions. Isolation is your job. - **Security tools trip antivirus.** capa ships rules that resemble malware features, and its PyInstaller packaging can alert AV/EDR. Download releases from the project's official release page, or build it yourself. - **Leaking private material in bug reports.** REA asks for private vulnerability reports through the repository's Security tab, without proprietary binaries, Ghidra projects, Hopper documents, or capability tokens. - **Jurisdiction.** Only the US and UK provisions are covered here. EU member states, contract law, export controls, and privacy law are not covered. ## Related Concepts - [[syntheses/overview]]: what RE covers and where to start - [[syntheses/malware-triage]]: safe handling and defensive analysis - [[syntheses/dynamic-analysis-workflow]]: why execution needs its own authorization and isolation - [[syntheses/android-apk-analysis]]: dual-use rebuild and proxy steps, framed for permitted testing - [[entities/rea]]: the agent toolkit whose responsible-use terms are quoted above ## Sources - `raw/github_doc-disclaimer-md.md` - `raw/github_doc-security-md.md` - `raw/web_community-17-u-s-code-1201-circumvention-of-copyright-protection-syste.md` - `raw/web_community-rulemaking-proceedings-under-section-1201-of-title-17-u-s-co.md` - `raw/web_community-copyright-designs-and-patents-act-1988.md` - `raw/web_community-faq-jeb-decompiler.md` - `raw/github_doc-doc-faq-md.md` - `raw/github_doc-readme-md-21.md` --- title: "WebAssembly Modules" type: concept tags: [webassembly, wasm, wat, wabt, wasm2wat, wasm-objdump, jeb, decompilation] created: 2026-10-16 updated: 2026-10-16 confidence: medium wabt_version: "1.0.42" sources: ["raw/web_community-overview-webassembly-3-0-2026-10-13.md", "raw/web_community-modules-webassembly-3-0-2026-10-13.md", "raw/github_doc-readme-md-14.md", "raw/github_doc-docs-doc-wasm2wat-1-html.md", "raw/github_doc-docs-doc-wasm-objdump-1-html.md", "raw/github_doc-docs-doc-wasm-validate-1-html.md", "raw/github_doc-docs-doc-wasm-strip-1-html.md", "raw/github_doc-docs-doc-wasm2c-1-html.md", "raw/github_doc-docs-doc-wasm-interp-1-html.md", "raw/web_community-webassembly-analysis-jeb-decompiler.md", "raw/github_doc-docs-wasm-artifacts-md.md", "raw/web_community-source-map-format-specification.md"] --- # WebAssembly Modules A WebAssembly (Wasm) module is a compact, validated binary for a stack-based virtual machine. In practice you analyse one in three moves: validate it and list its sections and imports/exports, decode it to the text format (WAT) to read the code, and decompile it to C-like pseudocode once the code is too large to read as WAT. WABT handles the first two. JEB Pro decompiles; `wasm2c` gives a mechanical C translation as an alternative. ## Definition The core specification (WebAssembly 3.0, spec build dated 2026-10-13) describes: - **Values.** Four basic number types: 32- and 64-bit integers and IEEE 754 floats. Integers have no signedness. Each operation decides whether to read them as signed (two's complement) or unsigned. 32-bit integers double as booleans and memory addresses. - **Instructions.** A stack machine: simple instructions pop operands and push results on an implicit operand stack. Control flow is **structured** (well-nested blocks, loops and branches), so there are no arbitrary jumps to recover. - **Functions** take and return sequences of values, can declare mutable locals that act like virtual registers, and share an implicit call stack that code can't access directly. - **Tables** hold opaque references selected by a dynamic index. This is how indirect calls and function pointers are emulated. - **Linear memory** is one contiguous, mutable array of raw bytes, accessed by load and store instructions. Data-section initializers are copied into it. - **Modules** define functions, tables, memories and globals. They can **import** definitions by a module/name pair and **export** them under names. The **embedder** (browser, Node, a standalone runtime) supplies the imports. That host boundary is where most of a module's behaviour becomes visible. - **Traps** abort execution immediately and are reported to the host. Wasm code can't catch them. ## How It Works ### Binary layout A module starts with the 4-byte magic `\0asm` (`0x00 0x61 0x73 0x6D`) and a version field. The current binary version is 1. Sections follow, each made of a one-byte id, a `u32` byte length, and the contents. Every section is optional. Custom sections may appear anywhere. All other sections appear at most once, in a prescribed order that doesn't always match their numeric ids. | Id | Section | Analyst use | |---|---|---| | 0 | custom | Debug names, `sourceMappingURL`, toolchain markers such as `dylink` | | 1 | type | Function signatures | | 2 | import | Host API surface: the first thing to read | | 3 | function | Type index of each defined function | | 4 | table | Indirect-call tables | | 5 | memory | Linear memory limits | | 6 | global | Globals | | 7 | export | Entry points the host can call | | 8 | start | Function run at instantiation | | 9 | element | Table initializers (indirect-call targets) | | 10 | code | Function bodies | | 11 | data | Memory initializers: strings and constants live here | | 12 | data count | Count of data segments | | 13 | tag | Exception tags | Function signatures and bodies are split between the function and code sections so engines can compile in parallel and while streaming. Their counts must match. Errors inside a custom section's data must not invalidate the module, which is why tools can offer to ignore custom-section errors. A module can point to a source map with a custom section named `sourceMappingURL` whose content is the URL. The source map spec says a module must not carry two of them. ### WABT: validate, inspect, decode WABT (the WebAssembly Binary Toolkit) aims for full spec fidelity, including 1:1 text/binary round-trips with no instruction changes. Unlike Binaryen, it is not an optimizer. | Task | Command | |---|---| | Validate | `wasm-validate test.wasm` | | Section headers + details (imports, exports, etc.) | `wasm-objdump -h -x module.wasm` | | Disassemble function bodies | `wasm-objdump -d module.wasm` | | One section / raw bytes / relocations | `-j SECTION`, `-s`, `-r` | | Binary to text | `wasm2wat test.wasm -o test.wat` | | Text without embedded debug names | `wasm2wat test.wasm --no-debug-names -o test.wat` | | Text back to binary | `wat2wasm` | | C source + header | `wasm2c test.wasm -o test.c` (also writes `test.h`) | | Remove custom sections | `wasm-strip test.wasm` (`-k SECTION` keeps one) | | Size/opcode statistics | `wasm-stats` | Useful `wasm2wat` switches for reading code: - `--generate-names` gives auto-generated names to unnamed functions and types. - `-f` / `--fold-exprs` writes nested (folded) expressions where possible. - `--inline-imports` / `--inline-exports` put import and export declarations on their items. - `--ignore-custom-section-errors` gets past a damaged custom section. **Feature flags matter.** Exceptions, SIMD, multi-value, tail calls, bulk memory, reference types, memory64, multi-memory, extended-const and relaxed SIMD are on by default. Threads, function references, custom page sizes, compact imports and wide arithmetic are off by default and need `--enable-threads`, `--enable-function-references` and so on. The man pages also list `--enable-gc` and `--enable-code-metadata`. When a module that runs fine in a browser fails `wasm-validate`, try `--enable-all` before concluding it's malformed. `wasm-interp` decodes **and runs** a module (`--run-export=FUNCTION`, `--run-all-exports`, `--trace`, `--wasi` (WebAssembly System Interface) with `--env`/`--dir`). It's handy for capture-the-flag (CTF) puzzles, but it executes the code, so treat it as dynamic analysis of an untrusted sample. ### Decompiling: JEB Pro JEB Pro parses, disassembles and decompiles Wasm into C-like pseudocode on top of its native-code pipeline. It maps the module into a pseudo address space so native tooling can work with it: | Pseudo-segment | Start | Holds | |---|---|---| | `.data` | `0` | The memory section and its data initializers | | `.table` | `0x4000000` | Pointers to functions referenced from the table | | `.code` | `0x50000000` | Internal function bodies, back to back in index order | | `.globals` | `0x60000000` | Globals, treated like ordinary global variables | | `.imports` | `0x70000000` | References to imported functions and globals | JEB assumes a wasm32, little-endian environment. A `dylink` custom section in the Sections view likely means an Emscripten build with `SIDE_MODULE=1`. You can't modify code, because that would break the function index space. Documented decompiler limits: advanced global analysis is partly disabled, floating-point operations aren't converted, and memory stack frames can't be accessed or customized. Wasm 3.0 parsing arrived in JEB 5.36. SIMD instructions are wrapped as untranslated IR, `try_table` exception control flow and `br_on_null` / `br_on_non_null` aren't decompiled, and atomics (the `0xFE` table) are only partly parsed. Where JEB fits among disassemblers is covered in [[syntheses/choosing-a-disassembler]]. ### REA's offline route [[entities/rea]] inspects modules without running them, using a caller-supplied **WABT 1.0.42**. Point `REA_WABT_BIN_DIRECTORY` at a directory containing `wasm-validate`, `wasm-objdump` and `wasm2wat`: ```bash REA_WABT_BIN_DIRECTORY=/absolute/wabt/bin rea inspect-wasm-artifact \ /artifacts/module.wasm --glue_paths /artifacts/glue.js \ --candidate_paths /artifacts/other/module.wasm --format json ``` Internally it runs `wasm-validate --enable-all`, `wasm-objdump -h -x` and `wasm2wat --enable-all`. Files over 8 MiB are refused. The optional JS glue files are parsed for `.wasm` string literals to suggest which file the page loads. Those are literal associations, not proven loading. `rea compare-wasm-interfaces comparison-input.json --json` diffs the typed imports and exports of two inspected modules. REA's general `open_binary` route deliberately refuses Wasm (`wasm_requires_static_inspection`) and redirects you to this tool. The real-tool profile has been exercised on macOS arm64. Other hosts need their own verification. ## Key Parameters | Item | Value | |---|---| | Magic / version | `0x00 0x61 0x73 0x6D` / 1 | | Section ids | 0 (custom) to 13 (tag) | | Enable every proposal | `--enable-all` | | Ignore debug names on decode | `--no-debug-names` | | Synthesize names | `--generate-names` | | JEB code base address | `0x50000000` | | REA toolchain variable | `REA_WABT_BIN_DIRECTORY` (WABT 1.0.42) | ## When To Use - **First pass on any `.wasm`:** run `wasm-validate`, then `wasm-objdump -h -x`. Read the import section to see which host functions (DOM, WASI, crypto, network glue) the module depends on, and the export section to see what the host calls. - **Small modules or CTF checks:** read `wasm2wat --generate-names -f` output directly. - **Large compiled C/C++/Rust:** use a decompiler (JEB Pro) or `wasm2c` and read the C. Concepts in [[concepts/decompilation-concepts]] carry over. - **Wasm inside a web or Electron app:** recover the JS glue first ([[syntheses/javascript-and-electron-apps]]). The glue shows how imports are wired and which file actually loads. ## Risks & Pitfalls - **WAT is a decoding, not source.** REA notes that custom annotations can preserve payloads, but WAT doesn't prove the original binary layout or byte-for-byte round-trip identity. Keep the original bytes and their hash. - **Debug names can mislead.** Names embedded in the binary come from whoever produced it. Decode once with `--no-debug-names` and compare when names look too convenient. - **Disabled proposals look like corruption.** Validation errors on threads, GC or function-reference opcodes often just mean a flag is missing. - **Running is not inspecting.** `wasm-interp`, browsers and runtimes execute the module. Use an isolated environment for untrusted samples ([[syntheses/malware-triage]], [[syntheses/dynamic-analysis-workflow]]). - **Static type equality is not compatibility.** REA states that matching interface signatures don't prove runtime or ABI compatibility or that linking will succeed. ## Related Concepts - [[concepts/executable-formats]]: native containers for comparison - [[concepts/decompilation-concepts]] - [[syntheses/javascript-and-electron-apps]]: the JS that loads most modules - [[syntheses/choosing-a-disassembler]]: JEB and other options - [[entities/rea]] - [[concepts/evm-bytecode]]: another stack-machine bytecode with its own recovery tools ## Sources - `raw/web_community-overview-webassembly-3-0-2026-10-13.md` - `raw/web_community-modules-webassembly-3-0-2026-10-13.md` - `raw/github_doc-readme-md-14.md` - `raw/github_doc-docs-doc-wasm2wat-1-html.md` - `raw/github_doc-docs-doc-wasm-objdump-1-html.md` - `raw/github_doc-docs-doc-wasm-validate-1-html.md` - `raw/github_doc-docs-doc-wasm-strip-1-html.md` - `raw/github_doc-docs-doc-wasm2c-1-html.md` - `raw/github_doc-docs-doc-wasm-interp-1-html.md` - `raw/web_community-webassembly-analysis-jeb-decompiler.md` - `raw/github_doc-docs-wasm-artifacts-md.md` - `raw/web_community-source-map-format-specification.md` --- title: "Frida" type: entity tags: [frida, dynamic-instrumentation, frida-trace, frida-server, gadget, android, ios, javascript, tracing, hooking] created: 2026-10-16 updated: 2026-10-16 confidence: medium frida_version: "17.24.0" sources: ["raw/github_doc-i18n-en-docs-index-md.md", "raw/github_doc-i18n-en-docs-modes-md.md", "raw/github_doc-i18n-en-docs-installation-md.md", "raw/github_doc-i18n-en-docs-quickstart-md.md", "raw/github_doc-i18n-en-docs-bridges-md.md", "raw/github_doc-i18n-en-docs-frida-cli-md.md", "raw/github_doc-i18n-en-docs-frida-ps-md.md", "raw/github_doc-i18n-en-docs-frida-ls-devices-md.md", "raw/github_doc-i18n-en-docs-frida-kill-md.md", "raw/github_doc-i18n-en-docs-frida-trace-md.md", "raw/github_doc-i18n-en-docs-gadget-md.md", "raw/github_doc-i18n-en-docs-android-md.md", "raw/github_doc-i18n-en-docs-ios-md.md", "raw/github_doc-i18n-en-docs-best-practices-md.md", "raw/github_doc-i18n-en-docs-troubleshooting-md.md", "raw/github_issue-java-is-not-defiend.md", "raw/github_release-frida-17-24-0.md", "raw/github_doc-docs-frida-instrumentation-md.md"] --- # Frida ## Overview **Frida** is a dynamic code instrumentation toolkit. It loads a JavaScript runtime into a running program so your script can hook functions, read and write memory, enumerate modules and their imports and exports, and call native functions from inside the process. Results flow back to your host over a two-way message channel. It runs on Windows, macOS, GNU/Linux, iOS, watchOS, tvOS, Android, FreeBSD and QNX. Use Frida when you want to watch what an app does at function level (which APIs it calls, with what arguments, in what order) without stopping it at every step the way a debugger does. Typical legitimate uses from Frida's own docs: tracing an app you need to interoperate with, adding diagnostics to your own deployed software without shipping a new build, and black-box testing in-house apps. Use it on your own builds, test devices, or apps you are authorized to analyze; see [[concepts/legal-and-ethics]]. The current release is **Frida 17.24.0** (published 2026-10-16). Its GitHub release page only points to frida.re/news for details, so per-release changes are not covered here. ## Characteristics ### Modes of operation | Mode | How it gets in | When to use | |---|---|---| | **Injected** | frida-core injects the GumJS runtime as a shared library into a process you spawn, attach to, or catch at spawn. On mobile devices, `frida-server` exposes this over TCP, listening on `localhost:27042` by default | The normal case: rooted Android, jailbroken iOS, desktop processes you own | | **Embedded** | You build `frida-gadget` (a shared library) into the program | When injection is not possible, e.g. jailed iOS or non-rooted Android, using your own debuggable build | | **Preloaded** | Gadget configured to load a script from disk on its own, like an `LD_PRELOAD` for JavaScript | Autonomous instrumentation with no host connection | The core (Gum) is written in C; scripts run in QuickJS by default, and `frida-trace` accepts `--runtime {qjs,v8}`. Bindings exist for Python, Node.js, Swift, .NET, QML, Go and C. ### The Frida 17 bridge change From Frida 17.0.0, the **Java, ObjC and Swift bridges are no longer bundled** with the GumJS runtime. Only the REPL (`frida`) and `frida-trace` still ship all three bridges for compatibility. A script you load through the Python (or other) API that calls `Java.perform()` fails with `ReferenceError: 'Java' is not defined` until you bundle the bridge: ``` $ frida-create -t agent $ npm install $ npm install frida-java-bridge ``` Then import it at the top of the TypeScript agent (`import Java from "frida-java-bridge";`; likewise `frida-objc-bridge` and `frida-swift-bridge`) and either compile with `frida-compile script.ts -o _agent.js -S -c` or build from Python with `frida.Compiler()` and `compiler.build("script.ts", project_root=...)` before `session.create_script(bundle)`. Putting a bare `import` into an inline Python script string does not work; it must go through the compiler. The same rule applies to Gadget's autonomous script mode. ## How to Use ### Install and smoke-test ``` $ pip install frida-tools ``` Requirements: Python 3.x on Windows, macOS or GNU/Linux. To check it works, start a throwaway process (`cat`, or a copy at `/tmp/cat` on macOS, which rejects attaching to system binaries) and attach to it from a Python script that calls `frida.attach("cat")`. On GNU/Linux, attaching to non-child processes needs `sudo sysctl kernel.yama.ptrace_scope=0`. ### The CLI tools | Tool | Use it to | Example | |---|---|---| | `frida` | Open the REPL attached to a process, load a script, live-reload it | `frida -U Safari`; `frida Calculator -l calc.js` (`%reload` reloads; `--debug` opens a Node.js-compatible debugger on port 5858) | | `frida-ps` | List processes or apps on a device | `frida-ps -U` (USB processes), `frida-ps -Ua` (running apps), `frida-ps -Uai` (installed apps), `frida-ps -D ` | | `frida-ls-devices` | List local, USB and remote devices with their IDs | `frida-ls-devices` | | `frida-trace` | Auto-generate hooks for matching functions and log calls | see below | | `frida-kill` | Kill a process on a device | `frida-kill -D ` | In the REPL, tab completion lists the JavaScript API objects (`Interceptor`, `Memory`, `Module`, `Process`, `NativeFunction`, `Stalker`, `ObjC`, `Dalvik` and so on), which is a quick way to explore a live process. ### Tracing with frida-trace `frida-trace` generates a handler file per matched function (`onEnter`/`onLeave`), prints each call, and reloads the handlers when you edit them. It is the fastest way to answer "does this app call X, and when?". | Flag | Meaning | |---|---| | `-U` / `-D ID` / `-H HOST` | Target a USB device, a device by ID, or a remote frida-server | | `-f TARGET` | Spawn the program or app | | `-n NAME` / `-N IDENTIFIER` / `-p PID` | Attach by name, app identifier or PID | | `-i` / `-x` `[MODULE!]FUNCTION` | Include or exclude functions by glob | | `-I` / `-X MODULE` | Include or exclude whole modules | | `-a MODULE!OFFSET` | Trace an unexported function at an offset | | `-m` / `-j` / `-y` | ObjC methods, Java methods, Swift functions | | `-d`, `--decorate` | Add the module name to each log line | | `-o OUTPUT` | Write messages to a file (useful as evidence) | | `-O FILE` | Read more options from a file | ``` $ frida-trace -i "recv*" -i "read*" # network reads $ frida-trace -U -i open -N com.android.chrome # open() on Android $ frida-trace -U -i "Java_*" # JNI entry points $ frida-trace -p 1372 -i "msvcrt.dll!*mem*" # one module on Windows $ frida-trace -p 1372 -a "libjpeg.so!0x4793c" # an unexported function ``` Edit a generated handler to print real arguments, for example `args[0].toInt32()` or `args[0].readUtf8String()`. Store per-call state on `this` in `onEnter` so `onLeave` can read it. ### Android setup (test device or emulator) Frida's tutorial uses a rooted device; it recommends a Pixel or Nexus on current official software, or a Google Android 9 arm/arm64 emulator image (x86 has had less testing). You need `adb` from the Android SDK. ``` $ adb shell getprop ro.product.cpu.abilist # pick the matching frida-server build $ unxz frida-server.xz $ adb root # might be required $ adb push frida-server /data/local/tmp/ $ adb shell "chmod 755 /data/local/tmp/frida-server" $ adb shell "/data/local/tmp/frida-server &" $ adb devices -l $ frida-ps -U ``` Run frida-server as root. If `adb root` says `adbd cannot run as root in production builds`, prefix commands with `su -c`. When writing your own Python tools, use `frida.get_usb_device().attach()` in place of `frida.attach()`. Without root, Frida's docs mention embedding Gadget into the app or using a debugger. For the wider APK workflow see [[syntheses/android-apk-analysis]]. ### iOS setup - **Jailbroken device**: add the `https://build.frida.re` repository in Cydia, install the `Frida` package, then `frida-ps -U` over USB (usbmuxd integration makes `-U` work on Linux too). Example trace: `frida-trace -U -i "CCCryptorCreate*" Twitter`. - **Non-jailbroken device**: Frida instruments **debuggable** apps (your own development builds) and injects Gadget automatically. It wants iOS 13 or newer (older is experimental), a mounted Developer Disk Image (Xcode mounts it, or use `ideviceimagemounter`), and the latest Gadget in the cache, on macOS `~/.cache/frida/gadget-ios.dylib`. ### Gadget Gadget starts when the dynamic linker runs its constructor. You load it by adding it to your program's build, linking it in, or with `LD_PRELOAD`/`DYLD_INSERT_LIBRARIES`. A config file named like the library with a `.config` extension (on Android, `libgadget.config.so` next to `libgadget.so`, because the package manager only copies `lib*.so` files) selects one of four interactions: | Interaction | Behaviour | |---|---| | `listen` (default) | frida-server-compatible endpoint on `127.0.0.1:27042`; the process appears as `Gadget` / `re.frida.Gadget`. `on_load: "wait"` blocks startup until you attach or resume; set `"resume"` to let it boot | | `connect` | Joins a `frida-portal` cluster (default port `27052`) | | `script` | Runs a script from disk before the entry point; `init(stage, parameters)` and `dispose()` hooks via `rpc.exports` | | `script-directory` | Loads scripts from a directory | Other root keys: `teardown` (`minimal` or `full`), `runtime` (`default`, `qjs`, `v8`), and `code_signing` (`optional` or `required`; `required` lets it run on jailed iOS without a debugger but disables the Interceptor API). Listen mode accepts `token` and `certificate` for authentication and TLS; keep the default loopback address unless you need remote access. ### Common failures | Symptom | Likely cause | |---|---| | `ValueError: ambiguous name` | Several processes share the name; attach by PID | | `PTRACE_ATTACH failed: 1` | No permission, or `ptrace_scope` restricts non-child attach | | `task_for_pid ... failure` on macOS | Frida not signed correctly, or a permission prompt you cannot answer over SSH | | `'Java' is not defined` | Frida 17 bridge not bundled (see above) | Two scripting pitfalls from the best-practices doc: writing a longer string over an argument can overflow the buffer, so allocate a new one with `Memory.allocUtf8String()` and keep it alive on `this`; and cache `args[n]` in a local when you read it more than once. ### Through REA REA exposes Frida device and process listing, attach or spawn sessions, script loading and resume as MCP tools and the one-shot `instrument-with-frida` CLI. It does not install frida-server, starts spawned processes paused so scripts load first, caps captured messages at 16 MiB, and records the script's path and SHA-256 rather than its source. See [[entities/rea]]. ## Related Entities - [[syntheses/dynamic-analysis-workflow]]: Frida versus a debugger, tracing or record/replay. - [[entities/gdb-and-pwndbg]]: breakpoint-level inspection when you need to stop the process. - [[syntheses/android-apk-analysis]]: where Frida fits in an APK investigation. - [[entities/rea]]: agent-driven Frida sessions with evidence capture. - [[syntheses/troubleshooting]]: more attach and spawn failures. ## Sources - `raw/github_doc-i18n-en-docs-index-md.md` - `raw/github_doc-i18n-en-docs-modes-md.md` - `raw/github_doc-i18n-en-docs-installation-md.md` - `raw/github_doc-i18n-en-docs-quickstart-md.md` - `raw/github_doc-i18n-en-docs-bridges-md.md` - `raw/github_doc-i18n-en-docs-frida-cli-md.md` - `raw/github_doc-i18n-en-docs-frida-ps-md.md` - `raw/github_doc-i18n-en-docs-frida-ls-devices-md.md` - `raw/github_doc-i18n-en-docs-frida-kill-md.md` - `raw/github_doc-i18n-en-docs-frida-trace-md.md` - `raw/github_doc-i18n-en-docs-gadget-md.md` - `raw/github_doc-i18n-en-docs-android-md.md` - `raw/github_doc-i18n-en-docs-ios-md.md` - `raw/github_doc-i18n-en-docs-best-practices-md.md` - `raw/github_doc-i18n-en-docs-troubleshooting-md.md` - `raw/github_issue-java-is-not-defiend.md` - `raw/github_release-frida-17-24-0.md` - `raw/github_doc-docs-frida-instrumentation-md.md` --- title: "GDB and pwndbg" type: entity tags: [gdb, pwndbg, debugger, gdbserver, remote-debugging, breakpoints, watchpoints, memory-inspection, heap-inspection, dynamic-analysis, linux] created: 2026-10-16 updated: 2026-10-16 confidence: medium pwndbg_version: "2026.09.15" sources: ["raw/web_community-starting-debugging-with-gdb.md", "raw/web_community-attach-debugging-with-gdb.md", "raw/web_community-breakpoints-debugging-with-gdb.md", "raw/web_community-set-watchpoints-debugging-with-gdb.md", "raw/web_community-continuing-and-stepping-debugging-with-gdb.md", "raw/web_community-memory-debugging-with-gdb.md", "raw/web_community-registers-debugging-with-gdb.md", "raw/web_community-backtrace-debugging-with-gdb.md", "raw/web_community-signals-debugging-with-gdb.md", "raw/web_community-core-file-generation-debugging-with-gdb.md", "raw/web_community-server-debugging-with-gdb.md", "raw/web_community-connecting-debugging-with-gdb.md", "raw/github_doc-readme-md-4.md", "raw/github_doc-docs-setup-md.md", "raw/github_doc-docs-features-md.md", "raw/github_doc-docs-commands-context-context-md.md", "raw/github_doc-docs-commands-memory-vmmap-md.md", "raw/github_doc-docs-commands-memory-telescope-md.md", "raw/github_doc-docs-commands-memory-search-md.md", "raw/github_doc-docs-commands-memory-xinfo-md.md", "raw/github_doc-docs-commands-memory-hexdump-md.md", "raw/github_doc-docs-commands-glibc-heap-heap-md.md", "raw/github_doc-docs-commands-glibc-heap-bins-md.md", "raw/github_doc-docs-commands-glibc-heap-arena-md.md", "raw/github_doc-docs-commands-glibc-heap-vis-heap-chunks-md.md", "raw/github_doc-docs-commands-start-attachp-md.md", "raw/github_doc-docs-commands-start-entry-md.md", "raw/github_doc-docs-reverse-engineering-tools-md.md"] --- # GDB and pwndbg ## Overview **GDB** is the GNU debugger: you run or attach to a process, stop it at chosen points, and look at its memory, registers and call stack to understand what it is actually doing. It debugs native programs locally and can also drive a program on another machine through **gdbserver**. **pwndbg** is a Python plug-in for GDB (and, experimentally, LLDB) that replaces hand-typed inspection such as `x/30gx $rsp` with richer views: a context panel printed at every stop, an annotated memory map, recursive pointer dereferencing, memory search and allocator-state views. The packaged release referenced in its setup docs is **pwndbg 2026.09.15**. Use this page to understand program behaviour at runtime. To decide whether a debugger is the right tool at all (versus Frida instrumentation, tracing or record/replay), see [[syntheses/dynamic-analysis-workflow]]. ## Characteristics | Aspect | GDB | pwndbg | |---|---|---| | Role | Core debugger: run, attach, stop, step, inspect, core files, remote targets | Inspection layer on top of GDB/LLDB | | Requirements | Native OS support for processes (attach does not work on bare-board targets without an OS) | Python 3.10+ and GDB 12.1+ for `pwndbg-gdb`; Python 3.12+ and LLDB 19+ for the experimental `pwndbg-lldb` | | Remote | `target remote` / `target extended-remote` over serial, Unix socket, TCP, UDP or a pipe | Works over the same remote connection; its docs single out Android phones over remote GDB | | Heap views | None built in beyond raw memory | glibc malloc, jemalloc, and the Linux buddy and SLUB allocators | | Other targets | — | qemu-user (QEMU 8.1+, vFile API needed for `vmmap`), qemu-system (QEMU 6.2+), Mach-O on macOS via LLDB only | When REA drives GDB for an agent, its persistent GDB sessions and the one-shot `rea debug-with-gdb` command run only on Linux; macOS lacks its descriptor verification and Windows is unsupported (see [[entities/rea]]). ## How to Use ### Start or attach | Goal | Command | Notes | |---|---|---| | Start under the debugger | `run` (`r`), with program arguments after it | Arguments go through `/bin/sh` (or `$SHELL`) unless you `set startup-with-shell off` | | Stop at `main` | `start` | A temporary breakpoint on the main procedure, then `run`. C++ static constructors may run first | | Stop at the very first instruction | `starti` | Use when you need the startup/elaboration phase | | Stop at the ELF entry point (pwndbg) | `entry` | Not always the first executed instruction; use `starti` for that | | Inject an environment variable for one run | `set exec-wrapper env 'LD_PRELOAD=libtest.so'` then `run` | Local debugging only; not DJGPP, Cygwin or Windows | | Attach to a running process | `attach ` | You need permission to signal the process. GDB stops it first; `continue` to let it run | | Attach by name (pwndbg) | `attachp ` | Looks up the PID via `pidof`, then falls back to partial matches from `ps -eo pid,args`; GDB only | | Release it | `detach` | The process keeps running independently | | Snapshot a live process | `gcore [file]` | Default name `core.`; implemented on GNU/Linux, FreeBSD, Solaris and S390 | If startup itself crashes with `During startup program terminated with signal SIGSEGV`, the shell or exec-wrapper crashed, not your program; check your shell's non-interactive init file or turn off `startup-with-shell`. Do not pipe the debuggee's output to another program; GDB may end up debugging the wrong process. When attaching, `set exec-file-mismatch ask|warn|off` controls what happens if the loaded file differs from the running one (compared by build ID where available); the default is `ask`. ### Stop where it matters - **Breakpoints** (`break`) stop at a line number, function name or exact address. Each gets a number; enable, disable and delete take single numbers or ranges such as `5-7`. - **Watchpoints** stop when data changes, so you don't have to guess where the write happens. `watch foo` breaks on writes that change the value; `rwatch` breaks on reads; `awatch` on reads or writes. To watch a raw address, dereference it: `watch 0x600850` is refused as a constant, `watch *(int *) 0x600850` works. `-l`/`-location` watches the memory an expression resolves to rather than respecting variable scope. - **Catchpoints** stop on events such as C++ exceptions or library loads; `catch signal` stops on signals. Hardware watchpoints are fast and report the exact instruction that changed the value. If GDB has to fall back to software watchpoints, it single-steps the program (hundreds of times slower) and reports the change at the next statement. `rwatch` and `awatch` only work in hardware. Too many hardware watchpoints surface only on resume as `Could not insert watchpoint`; delete or disable some. Wide values (for example an 8-byte double on a target that watches at most 4 bytes) may not fit a hardware watchpoint. Signals: by default GDB passes benign signals such as `SIGALRM` through and stops on error signals. `info signals` shows the table; `handle nostop noprint` changes it (keywords `stop`, `nostop`, `print`, `noprint`, among others). `SIGINT` and `SIGTRAP` belong to GDB and are excluded from `handle all`. ### Step through code | Command | Moves by | Calls | |---|---|---| | `step` / `s` | Source line | Enters functions that have line info | | `next` / `n` | Source line | Runs calls without stopping | | `stepi` / `si` | One machine instruction | Enters calls | | `nexti` / `ni` | One machine instruction | Runs over calls | | `finish` / `fin` | Until the selected frame returns | Prints the return value | | `until` / `u` | Past the current line, in this frame | Useful to leave a loop | | `advance ` | To a location, which may be in another frame | — | | `continue` / `c` | Until the next stop | `continue N` ignores the current breakpoint N more times | `step` silently runs through functions compiled without debug info; on stripped code use `stepi`, or `set step-mode on` so `step` stops at the first instruction of such functions. When single-stepping instructions, `display/i $pc` shows the next instruction at every stop. ### Inspect memory, registers and the stack - **Memory**: `x/nfu addr`. `n` is a count (negative reads backwards), `f` a format (`x`, `d`, `u`, `o`, `t`, `a`, `c`, `f`, `s`, `i`), `u` a unit (`b`, `h`, `w`, `g`). Examples from the manual: `x/4xw $sp` shows four words above the stack pointer in hex; `x/5i $pc-6` disassembles around the current instruction, marked with `=>`. After an `x`, `$_` holds the last address and `$__` its contents. `compare-sections -r` checks the loaded read-only sections against the file, to see whether the program has corrupted its own read-only sections. - **Registers**: `info registers` (general registers in the selected frame), `info all-registers` (adds floating-point and vector). `$pc`, `$sp`, `$fp` and `$ps` work as portable names, so `p/x $pc` and `x/i $pc` work on most machines. Register values are relative to the selected frame; select `frame 0` to see true hardware contents. Caller-saved registers in outer frames may print ``. - **Backtraces**: `bt` (alias `where`), `bt 3` for the innermost three frames, `bt -full` to add locals, and `thread apply all backtrace` for every thread, which is handy on a multi-threaded core dump. Optimised builds show `` arguments. `set backtrace past-main on` continues into startup code. ### Debug remotely with gdbserver Run the program on the target under `gdbserver`, keep an unstripped copy with symbols on the host, and connect: ``` target> gdbserver host:2345 ./prog args host$ gdb ./prog (gdb) set sysroot /path/to/target/libs (gdb) target remote target-ip:2345 ``` - Attach on the target instead with `gdbserver --attach :2345 `, or by name with `` gdbserver --attach :2345 `pidof prog` ``. - Over SSH without opening a port: `(gdb) target remote | ssh -T hostname gdbserver - hello`. - `target remote` mode does not support `run` or `attach`, and gdbserver exits when the program exits. `target extended-remote` (optionally with `gdbserver --multi`) stays connected so you can rerun or attach; end it with `monitor exit`. - `--once` stops listening after the first connection; `--debug` and `monitor set debug on` add diagnostics. - Don't use `load` in `target remote` mode; the program is already on the target. **gdbserver has no built-in security.** Anyone who connects gets the privileges of the user running it, so never expose it on a public network. ### Install pwndbg The recommended path is the install script, which provides a `pwndbg` binary you use like `gdb`: ``` curl --proto '=https' --tlsv1.2 -LsSf 'https://install.pwndbg.re' | sh -s -- -t pwndbg-gdb # system-wide curl --proto '=https' --tlsv1.2 -LsSf 'https://install.pwndbg.re' | sh -s -- -t pwndbg-gdb -u # current user ``` Other routes in the setup docs: `uv tool install git+https://github.com/pwndbg/pwndbg[gdb,lldb]`, Homebrew (`brew install pwndbg/tap/pwndbg-gdb`), Nix, distro package files named for 2026.09.15 (for example `apt install ./pwndbg_2026.09.15_amd64.deb`), or the classic setup that appends `source $(uv tool dir)/pwndbg/share/pwndbg/gdbinit.py` to `~/.gdbinit` so your system `gdb` loads it. Distro repository packages are not officially supported for bug reports. ### pwndbg inspection views | View | Command | What it tells you | |---|---|---| | Context | `context` (`ctx`), printed automatically at each stop | Registers, stack, backtrace, disassembly with resolved operands and call arguments, all pointers dereferenced and colour-coded by memory type. Pick sections with e.g. `context regs stack`; `contextprev`/`contextnext` page through history; `contextoutput` sends sections to other terminals; `layout pwndbg` uses GDB TUI windows | | Memory map | `vmmap` (aliases `lm`, `libs`) | Mappings with permissions; filter by address or module name, `-w` writable, `-x` executable, `--gaps` for unmapped holes | | Pointer chains | `telescope [address] [count]` | Recursive dereference from `$sp` by default, 8 lines; `-f` shows the frame from rsp to rbp | | Offsets | `xinfo [address]` | Where an address sits relative to useful locations (default `$pc`) | | Hex dump | `hexdump [address] [count]` | 64 bytes from `$sp` by default; accepts a module name | | Search | `search [mapping]` | Bytes, strings, integers (`-1`/`-2`/`-4`/`-8`), pointers (`-p`) or `--asm`; restrict with `-e`/`-w`; `--save` then `-n` narrows to earlier hits | | Heap walk | `heap` | Chunks of the current thread's heap; `-c N` limits count, `-v` prints every field | | Allocator bins | `bins`, `arena` | Contents of the arena's bins and the thread's tcache | | Heap picture | `vis-heap-chunks` (`vis`) | Visual layout of the next 10 chunks by default | | Process state | `procinfo` | UID/GID, groups, SELinux context, open file descriptors | Heap views are for understanding allocator state, for example confirming which chunk a pointer belongs to or why memory use grows. pwndbg also integrates with decompilers (IDA, Binary Ninja, Ghidra, angr-management). ## Related Entities - [[syntheses/dynamic-analysis-workflow]]: when to use a debugger versus instrumentation, tracing or record/replay. - [[entities/frida]]: instrumentation when breakpoints are too intrusive. - [[entities/rizin-and-cutter]]: an alternative debugger plus static views. - [[entities/ghidra]]: static context to set breakpoints from. - [[entities/rea]]: agent-driven GDB sessions (Linux only). - [[syntheses/triage-an-unknown-binary]]: what to do before you attach a debugger. ## Sources - `raw/web_community-starting-debugging-with-gdb.md` - `raw/web_community-attach-debugging-with-gdb.md` - `raw/web_community-breakpoints-debugging-with-gdb.md` - `raw/web_community-set-watchpoints-debugging-with-gdb.md` - `raw/web_community-continuing-and-stepping-debugging-with-gdb.md` - `raw/web_community-memory-debugging-with-gdb.md` - `raw/web_community-registers-debugging-with-gdb.md` - `raw/web_community-backtrace-debugging-with-gdb.md` - `raw/web_community-signals-debugging-with-gdb.md` - `raw/web_community-core-file-generation-debugging-with-gdb.md` - `raw/web_community-server-debugging-with-gdb.md` - `raw/web_community-connecting-debugging-with-gdb.md` - `raw/github_doc-readme-md-4.md` - `raw/github_doc-docs-setup-md.md` - `raw/github_doc-docs-features-md.md` - `raw/github_doc-docs-commands-context-context-md.md` - `raw/github_doc-docs-commands-memory-vmmap-md.md` - `raw/github_doc-docs-commands-memory-telescope-md.md` - `raw/github_doc-docs-commands-memory-search-md.md` - `raw/github_doc-docs-commands-memory-xinfo-md.md` - `raw/github_doc-docs-commands-memory-hexdump-md.md` - `raw/github_doc-docs-commands-glibc-heap-heap-md.md` - `raw/github_doc-docs-commands-glibc-heap-bins-md.md` - `raw/github_doc-docs-commands-glibc-heap-arena-md.md` - `raw/github_doc-docs-commands-glibc-heap-vis-heap-chunks-md.md` - `raw/github_doc-docs-commands-start-attachp-md.md` - `raw/github_doc-docs-commands-start-entry-md.md` - `raw/github_doc-docs-reverse-engineering-tools-md.md` --- title: "Ghidra" type: entity tags: [ghidra, disassembler, decompiler, nsa, sre, static-analysis, headless, pyghidra, version-tracking] created: 2026-10-16 updated: 2026-10-16 confidence: high ghidra_version: "12.1.4" sources: ["raw/github_release-ghidra-12-1-4.md", "raw/github_release-ghidra-12-1.md", "raw/github_tag-ghidra-12-1-4-ghidradocs-gettingstarted-md.md", "raw/github_doc-ghidra-configurations-public-release-src-global-docs-whatsne.md", "raw/github_doc-docs-installation-md.md", "raw/github_doc-third-party-notices-md.md", "raw/github_doc-ghidradocs-ghidraclass-beginner-introduction-to-ghidra-stude.md", "raw/github_doc-ghidra-features-base-src-main-help-help-topics-importerplugi.md", "raw/github_doc-ghidra-features-base-src-main-help-help-topics-autoanalysisp.md", "raw/github_doc-ghidradocs-cheatsheet-html.md", "raw/github_doc-ghidra-features-base-src-main-help-help-topics-search-search.md", "raw/github_doc-ghidra-features-base-src-main-help-help-topics-datatypemanag.md", "raw/github_doc-ghidradocs-ghidraclass-intermediate-versiontracking-html.md", "raw/github_doc-ghidra-runtimescripts-support-analyzeheadlessreadme-md.md", "raw/github_doc-ghidra-features-decompiler-src-main-help-help-topics-decompi-3.md", "raw/github_doc-ghidra-features-decompiler-src-main-help-help-topics-decompi.md", "raw/github_doc-ghidra-features-decompiler-src-main-help-help-topics-decompi-4.md", "raw/github_doc-readme-md-23.md"] --- # Ghidra ## Overview Ghidra is NSA's free software reverse-engineering framework. It covers disassembly, assembly, decompilation, debugging, emulation, graphing and scripting across many processors and executable formats, and it runs interactively or headless. It is licensed under Apache-2.0, with government-work qualifications in its NOTICE file. Work happens inside a **project**: you import binaries into it, run auto-analysis, then annotate in the **CodeBrowser** tool, whose Listing and Decompiler views stay in sync. The current release line is **12.1**. Ghidra 12.1 was published 2026-05-13 and the **12.1.4** patch release 2026-09-21. For how the decompiler works and why its output goes wrong, see [[concepts/decompilation-concepts]]. ## Characteristics | Aspect | Detail | |---|---| | Cost / licence | Free, Apache-2.0 | | Host OS | Windows 10 (build 1809+), Linux, macOS 10.13+. 32-bit OS installs are deprecated | | Prebuilt natives | Windows x86-64, Windows ARM64 (through x86 emulation), Linux x86-64. macOS (x86-64 and ARM64), Linux ARM64 and FreeBSD (no debugger support) need natives you build yourself | | Java | A 64-bit JDK 21 (runtime and development kit); free LTS builds come from Adoptium Temurin and Amazon Corretto | | Python | Python 3.9–3.14, for both the Debugger and PyGhidra (the built-in CPython 3 integration, formerly Pyhidra) | | Hardware | 4 GB RAM and 1 GB disk minimum; dual monitors "strongly suggested" | | Import formats | PE, ELF, Mach-O, DYLD Shared Cache, COFF, NE, MZ, PEF, OMF, DEX, Android APK, Java class, Intel/Motorola Hex, DBG/MAP/DEF, dump files, Raw Binary, Ghidra GZF/GDT/GZT, XML and SARIF | | Teaming | Ghidra Server gives check-in/check-out shared projects. **12.1 clients need Ghidra Server 12.1/12.0.5 or a newer compatible version** (stated in the 12.2 What's New) | | Agent access | No first-party MCP server is documented. Community GhidraMCP and REA drive it (see [[syntheses/re-with-ai-agents-mcp]]) | **Next version (12.2, unreleased).** Ghidra's in-development What's New describes 12.2. Its notable changes are a JDK 25 minimum, enforced TLS server authentication for Ghidra Server and BSim PostgreSQL connections, a Server Allow List, C99 built-in integer types (`int8_t`, `uint8_t`, `int16_t`, `uint16_t`, `int64_t`, `uint64_t`, `intptr_t`, `uintptr_t`), an interactive structure/union/enum merger, and beta "timeless debugging" (TENET-format traces captured with an Intel PIN tool). None of that applies to a 12.1.4 install. The requirements and install steps on this page come from the Getting Started document tagged `Ghidra_12.1.4_build`. ## How to Use ### Install and launch 1. Install a 64-bit JDK 21, on `PATH` or through `JAVA_HOME`. If both are set, `JAVA_HOME` wins. 2. Extract the zip. There is no installer. **Don't extract over an existing install.** On macOS, clear Gatekeeper quarantine first: `xattr -d com.apple.quarantine ghidra__.zip`. 3. Launch with `ghidraRun.bat` (Windows) or `ghidraRun` (Linux/macOS). For CPython scripting, run `support/pyghidraRun` instead. If the `pyghidra` module is missing it offers to install it, or install it yourself: ```bash python3 -m pip install --no-index -f /Ghidra/Features/PyGhidra/pypkg/dist pyghidra ``` 4. To build missing natives: `cd /support/gradle/` then `gradle buildNatives` (or `./gradlew buildNatives` with Internet access). This needs Gradle 8.5+ and a C/C++ toolchain (Xcode or its Command Line Tools on macOS; GCC or Clang plus make on Linux/FreeBSD; Visual Studio 2017+ or the C++ Build Tools on Windows). A path containing `!` (any OS) or `^` (Windows) stops Ghidra from launching. If it exits silently, set `LAUNCH_MODE` to `fg` in the launch script, or run `support/ghidraDebug`, which listens on `127.0.0.1:18001`. ### First analysis of a binary 1. **File → New Project** (`Ctrl+N`). Choose Non-Shared for solo work and keep the project directory on a local disk. 2. **File → Import File** (`I`), or drag the file onto a project folder. Ghidra proposes the detected format and a Language/compiler spec. **Raw Binary** is always offered; if you pick it you must choose the language yourself (see [[syntheses/firmware-analysis]]). Under **Options…**, *Load Libraries From Disk* / *Link Existing Project Libraries* resolve imported DLLs and shared objects into linked programs. 3. Open the program in the CodeBrowser and accept **Analyze**. Auto-analysis starts at the entry points, follows flow, creates functions at call targets and builds cross-references. Depending on options it also demangles names, recognises library functions, recovers switch tables and imports decompiler-derived signatures (*Decompiler Parameter ID*). 4. For large binaries, work in layers. Run a first pass without the speculative analyzers (stack analysis, for example), then run the rest from **Analysis → One Shot**: Decompiler Parameter ID, Decompiler Switch Analysis, Stack. Red X marks and error bookmarks point at bad flow. Bundled scripts help: `FixupNoReturnFunction.java`, `FindPotentialDecompilerProblems.java`, `FindSharedReturnFunctions.java`, `CreateFunctionsFromSelection.java`. 5. Analysis with a selection active is limited to that selection, though analyzers may still change addresses outside it. *Analyze All Open* only analyzes programs whose language and compiler spec match the current one. ### CodeBrowser keys you'll use constantly | Key | Action | Key | Action | |---|---|---|---| | `G` | Go To address or label | `L` | Add/edit label, rename function or variable | | `D` | Disassemble | `C` | Clear code/data | | `F` (at the start address) | Create Function, when analysis missed one (on defined data, `F` cycles float types) | `T` | Choose data type | | `Ctrl+L` | Retype variable (Decompiler) | `[` / `P` / `Shift+[` | Array / pointer / structure | | `Ctrl+E` | Open Decompiler window | `S` | Search Memory | | `Ctrl+Shift+E` | Search Program Text | `Ctrl+Shift+G` | Patch instruction | | `Alt+←` / `Alt+→` | Back / forward | `F1` / `F4` | Help / set key binding on hovered action | On macOS, `Ctrl` is `⌘`. Undo history is cleared when you save. ### Types, search and diffing - **Data types.** The Data Type Manager holds the built-in archive, the program's own types, and archives you open. *File archives* (`.gdt`) can live anywhere on disk; only one user can have one open for writing at a time. *Project archives* are versioned with the project. **File → Parse C Source** imports C headers. Ghidra's decompiler docs call variable names and data types its most important annotations, so accurate types pay off most. - **Memory search** (`S`) accepts hex, binary, string and decimal input. Hex and binary support nibble/bit wildcards, and strings support regular expressions. Results can be combined with set operations and re-scanned for changes, which is useful while debugging. - **Version Tracking** carries your markup from an analysed *source* program to a new *destination* version. Run validators first; poor memory-map similarity, missing functions or unmarked no-return calls make matches incomplete. Then run correlators (exact/similar data and symbol matches, exact function matches, reference correlators) and accept or apply matches from the table. ### Headless and scripting Batch import and analysis uses `support/analyzeHeadless`: ```bash analyzeHeadless /Users/user/ghidra/projects Project1 -import /binaries/binary1.exe analyzeHeadless /Users/user/ghidra/projects Project1 -import /Users/user/sourceFiles/*.exe -noanalysis ``` `-preScript`/`-postScript` run scripts around analysis, and `-process` re-runs over files already in the project. The full flag reference, PyGhidra, the Debugger and BSim are covered in the Pro reference on Ghidra scripting, headless use and the debugger. The Ghidra Decompiler timeout option applies to headless runs but not to the interactive window. ### Extensions and upgrades - **File → Install Extensions**, then **+** to add a zip. Restart to load it. Extensions installed this way go to `/Extensions`. Admins can unzip into `/Ghidra/Extensions` instead. - Before upgrading, **back up each project's `.rep` directory and `.gpr` file**. Opening an older program prompts an upgrade; saving over the original makes it unreadable by older Ghidra, so use **Save As** if others still run the old version. ## Related Entities - [[entities/ida-pro]] and [[entities/rizin-and-cutter]]: the main alternatives. [[syntheses/choosing-a-disassembler]] compares all of them. - [[concepts/decompilation-concepts]]: p-code, annotations, and why output goes wrong. - [[syntheses/triage-an-unknown-binary]]: what to check before importing. - [[syntheses/malware-triage]]: capa can use Ghidra as its analysis backend and shows results inside Ghidra. - [[entities/rea]] and [[syntheses/re-with-ai-agents-mcp]]: agent access to a Ghidra 12.1.x install. - [[concepts/dotnet-and-nativeaot]]: Ghidra plus ghidra-nativeaot for NativeAOT output. ## Sources - `raw/github_release-ghidra-12-1-4.md` - `raw/github_release-ghidra-12-1.md` - `raw/github_tag-ghidra-12-1-4-ghidradocs-gettingstarted-md.md` - `raw/github_doc-ghidra-configurations-public-release-src-global-docs-whatsne.md` - `raw/github_doc-docs-installation-md.md` - `raw/github_doc-third-party-notices-md.md` - `raw/github_doc-ghidradocs-ghidraclass-beginner-introduction-to-ghidra-stude.md` - `raw/github_doc-ghidra-features-base-src-main-help-help-topics-importerplugi.md` - `raw/github_doc-ghidra-features-base-src-main-help-help-topics-autoanalysisp.md` - `raw/github_doc-ghidradocs-cheatsheet-html.md` - `raw/github_doc-ghidra-features-base-src-main-help-help-topics-search-search.md` - `raw/github_doc-ghidra-features-base-src-main-help-help-topics-datatypemanag.md` - `raw/github_doc-ghidradocs-ghidraclass-intermediate-versiontracking-html.md` - `raw/github_doc-ghidra-runtimescripts-support-analyzeheadlessreadme-md.md` - `raw/github_doc-ghidra-features-decompiler-src-main-help-help-topics-decompi-3.md` - `raw/github_doc-ghidra-features-decompiler-src-main-help-help-topics-decompi.md` - `raw/github_doc-ghidra-features-decompiler-src-main-help-help-topics-decompi-4.md` - `raw/github_doc-readme-md-23.md` --- title: "IDA Pro" type: entity tags: [ida-pro, hex-rays, disassembler, decompiler, flirt, lumina, idapython, idalib, mcp, debugger] created: 2026-10-16 updated: 2026-10-16 confidence: high ida_version: "9.4sp1" sources: ["raw/web_community-9-4sp1-md.md", "raw/web_community-9-4-md.md", "raw/web_community-whats-new-md.md", "raw/web_community-basic-usage-md.md", "raw/web_community-get-started-md.md", "raw/web_community-microcode-view-md.md", "raw/web_community-ctree-view-md.md", "raw/web_community-failures-md.md", "raw/web_community-running-in-batch-mode-md.md", "raw/web_community-overview-md-2.md", "raw/web_community-makesig-md.md", "raw/web_community-overview-md-5.md", "raw/web_community-overview-md.md", "raw/web_community-overview-md-3.md", "raw/web_community-getting-started-md.md", "raw/web_community-idapython-environment-md.md", "raw/web_community-overview-md-4.md", "raw/web_community-getting-started-md-2.md", "raw/web_community-where-mcp-fits-md.md", "raw/web_community-agentic-ida-with-idalib-md.md", "raw/github_doc-readme-md-24.md", "raw/github_doc-readme-md-18.md", "raw/github_doc-docs-ida-provider-md.md"] --- # IDA Pro ## Overview IDA is Hex-Rays' commercial interactive disassembler. The Hex-Rays decompiler adds C-like pseudocode on top, and an integrated debugger, IDAPython scripting, headless use as a library (**idalib**) and an official **MCP server** for AI agents round it out. You load a file, IDA auto-analyses it into a database, and you refine that database by renaming, retyping and commenting, with the disassembly, pseudocode and hex views kept in sync. Current release: **IDA 9.4sp1** (build `9.4.260915`), a service pack on IDA 9.4 (build `9.4.260714`). For how its decompiler lifts code (microcode → ctree) and why output fails, see [[concepts/decompilation-concepts]]. ## Characteristics | Aspect | Detail | |---|---| | Editions named in the docs | IDA Home, IDA Pro (Essential / Expert / Ultimate), IDA Classroom. idalib and the official MCP server ship with all three. Embedding idalib in your own product, SaaS or a shared server needs an IDA Pro OEM licence | | Decompilers | Which architectures you can decompile, and whether decompilation is local or remote, depends on product and plan | | Database | Analysis lives in an IDB with the `.i64` extension. Once loaded, IDA no longer needs the original binary, and edits never touch it | | Debugger | Local backends: Win32 and WinDbg (kernel mode and Time Travel Debugging) on Windows, Linux, and Intel/ARM macOS. Remote debug servers, Android native (ARM32, AArch64, x86, x86_64), a Dalvik debugger, remote iOS through Apple's `debugserver` (including iOS 17 CoreDevice), and a trace Replayer that can step backwards | | Library recognition | FLIRT signatures. **IDA Feeds** (Pro only) bulk-applies the FLIRT Signature Bundle and can generate Rust signatures on demand. **Lumina** shares function metadata | | Scripting | IDC, IDAPython, the higher-level Domain API (v0.5.0 released with 9.4), and the C++ SDK | | Agent access | Official Hex-Rays IDA MCP Server (9.4+), plus community `ida-pro-mcp` | **What 9.4 added**, in brief: - A rebuilt Dyld Shared Cache workflow: a DSC Index subview with on-demand loading, scriptable through `ida_dscu`. - Swift ABI support (`__swiftself`, `__swiftthrows`, `__swiftasync`) and better Rust and Go recovery. - ARM SVE2/SME disassembly, plus new Qualcomm Hexagon and MCore processor modules. - A **Pathfinder** call-path widget (`Shift-F9`). - Jump Anywhere as the default `g` dialog, deep links into databases, Git-backed Teams, a unified Scripts window, and functions grouped by compilation unit. - A native Windows-on-ARM64 build. **What 9.4sp1 fixed**, among other things: - Faster decompilation of functions with many basic blocks. - User microcode changes not being applied in batch mode. - An idalib crash on exit when `close_database()` wasn't called. - An IDAPython link-time dependency that ignored the runtime chosen by `idapyswitch`. - Several decompiler INTERRs. ## How to Use ### Load and navigate 1. **Quick start → New**, pick the file, and accept the suggested loader and processor. Auto-analysis runs, and the status-bar `AU` indicator reads `idle` when it has finished. 2. The main views are IDA View (graph, linear, and proximity view), Pseudocode, Hex View, Local Types and Functions. **Options → Show command palette…** lists every action with its hotkey. | Key | Action | Key | Action | |---|---|---|---| | `Space` | Toggle graph / linear view | `F5` | Decompile to pseudocode | | `Tab` | Jump between disassembly and pseudocode | `G` | Jump Anywhere (names, addresses, expressions) | | `X` | Cross-references to the item | `N` | Rename | | `:` / `;` | Regular / repeatable comment | `Esc` / `Ctrl+Enter` | Back / forward | | `Y` | Set type (function, variable, data) | `Shift-F1` | Local Types | | `Ctrl+Shift+F8` | Microcode view | `Ctrl+F6` | CTree view (new; may change) | | `F2` / `F9` | Add breakpoint / start debugging | `Shift-F9` | Pathfinder (9.4) | ### Improve the pseudocode The Hex-Rays primer comes down to one habit: **give the decompiler types.** Define the structure in Local Types (`Shift-F1`), put the cursor on the variable in pseudocode, press `Y`, and the casts disappear. When decompilation fails, work through these in order: 1. Function boundaries. 2. Stack-pointer values: show the column with Options, General, Stack pointer, and fix values with `Alt-K`. 3. Stack variables. 4. The function's own type. 5. The types of every callee. Use a database created by the latest IDA. The full list of failure messages is in [[syntheses/troubleshooting]]. The **Microcode view** lets you step through maturity levels, delete an instruction, or use *Specify value…* to pin an operand. Those edits carry through to the final pseudocode. ### Batch decompilation Pass `-Ohexrays` to the text or GUI binary. The format is `-Ohexrays:-option1:-option2...:outfile:func1:func2`, and `ALL` means every non-library, non-trivial function: ``` idat -Ohexrays:-errs:-mail=john@mail.com:outfile:ALL -A input ``` `-A` suppresses the startup dialogs. Useful options include `-nosave` (don't save the IDB), `-new` (only if the output doesn't already exist), `-libfuncs`, `-lumina`, and `-Dname=value` for a config directive. Leave out `-errs` unless you mean to upload problem databases to Hex-Rays. Prefix the output name with `+` to append to it. ### Library and metadata recognition - **FLIRT** recognises standard library functions. To carry your own work forward between versions of a binary, use **Makesig**: in the old database, **File → Produce file → Create SIG file…** (untick *Valid, user-specified names only* to include `sub_` functions). Then in the new database, **File → Load file → FLIRT signature file…**. - **Lumina** pushes and pulls function metadata keyed by an `md5` hash of each function: names, prototypes, comments, frames and operand representations. The binary itself is never uploaded, only the input filename, IDB name and the file's `md5`. Bulk pushes skip functions that still have dummy names or are under 32 bytes. Public Lumina is community-shared; Private Lumina is a self-hosted add-on. It is available for x86/x64, ARM, PPC, MIPS and RISC-V only. **Treat a push as disclosure** when the sample or your notes are sensitive. ### Debugging **Debugger → Select debugger…**, set **Process options** (path, host, port, password), add breakpoints with `F2`, run with `F9`. For a remote target, start the platform's debug server there and point Process options at it. To start a session straight from the command line without first creating a database, use `ida -rdebname{params}:pass@hostname:port+pid`. Only debug code you are allowed to run, and only inside an isolated VM (see [[syntheses/dynamic-analysis-workflow]]). ### Headless with idalib idalib runs IDA's engine without the GUI from Python or C++. From 9.4 the installer can activate it for you (*Use this installation as the default for idalib*). Otherwise install it with HCLI: ```bash hcli login hcli ida install --download-id ida-pro:latest --set-default --create-python-environment --accept-eula --yes uv pip install idapro ``` You can also activate it by hand by running the install's `idalib/python/py-activate-idalib.py` once. In scripts, **`import idapro` must come before any other IDA module.** For CI and Docker, use an API key (`hcli auth key create --name my-key`, exported as `HCLI_API_KEY`) instead of `hcli login`. IDAPython inside the GUI should use a virtual environment at `$IDAUSR/venv` whose Python major.minor matches the `libpython` that `idapyswitch` registered. Point `IDAPYTHON_VENV_EXECUTABLE` at it, or run `hcli ida python create-environment`. ### Agents and MCP - **Hex-Rays IDA MCP Server** (first-party, open source, runs locally, bring your own model). It needs IDA 9.4+ with idalib, plus Git, `uv` and Python 3.11+. Install with `uvx ida-hcli mcp install`, which also installs the GUI plugin. It can attach to databases open in the GUI or start idalib workers headlessly, and it coordinates several databases and agents. Hex-Rays recommends disabling other IDA MCP servers first. - **Community `ida-pro-mcp`** needs IDA Pro 8.3 or higher (9 recommended). **IDA Free is not supported.** Its headless mode is `uv run idalib-mcp --host 127.0.0.1 --port 8745 path/to/executable`. - **Code mode:** let the agent write and run idalib scripts directly. See [[syntheses/re-with-ai-agents-mcp]] for how these compare with REA and the JEB and Ghidra bridges. ## Related Entities - [[entities/ghidra]] (the free alternative) and [[entities/rizin-and-cutter]]. [[syntheses/choosing-a-disassembler]] covers cost, formats and scripting side by side. - [[concepts/decompilation-concepts]]: microcode, ctree, and fixing bad output. - [[syntheses/malware-triage]]: the capa explorer plugin runs inside IDA Pro. - [[entities/rea]]: drives IDA through an existing IDA MCP server. ## Sources - `raw/web_community-9-4sp1-md.md` - `raw/web_community-9-4-md.md` - `raw/web_community-whats-new-md.md` - `raw/web_community-basic-usage-md.md` - `raw/web_community-get-started-md.md` - `raw/web_community-microcode-view-md.md` - `raw/web_community-ctree-view-md.md` - `raw/web_community-failures-md.md` - `raw/web_community-running-in-batch-mode-md.md` - `raw/web_community-overview-md-2.md` - `raw/web_community-makesig-md.md` - `raw/web_community-overview-md-5.md` - `raw/web_community-overview-md.md` - `raw/web_community-overview-md-3.md` - `raw/web_community-getting-started-md.md` - `raw/web_community-idapython-environment-md.md` - `raw/web_community-overview-md-4.md` - `raw/web_community-getting-started-md-2.md` - `raw/web_community-where-mcp-fits-md.md` - `raw/web_community-agentic-ida-with-idalib-md.md` - `raw/github_doc-readme-md-24.md` - `raw/github_doc-readme-md-18.md` - `raw/github_doc-docs-ida-provider-md.md` --- title: "REA (rea-agents): One MCP for Reverse Engineering" type: entity tags: [rea, mcp, agents, evidence, providers, ghidra, ida, frida, cli] created: 2026-10-16 updated: 2026-10-16 confidence: high rea_version: "6.5.0" sources: ["raw/github_doc-readme-md.md", "raw/github_doc-docs-installation-md.md", "raw/github_doc-docs-client-configuration-md.md", "raw/github_doc-docs-mcp-contracts-md.md", "raw/github_doc-docs-reverse-engineering-tools-md.md", "raw/github_doc-agents-skills-reverse-engineer-anything-references-evidence-.md", "raw/github_release-rea-agents-v6-5-0.md", "raw/github_doc-third-party-readme-md.md", "raw/github_doc-disclaimer-md.md", "raw/github_doc-docs-kuna-provider-md.md", "raw/github_doc-docs-ida-provider-md.md", "raw/github_doc-docs-mcp-prompts-md.md", "raw/github_doc-agents-skills-reverse-engineer-anything-skill-md.md", "raw/github_doc-docs-migration-6-2-md.md", "raw/github_doc-docs-cli-md.md", "raw/github_doc-docs-firmware-analysis-md.md"] --- # REA (rea-agents): One MCP for Reverse Engineering ## Overview REA ("Reverse Engineer Anything") is a single MCP server, published as the npm package `rea-agents` (6.5.0, 2026-10-13), that connects an AI agent to reverse-engineering tools across native binaries, applications and runtime behaviour. The same workflows are available from the terminal through the `rea` CLI. Analysis runs locally, and every result carries the evidence and limitations behind its conclusions. > **Get REA only from official sources.** The README warns: install from [morluto/rea](https://github.com/morluto/rea), [rea.tools](https://rea.tools/), or the [`rea-agents` npm package](https://www.npmjs.com/package/rea-agents). A similar repository name or a copied README does not make a download official. In the README's words, REA is "for lawful research, education, interoperability, software preservation, and analysis of software you own or are authorized to examine"; see [[concepts/legal-and-ethics]]. REA is MIT-licensed, but it is a *bridge*: it does not install Ghidra, IDA, JEB or the other caller-supplied engines (setup can install Hopper, only with your approval) and grants no license to the commercial ones. You must legally obtain and be authorized to use IDA Pro/Hex-Rays, Hopper and JEB under their own terms. ## Characteristics ### Setup ```bash npx rea-agents setup ``` Setup offers the supported agents in a multi-select, previews the exact paths and changes, and applies them only after approval, keeping backups (`.rea.backup`, and a verified `.rea.backup..recovery` when the current config differs). It registers REA's MCP server plus matching workflow instructions (omit with `--skill=false`). Restart the agents it names afterward. For the latest release use `npx rea-agents@latest setup`. npm's download approval and REA's setup approval are separate. Scripted forms: `rea setup --client codex --client cursor --dry-run`, `rea setup --yes --all-detected --install-hopper --json`. Without a scope flag, `--yes` only touches existing REA-owned registrations. `rea doctor --json` is a read-only readiness check; `rea update` updates only the npm/Bun global install that owns the running CLI; `rea uninstall [--purge-data]` removes REA-owned registrations and skill files. **Supported agents** (`--client` value): Claude Code (`claude_code`), Claude Desktop (`claude_desktop`), Codex (`codex`), Cursor (`cursor`), Gemini CLI (`gemini_cli`), Windsurf, Devin, OpenCode, Antigravity, GitHub Copilot CLI (`copilot_cli`), Command Code, Qwen Code (`qwen_code`), VS Code (`vscode`), Grok Build (`grok_build`), OMP, Pi, Hermes, Kimi Code (`kimi`), Qoder, Factory Droid (`droid`), Trae, WorkBuddy, ZCode, DeepSeek Harness (`dsh`). Seven of these — `droid`, `dsh`, `kimi`, `qoder`, `trae`, `workbuddy`, `zcode` — require `rea-agents@6.5.0` or later. ### Runtime requirements REA needs Node.js 22.x (>=22.19), 24.x (>=24.11) or 26+, plus npm. On Linux, several workflows (Ghidra, JADX, firmware tools, static JavaScript/Electron) require a procps-compatible `ps` on REA's `PATH` for process-ownership checks. Additional tools depend on the target (below). Install Hopper with approval during setup; Ghidra and IDA use your existing installations. ### The engines REA drives REA is a provider broker. Native binaries route to a deep provider, which must be selected once per session: | Provider | What it is | Notes | |---|---|---| | Ghidra | Existing 12.1.x install + JDK 21+ | 26 read-only ops; `GHIDRA_INSTALL_DIR` | | Hopper | Commercial; setup can install it (macOS 12+/several Linux) | demo or licensed | | IDA | Adapts an upstream IDA MCP (mrexodia/ida-pro-mcp, or a native bridge) | `REA_IDA_MCP_CONFIG` | | Kuna | Apache-2.0 single-binary decompiler, static | `REA_KUNA_COMMAND` | | JEB | Caller-started JEB serving MCP | `REA_JEB_MCP_URL` | | objdump / GDB / Rizin | Caller-supplied GNU binutils, GDB, Rizin | `REA_OBJDUMP_COMMAND`, `REA_GDB_COMMAND`, `REA_RIZIN_COMMAND` | Beyond native: static JavaScript/Electron and .NET (no engine), Go/Rust metadata and WASM (WABT 1.0.42), EVM bytecode, SQLite snapshots (Node 24.x >=24.15 or 26+), Android via headless JADX + JDK, Android devices via caller-supplied adb, Apktool resources, Flutter, firmware (binwalk 3.1.0 / unblob 26.6.4 on Linux), pcap/packet captures (tshark 4.x on Linux), HAR/SAZ captures, Frida instrumentation, browser observation via CDP, and process capture (Linux/macOS PTY). `auto` selection picks the single supporting provider; with more than one it returns `ambiguous` and asks you to choose with `--provider` / `provider_id`. ### The evidence model Evidence-producing tools return the complete canonical Evidence record in both text and `structuredContent`: read `structuredContent.normalized_result` for the operation result and `structuredContent.evidence_id` for its identity. `analysis_profile` is always present (object or `null`) and participates in identity; records omitting it are rejected. REA's workflow instructions require every conclusion to keep **observations**, **inferences** and **unknowns** distinct; residual unknowns are tracked with `record_unknown`/`update_unknown`. Comparisons (`compare_functions`, `compare_artifacts`, `verify_reconstruction`) only conclude equality or absence over complete, compatible page sets; a dimension with an unavailable facet stays `unknown` rather than being guessed. Target-derived content (strings, decompiled code, page text, logs) is marked `untrusted_content` in `_meta` and must be treated as data, never as instructions. Because results are complete records, they can be large. REA prepares results within a 10 MiB MCP response budget; if one won't fit it returns `resource_constraint` with `details.resource: "transport"` and a retained-evidence reference. Recover it with `inspect_analysis_view` (summary, one section, or a stable page) or `export_evidence_bundle`, or raise `REA_MCP_MAX_RESPONSE_BYTES` (≥10485760) if the client's receive buffer allows. Clients that choke on a large tool catalog can set `REA_MCP_INPUT_SCHEMA_PROFILE: compact` or `REA_MCP_OUTPUT_SCHEMA_PROFILE: off`; REA still validates complete canonical inputs/outputs. ### Headline platform limits - **Deep native analysis needs one of Hopper, Ghidra or IDA**; Hopper's automated installer supports macOS 12+ and a fixed set of Linux distros (elsewhere, point `HOPPER_LAUNCHER_PATH` at an existing install). - **GDB and Rizin debugger sessions are Linux-only** (they depend on `/proc` verification); macOS and Windows are unsupported for persistent debugging. Persistent sessions live only for the life of the MCP server process. - **Firmware, packet captures and signal recordings are Linux-only** and need util-linux `prlimit`. - **Windows Ghidra is experimental "P0"** — native PE (x86/x86-64/ARMNT/ARM64) and raw NMOS 6502 only, read-only. - **Ghidra cold start is slow.** The first query imports and auto-analyzes; REA's default startup allowance is 330,000 ms (`REA_GHIDRA_STARTUP_TIMEOUT_MS`), but the *client's* per-call deadline (pinned SDK default 60,000 ms) bounds the wait. On a timeout, `close_binary` then re-`open_binary` on the same connection. - **REA does not install caller-supplied engines** (Hopper only with setup approval) and never switches providers automatically; a provider timeout, install failure or permission denial needs its own recovery. - **Unrestricted consoles run with the user's privileges.** The GDB console and Rizin/Cutter commands execute shell commands, change target state and use the network in REA's process security context (see `## How to Use`). ## How to Use Point your agent at a local target in natural language, for example: *"Understand how search works in the Notes app, show me the evidence, and build a similar feature for my project."* Or use the CLI: ```bash # static JavaScript/Electron, no engine needed npx -y rea-agents@latest analyze-javascript-application /absolute/path/to/app --json # install the command for regular use npm install --global rea-agents rea --help # native analysis: pick a provider rea analyze /absolute/path/to/program --provider ghidra ``` Six guided MCP prompts (`investigate_feature`, `compare_application_versions`, `verify_reconstruction`, `trace_crash`, `audit_residual_unknowns`, `prepare_bounded_process_capture`) suggest starting tools but add no tools themselves. **On the unrestricted consoles:** `rea debug-with-gdb` / `start_gdb_session` and `rea debug-with-rizin` / `start_rizin_debug_session` give an interactive console that runs with full user privileges and can run shell commands, read/write files, change the inferior and use the network — treat them like a shell running with your user account's privileges on whatever you're debugging, and only against targets you control. Both require Linux. The Rizin debugger and the one-shot `rea debug-with-gdb` CLI require a caller-selected durable `inferior_tty` (e.g. `/dev/pts/7`) that stays available after the debugger exits (it is optional for MCP `start_gdb_session`, but then you must detach or kill a live inferior yourself before closing), because closing a session can detach and resume a live inferior. Running an unrestricted Rizin/Cutter or GDB console, or closing a debugger, retires the active binary-analysis session; call `open_binary` again before continuing. More in [[syntheses/re-with-ai-agents-mcp]]. Keep original saved artifacts until replacements are verified; `always-bump-minor` versioning means a minor bump can still be a breaking release, so refresh cached MCP tool definitions after upgrading. ## Related Entities - [[entities/ghidra]]: a free native provider (uses your existing 12.1.x install) - [[entities/ida-pro]]: adapted through an upstream IDA MCP - [[entities/gdb-and-pwndbg]]: the GDB console REA drives (Linux-only) - [[entities/frida]]: REA's runtime instrumentation path - [[syntheses/re-with-ai-agents-mcp]]: REA versus other RE MCP servers - [[syntheses/firmware-analysis]]: REA's binwalk/unblob and raw-binary lanes ## Sources - `raw/github_doc-readme-md.md` - `raw/github_doc-docs-installation-md.md` - `raw/github_doc-docs-client-configuration-md.md` - `raw/github_doc-docs-mcp-contracts-md.md` - `raw/github_doc-docs-reverse-engineering-tools-md.md` - `raw/github_doc-agents-skills-reverse-engineer-anything-references-evidence-.md` - `raw/github_release-rea-agents-v6-5-0.md` - `raw/github_doc-third-party-readme-md.md` - `raw/github_doc-disclaimer-md.md` - `raw/github_doc-docs-kuna-provider-md.md` - `raw/github_doc-docs-ida-provider-md.md` - `raw/github_doc-docs-mcp-prompts-md.md` - `raw/github_doc-agents-skills-reverse-engineer-anything-skill-md.md` - `raw/github_doc-docs-migration-6-2-md.md` - `raw/github_doc-docs-cli-md.md` - `raw/github_doc-docs-firmware-analysis-md.md` --- title: "Rizin and Cutter" type: entity tags: [rizin, cutter, rz-bin, rz-pipe, rz-ghidra, disassembler, cli, open-source, static-analysis] created: 2026-10-16 updated: 2026-10-16 confidence: medium rizin_version: "0.9.1" cutter_version: "2.5.0" sources: ["raw/github_doc-src-introduction-overview-md.md", "raw/github_doc-src-introduction-getting-rizin-md.md", "raw/github_doc-src-first-steps-intro-md.md", "raw/github_doc-src-first-steps-commandline-options-md.md", "raw/github_doc-src-basic-commands-intro-md.md", "raw/github_doc-src-analysis-intro-md.md", "raw/github_doc-src-analysis-code-analysis-md.md", "raw/github_doc-src-disassembling-intro-md.md", "raw/github_doc-src-visual-mode-intro-md.md", "raw/github_doc-src-scripting-intro-md.md", "raw/github_doc-src-scripting-rz-pipe-md.md", "raw/github_doc-src-tools-intro-md.md", "raw/github_doc-src-tools-rz-bin-intro-md.md", "raw/github_doc-docs-source-index-rst.md", "raw/github_doc-docs-source-user-docs-features-rst.md", "raw/github_doc-docs-source-user-docs-menus-menu-bar-windows-menu-rst.md", "raw/github_doc-docs-source-user-docs-command-line-rst.md", "raw/github_doc-docs-source-user-docs-common-issues-rst.md", "raw/github_doc-docs-reverse-engineering-tools-md.md", "raw/github_doc-src-refcard-intro-md.md", "raw/github_release-rizin-v0-9-1.md", "raw/github_release-cutter-v2-5-0.md", "raw/github_doc-src-visual-mode-visual-panels-md.md"] --- # Rizin and Cutter ## Overview **Rizin** is a free, open-source reverse-engineering framework built around one terminal program, `rizin`, plus a set of small `rz-*` companion tools. `rizin` is a disassembler, hex editor, patcher, analyser and debugger, and it treats files, processes and devices alike as byte streams you seek through. **Cutter** is the Qt/C++ desktop GUI that runs on top of Rizin. Use Rizin when you want scripting, terminal and pipeline work; use Cutter when you want graphs and a clickable decompiler view. Current releases are **Rizin 0.9.1** (2026-06-29) and **Cutter 2.5.0** (2026-06-30), and Cutter 2.5.0 is built on Rizin 0.9.1. Rizin 0.9.1 is a small patch release: visual-mode scrolling fixes for meta items, and string search now defaults to NUL as its newline character. Cutter 2.5.0 adds a Preferences tab for reading and setting Rizin evars, a searchable keybindings window, register and memory value tooltips while debugging or emulating, register-profile and RzRun-profile selection before a debug session, debuginfod support in the initial analysis options, optional docking, and a move to Qt 6.11.0. ## Characteristics | Aspect | Detail | |---|---| | Cost / licence | Free and open source | | Platforms | Binary packages for Windows, macOS and Linux; build from source elsewhere. Cutter ships as a `.dmg` (macOS), a `.zip` (Windows) and an `.AppImage` (Linux) | | Formats | ELF, PE, Mach-O, Java CLASS and any format a plugin adds | | Decompiler | `pdg`, the Ghidra decompiler plugin (rz-ghidra). Cutter is designed around decompiler plugins (Ghidra, RetDec, JSDec); RzGhidra is the one the Cutter team maintains | | Scripting | Command chaining in the shell, plus `rz-pipe` bindings (Python, Rust, Haskell, OCaml, Ruby) over spawn, pipe, HTTP or TCP | | Scale | Cutter's own docs warn that a few MB counts as large and over 100 MB as very large; default analysis may take minutes or freeze the UI | ### The companion tools | Tool | Use it to… | Example | |---|---|---| | `rz-bin` | Dump headers, imports, exports, sections, strings, libraries and security flags | `rz-bin -I unknown.bin` (info), `-i` imports, `-z` strings, `-S` sections, `-l` libraries, `-j` JSON | | `rz-asm` | Assemble or disassemble snippets | `rz-asm -a x86 -b 32 'mov eax, 33'` → `b821000000`; `rz-asm -a x86 -d '90'` → `nop` | | `rz-hash` | Hash files or blocks | `rz-hash -a md5 file.bin` | | `rz-diff` | Diff bytes, deltas or analysed code blocks | | | `rz-find` | Search files for byte patterns and strings in many encodings | | | `rz-ax` | Convert bases and evaluate expressions | `rz-ax 0x400000` → `4194304` | | `rz-run` | Launch a program with set args, stdin, chdir or sockets (profiles in `.rrz` files) | `rz-run program=/bin/ls connect=localhost:9999` | | `rz-gg` | Compile a tiny language into small x86, x86-64 or ARM binaries | | `rz-bin -I` is a fast first look during triage. It reports arch, bits, class, compiler, `stripped`, `canary`, `PIE`, `NX` and `relro` (see [[syntheses/triage-an-unknown-binary]]). ## How to Use ### Open a file | Command | What it does | |---|---| | `rizin -A file` | Open and run `aaa` (analyse all referenced code) | | `rizin -d /bin/ls` | Debug a program, or a PID | | `rizin -w file` | Open writable (the default is read-only) | | `rizin -nw file` | Writable, without parsing format headers | | `rizin -a ppc -b 32 ls.fat` | Force arch and bits | | `rizin -B file` | Set the base address for PIE binaries | | `rizin -qc 'iij' hi.bin > imports.json` | Run one command, print, quit; good for scripts | | `rizin -p test.rzdb` | Reopen a saved project | | `rizin -N file` | Skip user settings and scripts (`-NN` also skips plugins) | | `rizin =` | Scratch 512-byte writable buffer | Files open in virtual-addressing mode, positioned at the entry point. `-n` switches to raw file offsets. ### The command grammar Commands are short mnemonics: the first letter is the family and later letters refine it (`p` print, `pd` print disassembly, `pdf` disassemble function). The general shape is: ``` [.][times][cmd][~grep][@[@iter]addr!size][|>pipe] ; ... ``` - `@ addr` runs one command at another address without moving the seek: `p8 10 @ 0x4010`. - `@@` iterates over a list (flags, functions, hits): `p8 20 @@f:hit0_*`. - `~` is the built-in grep, `>` writes to a file, `|` pipes to a shell command, `;` chains commands, and backticks substitute output. - Help is built in: append `?` to any command, `??` for long help with examples, `?**` to search every command's description, `?**e` to search settings. `el~color` lists settings mentioning "color". Persist settings in `~/.rizinrc`. ### A first static pass ``` [0x00001100]> aa # analyse symbols and entry points ("aaa" for stripped binaries) [0x00001100]> afl # list functions [0x00001100]> s main # seek [0x00001100]> pdf # disassemble the current function [0x00001100]> pdg # decompile it (needs the rz-ghidra plugin) [0x00001100]> axt 0x2004 # who references this address [0x00001100]> iz # list strings (izz for more) ``` Deeper passes are `aab`, `aar` and `aac`, or `aaaa` (experimental). Fully automatic analysis can be wrong, so the `af` family lets you define functions by hand, and the `analysis.*` and `emu.*` settings tune it. Write with `w "text"`, `wx 90 90`, or `wa "jmp 0x8048140 ; nop"` once the file is open writable. Patch only copies you are allowed to modify. ### Visual modes `V` enters visual mode: `hjkl` move, `p`/`P` rotate panels (hex, disassembly, debugger and more), `c` toggles the cursor, `:` runs a command, and `q` returns to the prompt. From the prompt, `v` opens the panels interface (split screens, menus and tabs); from inside visual mode, press `!`. In visual mode the debugger keys default to `F2` breakpoint, `F7` step, `F8` step over and `F9` continue. ### Scripting with rz-pipe ```shell pip install rzpipe ``` ```python import rzpipe rz = rzpipe.open("/bin/ls") rz.cmd('aa') print(rz.cmdj("aflj")) # JSON output parsed into Python objects ``` Most commands have a `j` variant (`aflj`, `ij`, `iij`) that returns machine-readable output. That is what makes Rizin practical to drive from scripts and agents. ### Cutter Download a release and run it (on Linux, `chmod +x Cutter*.AppImage` first). Command-line options: | Option | Meaning | |---|---| | `-A, --analysis ` | Analyse on open: `0` none, `1` `aaa`, `2` `aaaa` (experimental) | | `-a` / `-b` / `-c` / `-o` / `-e` | Arch, bits, CPU, OS, endianness | | `-F, --format`, `-B, --base`, `-m, --map` | Force a bin plugin, set the load base, set the map address | | `-w, --writemode` | Open writable (with `-A`, no confirmation prompt) | | `-P, --phymode` | Turn off virtual addressing | | `-p, --project`, `-i ` | Load a project, run a script | | `--no-plugins` (`--no-cutter-plugins`, `--no-rizin-plugins`) | Start clean when a plugin misbehaves | The Decompiler window (Windows → Decompiler) stays in sync with the disassembly and supports renaming and retyping. **Common problems:** - If the AppImage crashes at startup, empty `LD_LIBRARY_PATH`. - Keyboard mix-ups usually mean a wrong Xorg layout; `setxkbmap us` typically fixes it. - If analysis runs longer than 5–15 minutes, reopen the file and choose narrower options in the Load Options dialog's Advanced Analysis view. ### Driving Rizin from an agent REA can call a Rizin you install yourself; set `REA_RIZIN_COMMAND`, otherwise it searches `PATH`. One-shot commands run with `-N -q -c`, so user settings and scripts are skipped but plugins stay loaded. **Persistent Rizin debugger sessions through REA are Linux-only**, because REA verifies them through `/proc`. Cutter is reached through REA's local bridge. Rizin commands run with your user's full privileges, so treat an agent's access to the Rizin console as unrestricted shell access (see [[syntheses/re-with-ai-agents-mcp]]). ## Related Entities - [[entities/ghidra]]: supplies the decompiler behind `pdg` and Cutter's default decompiler. - [[entities/ida-pro]]: the commercial alternative. [[syntheses/choosing-a-disassembler]] compares all of them. - [[entities/gdb-and-pwndbg]]: the usual Linux debugger stack alongside Rizin. - [[entities/rea]]: agent integration for Rizin and Cutter. - [[syntheses/triage-an-unknown-binary]]: where `rz-bin` fits in a first pass. ## Sources - `raw/github_doc-src-introduction-overview-md.md` - `raw/github_doc-src-introduction-getting-rizin-md.md` - `raw/github_doc-src-first-steps-intro-md.md` - `raw/github_doc-src-first-steps-commandline-options-md.md` - `raw/github_doc-src-basic-commands-intro-md.md` - `raw/github_doc-src-analysis-intro-md.md` - `raw/github_doc-src-analysis-code-analysis-md.md` - `raw/github_doc-src-disassembling-intro-md.md` - `raw/github_doc-src-visual-mode-intro-md.md` - `raw/github_doc-src-scripting-intro-md.md` - `raw/github_doc-src-scripting-rz-pipe-md.md` - `raw/github_doc-src-tools-intro-md.md` - `raw/github_doc-src-tools-rz-bin-intro-md.md` - `raw/github_doc-docs-source-index-rst.md` - `raw/github_doc-docs-source-user-docs-features-rst.md` - `raw/github_doc-docs-source-user-docs-menus-menu-bar-windows-menu-rst.md` - `raw/github_doc-docs-source-user-docs-command-line-rst.md` - `raw/github_doc-docs-source-user-docs-common-issues-rst.md` - `raw/github_doc-docs-reverse-engineering-tools-md.md` - `raw/github_doc-src-refcard-intro-md.md` - `raw/github_release-rizin-v0-9-1.md` - `raw/github_release-cutter-v2-5-0.md` - `raw/github_doc-src-visual-mode-visual-panels-md.md` --- title: "Activity Log" type: log --- # Activity Log Append-only record of all wiki changes. ## Format Each entry follows this format: ``` ### YYYY-MM-DD HH:MM — [Action Type] - **Source/Trigger**: what initiated the action - **Pages created**: list of new pages - **Pages updated**: list of updated pages - **Notes**: any contradictions flagged, decisions made ``` --- ### 2026-10-16 — Initial build - **Source/Trigger**: new topic wiki on reverse engineering, anchored on REA (`rea-agents` 6.5.0) and each tool's own documentation - **Pages created**: 24 standard pages (7 concepts, 6 entities, 11 syntheses) and 8 XL reference pages; see [[index]] - **Pages updated**: none - **Notes**: Scope is legitimate analysis only (see [[concepts/legal-and-ethics]]). Debugging coverage is limited to debugging and inspection; exploit tooling is out of scope. Ghidra requirements follow the 12.1.4 release documentation; notes from the unreleased 12.2 are labelled as such. Not covered: Windows kernel/driver RE and WinDbg, commercial protector unpacking, and EU decompilation law (the EU directive text could not be retrieved). --- title: "Android APK Analysis" type: synthesis tags: [android, apk, dex, jadx, apktool, adb, logcat, frida, mitmproxy, manifest, apk-signing, emulator] created: 2026-10-16 updated: 2026-10-16 confidence: medium jadx_version: "1.5.6" apktool_version: "3.0.3" sources: ["raw/web_community-application-fundamentals-app-architecture-android-developers.md", "raw/web_community-app-manifest-overview-app-architecture-android-developers.md", "raw/web_community-app-signing-security-android-open-source-project.md", "raw/web_community-analyze-your-build-with-the-apk-analyzer-android-studio-andr.md", "raw/github_doc-wiki-the-basics-intro-mdx.md", "raw/github_doc-wiki-the-basics-decoding-mdx.md", "raw/github_doc-docs-cli-parameters-mdx.md", "raw/github_doc-docs-install-mdx.md", "raw/github_doc-docs-faq-mdx.md", "raw/github_doc-wiki-the-basics-frameworks-mdx.md", "raw/github_release-v3-0-3.md", "raw/github_doc-readme-md-5.md", "raw/github_release-1-5-6.md", "raw/web_community-android-debug-bridge-adb-android-studio-android-developers.md", "raw/web_community-logcat-command-line-tool-android-studio-android-developers.md", "raw/github_doc-i18n-en-docs-android-md.md", "raw/github_doc-i18n-en-docs-bridges-md.md", "raw/web_community-certificates.md", "raw/web_community-system-ca-on-android-emulator.md", "raw/github_doc-docs-android-analysis-md.md", "raw/github_doc-docs-apktool-resource-analysis-md.md", "raw/github_doc-docs-adb-device-analysis-md.md", "raw/github_doc-i18n-en-docs-frida-ps-md.md", "raw/github_doc-i18n-en-docs-frida-trace-md.md", "raw/github_doc-docs-unreleased-mdx.md"] --- # Android APK Analysis This page walks through inspecting an Android app you are authorized to examine: your own build, a test app, or an app under an agreed security assessment. It covers what is inside an APK, reading the code with JADX, decoding resources with apktool, pulling an installed app and its logs over ADB, observing it with Frida on a test device, and viewing its own HTTPS traffic through mitmproxy on an emulator. Running, instrumenting and intercepting an app each need their own authorization on top of the right to read it; see [[concepts/legal-and-ethics]]. ## Comparison | Task | Tool | Command to start | What you get | |---|---|---|---| | See the layout | `unzip`, Android Studio APK Analyzer | `unzip app.apk` | Raw entries: `AndroidManifest.xml` (binary), `classes.dex`, `resources.arsc`, `res/`, `META-INF/` | | Read the code | JADX 1.5.6 | `jadx -d out app.apk` or `jadx-gui app.apk` | Java source from Dalvik bytecode, plus a decoded manifest and resources | | Decode resources and manifest | apktool 3.0.3 | `apktool d app.apk -o app_decoded` | Readable `AndroidManifest.xml`, `res/` XML, strings, `apktool.yml`, and smali unless `-s` | | Get the installed app | `adb` | `adb shell pm path ` then `adb pull` | The base APK and any split APKs | | Read logs | `adb logcat` | `adb logcat -b crash` | System, app and crash log buffers | | Watch it run | Frida | `frida-ps -Uai`, `frida-trace -U ...` | Live call traces on a rooted test device or emulator | | See its traffic | mitmproxy | Proxy the emulator, trust the CA | Decrypted HTTP(S) requests the app makes | JADX is the fastest route to readable logic; apktool is the more faithful route for resources and the manifest. Use both: JADX for "what does this code do", apktool for "what does the app declare". ## Analysis ### 1. Know what an APK contains An APK is a ZIP archive holding everything the app needs at runtime. An Android App Bundle (`.aab`) is a publishing format that cannot be installed on a device; Google Play turns it into device-specific APKs. That is why an installed app often shows up as a base APK plus splits. | Entry | What it is | Why you care | |---|---|---| | `AndroidManifest.xml` | Binary XML (unreadable until decoded) declaring the package, components, permissions and required features | Activities, services and content providers must be declared here or the system can't start them (broadcast receivers can also be registered in code), so it is your map of most entry points | | `classes.dex` (and further `classes*.dex`) | Dalvik bytecode for the app's Kotlin/Java code | What JADX decompiles | | `resources.arsc` | Compiled resource table | Strings, IDs and configuration-specific values | | `res/`, `assets/`, `lib/` | Resources, raw assets, native libraries | Native `.so` files go to a native disassembler | | `META-INF/` and the APK signing block | Signatures | Identify the signer | **Signing schemes.** Every app must be signed; Android does no CA verification of app certificates, so self-signed is normal. The AOSP page describes v1 (JAR signing, which leaves ZIP metadata unprotected), v2 (added in Android 7.0, signs the whole file so any change invalidates it), and v3 (Android 9, same idea with extra data in the signing block). The signer certificate also decides which Linux user ID the app runs under, so apps signed with the same key can share a UID or signature-level permissions. Each app otherwise runs as its own Linux user in its own sandbox. ### 2. Read the code with JADX JADX turns Dalvik bytecode into Java and also decodes `AndroidManifest.xml` and `resources.arsc`. It needs 64-bit Java 11 or later (the `with-jre` bundles include one). It accepts `.apk`, `.dex`, `.aab`, `.apks`, `.apkm`, `.xapk`, `.jar`, `.aar` and more. ``` jadx -d out app.apk # sources and resources to ./out jadx -s -d out app.apk # resources only (--no-src) jadx -r -d out app.apk # code only (--no-res) jadx --deobf -d out app.apk # rename short/obfuscated identifiers jadx --single-class com.example.Foo app.apk jadx-gui app.apk # search, find usage, jump to declaration ``` JADX warns that it usually can't decompile 100% of the code. For methods that fail, `-m simple` or `-m fallback` shows lower-level output and `--show-bad-code` prints the inconsistent result instead of hiding it. `--mappings-path` loads a deobfuscation mapping if you have one (the `rename-mappings` plugin also reads ProGuard-format files). JADX 1.5.6 (2026-07-10) leads with security fixes: it rejects absolute or current-directory zip entry paths and sanitises values written into exported Gradle projects. Its zip-bomb and XML checks can be tuned with `JADX_ZIP_MAX_ENTRIES_COUNT` and related variables. ### 3. Decode resources with apktool Unzipping only gives you compiled files; apktool decodes them back to readable form. ``` apktool d app.apk # decodes into ./app apktool d app.apk -o out_dir # choose the output folder apktool d -s app.apk # skip dex disassembly (leave dex untouched) apktool d --only-manifest app.apk # just the manifest apktool d -r app.apk # keep resources.arsc as-is ``` Useful decode options: `-f` overwrites the destination, `-j ` sets threads (default: CPU count, max 8), `--keep-broken-res` keeps going after `Invalid config flags detected. Dropping resources`, and `--res-resolve-mode default|greedy|lazy` controls how missing resources are handled. Apps that depend on OEM framework resources need that framework installed first with `apktool if framework-res.apk` (frameworks are cached under `$HOME/.local/share/apktool` on Linux, `$HOME/Library/apktool` on macOS, `$HOME/AppData/Local/apktool` on Windows). "Magic APKs" built with modified OEM tooling can't be decoded at all. apktool's install guide says a minimum of Java 8 is required; building apktool from source needs a newer JDK (its unreleased-changes notes move the build requirement to JDK 17). On Windows, the guide asks you to adjust case sensitivity, because Windows paths are case-insensitive. The current release is **apktool 3.0.3** (2026-07-20). This page covers decoding for inspection only. ### 4. Pull an installed app and its logs with ADB Enable USB debugging in Developer options, then: ``` adb devices -l # confirm the device; note its serial adb shell pm list packages -3 # third-party packages (-f adds the APK path) adb shell pm path com.example.app # one line per APK: base plus any splits adb pull ./acq/ # copy each listed path ``` With several devices attached, add `-s ` (e.g. `adb -s emulator-5554 shell`). Pull **every** path `pm path` prints; analysing only `base.apk` misses code and resources shipped in splits. Hash what you pulled before you analyse it. Logs live in circular buffers kept by `logd` (`main`, `system`, `crash` and others): ``` adb logcat -b crash # crash buffer only adb logcat ActivityManager:I MyApp:D *:S # filter by tag:priority, silence the rest adb logcat -b all -v color -d # dump everything once and exit ``` Many logcat options need root, and release builds may have stripped debug logging at compile time. ### 5. Observe it with Frida on a test device Use a rooted test device or an emulator, never a personal phone. Frida's docs recommend a Pixel or Nexus on current official software, or a Google Android 9 arm/arm64 emulator image. Push and start `frida-server` (steps in [[entities/frida]]), then: ``` frida-ps -Uai # installed apps and identifiers frida-trace -U -i "Java_*" com.example.app # JNI entry points frida-trace -U -f com.example.app -I "libnative-lib.so" ``` Use `-j` to trace Java methods. Under Frida 17, scripts you load from Python must pull in `frida-java-bridge` explicitly (compile with `frida-compile` or the bindings' `frida.Compiler`); the REPL and `frida-trace` include it already. Without root, Frida's options are embedding Gadget into your own build or using a debugger. ### 6. Inspect its traffic with mitmproxy on an emulator mitmproxy can decrypt TLS only if the client trusts its CA. It generates a unique CA on first run in `~/.mitmproxy` (`mitmproxy-ca-cert.cer` is the copy for Android). - **User CA.** Proxy the device, visit `mitm.it` and install the certificate. Since Android 7, apps ignore user-installed CAs unless they are configured to use them, so this mainly works for browsers and for your own builds configured to trust user certificates. - **System CA on an emulator.** Use an AVD (Android Virtual Device) image that is not a "Google Play" production build, which blocks `adb root`. Name the certificate by its hash, then push it into the system store: ``` cd ~/.mitmproxy hashed_name=`openssl x509 -inform PEM -subject_hash_old -in mitmproxy-ca-cert.cer | head -1` && cp mitmproxy-ca-cert.cer $hashed_name.0 emulator -avd -writable-system adb root adb shell avbctl disable-verification # API 29+ only adb reboot adb root adb remount adb push .0 /system/etc/security/cacerts adb shell chmod 644 /system/etc/security/cacerts/.0 adb reboot ``` Always start that emulator with `-writable-system`, or it boots a clean system image without your CA. Point it at the proxy with `-http-proxy 127.0.0.1:8080`, and confirm the CA under Settings → Security → Advanced → Encryption & credentials → Trusted credentials. For a Google Play image, mitmproxy documents a Magisk-module route instead. Some apps ignore the system store or pin certificates, and their connections will fail through the proxy. mitmproxy's `ignore_hosts` option lets those domains pass through untouched. Bypassing pinning is out of scope for this wiki. For capture concepts and TLS key logging, see [[syntheses/network-captures-and-protocols]]. ### Doing it through REA REA wraps the same tools for agents: `rea pull-adb-package --output-directory ` pulls the complete split set with a digest per file, `rea read-adb-logcat --count 200` reads a bounded dump, `rea inspect-android-package ` runs headless JADX, and `rea decode-android-resources ` runs apktool with `--no-src` (REA's apktool lane was verified with apktool 2.7.0). REA marks install, push, start and uninstall as device-mutating. See [[entities/rea]]. ## Recommendations 1. Start static: hash the APK, `unzip -l` it, decode the manifest with apktool, and list components and permissions. 2. Open it in `jadx-gui`, start from the manifest's launcher activity and exported components, and search for strings that interest you. 3. Only then move to runtime, on an emulator or dedicated test device: logcat first, Frida tracing next, traffic last. 4. Pull every split, keep the hashes, and save trace and proxy output with the scenario you ran (see [[syntheses/dynamic-analysis-workflow]]). 5. If decompilation output is wrong or missing, try another JADX mode, then compare with apktool's smali, then see [[syntheses/troubleshooting]]. ## Pages Compared - [[entities/frida]]: Frida setup on Android, `frida-trace`, the Frida 17 bridge change. - [[syntheses/dynamic-analysis-workflow]]: choosing tracing versus debugging, keeping evidence. - [[concepts/executable-formats]]: dex format in the context of other executable formats. - [[syntheses/network-captures-and-protocols]]: mitmproxy modes and packet capture. - [[entities/rea]]: agent-driven ADB, JADX and apktool workflows. - [[syntheses/choosing-a-disassembler]]: JEB and others for heavier Android work and native libraries. ## Sources - `raw/web_community-application-fundamentals-app-architecture-android-developers.md` - `raw/web_community-app-manifest-overview-app-architecture-android-developers.md` - `raw/web_community-app-signing-security-android-open-source-project.md` - `raw/web_community-analyze-your-build-with-the-apk-analyzer-android-studio-andr.md` - `raw/github_doc-wiki-the-basics-intro-mdx.md` - `raw/github_doc-wiki-the-basics-decoding-mdx.md` - `raw/github_doc-docs-cli-parameters-mdx.md` - `raw/github_doc-docs-install-mdx.md` - `raw/github_doc-docs-faq-mdx.md` - `raw/github_doc-wiki-the-basics-frameworks-mdx.md` - `raw/github_release-v3-0-3.md` - `raw/github_doc-readme-md-5.md` - `raw/github_release-1-5-6.md` - `raw/web_community-android-debug-bridge-adb-android-studio-android-developers.md` - `raw/web_community-logcat-command-line-tool-android-studio-android-developers.md` - `raw/github_doc-i18n-en-docs-android-md.md` - `raw/github_doc-i18n-en-docs-bridges-md.md` - `raw/web_community-certificates.md` - `raw/web_community-system-ca-on-android-emulator.md` - `raw/github_doc-docs-android-analysis-md.md` - `raw/github_doc-docs-apktool-resource-analysis-md.md` - `raw/github_doc-docs-adb-device-analysis-md.md` - `raw/github_doc-i18n-en-docs-frida-ps-md.md` - `raw/github_doc-i18n-en-docs-frida-trace-md.md` - `raw/github_doc-docs-unreleased-mdx.md` --- title: "Choosing a Disassembler" type: synthesis tags: [disassembler, decompiler, ghidra, ida-pro, jeb, hopper, rizin, cutter, objdump, mcp, comparison] created: 2026-10-16 updated: 2026-10-16 confidence: medium sources: ["raw/github_tag-ghidra-12-1-4-ghidradocs-gettingstarted-md.md", "raw/github_doc-ghidra-features-base-src-main-help-help-topics-importerplugi.md", "raw/github_doc-docs-installation-md.md", "raw/github_doc-third-party-notices-md.md", "raw/github_doc-readme-md-23.md", "raw/github_doc-docs-ghidra-provider-md.md", "raw/web_community-9-4-md.md", "raw/web_community-basic-usage-md.md", "raw/web_community-overview-md-3.md", "raw/web_community-overview-md-4.md", "raw/web_community-running-in-batch-mode-md.md", "raw/github_doc-readme-md-24.md", "raw/github_doc-docs-ida-provider-md.md", "raw/web_community-jeb-decompiler.md", "raw/web_community-faq-jeb-decompiler.md", "raw/web_community-decompiling-jeb-decompiler.md", "raw/web_community-native-code-analysis-jeb-decompiler.md", "raw/web_community-android-analysis-jeb-decompiler.md", "raw/web_community-webassembly-analysis-jeb-decompiler.md", "raw/web_community-ethereum-analysis-jeb-decompiler.md", "raw/web_community-mcp-server-jeb-decompiler.md", "raw/github_doc-docs-jeb-analysis-md.md", "raw/web_community-hopper-tutorial.md", "raw/github_doc-docs-kuna-provider-md.md", "raw/github_doc-src-introduction-overview-md.md", "raw/github_doc-docs-source-user-docs-features-rst.md", "raw/github_doc-docs-source-user-docs-common-issues-rst.md", "raw/github_doc-docs-reverse-engineering-tools-md.md", "raw/web_community-objdump-gnu-binary-utilities.md", "raw/github_doc-readme-md-18.md", "raw/github_doc-doc-usage-md.md", "raw/github_doc-readme-md-21.md", "raw/github_doc-docs-run-md.md", "raw/github_doc-readme-md-20.md", "raw/web_community-9-4sp1-md.md", "raw/github_doc-src-introduction-getting-rizin-md.md", "raw/github_doc-docs-source-index-rst.md", "raw/github_release-rizin-v0-9-1.md", "raw/github_release-cutter-v2-5-0.md", "raw/web_community-whats-new-md.md", "raw/web_community-getting-started-md-2.md", "raw/web_community-agentic-ida-with-idalib-md.md", "raw/github_doc-src-scripting-rz-pipe-md.md", "raw/github_doc-src-first-steps-commandline-options-md.md", "raw/github_doc-src-disassembling-intro-md.md", "raw/github_doc-src-analysis-code-analysis-md.md", "raw/github_doc-ghidra-features-decompiler-src-main-help-help-topics-decompi.md", "raw/github_doc-ghidradocs-ghidraclass-intermediate-versiontracking-html.md"] --- # Choosing a Disassembler ## Comparison Six tools, compared on what usually decides the choice. Versions: Ghidra 12.1.4, IDA 9.4sp1, Rizin 0.9.1 / Cutter 2.5.0; JEB as documented in its online manual (REA verifies against JEB 5.48.0). | | Ghidra | IDA Pro | JEB | Hopper | Rizin / Cutter | GNU objdump | |---|---|---|---|---|---|---| | **Cost** | Free, Apache-2.0 | Commercial: Home, Pro (Essential/Expert/Ultimate), Classroom; available decompilers depend on plan | Commercial subscription, no perpetual licences; OEM licensed per server; 30% student discount for non-profit research | Commercial; free demo with vendor-set limits | Free, open source | Free (GNU binutils) | | **Host** | Windows, Linux, macOS (prebuilt natives for Win x64, Win ARM64 via x86 emulation, and Linux x64) | Windows (incl. native ARM64 in 9.4), Linux, macOS | Windows, Linux, macOS on x64 and arm64; needs a JDK 21+ (21–23 recommended) | macOS and Linux (the platforms REA's Hopper installer supports) | Windows, macOS, Linux | Any binutils host | | **Decompiler** | Yes, built in and free (works from each processor's SLEIGH/p-code model) | Hex-Rays (per-architecture, per-plan) | `dexdec` (Dalvik/Java) and `gendec` (x86, ARM, MIPS, RISC-V, wasm, EVM, Simatic S7, Nvidia SASS) | Pseudo-code mode | `pdg` via rz-ghidra; Cutter also takes RetDec/JSDec plugins | None | | **Standout strengths** | Broad loader set (PE, ELF, Mach-O, DYLD cache, DEX/APK, raw); Version Tracking; team server | Mature interactive analysis; 9.4 Dyld Shared Cache workflow, Swift ABI, SVE2/SME, Hexagon; FLIRT and Lumina | Android end to end (APK, resources, certs, multi-DEX, Dalvik/native debugging); deobfuscating decompiler (control-flow unflattening, opaque predicates); wasm and EVM decompilers | Readable macOS-native workflow with CFG and pseudo-code views | Scriptable terminal workflow, `rz-bin` one-shot triage, JSON output (`j` suffix) on many commands | Already installed; exact, raw linear disassembly | | **Scripting / headless** | Java and PyGhidra; `analyzeHeadless` | IDC, IDAPython, Domain API, C++ SDK; idalib headless; `-Ohexrays` batch decompile | Python client scripts and back-end plugins through the JEB API; command-line runners | Not covered here | `rz-pipe` (Python, Rust, Haskell, OCaml, Ruby); `rizin -qc` | Shell pipelines | | **Agent / MCP** | Community GhidraMCP (targets Ghidra 12.1.4); REA provider | Official Hex-Rays IDA MCP Server (9.4+); community `ida-pro-mcp` (IDA Pro 8.3+, **not IDA Free**); REA adapter | Built-in MCP server (default port `8425`) and the VIBRE in-GUI assistant | Driven through REA | REA bridge (persistent debugger sessions Linux-only) | REA `inspect-with-objdump` | ## Analysis ### Format and architecture decide most cases - **Android apps.** JEB is built for this: APK, encoded resources, legacy/v2/v3 certificates, multi-DEX decompilation, and seamless Dalvik↔native debugging. The free route is JADX plus apktool, covered in [[syntheses/android-apk-analysis]]. JEB also analyses the APK's native `.so` libraries; on the free route they go to Ghidra (or IDA). - **Apple platforms.** IDA 9.4's rebuilt Dyld Shared Cache workflow loads cache images on demand and searches by address, symbol or string across unloaded parts. Its Swift ABI annotations (`__swiftself`, `__swiftthrows`, `__swiftasync`) make it the strongest documented choice for iOS and macOS system code. Ghidra also imports DYLD shared caches and Mach-O. Hopper's pseudo-code reads "more or less like an Objective-C method", which suits light macOS work. - **WebAssembly and EVM.** JEB has dedicated decompilers for both. Its EVM analyser identifies public and private methods and tries to recover method and event names without an ABI, and its wasm output is C-like. See [[concepts/webassembly]] and [[concepts/evm-bytecode]] for the free toolchains. - **Firmware and unusual CPUs.** Ghidra's SLEIGH processor set plus the Raw Binary loader with a chosen Language ID is the default free path ([[syntheses/firmware-analysis]]). IDA 9.4 added Hexagon (QDSP6) with a Qualcomm MBN loader, MCore, more TriCore and RISC-V extensions, and ARM SVE2/SME. - **Quick looks and scripting.** `objdump -d` disassembles only the sections expected to hold code and won't cross a symbol boundary. `-D` disassembles every non-empty, non-bss section and drops that assumption, so the two can differ when data sits in code. `-M intel` switches x86 output to Intel syntax, and `-b -m ` forces format and architecture. `rz-bin -I` gives a one-screen security and format summary. Neither builds a function database. ### Budget and licensing Ghidra and Rizin/Cutter cost nothing and have no seat limits. IDA's decompiler coverage depends on the product you buy. Embedding idalib in a product, SaaS or shared server needs an IDA Pro OEM licence. JEB keeps opening existing projects after a subscription lapses but won't create new ones. Its published EULA also restricts public or third-party disclosure of decompiled code and analysis reports unless your licence type allows it, which matters if you publish write-ups. Hopper's personal and computer licences have different user and installation rules. For IDA, having an API or a bridge explicitly doesn't grant hosting, service or extra-user rights; check each vendor's agreement the same way. See [[concepts/legal-and-ethics]]. ### Scripting and automation For large batch jobs: Ghidra's `analyzeHeadless` and IDA's idalib both import and analyse without a GUI, and IDA can batch-decompile with `idat -Ohexrays:...:outfile:ALL -A input`. Rizin is the lightest to script, since many commands take a `j` suffix for JSON output and `rz-pipe` parses it. JEB's back end runs separately from the GUI and is designed for analysis pipelines. ### Agent and MCP support - **IDA**'s MCP server is first-party, open source and vendor-supported. It needs IDA 9.4+ with idalib, attaches to GUI databases or starts headless workers, and coordinates several databases. - **JEB** ships MCP in the product. The manual registers it with `claude mcp add --transport http jeb http://localhost:8425/mcp` or `codex mcp add jeb --url http://localhost:8425/mcp`. The manual also lists `jeb_wincon.bat -c --mcp` as a command-line start. REA's testing found that JEB 5.48's `-c` headless mode does not accept `--mcp` and that headless instances don't offer `open_project`, so use the GUI or the programmatic `JebMcpServerInstance` route. - **Ghidra** relies on community GhidraMCP or REA. REA imports each target into a throwaway Ghidra database: read-only analysis plus function-name and comment edits on Linux and macOS, read-only on Windows. - REA can also use **Kuna**, an Apache-2.0 static decompiler, for ELF and thin Mach-O on x86-64, AArch64 and ARM. It doesn't support PE or Windows. Details and safety notes are in [[syntheses/re-with-ai-agents-mcp]]. ### Where triage tools sit before the disassembler Don't start with a disassembler on a suspicious file. Run the pre-filters first and let them tell you where to look ([[syntheses/malware-triage]], [[syntheses/triage-an-unknown-binary]]): 1. **Detect It Easy** (`diec `) identifies format, compiler and packer or protector, and flags structural anomalies, without running the file. A packed result means unpack or run dynamically before deep static work. 2. **FLOSS** pulls static, stack, tight and decoded strings that plain `strings` misses. 3. **capa** reads a PE, ELF, .NET module, shellcode or sandbox report and lists capabilities mapped to ATT&CK. It plugs into the disassembler step directly. The **capa explorer** plugin runs inside **IDA Pro** and uses your IDB edits to extract better features. A **Ghidra** plugin shows results in the Ghidra UI, and Ghidra can serve as capa's feature-extraction backend through PyGhidra. capa also runs on Binary Ninja's backend. Only then open the sample in Ghidra or IDA, starting from the functions capa and FLOSS pointed at. ## Recommendations - **Default free choice:** Ghidra. Add Rizin for terminal and scripted work and `rz-bin` triage, and Cutter if you want a lighter GUI over Rizin. - **Professional native work, Apple code, or vendor-supported agent integration:** IDA Pro 9.4sp1 with Hex-Rays. Check that your plan includes the decompilers for your target architectures. - **Android-heavy, obfuscated Java/Dalvik, wasm or EVM:** JEB, if the licence and its disclosure terms fit. Otherwise JADX/apktool for Android and the free wasm and EVM tools. - **Occasional macOS reversing on a budget:** Hopper's demo, or Ghidra. - **Sanity checks and CI:** `objdump` and `rz-bin` give quick, reproducible output with nothing to configure. - **Malware:** DIE → FLOSS → capa first, then a disassembler with capa explorer loaded. Never run samples on your host. - **Whatever you pick:** results depend more on fixing prototypes and types than on the tool ([[concepts/decompilation-concepts]]). ## Pages Compared - [[entities/ghidra]] - [[entities/ida-pro]] - [[entities/rizin-and-cutter]] - [[concepts/decompilation-concepts]] - [[syntheses/malware-triage]] - [[syntheses/android-apk-analysis]] - [[syntheses/re-with-ai-agents-mcp]] - [[entities/rea]] ## Sources - `raw/github_tag-ghidra-12-1-4-ghidradocs-gettingstarted-md.md` - `raw/github_doc-ghidra-features-base-src-main-help-help-topics-importerplugi.md` - `raw/github_doc-docs-installation-md.md` - `raw/github_doc-third-party-notices-md.md` - `raw/github_doc-readme-md-23.md` - `raw/github_doc-docs-ghidra-provider-md.md` - `raw/web_community-9-4-md.md` - `raw/web_community-basic-usage-md.md` - `raw/web_community-overview-md-3.md` - `raw/web_community-overview-md-4.md` - `raw/web_community-running-in-batch-mode-md.md` - `raw/github_doc-readme-md-24.md` - `raw/github_doc-docs-ida-provider-md.md` - `raw/web_community-jeb-decompiler.md` - `raw/web_community-faq-jeb-decompiler.md` - `raw/web_community-decompiling-jeb-decompiler.md` - `raw/web_community-native-code-analysis-jeb-decompiler.md` - `raw/web_community-android-analysis-jeb-decompiler.md` - `raw/web_community-webassembly-analysis-jeb-decompiler.md` - `raw/web_community-ethereum-analysis-jeb-decompiler.md` - `raw/web_community-mcp-server-jeb-decompiler.md` - `raw/github_doc-docs-jeb-analysis-md.md` - `raw/web_community-hopper-tutorial.md` - `raw/github_doc-docs-kuna-provider-md.md` - `raw/github_doc-src-introduction-overview-md.md` - `raw/github_doc-docs-source-user-docs-features-rst.md` - `raw/github_doc-docs-source-user-docs-common-issues-rst.md` - `raw/github_doc-docs-reverse-engineering-tools-md.md` - `raw/web_community-objdump-gnu-binary-utilities.md` - `raw/github_doc-readme-md-18.md` - `raw/github_doc-doc-usage-md.md` - `raw/github_doc-readme-md-21.md` - `raw/github_doc-docs-run-md.md` - `raw/github_doc-readme-md-20.md` - `raw/web_community-9-4sp1-md.md` - `raw/github_doc-src-introduction-getting-rizin-md.md` - `raw/github_doc-docs-source-index-rst.md` - `raw/github_release-rizin-v0-9-1.md` - `raw/github_release-cutter-v2-5-0.md` - `raw/web_community-whats-new-md.md` - `raw/web_community-getting-started-md-2.md` - `raw/web_community-agentic-ida-with-idalib-md.md` - `raw/github_doc-src-scripting-rz-pipe-md.md` - `raw/github_doc-src-first-steps-commandline-options-md.md` - `raw/github_doc-src-disassembling-intro-md.md` - `raw/github_doc-src-analysis-code-analysis-md.md` - `raw/github_doc-ghidra-features-decompiler-src-main-help-help-topics-decompi.md` - `raw/github_doc-ghidradocs-ghidraclass-intermediate-versiontracking-html.md` --- title: "Dynamic Analysis Workflow" type: synthesis tags: [dynamic-analysis, debugging, instrumentation, tracing, record-replay, checkpoints, process-capture, core-dumps, evidence, sandboxing, gdb, frida, rea] created: 2026-10-16 updated: 2026-10-16 confidence: medium sources: ["raw/web_community-breakpoints-debugging-with-gdb.md", "raw/web_community-set-watchpoints-debugging-with-gdb.md", "raw/web_community-attach-debugging-with-gdb.md", "raw/web_community-process-record-and-replay-debugging-with-gdb.md", "raw/web_community-checkpoint-restart-debugging-with-gdb.md", "raw/web_community-core-file-generation-debugging-with-gdb.md", "raw/web_community-server-debugging-with-gdb.md", "raw/github_doc-i18n-en-docs-modes-md.md", "raw/github_doc-i18n-en-docs-index-md.md", "raw/github_doc-i18n-en-docs-frida-trace-md.md", "raw/github_doc-i18n-en-docs-gadget-md.md", "raw/github_doc-docs-frida-instrumentation-md.md", "raw/github_doc-docs-process-capture-md.md", "raw/github_doc-docs-recorded-crashes-md.md", "raw/github_doc-agents-skills-reverse-engineer-anything-references-runtime-o.md", "raw/github_doc-agents-skills-reverse-engineer-anything-references-evidence-.md", "raw/github_doc-docs-reverse-engineering-tools-md.md", "raw/github_doc-disclaimer-md.md"] --- # Dynamic Analysis Workflow Static analysis tells you what code *could* do; dynamic analysis shows what it *does* on a given run. This page helps you pick the right runtime technique for the question, run it without hurting your host, and keep results you can defend later. For tool detail see [[entities/gdb-and-pwndbg]] and [[entities/frida]]. Running a program is a separate act from reading it. The disclaimer of REA (rea-agents, an agent-driven reverse-engineering toolkit; see [[entities/rea]]) makes the point directly: permission to inspect an artifact does not necessarily cover executing it, intercepting its traffic or changing a device, and having a file or a reachable debugging endpoint does not by itself grant permission. Settle that first; see [[concepts/legal-and-ethics]]. ## Comparison | Technique | Best question it answers | How intrusive | Platform notes | What you keep | |---|---|---|---|---| | **Debugger** (GDB, pwndbg) | "What is the exact state at this instruction, and who wrote this value?" | Stops the process; software watchpoints single-step and run hundreds of times slower | GDB attach needs an OS with processes and permission to signal the target. REA's GDB sessions are Linux-only | Session notes, `gcore` snapshots, backtraces | | **Instrumentation** (Frida scripts) | "Every time this function runs, what were its arguments and result?" | Code runs inside the target with the target's memory, file and network authority; the process keeps running | Injected mode needs frida-server (root/jailbreak on mobile); Gadget embedded in your own build on non-rooted devices | Message logs; REA records script path and SHA-256 | | **Tracing** (`frida-trace`) | "Which of these APIs get called, and in what order?" | Light: auto-generated hooks that log and keep going | Same as Frida | `-o` writes the trace to a file | | **Record/replay** (GDB `record`) | "How did we get here?" Step backwards through a recorded window | Heavy: `full` method records every instruction (default cap 200000) | GNU/Linux on x86, ARM, AArch64, PowerPC, RISC-V, S/390 and others; also via gdbserver | `record save` writes the log to a file | | **Checkpoints** (GDB `checkpoint`) | "Let me retry from just before the bug." | Cheap: a snapshot copy of the process | GNU/Linux only | In-session only | | **Process capture** (REA) | "Did two runs of the same scenario behave the same?" | Runs the command as you; no isolation | Capture on Linux or macOS; not native Windows | Evidence JSON with terminal output, exit, process tree, file before/after hashes | | **Core inspection** (GDB, REA `inspect-recorded-crash`) | "What was the state when it crashed?" | None at analysis time; reads a file | REA reads Linux ELF64 cores, x86-64 and AArch64 | The core file plus its SHA-256 | ## Analysis ### Choosing a technique Start from the question, not the tool. 1. **You don't yet know where to look.** Trace first. `frida-trace -i "recv*" -i "read*" ` or `-I ` gives a cheap call timeline that tells you which functions matter, and it does not stop the program. Tracing is usually also the least disruptive option for UI apps and services that time out when paused. 2. **You know the function and need the values.** Write a small Frida script that hooks it and reports arguments and return values back to the host, or set a GDB breakpoint there. Pick Frida when stopping would change behaviour (timeouts, watchdogs, network peers) or on mobile; pick GDB when you need to stop and look around: registers, stack, heap, nearby memory. 3. **You know the data and need the writer.** A GDB hardware watchpoint (`watch *(int *) 0xADDR`) stops at the exact instruction that changed it. If only software watchpoints are available it still works, just much more slowly, and it reports at the next statement instead. 4. **The bug happens long before the symptom.** Use record/replay: `start`, then `record` (the process must already be running), run to the failure, then step backwards or `record goto begin`. The `full` method stops at 200000 instructions by default (`set record full insn-number-max` changes it), so start recording close to the region you care about. Intel's `record btrace` (`bts` or `pt`) has lower overhead but records no data, so variables and registers are unavailable when you step backwards. 5. **You keep overshooting.** Drop a `checkpoint` before the suspect area and `restart ` instead of re-running. On Linux a checkpoint is an identical process copy, so addresses stay put even with ASLR, which keeps address breakpoints valid. It rewinds file positions but cannot un-write file contents or recall bytes already sent to a device. 6. **You need to compare two builds or two runs.** REA process capture runs one scenario (`rea capture-process ./scenario.json --json > capture.json`) and `rea compare-process-captures a.json b.json` reports where terminal output, exit, files or process trees differ. It refuses to compare captures taken under different working directories, environments or observation paths, so keep those identical. 7. **It already crashed.** Analyse the core rather than reproducing. In a live session `gcore` saves one on demand. REA's `inspect-recorded-crash` reads Linux ELF64 cores for x86-64 and AArch64 and can optionally add pwndbg memory-map context. It needs a caller-supplied Python environment with pinned parsing libraries, and it treats the PIDs recorded in a core as metadata only, never as a live process to attach to. For browser and Electron targets, REA's runtime observation is passive by design: it attaches to a loopback DevTools (CDP) endpoint and never claims it clicked, navigated or ran page JavaScript unless you asked it to run a declared scenario. See [[syntheses/javascript-and-electron-apps]]. ### Sandboxing untrusted targets Every technique on this page except core inspection runs the target, and none of them contains it: - **Process capture is explicitly not a sandbox.** The command runs with your user's permissions and inherits your environment; observation paths only choose what gets snapshotted, not what the process may touch. - **Frida scripts** execute with the target process's memory, filesystem and network authority, so a hostile target is just as hostile while hooked. - **REA's resource limits** on crash inspection are not a sandbox for the engine code either. - **gdbserver has no authentication.** Whoever connects gets the privileges of the user running it, so never expose it on a public network. Frida's Gadget listens on `127.0.0.1` by default; keep it there, or set its `token` and `certificate` options. REA's guidance is to "use an appropriate environment for untrusted targets" and to review agent-generated scripts before running them. For a suspicious sample, follow the safe-handling steps in [[syntheses/malware-triage]] before running anything. For mobile work, use a dedicated test device or an emulator rather than a personal phone. ### Keeping evidence Dynamic results are only as good as your record of the run. Habits that hold up: - **Hash inputs first.** Record the SHA-256 of the binary, script and any core file. REA does this automatically: Frida evidence stores the script's path and digest (not its source), and crash evidence stores the core's digest and size. - **Save the run, not just your conclusion.** `frida-trace -o`, `record save ` (default name `gdb_record.`), `gcore` and REA's capture JSON all give you something a reviewer can re-examine. A saved record log can be loaded again with `record restore`. - **Write down the scenario.** Arguments, environment overrides, working directory and timing all change behaviour. REA's capture commits these into the set of settings both captures must share, and inputs marked `sensitive` are stored only as a byte count. - **Mark gaps honestly.** REA's evidence model records truncation and residual unknowns rather than treating missing data as absence: a filesystem snapshot is not a syscall trace and can miss short-lived changes, and a static/runtime correlation is a hypothesis, not proof of causality. - **Protect what you captured.** Traces and captures can contain credentials and personal data; you are responsible for storing and sharing them appropriately. ## Recommendations - **Default order:** trace, then hook, then break. Escalate only when the cheaper method can't answer the question. - **On Linux desktop binaries:** GDB with pwndbg for state, `checkpoint` to iterate, `record` for short "how did we get here" windows, `gcore` before anything destructive. - **On Android or iOS apps you are authorized to test:** Frida on a test device; see [[syntheses/android-apk-analysis]]. - **For regression or reconstruction checks:** REA process capture with identical scenarios on both sides; add `finalization_ms` if the target must write a final report before a timeout kills it. - **Remote targets:** gdbserver over SSH (`target remote | ssh -T host gdbserver - prog`) avoids opening a listening port. - **Agent-driven sessions:** REA's GDB sessions need Linux, and its process capture needs Linux or macOS; on Windows, run Linux REA inside WSL for Linux targets. ## Pages Compared - [[entities/gdb-and-pwndbg]]: breakpoints, watchpoints, record/replay, checkpoints, gdbserver. - [[entities/frida]]: injected, embedded and preloaded instrumentation; `frida-trace`. - [[entities/rea]]: process capture, recorded crashes, Frida and GDB providers, evidence. - [[syntheses/malware-triage]]: safe handling before execution. - [[syntheses/triage-an-unknown-binary]]: static first look before running anything. ## Sources - `raw/web_community-breakpoints-debugging-with-gdb.md` - `raw/web_community-set-watchpoints-debugging-with-gdb.md` - `raw/web_community-attach-debugging-with-gdb.md` - `raw/web_community-process-record-and-replay-debugging-with-gdb.md` - `raw/web_community-checkpoint-restart-debugging-with-gdb.md` - `raw/web_community-core-file-generation-debugging-with-gdb.md` - `raw/web_community-server-debugging-with-gdb.md` - `raw/github_doc-i18n-en-docs-modes-md.md` - `raw/github_doc-i18n-en-docs-index-md.md` - `raw/github_doc-i18n-en-docs-frida-trace-md.md` - `raw/github_doc-i18n-en-docs-gadget-md.md` - `raw/github_doc-docs-frida-instrumentation-md.md` - `raw/github_doc-docs-process-capture-md.md` - `raw/github_doc-docs-recorded-crashes-md.md` - `raw/github_doc-agents-skills-reverse-engineer-anything-references-runtime-o.md` - `raw/github_doc-agents-skills-reverse-engineer-anything-references-evidence-.md` - `raw/github_doc-docs-reverse-engineering-tools-md.md` - `raw/github_doc-disclaimer-md.md` --- title: "Firmware Analysis: binwalk, unblob and Loading Raw Images" type: synthesis tags: [firmware, binwalk, unblob, entropy, carving, ghidra, raw-binary, embedded] created: 2026-10-16 updated: 2026-10-16 confidence: medium binwalk_version: "3.1.0" unblob_version: "26.6.4" sources: ["raw/github_doc-readme-md-16.md", "raw/web_community-cargo-installation-md.md", "raw/web_community-file-analysis-and-extraction-md.md", "raw/web_community-carving-file-data-md.md", "raw/web_community-generating-entropy-graphs-md.md", "raw/web_community-json-analysis-results-md.md", "raw/web_community-errors-and-debugging-md.md", "raw/web_community-limitations-md.md", "raw/web_community-speed-and-accuracy-md.md", "raw/github_doc-readme-md-15.md", "raw/github_doc-docs-guide-md.md", "raw/github_doc-docs-installation-md-2.md", "raw/github_doc-docs-index-md-3.md", "raw/github_doc-docs-firmware-analysis-md.md", "raw/github_doc-docs-raw-binary-md.md", "raw/github_doc-docs-ghidra-mips-md.md", "raw/github_doc-docs-ghidra-riscv-md.md", "raw/github_doc-docs-ghidra-ppc-md.md", "raw/github_doc-ghidra-features-base-src-main-help-help-topics-importerplugi.md", "raw/github_doc-ghidra-runtimescripts-support-analyzeheadlessreadme-md.md"] --- # Firmware Analysis: binwalk, unblob and Loading Raw Images A firmware image is usually a container of containers: a vendor header, a compressed kernel, one or more filesystems, and padding. The workflow is to map the regions first, extract what can be extracted, check entropy for what can't, and only then load individual executables (or a headerless blob with a known CPU and load address) into a disassembler. Work only on images you own or are authorized to examine; see [[concepts/legal-and-ethics]]. ## Comparison | Need | binwalk v3 | unblob | |---|---|---| | Quick "what is in here?" map with offsets | Primary use: `binwalk image.bin` | Possible via `--report`, but extraction-first | | Recursive extraction | `-Me` | Default behaviour, depth 10 | | Carve unknown regions to disk | `--carve` (known and unknown sections) | Unknown chunks carved automatically; null/`0xFF` padding identified | | Entropy | `--entropy` PNG graph (0–8 scale) | Shannon entropy and chi-square per unknown chunk (`-n`, `-vvv` draws a chart) | | Machine-readable output | `--log=results.json` | `--report report.json` | | Confidence signal | Colour: green high, yellow medium, red magic-bytes only | Start and end offsets computed from the format standard | | Implementation | Rust rewrite with custom parsers | Python with Rust and Hyperscan; external extractors | | Install | `cargo install binwalk` (does not install external extraction dependencies) or Docker (bundles them) | `pip install unblob` plus extractors, Docker, Kali `apt install unblob`, Nix | | Privileges | Not stated in sources | Runs as a regular user | REA pins **binwalk 3.1.0** and **unblob 26.6.4** as its verified parser versions; other 3.1.x / 26.6.x builds are accepted but flagged as unverified. ## Analysis ### Step 1: map regions with binwalk ```bash binwalk /tmp/firmware.bin # signature scan binwalk -e /tmp/firmware.bin # scan and extract binwalk -Me /tmp/firmware.bin # scan and recursively extract binwalk --exclude=jpeg,png,gif /tmp/firmware.bin binwalk --log=results.json /tmp/firmware.bin ``` Signature names for `--include`/`--exclude` come from the "Signature Name" column of the supported-signatures list. Treat red (low-confidence) hits as leads, not facts: only the magic bytes matched. Version 3 parsers validate structure and learn each embedded file's size, so it skips over (for example) a gzip body instead of reporting false hits inside it. The project's own comparison shows v2 reporting MySQL and Zlib signatures inside a plain `.tgz` where v3 reports a single gzip entry. The JSON log records, per hit, `offset`, `size`, `name`, `confidence` and `description`, plus an `extractions` object when extraction was requested. That is the format to feed into scripts. ### Step 2: check entropy for what binwalk can't name ```bash binwalk --entropy firmware.bin # PNG saved to the current directory binwalk --entropy --log=results.json firmware.bin # per-block entropy in JSON ``` Add `--png` to write the graph to a file of your choosing instead of the current directory. Both compression and encryption push entropy toward 8. A long flat high-entropy region with no recognised signature is a candidate for encrypted or unknown-compressed data; low or zero blocks are usually padding. Entropy alone can't tell compression from encryption. ### Step 3: extract with unblob ```bash pip install unblob unblob --show-external-dependencies # confirm every extractor is present unblob firmware.bin # output in firmware.bin_extract/ unblob -e /tmp/output firmware.bin unblob --report report.json firmware.bin unblob -d 5 -n 2 firmware.bin # depth 5, entropy for two levels unblob --skip-magic "POSIX tar archive" firmware.bin ``` Key defaults from the CLI help: `-d/--depth` 10, `-n/--entropy-depth` 1 (0 turns it off), `-p/--process-num` CPU count. The default skip-magic list already ignores formats unlikely to hold more firmware (JPEG, PNG, SQLite, PDF, fonts, and similar). unblob's distinguishing idea is that it computes both start and end offsets from each format's specification, so the space between known chunks becomes explicit "unknown chunks" rather than silent gaps. The Python package does **not** include the extractors. On Ubuntu/Debian the docs install them with: ```bash sudo apt install android-sdk-libsparse-utils e2fsprogs p7zip-full unar zlib1g-dev liblzo2-dev lzop lziprecover libhyperscan-dev zstd lz4 ``` SquashFS additionally needs the project's `sasquatch` package. The Docker image (`ghcr.io/onekey-sec/unblob:latest`) bundles everything. The host directories you mount must share the container's `uid:gid`, so add `-u $UID:$GID` on multi-user hosts. ### Step 4: load executables, or the raw blob, in Ghidra Extracted ELF binaries import normally (see [[entities/ghidra]]). For a headerless image such as a bootloader, ECU (engine control unit) dump or ROM, Ghidra's **Raw Binary** format is always offered in the import dialog. Its options are Block Name (default: the default address space, usually `ram`), Base Address (default 0), File Offset (default 0) and Length (default: whole file). You must pick the language yourself. The headless equivalent: ```bash analyzeHeadless /path/projects MyProject -import image.bin -loader BinaryLoader \ -loader-baseAddr 0x1000 -loader-blockName MyBlock -processor x86:LE:32:default ``` Getting the base address and processor right is the whole game: a wrong base breaks every absolute pointer and cross-reference. ### Doing the same through REA [[entities/rea]] wraps both engines without installing them. Supply absolute paths and run on Linux; REA's firmware support is verified on Linux x64 only: ```sh export REA_BINWALK_COMMAND=/absolute/path/to/binwalk export REA_UNBLOB_COMMAND=/absolute/path/to/unblob rea inspect-firmware-regions /path/to/firmware.bin rea extract-firmware /path/to/firmware.bin /path/to/new-output --offset 64 --length 4096 --max-depth 3 ``` Its limits are worth knowing even if you run the tools directly: | Limit | Value | |---|---| | Input size | 128 MiB | | Deadline | 120 seconds; 1 GiB address space and 120 CPU seconds per process via `prlimit` | | Staging budget | 256 MiB and 10,000 entries (`--max-output-bytes`, `--max-output-files`) | | Depth | default 3, range 1–10 | | Output directory | must be absent, absolute, with an existing parent; never overwritten | It also needs util-linux `prlimit` (override with `REA_FIRMWARE_PRLIMIT_COMMAND`) and a procps-compatible `ps` on `PATH`. It keeps unblob's Landlock sandbox on and never retries with `--no-sandbox`. For headerless code REA requires an explicit CPU and entry address, and never guesses either from a `.bin` suffix: ```bash rea inspect /absolute/path/to/ecu.bin --target-format raw-binary --architecture arm --entry-point 0x8000000 --provider ghidra --json ``` | `--architecture` | Ghidra language | Alignment | |---|---|---| | `x86` / `x86_64` | `x86:LE:32:default` / `x86:LE:64:default` (compiler `gcc`) | byte | | `arm` | `ARM:LE:32:v7` | 4-byte | | `arm64` | `AARCH64:LE:64:v8A` | 4-byte | | `6502` | `6502:LE:16:default` | byte; image must fit in `0x0000..0xffff` | | `m68k` | `68000:BE:32:default` | 2-byte | Big-endian ARM, Thumb-only and Cortex-M are not supported for raw binaries, and Hopper and IDA refuse raw targets. For extracted ELF children, REA's MIPS, RISC-V and PowerPC ELF support pins languages because Ghidra's header auto-selection can be wrong. A plain `EM_PPC` header gets `PowerPC:BE:32:e500:default`, which misreads ordinary 750-family code. Recordless legacy MIPS32 executables get a 64-bit language unless pinned to `MIPS::32:default`. RISC-V admits little-endian `ET_EXEC` with the double-float ABI only. Ghidra 12.1.4 ships no big-endian RISC-V language. ## Recommendations - **Start with binwalk for the map, then use unblob to extract.** binwalk is the fast survey; unblob's end-offset accuracy and unknown-chunk reporting make it the better extractor when you need to account for every byte. - **Run `unblob --show-external-dependencies` before trusting an empty result.** A missing extractor (for example `debugfs` for ext filesystems, or `sasquatch` for SquashFS) leaves those chunks unextracted with only partial results, which is easy to mistake for "nothing there". - **Read red binwalk hits and lone magic matches skeptically**, and confirm them with entropy and a second tool. - **Size your machine:** binwalk needs at least as much free memory as the file being analysed. - **Debug noisy runs with `RUST_LOG`**: `RUST_LOG=off`, `RUST_LOG=info` or `RUST_LOG=debug binwalk -Me file.bin`. Logs go to stderr. - **Record base address and language** alongside any finding from a raw import, because the same bytes at a different base are a different program. - **Not covered here:** reset-vector inference, memory-mapped I/O, device trees, firmware emulation and encrypted-image recovery. None of the sources provide procedures for them, and REA explicitly excludes most of them (reset vectors, memory-mapped I/O, device-tree semantics, emulation). ## Pages Compared - [[entities/ghidra]]: raw import, language selection and auto-analysis - [[syntheses/triage-an-unknown-binary]]: what to do with each extracted ELF - [[concepts/executable-formats]]: ELF headers, `e_flags` and machine types - [[entities/rea]]: agent-driven firmware inspection and its limits - [[syntheses/choosing-a-disassembler]]: which tool handles the extracted architecture ## Sources - `raw/github_doc-readme-md-16.md` - `raw/web_community-cargo-installation-md.md` - `raw/web_community-file-analysis-and-extraction-md.md` - `raw/web_community-carving-file-data-md.md` - `raw/web_community-generating-entropy-graphs-md.md` - `raw/web_community-json-analysis-results-md.md` - `raw/web_community-errors-and-debugging-md.md` - `raw/web_community-limitations-md.md` - `raw/web_community-speed-and-accuracy-md.md` - `raw/github_doc-readme-md-15.md` - `raw/github_doc-docs-guide-md.md` - `raw/github_doc-docs-installation-md-2.md` - `raw/github_doc-docs-index-md-3.md` - `raw/github_doc-docs-firmware-analysis-md.md` - `raw/github_doc-docs-raw-binary-md.md` - `raw/github_doc-docs-ghidra-mips-md.md` - `raw/github_doc-docs-ghidra-riscv-md.md` - `raw/github_doc-docs-ghidra-ppc-md.md` - `raw/github_doc-ghidra-features-base-src-main-help-help-topics-importerplugi.md` - `raw/github_doc-ghidra-runtimescripts-support-analyzeheadlessreadme-md.md` --- title: "JavaScript Bundles and Electron Apps" type: synthesis tags: [javascript, electron, asar, fuses, source-maps, wakaru, bundles, minified, cdp, inspector] created: 2026-10-16 updated: 2026-10-16 confidence: medium sources: ["raw/github_doc-readme-md-13.md", "raw/github_doc-docs-cli-md-2.md", "raw/web_community-source-map-format-specification.md", "raw/github_doc-readme-md-12.md", "raw/web_community-asar-archives-electron.md", "raw/web_community-electron-fuses-electron.md", "raw/github_doc-docs-electron-fuses-md.md", "raw/github_doc-docs-electron-observation-md.md", "raw/github_doc-docs-javascript-runtime-observation-md.md", "raw/github_doc-docs-javascript-recovery-md.md", "raw/github_doc-docs-javascript-artifact-reconstruction-md.md", "raw/github_doc-docs-javascript-runtime-reconciliation-md.md"] --- # JavaScript Bundles and Electron Apps Shipped JavaScript is often not obfuscated in the reverse-engineering sense. Much of it has only been bundled, transpiled and minified. Recovering it is mostly a matter of applying the right tool in the right order: look for source maps, unpack the bundle into modules, restore modern syntax, then add runtime observation if you need it. Electron apps add a packaging layer (the ASAR archive) and package-time switches (fuses) that decide which observation techniques will work at all. ## Comparison | Technique | Input | What you get | Runs target code? | Main limits | |---|---|---|---|---| | **Source map recovery** | `.map` file referenced by the bundle | Original file names, and original sources when `sourcesContent` is embedded | No | Only works if a map shipped or is reachable | | **wakaru unpack/decompile** | Bundle, chunk set, directory, Bun single-file executable, Google Tag Manager (GTM) container | Per-module files with modern syntax (ESM, `async`/`await`, `??`, `?.`) | No | Minified local names stay short. Heavy control-flow or VM obfuscation is out of scope | | **ASAR extraction** | `app.asar` (+ `app.asar.unpacked/`) | The packaged app tree | No | Unpacked companions must be collected separately | | **Static app graph (REA, see [[entities/rea]])** | ASAR or extracted directory | Entry points, preload, `contextBridge` APIs, IPC channels/handlers, endpoints, native add-on requests | No | Inferences from syntax. Dynamic values stay unresolved | | **Fuse read** | Electron executable / framework binary | Which runtime switches (Inspector, `ELECTRON_RUN_AS_NODE`, ASAR integrity) are honored | No | Code can still enable debugging another way | | **Passive runtime observation** | Running Node/Electron with a loopback Inspector or Chrome DevTools Protocol (CDP) endpoint | Which scripts actually loaded, execution contexts, workers, page structure | Target is already running | Depends on fuses and on attach timing | | **Active Electron scenario (REA)** | Electron executable + entry point | Window/WebContents timeline, IPC channel and argument-shape metadata | Yes, launches it | Not a sandbox. Needs Inspector-capable fuses | ## Analysis ### 1. Find the code Electron normally bundles the app's source into an ASAR archive. With default fuses, Electron looks for code in `app.asar`, then `app`, then `default_app.asar`. ASAR is a flat, uncompressed, tar-like format: a Pickle-encoded 8-byte `header_size`, a JSON header, then the file bytes. Each header entry records `offset` (a UINT64 stored as a string, relative to the end of the header), `size`, an optional `executable` flag, and `integrity` (a SHA256 `hash` of the whole file plus per-block hashes at a stated `blockSize`). Files with identical contents are stored once, and several entries can point at the same offset. Files excluded at pack time with `--unpack-dir` live on disk in an `.asar.unpacked` companion, not inside the archive. ```bash npm install --engine-strict @electron/asar # needs Node 22.12.0+ asar list app.asar asar extract app.asar extracted/ asar extract-file app.asar package.json ``` Inside a running app, Electron patches Node's `fs` and `require` so they treat archives as read-only virtual directories. A few APIs (`child_process.execFile`, `fs.open`, `process.dlopen` for native modules) get the needed file extracted to a temporary path first. `fs.stat` results for archive members are guessed, so only size and file type are trustworthy. To read the archive as a plain file from Node, use the `original-fs` module or set `process.noAsar = true`. ### 2. Check for source maps before decompiling A bundle can point to its map through a `//# sourceMappingURL=` comment, or through a `sourcemap:` HTTP header when served over HTTP. The older `x-sourcemap` header is deprecated, and the HTTP header wins over the comment if both are present. The map is JSON with `"version": 3`, `sources`, `names`, `mappings`, an optional `sourcesContent` array of original source text, and an optional `ignoreList` marking third-party sources (some browsers still read the deprecated `x_google_ignoreList`). If `sourcesContent` is populated, you can recover the original files directly: ```bash wakaru extract input.js.map -o src/ ``` ### 3. Unpack and unminify with wakaru wakaru (Apache-2.0) splits bundles into modules and rewrites the AST to recover modern syntax. It removes recognized Babel/TypeScript/SWC helpers and converts CommonJS to ESM. ```bash npx wakaru input.js -o output.js # single file wakaru bundle.js --unpack -o out/ # unpack + decompile wakaru entry.js chunk.js --unpack -o out/ # code-split chunks together wakaru dist/ --unpack -o out/ # scan a build directory wakaru bundle.js --unpack=strict -o out/ # structural detection only wakaru bundle.js --unpack=inspect -o out/ # finer boundaries, not runnable wakaru bundle.js --unpack --provenance -o out/ # provenance.json byte ranges wakaru bun extract ./compiled-app -o extracted/ # every file in a Bun executable ``` | Option | Use it when | |---|---| | `--level minimal` / `standard` (default) / `aggressive` | Minimal for auditing or diffing where behavioural fidelity matters. Aggressive when you only need to read the code and can accept edge-case changes | | `--raw` | You want the split without the readability pipeline (`--level` doesn't apply) | | `--source-map ` | Single-file decompilation with an input map, which improves identifier recovery. Rejected together with `--unpack` | | `--emit-source-map` | Map output positions back to the input. Works with `--unpack` | | `--json` | Machine-readable results for scripts or agents | | `--dce` | Full dead-code sweep. By default only transform-induced dead code is removed | Structural unpacking covers webpack 4/5 (including Vercel ncc), Turbopack production chunks (Next.js 15.3+), Browserify, Metro, Closure ModuleManager, SystemJS, esbuild/Bun helper bundles and AMD/UMD. Scope-hoisted Rollup/Vite output goes through the default heuristic fallback. Hermes bytecode and Metro RAM bundles are not JavaScript inputs and are out of scope. For genuinely obfuscated input, the README suggests running a deobfuscator such as webcrack first. Names suggested by AI tools such as humanify are only reading aids. Only a source map gives you original names. REA can wrap this step. `rea recover-javascript-sources /tmp/web-scripts/app.js /tmp/recovered-app --json` runs a caller-supplied wakaru, set with `REA_WAKARU_COMMAND`. It accepts wakaru `^1.13.0` on Linux x64, with the report parser verified against 1.14.0, and it requires util-linux `prlimit`. Repeat `--additional-path` to recover related chunks together. The output directory must not already exist. ### 4. Map the Electron attack surface statically For a security review of an Electron app, the useful facts are which windows exist, what they preload, what the preload exposes, and which IPC handlers the main process trusts. REA's static analyzer reads an ASAR or extracted tree as inert text: ```bash rea analyze /absolute/path/to/apps/app.asar --json rea analyze-javascript-application /absolute/path/to/apps/app.asar \ --integrity-policy record-and-continue --json rea analyze /absolute/path/to/app.asar --source-path package.json --source-path main.js --json ``` It recovers `package.json` entry points, `BrowserWindow` options and `webPreferences`, preload paths, `contextBridge.exposeInMainWorld` keys, IPC operations with their channels and handler locations, sender/origin validation candidates, network endpoints, and `.node` add-on requests. ASAR integrity mismatches fail by default. `record-and-continue` analyzes the observed bytes and marks them untrusted. An unpacked entry whose companion bytes weren't supplied stays unavailable. ### 5. Read the fuses before trying runtime work Fuses are bytes in the Electron binary that are flipped when the app is packaged, before code signing. To find them, search for the sentinel `dL7pKGdnNz796PbbjQWNKmHXBZaB9tsX`. It is followed by a version byte, a length byte, then one byte per fuse: `0x30` disabled, `0x31` enabled, `0x72` removed. On macOS the wire is in the Electron Framework binary. On Windows and Linux it's in the main executable, not in `app.asar`. | Fuse (`FuseV1Options`) | Default | Why an analyst cares | |---|---|---| | `RunAsNode` | Enabled | Whether `ELECTRON_RUN_AS_NODE` is honored | | `EnableCookieEncryption` | Disabled | Whether the on-disk cookie store is OS-encrypted | | `EnableNodeOptionsEnvironmentVariable` | Enabled | Whether `NODE_OPTIONS` / `NODE_EXTRA_CA_CERTS` are honored | | `EnableNodeCliInspectArguments` | Enabled | Whether `--inspect`/`--inspect-brk` (and SIGUSR1) open a main-process Inspector | | `EnableEmbeddedAsarIntegrityValidation` | Disabled | Whether `app.asar` content is validated (macOS and Windows only) | | `OnlyLoadAppFromAsar` | Disabled | Whether Electron will load code only from `app.asar` | | `LoadBrowserProcessSpecificV8Snapshot` | Disabled | Main process uses `browser_v8_context_snapshot.bin` | | `GrantFileProtocolExtraPrivileges` | Enabled | Extra powers for `file://` pages | | `WasmTrapHandlers` | Enabled | Guard-page trapping for Wasm out-of-bounds access | Read them with `npx @electron/fuses read --app /Applications/Foo.app` or `rea inspect-electron-fuses /Applications/Example.app --json`. REA reports zero or multiple sentinels instead of guessing. No sentinel means the state is unknown, not that the fuses are off. ### 6. Observe at runtime (apps you are permitted to test) - **Node, or Electron main via Inspector.** Start the app yourself with `node --inspect=127.0.0.1:9229 ./app.mjs`, then `rea list-javascript-runtime-targets http://127.0.0.1:9229 --json` and `rea observe-javascript-runtime http://127.0.0.1:9229 TARGET_ID --runtime-kind node --json`. REA sends only `Runtime.enable` and `Debugger.enable`, records which scripts were parsed in which contexts, and never evaluates code. Use `--inspect`, not `--inspect-brk`: REA won't resume a paused target. - **Electron renderer pages via CDP.** `rea list-electron-targets http://127.0.0.1:9223 --json`, then `rea inspect-electron-page http://127.0.0.1:9223 TARGET_ID --include-script-sources --json`. Only literal-port loopback endpoints and local `file://` pages, including members inside `app.asar`, are accepted. - **Active scenario.** `rea capture-electron-scenario scenario.json --json` launches the app through Playwright's Electron API. It records the window, IPC (channel names and argument shapes, never payload values) and blocked side effects. It fails immediately when `EnableNodeCliInspectArguments` is disabled. The launched process keeps normal filesystem and network privileges. - **Reconcile.** `rea reconcile-javascript-runtime reconciliation-input.json --json` combines the static graph with runtime evidence and classifies each relationship as a match, an ambiguity, a mismatch or unknown. ## Recommendations 1. **Always try source maps first.** An embedded `sourcesContent` beats any decompiler. 2. **Decompile chunks together.** Pass the entry, runtime and lazy chunks in one wakaru run so cross-chunk module IDs resolve. 3. **Pick the rewrite level for the job.** Use `--level minimal` when diffing versions or auditing behaviour, and `aggressive` only for reading. 4. **Use `--provenance`** when you need to cite exactly which input bytes a recovered module came from. 5. **Read fuses before planning dynamic work.** If the Inspector fuse is disabled, expect no main-process target, and use passive CDP page inspection instead. REA's docs also mention running the extracted `app.asar` under an unrestricted development Electron build; do that only for your own app or with the owner's permission, since it sidesteps a hardening choice the packager made. 6. **Treat absence carefully.** An endpoint or IPC channel built dynamically won't appear statically. A script that never loaded during one observation window may still load later. 7. **For network behaviour**, pair this with traffic capture ([[syntheses/network-captures-and-protocols]]). For WebAssembly modules shipped beside the JS, see [[concepts/webassembly]]. Runtime attachment and app launching are dual-use. Do it only on apps and devices you're authorized to examine (see [[concepts/legal-and-ethics]]). ## Pages Compared - [[syntheses/dynamic-analysis-workflow]]: where Inspector/CDP observation fits among debuggers and tracers - [[syntheses/network-captures-and-protocols]]: capturing what the app sends - [[concepts/webassembly]]: Wasm modules loaded by JS glue - [[entities/rea]]: the static graph, fuse reader and runtime observers - [[syntheses/re-with-ai-agents-mcp]]: wakaru's agent skill and REA's MCP surface - [[syntheses/triage-an-unknown-binary]]: spotting Electron and Bun executables in the first pass ## Sources - `raw/github_doc-readme-md-13.md` - `raw/github_doc-docs-cli-md-2.md` - `raw/web_community-source-map-format-specification.md` - `raw/github_doc-readme-md-12.md` - `raw/web_community-asar-archives-electron.md` - `raw/web_community-electron-fuses-electron.md` - `raw/github_doc-docs-electron-fuses-md.md` - `raw/github_doc-docs-electron-observation-md.md` - `raw/github_doc-docs-javascript-runtime-observation-md.md` - `raw/github_doc-docs-javascript-recovery-md.md` - `raw/github_doc-docs-javascript-artifact-reconstruction-md.md` - `raw/github_doc-docs-javascript-runtime-reconciliation-md.md` --- title: "Malware Triage: DIE, FLOSS, capa and YARA/YARA-X" type: synthesis tags: [malware, triage, capa, floss, detect-it-easy, die, yara, yara-x, att&ck, mbc, safe-handling, defence] created: 2026-10-16 updated: 2026-10-16 confidence: high capa_version: "10.0.0" yara_x_version: "1.21.0" sources: ["raw/github_doc-disclaimer-md.md", "raw/github_doc-security-md.md", "raw/github_doc-readme-md-21.md", "raw/github_doc-docs-run-md.md", "raw/github_doc-readme-md-20.md", "raw/github_doc-doc-usage-md-2.md", "raw/github_doc-doc-theory-md.md", "raw/github_doc-doc-language-specific-strings-md.md", "raw/github_doc-readme-md-18.md", "raw/github_doc-doc-usage-md.md", "raw/github_doc-doc-rules-md.md", "raw/github_doc-doc-limitations-md.md", "raw/github_doc-doc-faq-md.md", "raw/github_doc-doc-installation-md.md", "raw/github_release-v10-0-0.md", "raw/github_doc-readme-md-19.md", "raw/github_doc-readme-md-22.md", "raw/github_doc-site-content-docs-intro-yara-vs-yara-x-md.md", "raw/github_doc-site-content-docs-cli-commands-md.md", "raw/github_doc-site-content-docs-writing-rules-differences-md.md", "raw/github_release-v1-21-0.md", "raw/web_community-running-yara-from-the-command-line-yara-4-4-0-documentation.md", "raw/github_doc-src-tools-rz-hash-rz-hash-tool-md.md", "raw/github_doc-doc-installation-md-2.md"] --- # Malware Triage: DIE, FLOSS, capa and YARA/YARA-X Use this workflow to decide quickly what a suspicious sample probably is and what it can do, without running it, and then hand it off to deeper analysis. Run it in this order: **handle safely → identify (DIE) → strings (FLOSS) → capabilities (capa) → rules (YARA / YARA-X) → hand off**. This page covers analysis and defence only. Malware development and evasion are out of scope (see [[concepts/legal-and-ethics]]). ## Comparison | Step | Tool | Question it answers | Executes the sample? | |---|---|---|---| | Identify | Detect It Easy (`die`, `diec`, `diel`) | File type, compiler/linker, packer/protector, anomalies | No. The file is never launched | | Strings | FLOSS (`floss`) | Static, stack, tight and decoded strings, Go/Rust strings | No. It **emulates** decoder functions | | Capabilities | capa 10.0.0 (`capa`) | What the program can do, mapped to ATT&CK and MBC | No for static. The dynamic mode reads sandbox reports | | Detect / hunt | YARA (`yara`) or YARA-X 1.21.0 (`yr`) | Does it match known families or your own patterns? | No | | | YARA | YARA-X | |---|---|---| | Status | Maintained for bug fixes and minor features. No new large features or modules | All new development, including new modules. Intended to replace YARA | | CLI | `yara [OPTIONS] RULES_FILE TARGET` | `yr scan [OPTIONS] RULES_PATH... TARGET_PATH` | | Compiled rules | `yarac`, then `yara -C` | `yr compile` (default `output.yarc`), then `yr scan -C` | | Process memory scanning | Yes | **Not implemented** | | Library APIs | C, Python, Go | Different and **incompatible** APIs, conceptually similar | | Regex strictness | Lenient (e.g. treats `\R` as `R`) | Stricter. `--relaxed-re-syntax` eases migration | | Extras | | `yr fmt`, `yr fix`, `yr dump` (module output as YAML/JSON without a rule), better errors, faster regex and loops | ## Analysis ### Step 0: Handle the sample safely None of the tools below is a containment boundary, so isolation has to come from your setup: - **Never execute on your host.** Every step on this page is static. The security policy of [[entities/rea]] (an MCP server for reverse engineering) points out that even opening an untrusted binary hands parsing to the analysis provider with *your* user's permissions, and that its bridges are not a sandbox. Do static work in a disposable analysis VM, and treat execution as a separate, deliberate step (see [[syntheses/dynamic-analysis-workflow]]). - **Cut the network for anything that might run.** REA's disclaimer notes that execution, interception, and device operations can affect accounts and services, and that running locally does not guarantee there are no external effects. - **Hash first.** Record the identity before anything touches the file, for example `rz-hash -a sha256 sample.bin`. rz-hash also computes `ssdeep` and `entropy`. Use the hash as the sample's name in notes and reports. - **Store samples inert.** Keeping samples in password-protected archives at rest is a common convention. It stops host antivirus and accidental clicks from touching them. Expect your triage tools to trigger AV too: capa's FAQ explains that its embedded rules look like malware features and that its PyInstaller packaging can alert AV/EDR. - **Don't load analysis caches you didn't create.** FLOSS and capa can reuse vivisect `.viv` workspaces, which are deserialized with pickle. A crafted `.viv` can execute code. capa 10.0.0 fixed this: it no longer loads `.viv` unless `CAPA_LOAD_VIV_WORKSPACE=1`, and versions up to 9.4.0 are affected. FLOSS loads one only with `FLOSS_LOAD_VIV_WORKSPACE=1`. YARA also requires `-C` for compiled rules because compiled rules from untrusted sources can execute code. - **Use official downloads.** DiE warns that `detectiteasy.com` is not affiliated with the project. capa recommends its GitHub releases page. ### Step 1: Identify with Detect It Easy DiE parses PE, ELF, Mach-O, DEX/APK/IPA, JAR, MS-DOS/COM, LE/LX, ZIP, ISO9660 and more. It reports operating system, linker, compiler, language, libraries, and packer or protector. Heuristic findings are marked `(Heur)` and kept separate from exact signature matches. For the fullest report: ```bash diec --heuristicscan --verbose sample.exe ``` The PE heuristic engine analyses headers, imports, resources, .NET metadata, overlays, and reachable entry-point code without launching the file. It flags packers and cryptors (including fake UPX-like layouts), anti-debug probes, hash-based API resolution, RunPE-like behaviour, embedded or XOR-encoded PE payloads, and debug leftovers such as PDB records. Verbose output tags evidence as `[HEUR/Any]`, `[HEUR/.NET]` or `[HEUR/EMU]`. How to read the results: DiE is **not an antivirus**. A clean report only means the enabled rules found nothing they recognise, and a heuristic hit is a lead, not proof. The GUI also runs Nauz File Detector, YARA, and legacy PEiD signatures. Treat agreement between engines as complementary evidence, not a vote, and treat PEiD hits as secondary because many of its signatures are noisy. **Packed?** If DiE (or high entropy) says the sample is packed, expect weak FLOSS and capa results. capa says so itself. ### Step 2: Recover strings with FLOSS FLOSS replaces `strings`. By default it extracts static ASCII/UTF-16LE strings, **stack strings**, **tight strings**, and **decoded strings**. To find decoded strings it uses heuristics to locate decoding routines, emulates them with recovered arguments, and diffs emulator memory before and after. For Go and Rust binaries it splits the non-NUL-terminated UTF-8 string blobs into the strings as written in source. | Goal | Command | |---|---| | First look: metadata, counts, tag histogram, top strings | `floss --summary malware.exe` | | Default full run | `floss malware.exe` | | Drop noisy/prevalent strings | `floss --interesting -- malware.exe` | | Only stack and tight strings | `floss --string-type stack tight -- malware.exe` | | Skip static strings | `floss --no-string-type static -- malware.exe` | | Grep-friendly flat list | `floss --plain malware.exe` or `floss -q malware.exe` | | Search | `floss --query "http://" -- malware.exe` | | JSON / HTML report | `floss -j malware.exe > out.json` · `floss --html malware.exe > report.html` | | Shellcode | `floss -f sc32 malware.raw32` · `floss -f sc64 malware.raw64` | | Known decoder addresses | `floss --analyze-functions 0x401000 0x402000 -- malware.exe` | Gotchas: - Options that take several values (`--string-type`, `--no-string-type`, `--tag`, `--analyze-functions`) need `--` before the sample. - `--string-type` and `--no-string-type` can't be combined. - Files over **64 MB** abort deobfuscation unless you pass `-L`/`--large-file`. - The minimum string length defaults to 4 (`-n` changes it). - Results are **cached by default**. Set `FLOSS_CACHE_ENABLE=0` when you are comparing runs. - The standalone binaries need no install. The pip package needs Python 3.12 or newer. ### Step 3: Enumerate capabilities with capa capa matches a rule library against PE, ELF, .NET modules, shellcode, or sandbox reports, and reports **ATT&CK** tactics and techniques, **MBC** behaviours, and capability namespaces (`anti-analysis`, `communication`, `host-interaction`, `persistence`, `load-code`, and others). ```bash capa suspicious.exe # top-level capabilities capa -v suspicious.exe # every match, incl. nested capa -vv suspicious.exe # how and where each rule matched (addresses) capa -j suspicious.exe > capa.json # JSON for capa Explorer Web or scripts capa -t communication suspicious.exe # only rules whose metadata matches capa sample.exe --restrict-to-functions 0x4019C0,0x401CD0 capa report.json # CAPE report (.json); DRAKVUF .log and VMRay .zip also work capa report.log --restrict-to-processes 3888,3214 ``` - `-vv` gives you the function addresses to open in a disassembler. That is the bridge to the next stage. - The standalone binary embeds the standard rules. With the pip package (`pip install flare-capa`), download capa-rules and pass `-r`/`--rules`, and pass signatures with `-s`. **Rules must match capa's major version**: mismatched rules fail with lint errors such as `unexpected statement`. - capa has explorer plugins for IDA Pro and Ghidra, and can also use Ghidra (via PyGhidra) or Binary Ninja as its analysis backend. - `CAPA_SAVE_WORKSPACE` caches analysis to speed up rule development. Loading it back needs `CAPA_LOAD_VIV_WORKSPACE=1` and should only be used with `.viv` files you trust. **Limitations to keep in mind:** - Packed or obfuscated input gives misleading or incomplete results. capa warns, and suggests unpacking or running it against a sandbox report instead. - Installers and AutoIt-style packaged programs are handled poorly. - Capabilities spread across wrapper or child functions are not combined, which matters for Go and other layered code. - There is no loop scope beyond `characteristic(loop)`. ### Step 4: Match and write rules with YARA / YARA-X Use rules to check samples against known families and to turn what you learned in steps 1–3 into a detection. ```bash # YARA yara -s -m rules.yar sample.exe # print matching strings and metadata yara -r rules.yar /samples/ # recurse into a directory yarac rules.yar rules.yarc && yara -C rules.yarc sample.exe # YARA-X yr scan rules.yar sample.exe yr scan --print-strings --print-meta --recursive rules/ /samples/ yr scan --output-format ndjson rules/ /samples/ | jq .path yr dump --module=pe --module=dotnet sample.exe # inspect parsed PE/.NET fields yr fmt rules/ # format rule sources ``` **When to migrate to YARA-X.** New rule work and bulk scanning should default to YARA-X: it gets the new modules, gives better errors, and is faster on regex-heavy and loop-heavy rules. Stay on YARA when you need **process memory scanning** or have tooling built on the YARA C, Python, or Go APIs, which YARA-X does not drop-in replace. Before switching, check existing rules for the documented differences: `{` must be escaped in regexes, escape sequences are stricter, base64 patterns behave differently, and `xor` with `fullword` behaves differently. `--relaxed-re-syntax` covers the regex cases while you fix them. capa rules are a separate YAML format that mixes ideas from OpenIOC, YARA, and YAML. ## Recommendations 1. **Hash, then isolate.** Record the SHA-256 and work in a disposable VM. Treat every tool as a parser of hostile input. 2. **DiE first.** If it reports a packer or protector, note it and lower your confidence in FLOSS and capa output. Get dynamic evidence (capa on a sandbox report) rather than over-reading static results. 3. **`floss --summary`, then `--interesting`**, to pull IOCs (domains, paths, registry keys, mutexes) and decoded configuration. 4. **`capa -vv`** to get capabilities *with addresses*. Note the ATT&CK IDs for your report. 5. **Codify.** Write a YARA-X rule from the strongest unique strings and byte patterns, and test it with `yr scan` across clean and malicious sets. 6. **Hand off** with the capa addresses and FLOSS decoder locations: - static deep-dive: [[syntheses/choosing-a-disassembler]] (Ghidra, IDA, JEB, Rizin/Cutter), - controlled execution, debugging, or tracing: [[syntheses/dynamic-analysis-workflow]], - .NET samples: [[concepts/dotnet-and-nativeaot]]. Go/Rust samples: [[concepts/go-rust-and-dart-binaries]]. - Tool failures (capa or FLOSS errors): [[syntheses/troubleshooting]]. ## Pages Compared - [[syntheses/triage-an-unknown-binary]]: the general first-15-minutes path this page specialises - [[concepts/executable-formats]]: the PE/ELF/Mach-O structures DiE and capa parse - [[syntheses/choosing-a-disassembler]]: where capa's IDA/Ghidra integrations live - [[syntheses/dynamic-analysis-workflow]]: execution-side follow-up - [[concepts/legal-and-ethics]]: scope and handling responsibilities ## Sources - `raw/github_doc-disclaimer-md.md` - `raw/github_doc-security-md.md` - `raw/github_doc-readme-md-21.md` - `raw/github_doc-docs-run-md.md` - `raw/github_doc-readme-md-20.md` - `raw/github_doc-doc-usage-md-2.md` - `raw/github_doc-doc-theory-md.md` - `raw/github_doc-doc-language-specific-strings-md.md` - `raw/github_doc-readme-md-18.md` - `raw/github_doc-doc-usage-md.md` - `raw/github_doc-doc-rules-md.md` - `raw/github_doc-doc-limitations-md.md` - `raw/github_doc-doc-faq-md.md` - `raw/github_doc-doc-installation-md.md` - `raw/github_release-v10-0-0.md` - `raw/github_doc-readme-md-19.md` - `raw/github_doc-readme-md-22.md` - `raw/github_doc-site-content-docs-intro-yara-vs-yara-x-md.md` - `raw/github_doc-site-content-docs-cli-commands-md.md` - `raw/github_doc-site-content-docs-writing-rules-differences-md.md` - `raw/github_release-v1-21-0.md` - `raw/web_community-running-yara-from-the-command-line-yara-4-4-0-documentation.md` - `raw/github_doc-src-tools-rz-hash-rz-hash-tool-md.md` - `raw/github_doc-doc-installation-md-2.md` --- title: "Network Captures and Protocols: Wireshark, tshark, TLS Keys and mitmproxy" type: synthesis tags: [wireshark, tshark, mitmproxy, tls, pcap, http3, quic, network, sslkeylogfile] created: 2026-10-16 updated: 2026-10-16 confidence: medium sources: ["raw/web_community-6-4-building-display-filter-expressions.md", "raw/web_community-7-2-following-protocol-streams.md", "raw/web_community-5-7-exporting-data.md", "raw/web_community-d-2-tshark-terminal-based-wireshark.md", "raw/web_community-tls-wireshark-wiki.md", "raw/web_community-sslkeylogfile-everything-curl.md", "raw/web_community-wireshark-and-ssl-tls.md", "raw/web_community-proxy-modes.md", "raw/web_community-certificates.md", "raw/web_community-how-mitmproxy-works.md", "raw/web_community-system-ca-on-android-emulator.md", "raw/web_community-http-3-with-curl.md", "raw/github_doc-docs-pcap-analysis-md.md", "raw/github_doc-docs-packet-captures-md.md", "raw/github_doc-docs-web-network-captures-md.md", "raw/github_doc-docs-http3-capture-lab-md.md"] --- # Network Captures and Protocols: Wireshark, tshark, TLS Keys and mitmproxy Two broad jobs sit under "look at the traffic": reading a capture that already exists (Wireshark/tshark on a pcapng, a HAR or SAZ export), and sitting in the path of live traffic to decrypt it (mitmproxy as a proxy). Decrypting TLS from a passive capture needs the session keys, which only the client or server can hand over. Only intercept or capture traffic for a device, app or account you are authorized to test; see [[concepts/legal-and-ethics]]. ## Comparison | Task | Tool / mechanism | |---|---| | Read a saved pcap/pcapng interactively | Wireshark GUI | | Script over a capture, extract fields | `tshark -r file.pcapng -Y '' -T fields -e ` | | Isolate one conversation | Follow Stream (Analyze → Follow) | | Pull transferred files out | File → Export Objects (per-protocol) | | Decrypt TLS from a passive capture | Key log file via `SSLKEYLOGFILE`, loaded into Wireshark | | Intercept and decrypt live HTTPS | mitmproxy, client trusts its CA | | Capture a specific local process | `mitmproxy --mode local:` | | HTTP/3 (QUIC) over the wire | curl `--http3`; mitmproxy reverse `http3://`; Wireshark follows QUIC streams | ## Analysis ### Reading captures with Wireshark and tshark Display filters are the core skill. Type a protocol (`tcp`, `http.request`) or a field, and compare with English or C-like operators (`ip.addr == 10.0.0.5`, `frame.len gt 10`). Useful operators from the filter reference: - `contains` and `matches` (`~`, PCRE2): `http.host matches "acme\\.(org|com|net)"`. Regex strings are parsed twice (filter engine then PCRE), so use raw strings `r"..."` to avoid double-escaping. - Membership: `tcp.port in {80, 443, 8080}`; ranges `tcp.port in {443, 4430..4434}`. - Slices: `eth.src[0:3] == 00:00:83`; `frame[-4:]` for the last four bytes. - Functions: `len(http.request.uri) > 100`, `lower(http.server) contains "apache"`, `count(ip.addr) > 2`. - CIDR subnets: `ip.addr == 129.111.0.0/16`. Two gotchas the reference calls out: `!=` changed in Wireshark 3.6 to mean "all not equal" (`===` means all equal and `!==` means any not equal), and bare tokens such as `fc` can be read as a protocol name rather than a hex value — prefix with a dot for a protocol (`.fc`) or a colon for a byte array (`:fc`). **Follow Stream** (Analyze → Follow, or the packet context menu) sets a filter selecting one TCP/UDP/TLS/HTTP/HTTP2/QUIC conversation and shows its payload; client→server is red, server→client blue. For HTTP/2 and QUIC a "Substream" selector picks the stream ID within the connection. To follow TLS you must first supply keys (below). **Export** paths: *File → Export Packet Dissections* writes the packet list/details/bytes as plain text, CSV, JSON, PSML or PDML. *File → Export Objects* reassembles a protocol's streams and saves transferred files (HTML, images, executables) to disk. *Export PDUs to File* and *Strip Headers* let you re-export reassembled or decrypted payloads without their lower layers. `tshark` takes the same display-filter language from the terminal. The common shape is `tshark -r in.pcapng -Y '' -T fields -e -e `. Other flags from the man-page help: `-2` two-pass analysis, `-n` disable name resolution, `-d tcp.port==8888,http` for Decode As, `-z ` for statistics, `--export-objects ,`, and `--export-tls-session-keys `. ### Decrypting TLS Wireshark offers three decryption methods; the key log file is the one that always works, including with (EC)DHE and TLS 1.3. An RSA private key only works in narrow cases: no (EC)DHE, SSLv3–TLS 1.2 only (not 1.3), matching server cert, no session resumption, and a ClientKeyExchange present. To produce a key log file, set the `SSLKEYLOGFILE` environment variable before launching the client: ```bash export SSLKEYLOGFILE=$HOME/keylog.txt firefox # or chrome, or curl ``` Then point Wireshark at it: *Edit → Preferences → Protocols → TLS → (Pre)-Master-Secret log filename* (`tls.keylog_file`). curl, Firefox and Chrome all honour `SSLKEYLOGFILE`; curl requires a TLS backend that supports it (OpenSSL, AWS-LC, BoringSSL, GnuTLS, wolfSSL — LibreSSL only up to TLS 1.2). As of the Wireshark wiki's 2019 note, it did not work with Safari or legacy Edge (SChannel/SecureTransport). mitmproxy writes the same file when you set `SSLKEYLOGFILE` (or `MITMPROXY_SSLKEYLOGFILE` to avoid affecting other apps). To ship keys with a capture, embed them in a pcapng Decryption Secrets Block: ```bash editcap --inject-secrets tls,keys.txt in.pcap out-dsb.pcapng ``` For embedded devices that use a Pre-Shared-Key (common with MQTT/IoT), set the PSK in hex in the TLS preferences; the same PSK decrypts past and future traffic using that key. ### Intercepting live HTTPS with mitmproxy mitmproxy becomes a man-in-the-middle by acting as its own CA and generating per-site certificates on the fly; the client must trust that CA. The quick path is to proxy the device, visit `mitm.it`, and install the certificate. The CA files live in `~/.mitmproxy` (`mitmproxy-ca-cert.pem`, `.p12`, `.cer`). Choose a mode: | Mode | Command | Use | |---|---|---| | Regular | `mitmproxy` (listens :8080) | Client configured to use an HTTP proxy | | Local capture | `mitmproxy --mode local:curl` | Capture one process on this host; `!curl` negates, comma-separated lists allowed | | WireGuard | `mitmweb --mode wireguard` | External devices / individual Android apps, no root | | Reverse | `mitmdump --mode reverse:https://example.com` | Put mitmproxy in front of a server | | Transparent | `mitmdump --mode transparent` | Network-layer redirect, no client config | Verify traffic with `curl --proxy 127.0.0.1:8080 --cacert ~/.mitmproxy/mitmproxy-ca-cert.pem https://example.com/`. Linux local mode is egress-only, needs sudo, and officially supports kernel 6.8+; interception spec names match the first 16 characters of the process name. To intercept with your own leaf certificate instead of one signed by mitmproxy's CA, pass `--certs *=cert.pem` or `--set client_certs=...` for mTLS to an upstream. Because most Android 7+ apps ignore user-installed certificates, on an emulator, the CA has to go into the system store under a hashed filename: ```bash cd ~/.mitmproxy hashed_name=$(openssl x509 -inform PEM -subject_hash_old -in mitmproxy-ca-cert.cer | head -1) cp mitmproxy-ca-cert.cer $hashed_name.0 # then remount /system read-write and copy into /system/etc/security/cacerts ``` Note the honest limit from the docs: some apps pin certificates and will reject mitmproxy's CA regardless. The sources mention that pinned connections exist and that the usual response is to exclude those hosts (`ignore_hosts`); defeating pinning on an app you do not control is out of scope here and in [[concepts/legal-and-ethics]]. ### HTTP/3 and QUIC curl drives HTTP/3 with `--http3-only` (fail if not available) or `--http3` (fall back to HTTP/2 or HTTP/1.1 via happy-eyeballing, 200 ms default), or upgrade through `--alt-svc altsvc.cache`. The non-experimental backend is ngtcp2 (quiche is experimental). Confirm the build advertises HTTP3/HTTP2 with `curl --version`. mitmproxy reverse mode proxies `http3://` and raw `quic://`; Wireshark follows QUIC streams the same way as HTTP/2 substreams. ### Offline capture inspection through REA [[entities/rea]] inspects saved captures without touching the network, Linux-verified. `inspect_packet_capture` selects tshark fields from a pcapng; `inspect_pcap_capture` summarises endpoints, DNS, TLS SNI, protocol distribution and HTTP URIs; `inspect_web_network_capture` reads HAR 1.2, native mitmproxy `.mitm` (mitmdump 12.2.3 on Linux) and Fiddler SAZ. Useful facts to carry over even when using the tools directly: - `packet_limit` caps packets read *before* filtering, so a limit of 1 can yield zero matches even when later frames match; it never implies the capture's total size. - tshark two-pass (`-2`; REA turns it on by default for fields needing reassembly) cannot recover bytes that were never captured. - An empty result or an exhausted page proves nothing about traffic outside the recorded file, filter or range. - Field names come from `tshark -G fields` (REA: `inspect-packet-fields`); the full glossary is ~22 MB, so query narrowly. - REA's HTTP/3 verification is a Linux-only lab (mitmproxy 12.2.3, aioquic, curl 8.22.0) and does not establish general HTTP/3 support. ## Recommendations - **Capture keys at capture time.** TLS you didn't log keys for during the session is not decryptable later for (EC)DHE/TLS 1.3. Set `SSLKEYLOGFILE` before you start. - **Prefer the key log file over the RSA private key** — the RSA method fails on modern cipher suites and TLS 1.3. - **Pick the mitmproxy mode by how you can reach the client:** proxy settings → regular; same host → local; a phone or app you can't reconfigure → WireGuard; in front of a server → reverse. - **Scope interception narrowly** (`local:name`, `ignore_hosts`) and only to targets you are authorized to test. - **Use `tshark -T fields` for repeatable extraction** and `tshark -z`/Export Objects for summaries and files; reach for the GUI for exploratory work and Follow Stream. - **Embed secrets in the pcapng** with `editcap --inject-secrets` when sharing a capture that needs decryption. ## Pages Compared - [[syntheses/android-apk-analysis]]: proxying an Android app you're permitted to test - [[syntheses/dynamic-analysis-workflow]]: where traffic capture fits among debugging and instrumentation - [[entities/rea]]: offline capture inspection and its evidence model - [[concepts/legal-and-ethics]]: authorization for interception and TLS decryption - [[syntheses/javascript-and-electron-apps]]: runtime/CDP observation of web clients ## Sources - `raw/web_community-6-4-building-display-filter-expressions.md` - `raw/web_community-7-2-following-protocol-streams.md` - `raw/web_community-5-7-exporting-data.md` - `raw/web_community-d-2-tshark-terminal-based-wireshark.md` - `raw/web_community-tls-wireshark-wiki.md` - `raw/web_community-sslkeylogfile-everything-curl.md` - `raw/web_community-wireshark-and-ssl-tls.md` - `raw/web_community-proxy-modes.md` - `raw/web_community-certificates.md` - `raw/web_community-how-mitmproxy-works.md` - `raw/web_community-system-ca-on-android-emulator.md` - `raw/web_community-http-3-with-curl.md` - `raw/github_doc-docs-pcap-analysis-md.md` - `raw/github_doc-docs-packet-captures-md.md` - `raw/github_doc-docs-web-network-captures-md.md` - `raw/github_doc-docs-http3-capture-lab-md.md` --- title: "Reverse Engineering: Overview and Where to Start" type: synthesis tags: [overview, reverse-engineering, intent-map, tool-landscape, scope, start-here] created: 2026-10-16 updated: 2026-10-16 confidence: high sources: ["raw/github_doc-readme-md.md", "raw/github_doc-docs-index-md.md", "raw/github_doc-docs-reverse-engineering-tools-md.md", "raw/github_doc-third-party-readme-md.md", "raw/github_doc-disclaimer-md.md", "raw/github_release-rea-agents-v6-5-0.md", "raw/github_doc-readme-md-2.md", "raw/web_community-basic-usage-md.md", "raw/github_doc-src-tools-rz-bin-intro-md.md", "raw/github_doc-readme-md-4.md", "raw/github_doc-i18n-en-docs-index-md.md", "raw/github_doc-readme-md-5.md", "raw/github_doc-readme-md-7.md", "raw/github_doc-readme-md-8.md", "raw/github_doc-readme-md-9.md", "raw/github_doc-readme-md-10.md", "raw/github_doc-readme-md-11.md", "raw/github_doc-readme-md-13.md", "raw/github_doc-readme-md-14.md", "raw/github_doc-readme-md-15.md", "raw/github_doc-readme-md-16.md", "raw/github_doc-readme-md-17.md", "raw/github_doc-readme-md-18.md", "raw/github_doc-readme-md-20.md", "raw/github_doc-readme-md-21.md", "raw/github_doc-readme-md-22.md", "raw/github_release-v10-0-0.md", "raw/github_release-v1-21-0.md", "raw/web_community-chapter-1-introduction.md", "raw/web_community-getting-started-md-2.md", "raw/web_community-ethereum-analysis-jeb-decompiler.md"] --- # Reverse Engineering: Overview and Where to Start Reverse engineering (RE) means working out how software behaves when you only have the shipped artifact: a native executable, an APK, a .NET assembly, a JavaScript bundle, a firmware image, a WebAssembly module, smart-contract bytecode, or a packet capture. You read structure statically (headers, disassembly, decompiled pseudocode, strings), observe behaviour dynamically (debuggers, instrumentation, traffic capture), and combine the two into evidence you can act on. Typical uses are interoperability, vulnerability research, malware analysis and defence, CTFs, and understanding a feature so you can build your own version. This wiki covers **authorized, legitimate analysis only**. Read [[concepts/legal-and-ethics]] once before you start. It explains the statutory hooks (17 U.S.C. 1201(f) and (j), UK CDPA s50B) and lists what the wiki will not cover. ## Comparison ### Intent map: "I have X, I want Y" | I have… / I want to… | Read | |---|---| | An unknown file and need to know what it is | [[syntheses/triage-an-unknown-binary]] | | A suspicious sample. I want to know what it does and write detections | [[syntheses/malware-triage]] | | To understand ELF / PE / Mach-O / DEX headers, sections, imports | [[concepts/executable-formats]] | | Decompiler output that looks wrong | [[concepts/decompilation-concepts]] | | To choose between Ghidra, IDA, JEB, Hopper, Rizin/Cutter, objdump | [[syntheses/choosing-a-disassembler]] | | To learn Ghidra | [[entities/ghidra]] | | To learn IDA Pro | [[entities/ida-pro]] | | A preference for CLI or open-source tooling | [[entities/rizin-and-cutter]] | | A Linux process to debug and inspect live | [[entities/gdb-and-pwndbg]] | | To hook or trace functions in a running process | [[entities/frida]] | | To pick between debugging, instrumentation, tracing, record/replay | [[syntheses/dynamic-analysis-workflow]] | | An Android APK | [[syntheses/android-apk-analysis]] | | A .NET assembly, or a NativeAOT build | [[concepts/dotnet-and-nativeaot]] | | A Go, Rust, or Flutter/Dart binary | [[concepts/go-rust-and-dart-binaries]] | | An Electron app, ASAR, or minified JS bundle | [[syntheses/javascript-and-electron-apps]] | | A `.wasm` module | [[concepts/webassembly]] | | A firmware image or headerless blob | [[syntheses/firmware-analysis]] | | EVM contract bytecode | [[concepts/evm-bytecode]] | | A pcap, or traffic from an app I may test | [[syntheses/network-captures-and-protocols]] | | My coding agent to do RE through MCP | [[entities/rea]] · [[syntheses/re-with-ai-agents-mcp]] | | A tool that crashes, hangs, or produces garbage | [[syntheses/troubleshooting]] | | To know what's legal and in scope | [[concepts/legal-and-ethics]] | ### Tool landscape | Area | Tools | What they do | Main page | |---|---|---|---| | Identification | binutils (`readelf`, `objdump`, `nm`, `strings`), `rz-bin`, Detect It Easy | Format, architecture, sections, imports, compiler/packer guesses | [[syntheses/triage-an-unknown-binary]] | | Malware pre-filters | DIE, FLOSS, capa 10.0.0, YARA / YARA-X 1.21.0 | Packer ID, obfuscated-string recovery, ATT&CK-mapped capabilities, rule matching | [[syntheses/malware-triage]] | | Disassemblers / decompilers | Ghidra (NSA, open source), IDA Pro + Hex-Rays, JEB, Hopper, Rizin + Cutter | Disassembly, pseudocode, cross-references, types, scripting | [[syntheses/choosing-a-disassembler]] | | Debugging | GDB + pwndbg (GDB/LLDB plug-in) | Breakpoints, stepping, memory and heap inspection | [[entities/gdb-and-pwndbg]] | | Instrumentation | Frida | Function tracing and hooking from the CLI or its APIs | [[entities/frida]] | | Android | JADX (Dex to Java), apktool (resources), adb | Decompile, decode resources and manifest, pull from devices | [[syntheses/android-apk-analysis]] | | .NET | ILSpy (decompiler), dnSpyEx (debugger/editor), ghidra-nativeaot | IL decompilation. NativeAOT type and metadata recovery in Ghidra | [[concepts/dotnet-and-nativeaot]] | | Go / Rust / Flutter | GoReSym, FLOSS language strings, blutter (Android arm64 `libapp.so`) | Symbol and metadata recovery for runtimes that defeat generic tools | [[concepts/go-rust-and-dart-binaries]] | | JavaScript | wakaru, source maps, ASAR tools | Split bundles into modules, unminify | [[syntheses/javascript-and-electron-apps]] | | WebAssembly | WABT (`wasm2wat`, `wat2wasm`, `wasm-objdump`) | Binary ↔ text round-trips, inspection | [[concepts/webassembly]] | | Firmware | binwalk v3, unblob | Signature scan, entropy, recursive extraction and carving | [[syntheses/firmware-analysis]] | | Smart contracts | EVMole, JEB | Selectors, arguments, mutability, storage layout from bytecode | [[concepts/evm-bytecode]] | | Network | Wireshark / tshark, mitmproxy | Packet analysis and capture summaries; HTTP interception of apps you may test | [[syntheses/network-captures-and-protocols]] | | Agents | REA (rea-agents 6.5.0), Hex-Rays IDA MCP Server (IDA 9.4+ with idalib), JEB MCP, community MCP servers | Drive the tools above from Claude Code, Codex, Cursor and others, with evidence | [[syntheses/re-with-ai-agents-mcp]] | ## Analysis **The usual arc.** Almost every investigation goes the same way: **identify** the artifact, **choose** a static toolchain for that format, **reduce** the search space (strings, imports, capabilities, cross-references to interesting APIs), **read** the relevant functions in a decompiler, then **confirm** at runtime only where static reading leaves a question open. The intent map sends you into that arc at the right point. The tool landscape shows which tool covers each step. **Static first, dynamic on purpose.** Static work only reads bytes. Dynamic work executes or attaches to the target, and that can change files, accounts, devices, or remote services. REA's disclaimer makes the point that permission to inspect an artifact is not automatically permission to run it, intercept its traffic, or touch a device. Treat each move to runtime as its own decision, made in an appropriate environment ([[syntheses/dynamic-analysis-workflow]]). **Specialist runtimes need specialist tools.** Generic disassemblers struggle with Go's runtime metadata, Rust's mangling, Dart AOT snapshots, .NET NativeAOT, and minified JavaScript. Each has a concept page with the tools that recover the missing structure. **Agents change the workflow, not the evidence bar.** REA connects a coding agent to Hopper, Ghidra, IDA, JADX, objdump, GDB, Rizin, Frida, binwalk/unblob, tshark and more, and returns findings together with their evidence and limitations. It never installs or updates objdump, GDB, or Rizin for you. Some capabilities are platform-bound: REA's GDB and Rizin debugger sessions are **Linux-only**, and its firmware engines run on Linux. Decompiler and AI output can still be wrong, so check the underlying evidence before relying on a conclusion ([[syntheses/re-with-ai-agents-mcp]]). ### What this wiki does not cover - DRM, licence-check, or anti-cheat circumvention, game cheats, piracy, malware development, AV/EDR evasion, or certificate-pinning bypass (policy; see [[concepts/legal-and-ethics]]). - Unpacking or defeating commercial protectors. - Windows kernel and driver RE, and WinDbg deep dives (not yet covered). - Full per-command manuals. Tool pages curate the commands people actually use. ## Recommendations 1. **New to a file?** Start at [[syntheses/triage-an-unknown-binary]]. It ends with a "go to" table for every format. 2. **Possibly malicious?** Go to [[syntheses/malware-triage]] first. Safe handling comes before any tool. 3. **Picking a primary tool?** Read [[syntheses/choosing-a-disassembler]] before committing to a GUI ecosystem. Scripting and agent support differ a lot. 4. **Using an AI agent?** Set up [[entities/rea]] and read the evidence-discipline notes in [[syntheses/re-with-ai-agents-mcp]]. 5. **Stuck?** [[syntheses/troubleshooting]] is organized by symptom. ## Pages Compared All free-tier pages, grouped by role: - **Start and scope:** [[syntheses/overview]], [[concepts/legal-and-ethics]], [[syntheses/triage-an-unknown-binary]], [[syntheses/malware-triage]] - **Foundations:** [[concepts/executable-formats]], [[concepts/decompilation-concepts]] - **Static tools:** [[entities/ghidra]], [[entities/ida-pro]], [[entities/rizin-and-cutter]], [[syntheses/choosing-a-disassembler]] - **Dynamic tools:** [[entities/gdb-and-pwndbg]], [[entities/frida]], [[syntheses/dynamic-analysis-workflow]] - **By target type:** [[syntheses/android-apk-analysis]], [[concepts/dotnet-and-nativeaot]], [[concepts/go-rust-and-dart-binaries]], [[syntheses/javascript-and-electron-apps]], [[concepts/webassembly]], [[syntheses/firmware-analysis]], [[concepts/evm-bytecode]], [[syntheses/network-captures-and-protocols]] - **Agents and fixes:** [[entities/rea]], [[syntheses/re-with-ai-agents-mcp]], [[syntheses/troubleshooting]] ## Sources - `raw/github_doc-readme-md.md` - `raw/github_doc-docs-index-md.md` - `raw/github_doc-docs-reverse-engineering-tools-md.md` - `raw/github_doc-third-party-readme-md.md` - `raw/github_doc-disclaimer-md.md` - `raw/github_release-rea-agents-v6-5-0.md` - `raw/github_doc-readme-md-2.md` - `raw/web_community-basic-usage-md.md` - `raw/github_doc-src-tools-rz-bin-intro-md.md` - `raw/github_doc-readme-md-4.md` - `raw/github_doc-i18n-en-docs-index-md.md` - `raw/github_doc-readme-md-5.md` - `raw/github_doc-readme-md-7.md` - `raw/github_doc-readme-md-8.md` - `raw/github_doc-readme-md-9.md` - `raw/github_doc-readme-md-10.md` - `raw/github_doc-readme-md-11.md` - `raw/github_doc-readme-md-13.md` - `raw/github_doc-readme-md-14.md` - `raw/github_doc-readme-md-15.md` - `raw/github_doc-readme-md-16.md` - `raw/github_doc-readme-md-17.md` - `raw/github_doc-readme-md-18.md` - `raw/github_doc-readme-md-20.md` - `raw/github_doc-readme-md-21.md` - `raw/github_doc-readme-md-22.md` - `raw/github_release-v10-0-0.md` - `raw/github_release-v1-21-0.md` - `raw/web_community-chapter-1-introduction.md` - `raw/web_community-getting-started-md-2.md` - `raw/web_community-ethereum-analysis-jeb-decompiler.md` --- title: "Reverse Engineering with AI Agents: REA vs IDA MCP, JEB, GhidraMCP and the rest" type: synthesis tags: [mcp, agents, rea, ida-mcp, idalib, jeb, ghidramcp, ida-pro-mcp, jadx-mcp, evmole, evidence] created: 2026-10-16 updated: 2026-10-16 confidence: medium sources: ["raw/github_doc-docs-mcp-contracts-md.md", "raw/github_doc-docs-mcp-prompts-md.md", "raw/github_doc-agents-skills-reverse-engineer-anything-references-evidence-.md", "raw/github_doc-docs-reverse-engineering-tools-md.md", "raw/github_doc-docs-ida-provider-md.md", "raw/web_community-overview-md-4.md", "raw/web_community-getting-started-md-2.md", "raw/web_community-multiplexing-md.md", "raw/web_community-where-mcp-fits-md.md", "raw/web_community-agentic-ida-with-idalib-md.md", "raw/web_community-overview-md-3.md", "raw/web_community-mcp-server-jeb-decompiler.md", "raw/github_doc-readme-md-23.md", "raw/github_doc-readme-md-24.md", "raw/github_doc-readme-md-6.md", "raw/github_doc-agent-mcp-readme-md.md", "raw/github_doc-agent-readme-md.md", "raw/github_doc-docs-evm-bytecode-md.md"] --- # Reverse Engineering with AI Agents: REA vs IDA MCP, JEB, GhidraMCP and the rest MCP (Model Context Protocol) servers let an agent call reverse-engineering tools directly. They fall into two camps: **brokers** that wrap several engines behind one evidence-disciplined interface (REA), and **single-engine bridges** that expose one tool's API (IDA, JEB, Ghidra, JADX, evmole). The questions that actually decide which to use are: does it give the agent evidence it can trust, does its output fit the response budget, and how dangerous is its console. Use any of these only on software you're authorized to examine; see [[concepts/legal-and-ethics]]. ## Comparison | Server | Engine | Transport | Modes | Writes to target DB? | |---|---|---|---|---| | [[entities/rea]] (`rea-agents`) | Broker: Ghidra/IDA/Hopper/JEB/Kuna + objdump/GDB/Rizin, JADX, Frida, binwalk/unblob, evmole, pcap, SQLite | stdio (local) | Read-only native ops; opt-in runtime/debug | No (session-scoped metadata only) | | Hex-Rays IDA MCP (official) | IDA (idalib or attached GUI) | agent harness | Attach to open GUI, or managed idalib worker; multiplexes multiple agents/DBs | Yes (shared DB) | | idalib | IDA as a library (headless) | your own code | Scripts, CI, "code mode" | Yes | | JEB MCP | JEB | HTTP `:8425/mcp` | GUI/`-c --mcp`/programmatic; VIBRE assistant | Yes (rename, scripts) | | GhidraMCP (LaurieWired) | Ghidra | stdio or HTTP to a Ghidra plugin on :8080; or headless PyGhidra | GUI plugin or `--headless` | Yes (rename methods/data) | | ida-pro-mcp (mrexodia) | IDA Pro (not Free) | HTTP :13337/mcp, SSE, or stdio idalib | GUI plugin or headless `idalib-mcp` | Yes (patch, rename, types, bookmarks) | | jadx-headless-mcp | jadx-core | stdio or Streamable HTTP | Headless, no GUI/plugin | No (read-only decompilation) | | evmole-mcp | EVMole | stdio | One tool `analyze_evm_bytecode` | No | ### Who makes what - **Official IDA MCP** is first-party (Hex-Rays), open source, and multiplexes: several agents on one machine attach to the same running server and see each other's renames and comments live. It can attach to a database open in the GUI or spin up a managed idalib worker headlessly. Needs IDA 9.4+ with idalib, Git, uv, Python 3.11+; installs via `uvx ida-hcli mcp install`. It is one of three Hex-Rays AI entry points: **MCP** (connect your agent), **Assist** (in-GUI copilot), **idalib** (headless library for scripting/CI/"code mode" where the agent writes and runs idalib scripts). - **ida-pro-mcp (mrexodia)** is a mature community server; its own README now recommends the official Hex-Rays server. It requires IDA Pro (IDA Free unsupported), exposes a very large tool set (decompile, disasm, xrefs, types, patching, stack frames, structures, an optional `?ext=dbg` debugger extension) and a persistent headless idalib supervisor (`idalib-mcp`) where every call carries an explicit `database` session ID. - **GhidraMCP** pairs a Ghidra plugin (installed via File → Install Extensions, port configurable, default :8080) with a Python client; it can also run headless over PyGhidra with no GUI. It decompiles, lists methods/classes/imports/exports, and renames methods and data. - **jadx-headless-mcp** builds directly on `jadx-core` with no GUI and no Python adapter — one JVM over stdio exposing ~26 tools (class tree, decompiled Java with automatic smali fallback, xrefs, resources). Remote `--transport http` keeps DNS-rebinding protection on by default and has no authentication (tunnel it). - **evmole-mcp** is a single-tool stdio server (`npx -y evmole-mcp@latest`, Node 22+) exposing `analyze_evm_bytecode` for selectors, arguments, mutability, storage, metadata and optional disassembly/CFG. ## Analysis ### Evidence discipline is the real differentiator [[entities/rea]] is built around the idea that an agent should not trust a bare decompiler string. Its workflow instructions and guided prompts require keeping observations, inferences and unknowns distinct; `analysis_profile` is mandatory and part of each record's identity; comparisons only conclude equality or absence over complete, compatible page sets, leaving a dimension `unknown` rather than guessing when a facet is unavailable. Crucially, target-derived content (strings, pseudocode, page text, logs) is flagged `untrusted_content` in `_meta`, and REA's instructions tell the agent to treat it as data and report any embedded "run this" directive as prompt injection. None of the other servers' cited docs describe an equivalent untrusted-content marker, so with them the discipline has to live in your prompt instead. Note that the ida-pro-mcp README's own prompt-engineering advice — "NEVER convert number bases yourself, use the `int_convert` tool", de-obfuscate before asking the LLM, LLMs hallucinate on math — is the same lesson from the other direction: single-engine bridges put the burden on the operator. ### Response-size limits Big functions and class dumps overflow MCP frames, and each server handles it differently: - **REA** targets a 10 MiB budget, returns `resource_constraint` (`details.resource: "transport"`) with a retained-evidence reference when a result won't fit, and expects you to page it with `inspect_analysis_view` or `export_evidence_bundle`; raise `REA_MCP_MAX_RESPONSE_BYTES` (≥10485760) only if the client's buffer allows. For oversized native functions it even returns a ready-to-call continuation for the first page of pseudocode. - **ida-pro-mcp** uses cursor-based pagination on search tools (default limit 1000, hard max 10000 "to prevent token overflow"). - **jadx-headless-mcp** truncates with `max_bytes` only *after* the class is materialized (so it does not stop a slow decompile early) and adds a hard `--decompile-timeout-ms` (default 90000) that returns an error banner; for fat classes it tells you to prefer `get_class_summary` + `get_method_by_name`. - **evmole-mcp** keeps disassembly/CFG opt-in because they're large, and exposes `offset`/`limit` paging; check `warnings` and `pagination` before trusting a result. ### The safety of unrestricted consoles This is the sharpest operational difference. REA's GDB and Rizin/Cutter consoles are deliberately **unrestricted and run with the user's privileges**: the GDB console "can run shell commands, change target state, access files, and use network in the REA process user's security context," and Rizin commands/plugins "run with the REA process user's security context and may access files, the network, or perform other actions." Treat them as a shell on the host. They are Linux-only, the Rizin debugger (and the one-shot GDB CLI) requires a caller-selected durable `inferior_tty` (optional for MCP `start_gdb_session`), and closing a session can detach and resume a live inferior; running such a command also retires the active analysis session, so you must `open_binary` again afterward. ida-pro-mcp's `py_eval` ("execute arbitrary Python code in IDA context") and its `?ext=dbg` debugger extension carry the same open-ended power with even less framing. The read-only servers (jadx-headless, evmole, and REA's static native ops) are far safer to point an autonomous agent at. evmole-mcp is the clean counter-example on exposure: stdio only, no network requests, no credentials, no file writes, no address fetching — a good model for a tool that should never do more than analyze the bytes it's given. ### Attachment, multiplexing and database effects The official IDA MCP's multiplexing lets two agents (or an agent plus a human in the GUI) edit the same database and see each other's changes immediately — powerful, but it means the agent is mutating your real `.idb`. ida-pro-mcp's `idb_open` modes (`prefer_headless`/`force_headless`/`prefer_gui`/`force_gui`) and detached, self-adopting workers give similar shared-state behavior. REA, by contrast, keeps native analysis read-only and discards session metadata on close, and for IDA it adapts an *upstream* server rather than bundling one (configured via `REA_IDA_MCP_CONFIG`, including an optional native bridge whose plugin binds `0.0.0.0` — firewall it). If you want the agent to annotate a persistent database, use IDA MCP or GhidraMCP; if you want non-destructive, evidence-tagged analysis across many formats, use REA. ## Recommendations - **Want one interface over many engines, with evidence discipline and non-destructive native analysis** → REA. - **Living in IDA and want the agent beside you in the GUI, or multiple agents on one DB** → official Hex-Rays IDA MCP; use idalib for headless/CI. - **Already invested in ida-pro-mcp** → fine, but heed its own pointer to the official server, and keep `py_eval`/`?ext=dbg` off an unsupervised agent. - **Android** → jadx-headless-mcp for safe read-only decompilation; tunnel its HTTP mode (no auth). - **Smart contracts** → evmole-mcp. - **Whatever the server, treat decompiler/strings output as untrusted data**, and never give an autonomous agent an unrestricted GDB/Rizin console or `py_eval` on a target you don't fully control. - **Page large results** instead of raising budgets blindly, and prefer summary tools (`get_class_summary`, REA summaries) for big objects. ## Pages Compared - [[entities/rea]]: the broker and its evidence model - [[entities/ida-pro]]: IDA, idalib and the official MCP - [[entities/ghidra]]: the engine behind GhidraMCP - [[syntheses/android-apk-analysis]]: where jadx-headless-mcp fits - [[concepts/evm-bytecode]]: what evmole extracts - [[concepts/legal-and-ethics]]: authorization and the unrestricted-console risk ## Sources - `raw/github_doc-docs-mcp-contracts-md.md` - `raw/github_doc-docs-mcp-prompts-md.md` - `raw/github_doc-agents-skills-reverse-engineer-anything-references-evidence-.md` - `raw/github_doc-docs-reverse-engineering-tools-md.md` - `raw/github_doc-docs-ida-provider-md.md` - `raw/web_community-overview-md-4.md` - `raw/web_community-getting-started-md-2.md` - `raw/web_community-multiplexing-md.md` - `raw/web_community-where-mcp-fits-md.md` - `raw/web_community-agentic-ida-with-idalib-md.md` - `raw/web_community-overview-md-3.md` - `raw/web_community-mcp-server-jeb-decompiler.md` - `raw/github_doc-readme-md-23.md` - `raw/github_doc-readme-md-24.md` - `raw/github_doc-readme-md-6.md` - `raw/github_doc-agent-mcp-readme-md.md` - `raw/github_doc-agent-readme-md.md` - `raw/github_doc-docs-evm-bytecode-md.md` --- title: "Triage an Unknown Binary: The First 15 Minutes" type: synthesis tags: [triage, file-identification, readelf, objdump, nm, strings, c++filt, rz-bin, rz-hash, binwalk, entropy, detect-it-easy, floss, mitigations] created: 2026-10-16 updated: 2026-10-16 confidence: high sources: ["raw/web_community-readelf-gnu-binary-utilities.md", "raw/web_community-objdump-gnu-binary-utilities.md", "raw/web_community-nm-gnu-binary-utilities.md", "raw/web_community-strings-gnu-binary-utilities.md", "raw/web_community-c-filt-gnu-binary-utilities.md", "raw/github_doc-src-tools-rz-bin-intro-md.md", "raw/github_doc-src-tools-rz-bin-file-identification-md.md", "raw/github_doc-src-tools-rz-bin-strings-md.md", "raw/github_doc-src-tools-rz-bin-imports-md.md", "raw/github_doc-src-tools-rz-hash-rz-hash-tool-md.md", "raw/web_community-generating-entropy-graphs-md.md", "raw/github_doc-readme-md-16.md", "raw/github_doc-readme-md-21.md", "raw/github_doc-readme-md-20.md", "raw/github_doc-doc-usage-md-2.md", "raw/github_doc-docs-binary-diagnostics-md.md", "raw/github_doc-docs-raw-binary-md.md", "raw/github_doc-docs-reverse-engineering-tools-md.md", "raw/web_community-elf-5-linux-manual-page.md"] --- # Triage an Unknown Binary: The First 15 Minutes Use this when someone hands you a file and asks "what is this?". The goal is to answer five questions quickly, from the outside, without running anything: **what format, what architecture, packed or not, what does it say (strings, imports, symbols), and is there debug info?** Then pick the toolchain. If the file might be hostile, follow [[syntheses/malware-triage]] instead. It starts with safe handling and adds capability analysis. ## Comparison Which tool answers which triage question: | Question | GNU binutils | Rizin | Others | |---|---|---|---| | Identity / hash | | `rz-hash -a sha256 f` | | | Format, arch, bits, endianness | `readelf -h f` · `objdump -f f` | `rz-bin -I f` | `diec f` (any format) | | Compiler / packer / protector | | `rz-bin -I` (`compiler`, `lang` fields) | `diec --heuristicscan --verbose f` | | Sections and segments | `readelf -S -l f` · `objdump -h f` | `rz-bin -S f` · `-SS` · `-SSS` | | | Imports / linked libraries | `readelf -d f` (DT_NEEDED) · `nm -D -u f` | `rz-bin -i f` · `rz-bin -l f` | | | Exports / symbols | `nm -C f` · `readelf -s --dyn-syms f` | `rz-bin -E f` · `rz-bin -s f` | | | Strings | `strings -a -n 6 f` · `strings -e l f` (UTF-16LE) | `rz-bin -z f` (data) · `-zz` (whole file) | `floss f` (adds decoded/stack strings) | | Entropy / packing | | `rz-hash -a entropy f` | `binwalk --entropy f` | | Debug info | `readelf --debug-dump=info f` · `objdump --dwarf f` | `rz-bin -d f` | | | Mitigations (NX, PIE, canary, RELRO) | `readelf -l` (`PT_GNU_STACK`) · `readelf -d` | `rz-bin -I` (`NX`, `PIE`, `canary`, `relro`) | REA `inspect-binary-layout` | | Embedded files | | `rz-bin -x f` (sub-binaries) | `binwalk f` | | Demangle C++ names | `c++filt _Z...` · `nm -C` | `rz-bin -D lang name` | | binutils handles ELF best. `rz-bin` treats ELF, PE, Mach-O, and Java class files the same way and outputs JSON with `-j`. DiE covers the widest range of formats, and its heuristic scan never launches the file. ## Analysis ### Minute 0–2: identity and format ```bash rz-hash -a sha256 sample # record identity before anything else rz-bin -I sample # arch, bits, class, os, lang, compiler, stripped, canary, NX, PIE, relro diec sample # format, compiler/linker, packer/protector guess ``` `rz-bin -I` gives you most of triage in one screen: `arch`, `bits`, `endian`, `bintype`, `class` (e.g. `ELF64`), `os`, `lang`, `intrp` (the dynamic loader), `stripped`, plus static mitigation flags `canary`, `NX`, `PIE`, `relro`. For ELF, `readelf -h` shows the raw header: class, data encoding, `e_type` (`ET_EXEC`, `ET_DYN`, `ET_REL`, `ET_CORE`), machine, and entry point. Note that `ET_DYN` covers both PIE executables and shared libraries. If neither tool recognises a header, the file may be raw firmware or a blob (see "Headerless blobs" below) or a container. Run `binwalk sample` to look for embedded signatures. How each format identifies itself is covered in [[concepts/executable-formats]]: the ELF `\x7fELF` magic, the PE `MZ` stub with the `PE\0\0` offset at `0x3c`, Mach-O `0xfeedfacf`, and dex `dex\n039\0`. ### Minute 2–5: packed or not? - **Entropy.** `rz-hash -a entropy sample` gives a whole-file figure on a 0–8 scale. `binwalk --entropy sample` plots entropy against file offset and saves a PNG (`--png` sets the path). Compressed and encrypted regions both look close to random. A long plateau near the top of the scale, especially over what should be code, suggests packing or an encrypted payload. - **Structure.** Very few imports, odd section names, a writable+executable section, or an entry point in the last section are classic packer signs. DiE's heuristic mode reports these as `(Heur) Packer` or `(Heur) Protection` with the evidence listed. - **Consequence.** If the file is packed, static strings and imports mostly describe the unpacking stub. Note it and keep going, but lower your confidence. ### Minute 5–10: strings, imports, symbols ```bash strings -a -n 6 sample | less # -a scans the whole file; default min length is 4 strings -a -e l sample # 16-bit little-endian (UTF-16LE, common on Windows) floss --summary sample # if strings look thin or obfuscated rz-bin -i sample # imports (with PLT addresses on ELF) rz-bin -l sample # linked libraries nm -C -D sample # dynamic symbols, demangled readelf -d sample # DT_NEEDED, RPATH/RUNPATH, flags ``` - **`strings` defaults.** Whole-file scanning (`-a`) is normally the default, but builds can be configured to default to `-d` (initialized data sections only). `-d` cuts noise but runs the input through the BFD library, so it is exposed to any BFD parsing bugs. Pass `-a` explicitly for hostile files. - **`rz-bin -z` vs `-zz`.** `-z` reads strings from data sections (`.rodata` on ELF). `-zz` scans raw bytes across the whole binary, and `-zzz` dumps raw strings for huge files. - **Go and Rust** store strings without NUL terminators, so `strings` shows them as long blobs. FLOSS splits them correctly, and [[concepts/go-rust-and-dart-binaries]] covers the metadata worth extracting. - **C++ names.** Pipe through `c++filt`, or use `nm -C` / `readelf --demangle`. - **What you're looking for:** URLs, paths, registry keys, format strings, error messages, version banners, crypto constants, and imports that reveal behaviour (networking, process creation, file I/O, crypto). ### Minute 10–13: debug info and build provenance - `rz-bin -I` shows `stripped`, `linenum`, `lsyms`, and `dbg_file`. `readelf -S` shows whether `.symtab` and `.debug_*` sections exist. - `readelf --debug-dump=info` (or `-wi`) dumps DWARF. `objdump --dwarf` does the same, and REA's `rea inspect-with-objdump ./program dwarf` wraps it. - **Network side effect.** Following external debug links or debuginfod can reach out over the network. readelf has `-wK`/`-wN` to follow or not follow links and `-wE` to avoid debuginfod. REA passes `-WK` only when `--follow-debug-links` is set, and clears `DEBUGINFOD_URLS`. - For PE, `rz-bin -P` shows PDB info, and DiE reports embedded PDB paths and other debug leftovers that reveal build paths and project names. ### Minute 13–15: pick the toolchain | What triage found | Go to | |---|---| | Native ELF/PE/Mach-O, unpacked | [[syntheses/choosing-a-disassembler]] → [[entities/ghidra]], [[entities/ida-pro]], [[entities/rizin-and-cutter]] | | Looks hostile, or packed | [[syntheses/malware-triage]] | | .NET assembly (CLR header present) | [[concepts/dotnet-and-nativeaot]] | | Go, Rust, or Flutter/Dart | [[concepts/go-rust-and-dart-binaries]] | | APK / DEX | [[syntheses/android-apk-analysis]] | | Electron app / ASAR / bundled JS | [[syntheses/javascript-and-electron-apps]] | | `.wasm` | [[concepts/webassembly]] | | Firmware image or no recognisable header | [[syntheses/firmware-analysis]] | | EVM bytecode | [[concepts/evm-bytecode]] | | Need to watch it run | [[syntheses/dynamic-analysis-workflow]] | | Needs live debugging (Linux) | [[entities/gdb-and-pwndbg]] | ### Headerless blobs A file with no header has no format to detect, so you must supply the CPU and the load address yourself. REA does not infer them from a `.bin` suffix. Its Ghidra path maps the whole file at a caller-chosen entry address: ```bash rea inspect /abs/path/ecu.bin --target-format raw-binary --architecture arm --entry-point 0x8000000 --provider ghidra --json ``` Supported `--architecture` values are `x86`, `x86_64`, `arm`, `arm64`, `6502`, and `m68k`. ARM and AArch64 entries must be 4-byte aligned. The compiler spec chosen for raw targets sets analysis conventions only. It says nothing about the original compiler. `rz-bin -Y` lists candidate base addresses for a firmware blob. ### Offline ELF layout with REA For x86-64 ELF on Linux, `REA_PWNTOOLS_PYTHON=/abs/env/bin/python rea inspect-binary-layout ./f.elf --json` reports sections, segments, original symbols and relocations, and static mitigation candidates, and never launches the file. Its caveats apply to every tool: linked addresses are not runtime addresses, `DT_NEEDED` and `PT_INTERP` are names rather than resolved paths, and an absent canary symbol does not prove every function is unprotected. ## Recommendations 1. Always start with **hash → `rz-bin -I` → `diec`**. Those three commands answer format, architecture, packing suspicion, and mitigations quickly. 2. Pass **`strings -a`** on untrusted input, and add **`-e l`** for Windows targets. Move to FLOSS as soon as strings look sparse. 3. Treat **high entropy plus few imports** as packed until shown otherwise, and move to [[syntheses/malware-triage]]. 4. Write down what you *didn't* find (no symbols, no debug info, unknown packer). It shapes how far you can trust decompiler output (see [[concepts/decompilation-concepts]]). 5. If a tool misparses the file, cross-check with another. binutils, rz-bin, and DiE parse formats with separate code, so one often catches another's misparse. ## Pages Compared - [[syntheses/malware-triage]]: the hostile-sample version of this workflow - [[concepts/executable-formats]]: what the headers, sections, and imports mean - [[syntheses/choosing-a-disassembler]]: the next step for native code - [[entities/rizin-and-cutter]]: `rz-bin` and `rz-hash` in context - [[syntheses/firmware-analysis]]: when there is no header - [[entities/rea]]: agent-driven triage with evidence records ## Sources - `raw/web_community-readelf-gnu-binary-utilities.md` - `raw/web_community-objdump-gnu-binary-utilities.md` - `raw/web_community-nm-gnu-binary-utilities.md` - `raw/web_community-strings-gnu-binary-utilities.md` - `raw/web_community-c-filt-gnu-binary-utilities.md` - `raw/github_doc-src-tools-rz-bin-intro-md.md` - `raw/github_doc-src-tools-rz-bin-file-identification-md.md` - `raw/github_doc-src-tools-rz-bin-strings-md.md` - `raw/github_doc-src-tools-rz-bin-imports-md.md` - `raw/github_doc-src-tools-rz-hash-rz-hash-tool-md.md` - `raw/web_community-generating-entropy-graphs-md.md` - `raw/github_doc-readme-md-16.md` - `raw/github_doc-readme-md-21.md` - `raw/github_doc-readme-md-20.md` - `raw/github_doc-doc-usage-md-2.md` - `raw/github_doc-docs-binary-diagnostics-md.md` - `raw/github_doc-docs-raw-binary-md.md` - `raw/github_doc-docs-reverse-engineering-tools-md.md` - `raw/web_community-elf-5-linux-manual-page.md` --- title: "Troubleshooting: Symptom-First Fixes by Tool" type: synthesis tags: [troubleshooting, ghidra, ida, frida, jadx, apktool, capa, floss, yara-x, rea, errors] created: 2026-10-16 updated: 2026-10-16 confidence: medium sources: ["raw/github_doc-ghidra-debug-debugger-src-main-help-help-topics-debugger-tro.md", "raw/github_issue-decompiler-initialization-failed.md", "raw/github_issue-classnotfoundexception-ghidrarun-bat-launch-bat-cannot-run-g.md", "raw/github_issue-launchsupport-expected-2-to-4-arguments-but-got-1.md", "raw/github_issue-importing-executable-files-with-auto-detected-format-exports.md", "raw/github_issue-pdb-parsing-issues.md", "raw/github_issue-in-vm-gdb-local-debugger-crashes-for-arm-toolchain-on-window.md", "raw/github_issue-unable-to-run-the-debugger-on-win10.md", "raw/github_issue-freezing-and-gui-issues.md", "raw/github_issue-no-module-named-jintrospect.md", "raw/web_community-failures-md.md", "raw/web_community-troubleshooting-md.md", "raw/github_doc-i18n-en-docs-troubleshooting-md.md", "raw/github_issue-failed-to-spawn-remote-write-ptrace-pokedata-head-failed-5-h.md", "raw/github_issue-failed-to-spawn-the-connection-is-closed.md", "raw/github_issue-java-is-not-defiend.md", "raw/github_issue-frida-ps-command-not-found.md", "raw/github_issue-failed-to-attach-unable-to-inject-library-into-process-witho.md", "raw/github_issue-this-feature-requires-an-ios-developer-disk-image-to-be-moun.md", "raw/github_issue-cant-start-frida-server-on-ios-16.md", "raw/github_issue-unable-to-load-selinux-policy-from-the-kernel-failed-to-open.md", "raw/github_issue-latest-google-play-system-update-ruins-frida.md", "raw/github_issue-unable-to-perform-state-trasition.md", "raw/github_issue-core-caused-by-java-util-zip-zipexception-invalid-cen-header.md", "raw/github_issue-stop-responding-because-of-using-too-high-ram.md", "raw/github_issue-indexing-stuck.md", "raw/github_issue-ui-font-and-icons-are-crazy-tiny-on-windows-10.md", "raw/github_doc-readme-md-5.md", "raw/github_doc-docs-faq-mdx.md", "raw/github_doc-wiki-in-depth-frameworks-mdx.md", "raw/github_doc-doc-faq-md.md", "raw/github_doc-doc-limitations-md.md", "raw/github_doc-site-content-docs-errors-and-warnings-errors-md.md", "raw/github_doc-site-content-docs-errors-and-warnings-warnings-md.md", "raw/github_doc-site-content-docs-writing-rules-disabling-warnings-md.md", "raw/github_doc-agents-skills-reverse-engineer-anything-references-connectio.md", "raw/github_doc-docs-migration-6-2-md.md", "raw/github_doc-docs-mcp-contracts-md.md", "raw/github_issue-address-not-in-trace.md", "raw/github_issue-10-0-3-debugger-resync-issue.md", "raw/github_issue-jadx-next-issues.md", "raw/github_doc-docs-cli-parameters-mdx.md"] --- # Troubleshooting: Symptom-First Fixes by Tool Find the tool, match the symptom, apply the fix the source actually gives. Every entry below comes from an official doc or a GitHub issue thread; where a thread never reached a confirmed fix, that's stated. For dynamic-analysis work on devices you must own or be authorized to test — see [[concepts/legal-and-ethics]]. ## Comparison Which tool each symptom class belongs to: | Symptom | Tool | |---|---| | Decompiler/analysis/debugger won't start or produces wrong code | Ghidra, IDA | | `Failed to attach`/`Failed to spawn`, `Java is not defined` | Frida | | `invalid CEN header`, out-of-memory, tiny UI | JADX | | `Can't find framework resources`, Magic APKs | apktool | | Packed/installer warnings, missed wrapper functions | capa | | `error[E0xx]`, noisy warnings | YARA-X | | No MCP tools, `provider_unavailable`, cold-start timeout | REA | ## Analysis ### Ghidra | Symptom | Fix | |---|---| | "Decompiler initialization failed!" / missing decompiler | Confirm `./Ghidra/Features/Decompiler/os//decompile` exists and is executable, and that the host is 64-bit x86. Try running the `decompile` executable directly from a terminal to see the real error. (unresolved on some RHEL hosts even when the file exists.) | | Windows 11 + JDK 21: `Could not find or load main class ...\ghidra` from `ghidraRun.bat` | Check `~/.ghidra/.ghidra_/application.log` for the real error; try renaming `.ghidra` to `.ghidra.save` and starting a fresh project; re-download the distribution. A maintainer also advised reverting any environment-variable changes (e.g. a custom `CLASSPATH`); with JDK 17+ on `PATH` nothing else should need changing. The thread ends without a confirmed fix. | | "LaunchSupport expected 2 to 4 arguments but got 1" | A maintainer suspected a conflicting tool on `PATH` (e.g. Cygwin; unconfirmed). One reporter fixed it by removing a trailing `\` from `%INSTALL_DIR%\` per the referenced PR; try running Ghidra from a different directory to confirm. | | Exported binary is corrupted / segfaults after import as auto-detected ELF or PE | By design per the thread: binary export only dumps Ghidra's memory blocks and is not meant to produce a valid executable. Reported workaround: re-export after importing as **Raw Binary** with the language selected manually. But raw import skips ELF/PE-specific analysis (missing functions/xrefs), so it is a round-trip workaround, not an analysis substitute. | | PDB parsing fails on Windows | Register the DIA SDK DLL: `regsvr32` the `msdia140` as x64 (matching your OS bitness) (documented in `docs/README_PDB.html`). | | GUI freezes / won't populate the Code Browser | From an OS terminal run `jps` to get the PID, then `jstack ` to capture what Ghidra is doing, and check the application log (`~/.ghidra/.ghidra_/application.log`, or the macOS equivalent). | | "No module named jintrospect" after long uptime | Unconfirmed: a maintainer suspected the user temp directory (`-Ghidra\jython_cachedir`) being cleared, and one user once deleted that directory after a permissions problem. Only a full Ghidra restart reliably cleared it. | **Ghidra Debugger** (official troubleshooting help): first confirm the target's own debugger works standalone (gdb on Linux, LLDB on macOS, WinDbg on Windows) — if it fails there it won't work in Ghidra. Check, in order: the debugger's **Terminal** (no terminal after launch means no back-end started — check Window → Terminals), the **Debug Console** (launchers post diagnostics and sometimes remedies there), and the **application log** (Help → Show Log; search "debugger", "launch", "tracermi"). If misconfigured, re-import the default Debugger tool and verify `TraceRmiPlugin`, `TraceRmiLauncherServicePlugin`, `TraceRmiConnectionManagerPlugin` and `DebuggerModelPlugin` are enabled. - **Windows "IN-VM GDB" crashes / empty terminal with ARM toolchains**: known issue; the standing workaround is to use the "GDB over SSH" agent against a WSL client or a Linux VM running gdbserver rather than IN-VM GDB. When you do supply a Windows path in the "GDB launch command" field, use **double backslashes**. - **WinDbg launch fails (dbgeng/dbgmodel mismatch)**: unselecting `dbgmodel` lets the debugger use (almost) any `dbgeng.dll` but drops TTD/model features, and it still failed for the reporter. The fix that worked: copy the newer WinDbg `amd64` directory (`dbg*` DLLs; under `C:\Program Files\WindowsApps\Microsoft.WinDbg_..._x64_...`, hidden in Explorer) into the active JDK's `bin` and point "Path to dbgeng" there. - **"Address not in trace" after `LoadLibrary`** (Ghidra 10.x): a maintainer suggested a stale memory map: refresh the `Memory` node in the Objects view, or toggle "Force Full View" in the Regions view (not confirmed in the thread). **"Resync: Missed loaded module"** with qemu-arm static binaries (10.0.3/10.0.4) was tied to `set architecture arm`; letting gdb pick the architecture worked for the maintainer, only partly for the reporter. ### IDA (Hex-Rays decompiler) The decompiler distinguishes crashes, internal errors ("interr"), graceful failures, and merely poor output. Key graceful-failure fixes from the failures reference: | Message | What to do | |---|---| | internal error ("interr") | You can't decompile after one. Reload the database, or better, restart IDA; send the database via Help → Report a bug so it's reproducible. | | `call analysis failed` | Specify the callee's type (jump to it, press **Y**); for an indirect call, set the call operand type or add an xref to a function of the right type. | | `switch analysis failed` | Specify the switch idiom manually (Edit → Other → Specify switch idiom); on old databases, delete and recreate the jump instruction. | | `invalid basic block` | Fix function boundaries; if a non-returning call is the cause, mark the callee **noret** (or add an xref to a noret function for indirect calls); reanalyze with the latest IDA. | | `positive sp value has been found` | Correct the stack pointer with Alt-K (Edit → Functions → Change stack pointer). | | `undefined or illegal type` | A referenced typedef is undefined (often an unloaded type library); redefine it in Local Types (Shift-F1). | | `wrong basic type sizes in compiler settings` | In Options → Compiler, ensure `sizeof(int)==4`, `sizeof(enum)==4`, "near data, near code", and the right pointer model (32-bit: near 32/far 48; 64-bit: 64). | | `stack frame is too big` / `too big function` / `too complex function` | `stack frame is too big` (unaliased stack >1 MB) and `too complex function` are hard limits; `too big function` is governed by the configurable `MAX_FUNCSIZE` parameter. | | `no license available` | IDA can't locate your decompiler license. | | `only 64-bit functions can be decompiled...` | Hex-Rays' page says to use IDA32 for 32-bit functions and IDA64 for 64-bit; IDA 9.x ships a single unified binary, so check this against your install. | General decompiler checklist when output is wrong: verify function boundaries (no wild branches; ends in return or tail-call; non-returning callees marked noret), stack-pointer values (Options → General → Stack pointer), stack variables, the function type (**Y**), and the types of called functions/data; use a database made by the latest IDA. Variables shown in red mean local-variable allocation failed. For UI-level warnings and analysis issues, the GitBook troubleshooting page points to the Help Messages and the Problems window. ### Frida From the official troubleshooting doc: | Symptom | Fix | |---|---| | `ValueError: ambiguous name; it matches:` | More than one process matches; attach by PID instead: `frida.attach(12345)`. | | `PTRACE_ATTACH failed: 1` (Linux) | No permission to attach. `sudo sysctl kernel.yama.ptrace_scope=0`, or run as root; can also be Magisk Hide — disable it and reboot. | | macOS `Failed to spawn: ... task_for_pid returned '(os/kern) failure'` | Sign Frida properly; or if a signing/permission issue, `sudo security authorizationdb write system.privilege.taskport allow` (weakens security); SIP may need disabling for system binaries. | | `ImportError: dynamic module does not define init function` | Python 2/3 mismatch — the `_frida.so` was built for a different Python; check your interpreter and `PYTHONPATH`. | From resolved issues: | Symptom | Fix | |---|---| | `frida-ps`/`frida` : command not found | Install `frida-tools` (`pip3 install frida-tools`) and fix the Python scripts PATH; privileges can require `sudo pip install frida-tools`. | | Android `remote_write PTRACE_POKEDATA head failed: 5` | Huawei/EMUI-specific (the reporter already had SELinux permissive and a debuggable build): rebuild the kernel with `CONFIG_HUAWEI_PTRACE_POKE_ON=y`; one user also had to disable SELinux. | | `Failed to spawn: the connection is closed` | Per the maintainer, the agent injected into zygote or system_server crashes that process; run `frida-server` interactively and watch its stdout/stderr. No confirmed fix in the thread (matching versions did not help one reporter). | | `Failed to attach: unable to inject library into process without libc` | Suggested, not confirmed in the thread: use a `frida-server` whose ABI matches the device; one user fixed it with a different Frida version on a physical device instead of an emulator. | | `'Java' is not defined` (Frida 17+) | Bridges are no longer bundled; install `frida-java-bridge` (and matching `frida-compile`/`@types/frida-gum`) and import it in your agent. | | `Unable to load SELinux policy ... Permission denied` on frida-server start | Run `frida-server` as root (`adb root` then start it, or `su`). | | iOS `Failed to spawn: ... Developer Disk Image to be mounted` | Mount a DDI (run Xcode briefly or `ideviceimagemounter`); or use a supported jailbreak (checkra1n) for pre-A12 devices. | | iOS 16 jailbreak: frida-server won't start | Edit the launch plist to remove `LimitLoadToSessionTypeSystem`; fixed in Frida 16.0.9+. | | Android: Frida stops working after a Google Play System Update | The ART library updated; workaround reported in the thread is `pm uninstall com.google.android.art` then reboot (removes a core component — use with caution). | | `Unable to perform state transition; please file a bug` | Same ART-update cause; the same `pm uninstall com.google.android.art` + reboot worked for some, not all. | A recurring theme: match host and device Frida versions exactly. ### JADX | Symptom | Fix | |---|---| | `java.util.zip.ZipException: invalid CEN header (bad compression method)` | Java's own ZIP implementation rejects these tampered/encrypted APKs at `ZipFile` creation; there is no in-JADX skip option. The thread's conclusion is that only a different ZIP implementation would help — no clean fix. | | Out of memory / "stop responding" during indexing | Assign more RAM. On Windows with `jadx-gui.exe`, create `jadx-gui.l4j.ini` next to it containing `-Xmx6g`; or exclude packages from decompilation in Preferences before starting. See the project Troubleshooting Q&A. | | Indexing stuck at ~63%, CPU pegged | Likely out of memory (GC thrashing at 100% CPU); raise `-Xmx`, and if that doesn't help, update JADX (the maintainer pointed to index-generation fixes in newer builds). | | Tiny UI/icons on Windows HiDPI | Use Java 9+ and add `-Dsun.java2d.uiScale=2` to `DEFAULT_JVM_OPTS` in `jadx-gui.bat`, or use the bundled-JRE release. | | Almost every class renamed to `PG` (jadx-next regression) | Disable "Use source file name as class name alias" in Preferences. | | Incorrectly decompiled code hidden | Run with `--show-bad-code` to see inconsistent output; or `-m fallback` / `-f` for raw instructions without restructuring (`-m auto|restructure|simple|fallback`). | ### apktool From the FAQ and frameworks docs: | Symptom | Fix | |---|---| | `Can't find framework resources for package of id: N` | Install the vendor framework: `apktool if com.htc.resources.apk` (installs as `N.apk`); tag device-specific frameworks (`-t htc`) and use the same tag when decoding. Find them in `/system/framework` (or `/data/system-framework`, `/system/app`). | | `java.nio` / `aapt` errors trying to run apktool on-device | Not officially supported on Android. | | "Magic APKs" won't decode/build | APKs built with OEM-modified, non-AOSP tools are not compatible — apktool can't decode or build them. | | Stale internal framework after an upgrade | apktool doesn't track framework versions; delete installed frameworks on upgrade (`apktool empty-framework-dir`, or `clean-frameworks`). Framework dirs: Linux `$HOME/.local/share/apktool`, Windows `%UserProfile%\AppData\Local\apktool`, macOS `$HOME/Library/apktool`. | ### capa From the limitations and FAQ docs: | Situation | What it means | |---|---| | Packed input | capa can't handle obfuscation well; unpack first. It warns when its rules detect probable packing. | | Installers / run-time programs (AutoIt etc.) | Results may be misleading or incomplete; capa warns when it detects one. | | Capability in a wrapper/child function not matched | capa does not currently propagate matches from child functions to parents (e.g. a `WriteFile` wrapper called by `f1` won't make `f1` match a file-write+exec rule). | | Want loop-scoped matching | Not implemented; use the `characteristic(loop)` feature to filter functions that contain a loop. | | Antivirus flags capa | Expected — its embedded rules and PyInstaller packaging look malware-like. Download only from the official Releases page or build it yourself; verify via VirusTotal. | ### YARA-X Compiler errors are `E001`–`E047`; warnings are named. Common ones and their fixes: | Code | Cause → fix | |---|---| | `E001` syntax error | Malformed rule (missing keyword, unclosed delimiter). | | `E002` wrong type | An expression must be `integer` where you used a string (range bounds, offsets, indices). | | `E009` unknown identifier | Not declared — often a module you forgot to `import "..."`, a typo, or an undefined external variable. | | `E017` `entrypoint` is unsupported | The deprecated `entrypoint` keyword; use `pe.entry_point` / `elf.entry_point` / `macho.entry_point`. | | `E022` unused pattern | A string defined but not used in `condition`; prefix with `_` (e.g. `$_c`) if intentional. | | `E045` arbitrary regular expression prefix (unanchored `.*`/`.+`) | Remove the leading `.*`/`.+`; it usually doesn't change meaning and matches at every offset. | | `slow_pattern` warning | A pattern with no long fixed atom; add a longer literal sub-pattern. | Disable a specific warning at one location with a comment: `// suppress: ` (comma-separate multiple, since 1.19.0). Placed before a rule it covers the rule; before a pattern, the pattern; at end of a line, that line; on its own line, the next line. Globally: `--disable-warnings=` or the config file. ### REA connection and recovery From the connection-and-recovery skill and MCP contracts: | Observation | Meaning and next step | |---|---| | No REA tools in the session | Skill install alone doesn't register MCP. Inspect with `rea doctor --client codex --json`, then plan a scoped `rea setup --client codex --dry-run --json`. | | Aligned registration but no connected tools | Restart/reconnect the client; doctor checks files, not the live connection. | | `provider_unavailable` or an unavailable tool | Read that operation's provider diagnostics or `binary_session.result.tool_availability`; a full catalog doesn't mean every op is available. Repair the engine. | | `MCP tool call requires approval, but approval policy is never` (Codex) | A client-policy rejection, not a REA problem — don't reinstall or install an engine. Use the client's approval flow, or preapprove named tools in the Codex config. | | `rea` missing in a child shell / Node incompatible | A prefix install absent from the login shell's PATH; inspect the actual PATH and launcher. Not a broken registration. | | Ghidra first query times out (cold start) | The first query imports and auto-analyzes. On the same connection: keep/export useful Evidence, `close_binary` (resolve any `cleanup_incomplete`), then `open_binary` again with `provider_id: "ghidra"` and a longer client request deadline. Raise `REA_GHIDRA_STARTUP_TIMEOUT_MS`, but note the *client's* per-call deadline (SDK default 60 s) bounds the wait, not the server allowance. | After upgrading REA, refresh cached MCP tool definitions (the 6.2 migration removed the old `{result, evidence_id, evidence}` wrapper — read `structuredContent` directly and check `isError` before success fields) and preserve old saved snapshots/captures rather than converting them, since `always-bump-minor` means a minor bump can be breaking. ## Recommendations - **Reproduce outside the wrapper first.** For Ghidra/IDA debugger trouble, confirm the native debugger works standalone; for REA, confirm the underlying engine with `rea doctor --provider `. - **Read the logs the source names**: Ghidra `application.log` + `jstack`, Frida `frida-server` stderr, IDA's interr dialog/Problems window. - **Match versions**: Frida host/device exact match; Ghidra 12.1.x + JDK 21; the right IDA bitness for the target. - **Unpack before analyzing** with capa; **install the vendor framework** before decoding OEM APKs with apktool. - **Don't treat workarounds as fixes**: Ghidra raw-import round-trips and `pm uninstall com.google.android.art` have real downsides noted above. ## Pages Compared - [[entities/ghidra]], [[entities/ida-pro]], [[entities/frida]]: the tools these fixes target - [[syntheses/android-apk-analysis]]: JADX and apktool in context - [[syntheses/malware-triage]]: capa, FLOSS and YARA in the triage flow - [[entities/rea]]: the connection model behind REA recovery ## Sources - `raw/github_doc-ghidra-debug-debugger-src-main-help-help-topics-debugger-tro.md` - `raw/github_issue-decompiler-initialization-failed.md` - `raw/github_issue-classnotfoundexception-ghidrarun-bat-launch-bat-cannot-run-g.md` - `raw/github_issue-launchsupport-expected-2-to-4-arguments-but-got-1.md` - `raw/github_issue-importing-executable-files-with-auto-detected-format-exports.md` - `raw/github_issue-pdb-parsing-issues.md` - `raw/github_issue-in-vm-gdb-local-debugger-crashes-for-arm-toolchain-on-window.md` - `raw/github_issue-unable-to-run-the-debugger-on-win10.md` - `raw/github_issue-freezing-and-gui-issues.md` - `raw/github_issue-no-module-named-jintrospect.md` - `raw/web_community-failures-md.md` - `raw/web_community-troubleshooting-md.md` - `raw/github_doc-i18n-en-docs-troubleshooting-md.md` - `raw/github_issue-failed-to-spawn-remote-write-ptrace-pokedata-head-failed-5-h.md` - `raw/github_issue-failed-to-spawn-the-connection-is-closed.md` - `raw/github_issue-java-is-not-defiend.md` - `raw/github_issue-frida-ps-command-not-found.md` - `raw/github_issue-failed-to-attach-unable-to-inject-library-into-process-witho.md` - `raw/github_issue-this-feature-requires-an-ios-developer-disk-image-to-be-moun.md` - `raw/github_issue-cant-start-frida-server-on-ios-16.md` - `raw/github_issue-unable-to-load-selinux-policy-from-the-kernel-failed-to-open.md` - `raw/github_issue-latest-google-play-system-update-ruins-frida.md` - `raw/github_issue-unable-to-perform-state-trasition.md` - `raw/github_issue-core-caused-by-java-util-zip-zipexception-invalid-cen-header.md` - `raw/github_issue-stop-responding-because-of-using-too-high-ram.md` - `raw/github_issue-indexing-stuck.md` - `raw/github_issue-ui-font-and-icons-are-crazy-tiny-on-windows-10.md` - `raw/github_doc-readme-md-5.md` - `raw/github_doc-docs-faq-mdx.md` - `raw/github_doc-wiki-in-depth-frameworks-mdx.md` - `raw/github_doc-doc-faq-md.md` - `raw/github_doc-doc-limitations-md.md` - `raw/github_doc-site-content-docs-errors-and-warnings-errors-md.md` - `raw/github_doc-site-content-docs-errors-and-warnings-warnings-md.md` - `raw/github_doc-site-content-docs-writing-rules-disabling-warnings-md.md` - `raw/github_doc-agents-skills-reverse-engineer-anything-references-connectio.md` - `raw/github_doc-docs-migration-6-2-md.md` - `raw/github_doc-docs-mcp-contracts-md.md` - `raw/github_issue-address-not-in-trace.md` - `raw/github_issue-10-0-3-debugger-resync-issue.md` - `raw/github_issue-jadx-next-issues.md` - `raw/github_doc-docs-cli-parameters-mdx.md`