diff options
Diffstat (limited to 'README.md')
| -rw-r--r-- | README.md | 151 |
1 files changed, 118 insertions, 33 deletions
@@ -1,21 +1,26 @@ # ida-tui A minimal, keyboard-first (mouse-capable) **TUI frontend for IDA Pro**, built with -[Textual](https://textual.textualize.io/) and talking to the -[ida-pro-mcp](https://github.com/mrexodia/ida-pro-mcp) (idalib) server. +[Textual](https://textual.textualize.io/) and driving **idalib** (IDA headless). + +Opening a binary spawns our own **idalib worker** — a private subprocess talking a +unix socket (`idatui/worker.py` + `WorkerClient`), ~50–100× cheaper per call than +an HTTP transport. It reuses [ida-pro-mcp](https://github.com/mrexodia/ida-pro-mcp)'s +tool implementations in-process; the old ida-pro-mcp HTTP server/supervisor path +has been **removed**. ## ⚠️ Status: not ready for public consumption This is a personal, actively-hacked-on project. It is **not** packaged, polished, or supported for general use. Expect sharp edges: -- Hardcoded paths and assumptions (e.g. a venv at `~/ida-venv`, a supervisor on - `127.0.0.1:8745`). +- Hardcoded paths and assumptions (e.g. a venv at `~/ida-venv`, a specific + IDA/idalib layout). - No stable API, no versioning promises, no changelog — things move and break. - Requires a working IDA Pro + idalib install, which you must license and set up yourself. -- Known open bugs (see the backlog below), including wonky xref navigation and no - handling of PLT/import stubs. +- Known open bugs (see the backlog below), including no handling of PLT/import + stubs. - Basically undocumented beyond this file and `docs/`. If you found this expecting a finished tool: it isn't one yet. Poke around, but @@ -23,47 +28,119 @@ don't file expectations. **Use at your own risk.** ## What it does -- Virtualized **disassembly** and **decompilation (pseudocode)** views that page - lazily over the MCP server. -- Keyboard navigation: follow (`enter`), xrefs (`x`), rename (`n`), incremental - search (`/` `?`), history (`back`), view toggle. -- A **functions panel**, **hex viewer**, **struct editor**, and **(re-)typing**. +- A unified **IDA-style listing** (continuous disassembly interleaved with data / + undefined heads) as the default code view; `F5`/`Tab` drops into the + **decompiler (pseudocode)** for the function under the cursor. Both are + line-virtualized and page lazily over the worker. +- A **Ghidra-style split view** (`s`): listing and pseudocode side by side, kept + in cursor sync — the focused pane drives and the other highlights the linked + region (every instruction a C line owns), following you across functions. + `Tab` or a click switches which pane leads. +- Keyboard navigation: follow (`enter`), xrefs (`x`, tagged call/read/write/ + offset), rename (`n`), retype (`y`), comment (`;`), incremental search (`/` + `?`), history (`back`), hex view (`\`), and `home`/`end`/`shift+home` line + motions. +- A **functions panel** (fuzzy symbol palette on `Ctrl+N`), a **strings browser** + (`"`, filterable, Enter jumps to the literal), **hex viewer**, **struct + editor**, and inline **make code/data/function/string** edits. +- A **command palette** (`Ctrl+P`) with the real ida-tui actions. - An optional unix-socket **RPC layer** to puppeteer the live TUI from another process (agent-driven RE / livestreaming). See `docs/RPC.md`. ## Architecture (three layers, kept separate) -- **`idatui/client.py`** — stdlib-only persistent MCP client (`http.client` pool, - warm handshake, session recovery, keep-alive). No third-party deps. -- **`idatui/domain.py`** — paging/caching over the client (`FunctionIndex`, - `DisasmModel`, `decompile`, xrefs, resolve). Synchronous, thread-safe. +- **`idatui/worker.py` + `idatui/worker_client.py`** — the backend. `worker.py` + opens one DB with idalib (on its main thread) and serves ida-pro-mcp's tool + functions over a unix socket; `WorkerClient` spawns it and is a stdlib-only + drop-in client (length-prefixed pickle, calls serialized under a lock). Shared + error types + the `Session` model live in `idatui/errors.py`. +- **`idatui/domain.py`** — paging/caching over the worker client (`FunctionIndex`, + `DisasmModel`, `ListingModel`, `decompile`, xrefs, resolve). Synchronous, + thread-safe. Tools ida-pro-mcp lacks (`heads`, `read_raw`, `resolve_names`, + `xref_types`, …) are injected by `server/patch_server.py`, which the worker + runs itself on startup. - **`idatui/app.py`** — the Textual app (virtualized `ScrollView`s, shared cursor/ search/nav mixins, modals). -The client and domain layers are intentionally **stdlib-only**; only the TUI layer -pulls in Textual + Pygments. +The domain + worker-client layers are intentionally **stdlib-only** (the worker +process links idalib); only the TUI layer pulls in Textual + Pygments. ## Requirements - Python ≥ 3.11 -- A working **IDA Pro** with **idalib** and **ida-pro-mcp** installed. +- A working **IDA Pro** with **idalib** and **ida-pro-mcp** installed (the worker + reuses ida-pro-mcp's tool implementations in-process — no server runs). - Textual ≥ 8 and Pygments ≥ 2 for the TUI (`pip install -e '.[tui]'`). +Two python environments are expected: one with **textual + idapro** for the TUI +(`~/ida-venv`, override `$IDATUI_PYTHON`) and one with **idapro + ida_pro_mcp** +for the worker (auto-detected, override `$IDATUI_WORKER_PYTHON`). + ## Running +One command — it spawns a private idalib worker for the binary (which opens + +auto-analyzes it in its own process over a unix socket) and drops you into the +TUI behind a loading overlay: + ```sh -# 1. Start the ida-pro-mcp supervisor (opens bin/ls by default). -./spawn.sh # supervisor on 127.0.0.1:8745 +./ida-tui /path/to/binary # open a binary and drive it — that's it +``` + +It uses `~/ida-venv/bin/python` for the TUI (override with `$IDATUI_PYTHON`) and +resolves binary paths against your real cwd. The binary's directory must be +writable (idalib writes a `.i64` there). + +Headerless blobs need to be told what they are — a raw firmware dump has no +format to detect, and IDA falls back to x86 at address 0, which analyses to +nothing: -# 2. Launch the TUI (use a python that has textual + idapro). -python -m idatui.tui # auto-resolve the sole session -python -m idatui.tui --db <session> -python -m idatui.tui --open /abs/path/bin # dir must be WRITABLE (.i64) +```sh +./ida-tui fw.bin --processor arm --base 0x8000000 ``` -The `spawn.sh` host/port/target are overridable via `IDA_MCP_HOST`, -`IDA_MCP_PORT`, `IDA_MCP_TARGET`, `IDA_MCP_MAX_WORKERS`. A systemd unit is in -`systemd/`. +ARM images that use Thumb need one more thing: press `t` on the listing to switch +ARM/Thumb decoding at the cursor (it sets IDA's `T` register, and the segment to +32-bit, since Thumb doesn't exist in AArch64). + +`--base` is a real address (IDA's own `-b` is in paragraphs; the conversion is +done for you). In a project the options are recorded per binary, which is what a +multi-image firmware wants. They apply to the first open only — after that the +`.i64` records how the image was loaded. See `docs/PROJECTS.md`. + +> Recovering a wedged database: if a worker was hard-killed it leaves unpacked +> `foo.id0/.id1/.id2/.nam/.til` next to `foo.i64`, and the `.i64` then refuses to +> reopen. Delete those stale files (never the `.i64`) and retry — `ida-tui` does +> this automatically. + +## Execution traces + +Load a [Tenet](https://github.com/gaasedelen/tenet) trace alongside the binary +and explore it in time: + +```sh +./ida-tui /path/to/binary --trace trace.0.log +``` + +A docked pane on the right shows the registers at the current timestamp (the +ones the current instruction wrote are highlighted) and a timeline. `]` and `[` +step one instruction forward and back; `}` and `{` step over a call by following +the stack pointer. The code view follows. + +Both code views are painted with the execution trail: where you just came from, +where you're about to go, and the instruction you're standing on. The pseudocode +view is painted too — a trace records instructions, but `decomp_map` says which +instructions each C line covers, so the same trail lands on the decompilation. + +The dock also shows the **stack as of that instant**, read out of the trace. +Bytes the trace never observed print as `??` rather than zeros — a trace knows +what it saw and nothing else. The hex view (`\`) gets the same treatment: bytes +the trace saw at this timestamp are shown in green over the file's own contents. + +Trace addresses are rebased onto the database automatically — a traced process +is relocated, so nothing lines up until that's solved. + +Traces are recorded separately; see `~/dev/tenet/tenet-original/tracers/` for the +QEMU tracer. ## RPC / driving the TUI @@ -71,27 +148,35 @@ Give the TUI `--rpc <sock>` to expose a unix-socket control channel, then drive it from another pane: ```sh -python -m idatui.tui --db <s> --rpc /tmp/ida.sock +./ida-tui /abs/path/bin --rpc /tmp/ida.sock python -m idatui.drive where # ergonomic terse-text helper python -m idatui.drive pc main # pseudocode of main python -m idatui.drive rename sub_5BE0 foo # goto + rename ``` +Or let `idatui.pane` spawn + manage TUI panes in tmux (see the idatui-rpc skill): + +```sh +python -m idatui.pane spawn --open /abs/path/bin # -> {sock, pane, ready} +python -m idatui.pane list +python -m idatui.pane stop --sock <sock> +``` + See `docs/RPC.md` for the full protocol. ## Tests -Headless Textual `Pilot` suites live in `tests/` and need a live session id: +A headless Textual `Pilot` suite lives in `tests/`; it spawns a worker on the +given binary (default `targets/echo`): ```sh -python tests/test_scenarios.py --db <session> # UI suite -python tests/test_scenarios.py --db <s> --only hex,rename -python tests/test_domain.py --db <session> # domain/paging (stdlib) +python tests/test_scenarios.py targets/echo # full UI suite +python tests/test_scenarios.py --only hex,rename ``` ## Docs - `docs/RPC.md` — the RPC protocol -- `docs/PAGING_FINDINGS.md` — ida-pro-mcp/idalib paging quirks +- `docs/PAGING_FINDINGS.md` — idalib tool paging/scale quirks - `docs/TEXTUAL_NOTES.md` — Textual pitfalls encountered - `docs/TUI_DRIVING_BLUEPRINT.md` — generalizing the driving layer |
