aboutsummaryrefslogtreecommitdiffstats
path: root/idatui/app.py
diff options
context:
space:
mode:
authorblasty <blasty@local>2026-07-25 23:49:14 +0200
committerblasty <blasty@local>2026-07-25 23:49:14 +0200
commit57b09047881d4bb42b2b98e4bb0739d5bc5e5af8 (patch)
treef55ca12add86873a875fe70cf318524fca694d95 /idatui/app.py
parentxrefs: show project binaries that import this export (diff)
downloadida-tui-57b09047881d4bb42b2b98e4bb0739d5bc5e5af8.tar.gz
ida-tui-57b09047881d4bb42b2b98e4bb0739d5bc5e5af8.tar.xz
ida-tui-57b09047881d4bb42b2b98e4bb0739d5bc5e5af8.zip
loading: say how to read a headerless blob (processor, base)
A raw firmware dump has no format to detect, so IDA fell back to x86 at address 0. It doesn't fail — it opens, analyses, and finds nothing. An AArch64 image loaded this way gave 0 functions; told the truth it gives 35. ida-tui fw.bin --processor arm --base 0x8000000 and per binary in a project, which is what a multi-image firmware actually needs: {"path": "app.bin", "processor": "arm", "base": "0x8000000"} idapro.open_database() already accepted IDA command-line switches; nothing was passing any. Plumbed BinaryRef -> WorkerPool -> WorkerClient -> worker argv, plus a load_args for the single-binary path that has no project ref. base is written the way people say it (0x8000000, int or string, any base). IDA's -b is in PARAGRAPHS — -b1000 loads at 0x10000 — so BinaryRef.load_args converts, and a base that isn't 16-byte aligned is refused rather than silently landing 16x off. ida_args passes anything else through. Two bugs found by testing the whole path rather than the happy one: * Project.load() whitelisted path/label when normalising entries, so the load options were dropped the first time a project was reopened — set a processor, come back tomorrow, it's gone. * Re-passing the switches to an EXISTING database makes IDA refuse the open (rc != 0, no functions). The .i64 already records how the image was loaded, so the worker skips them once a database exists. My first guard checked splitext(path) + ".i64" and never fired, because IDA names it "<file>.i64" — keeping the extension. It checks both spellings now. Verified on a real AArch64 blob: fresh load 35 functions based at 0x8002440, reopen 35 again, and the CLI rejects an unaligned or non-numeric --base. tests: +6 project (options recorded, paragraph conversion, file round-trip, add() takes them, an ELF passes nothing, hex-string base). 39/0 project, 195/0 scenarios, 30/0 project UI, 36/0 index, 27/0 pool.
Diffstat (limited to 'idatui/app.py')
-rw-r--r--idatui/app.py9
1 files changed, 6 insertions, 3 deletions
diff --git a/idatui/app.py b/idatui/app.py
index ce2c315..7f00f92 100644
--- a/idatui/app.py
+++ b/idatui/app.py
@@ -3162,7 +3162,7 @@ class IdaTui(App):
def __init__(self, open_path: str | None = None, keepalive: bool = True,
rpc_path: str | None = None, ttl: int = 1800,
- project=None) -> None:
+ project=None, load_args: str = "") -> None:
super().__init__()
# Project mode is additive: with no project this is the plain
# single-binary app, unchanged.
@@ -3188,6 +3188,7 @@ class IdaTui(App):
open_path = project.refs[0].staged
self._open_path = open_path
self._ttl = ttl
+ self._load_args = load_args or "" # IDA switches for a headerless blob
self._do_keepalive = keepalive
self._rpc_path = rpc_path
self._rpc = None
@@ -3390,7 +3391,8 @@ class IdaTui(App):
self.app.call_from_thread(self._reconnect_failed,
"no binary to reopen")
return
- client = WorkerClient(self._open_path, ttl=self._ttl)
+ client = WorkerClient(self._open_path, ttl=self._ttl,
+ load_args=self._load_args)
client.connect(progress=lambda m: self.app.call_from_thread(
self._conn_note, m))
except Exception as e: # noqa: BLE001
@@ -3456,7 +3458,8 @@ class IdaTui(App):
base = os.path.basename(self._open_path)
self.app.call_from_thread(
self._status, f"starting worker — initial auto-analysis of {base}…")
- client = WorkerClient(self._open_path, ttl=self._ttl)
+ client = WorkerClient(self._open_path, ttl=self._ttl,
+ load_args=self._load_args)
client.connect(progress=lambda m: self.app.call_from_thread(
self._status, m))
return client