From 14ca7c7e5c56c3fdd059d168957a2b2e3dbe504e Mon Sep 17 00:00:00 2001 From: user Date: Sat, 1 Aug 2026 17:18:57 +0200 Subject: rpc: make a raw firmware image drivable (load options, define, bulk symbols) Opening a headerless blob was the one workflow that fell out of the driving surface entirely, and each gap hid the next: - `pane spawn` couldn't pass --processor/--base/--ida-args, so the pane came up "ready" with zero functions (x86 at 0) and the only way through was to hand-write a project file. It now forwards them to idatui.launch. - c/p/t/T (code, function, ARM<->Thumb, vector scan) existed as listing bindings with no verb, so a driver had to guess raw keys -- and raw keys are swallowed by whatever modal happens to be up. `define {kind,target?}` goes through the app's own edit worker and reports what IDA actually did. - every name went through the typed rename prompt: a navigation (listing page + decompile) plus two prompt round-trips each. A 427-symbol map took tens of minutes of driving. `rename_many {items|file}` hands IDA's rename tool the whole list in one call (371 symbols in 3s) and refreshes the caches and the function table once. drive gains `define [target...]` and `syms `. Verified live against a real pane (tests/test_rawimage_rpc.py, 13 checks: spawn load options, define thumb/func + unknown-kind rejection, rename_many from a file and inline, with resolve/functions readback). --- idatui/pane.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'idatui/pane.py') diff --git a/idatui/pane.py b/idatui/pane.py index 37a5f0c..8a2e4a4 100644 --- a/idatui/pane.py +++ b/idatui/pane.py @@ -165,6 +165,14 @@ def spawn(args) -> int: inner += ["--rpc", sock] else: inner = [args.python, "-m", "idatui.launch", target, "--rpc", sock] + # Loading a headerless blob: without these IDA reads a raw firmware image as + # x86 at 0 and analyses to nothing, and the pane comes up ready-but-empty. + # They are launch's options; spawn just forwards them (a project records + # them per binary, so they're only needed on the first open). + for opt in ("processor", "base", "ida_args"): + val = getattr(args, opt, None) + if val: + inner += ["--" + opt.replace("_", "-"), str(val)] if getattr(args, "trace", None): inner += ["--trace", os.path.abspath(os.path.expanduser(args.trace))] cmd = f"cd {REPO!r} && exec " + " ".join(_q(a) for a in inner) @@ -340,6 +348,14 @@ def main(argv: list[str]) -> int: sp.add_argument("--project", metavar="FILE", help="project file to open instead of a single binary; " "any --open paths are added to it (created if absent)") + sp.add_argument("--processor", metavar="NAME", + help="IDA processor for a headerless blob: arm, armb, " + "mipsb, metapc, … (passed to idatui.launch)") + sp.add_argument("--base", metavar="ADDR", + help="load address for a headerless blob, e.g. 0x8000000 " + "(16-byte aligned)") + sp.add_argument("--ida-args", metavar="STR", dest="ida_args", + help="extra IDA command-line switches, passed through") sp.add_argument("--sock", help="RPC socket path (default: auto in $XDG_RUNTIME_DIR)") sp.add_argument("--python", default=DEFAULT_PY, help=f"python for the TUI ({DEFAULT_PY})") sp.add_argument("--vertical", action="store_true", help="split vertically (stacked)") -- cgit v1.3.1-sl0p