aboutsummaryrefslogtreecommitdiffstats
path: root/idatui/launch.py
diff options
context:
space:
mode:
Diffstat (limited to 'idatui/launch.py')
-rw-r--r--idatui/launch.py118
1 files changed, 84 insertions, 34 deletions
diff --git a/idatui/launch.py b/idatui/launch.py
index a0201a7..6e3b432 100644
--- a/idatui/launch.py
+++ b/idatui/launch.py
@@ -9,12 +9,14 @@ Usage::
ida-tui /path/to/binary
ida-tui # attach when exactly one database is registered
"""
+
from __future__ import annotations
import argparse
import os
import sys
+
def _load_args(load: dict) -> str:
"""``load`` as IDA switches, for the single-binary path (no project ref).
@@ -25,8 +27,12 @@ def _load_args(load: dict) -> str:
"""
from .formats import load_args
from .project import _as_addr
- return load_args(load.get("processor", ""), _as_addr(load.get("base", 0)),
- str(load.get("ida_args", "") or ""))
+
+ return load_args(
+ load.get("processor", ""),
+ _as_addr(load.get("base", 0)),
+ str(load.get("ida_args", "") or ""),
+ )
def _log(msg: str) -> None:
@@ -62,32 +68,63 @@ def _registered_databases() -> tuple[list[dict], list[dict]]:
def main(argv: list[str] | None = None) -> int:
p = argparse.ArgumentParser(
prog="ida-tui",
- description="Open a registered GUI or managed idalib database in the IDA TUI.")
- p.add_argument("binary", nargs="*",
- help="binary to open and analyze (several with --project "
- "creates/extends that project)")
- p.add_argument("--project", metavar="FILE",
- help="open a multi-binary project (created from the given "
- "binaries if FILE doesn't exist)")
- p.add_argument("--ttl", type=int, default=1800,
- help="deprecated compatibility option (IDA Nexus uses leases)")
- p.add_argument("--no-keepalive", action="store_true",
- help="deprecated compatibility option (the lease is the heartbeat)")
- p.add_argument("--rpc", metavar="PATH",
- help="listen for RPC on this unix socket (puppeteer the TUI)")
- p.add_argument("--trace", metavar="FILE",
- help="Tenet execution trace to explore alongside the binary")
+ description="Open a registered GUI or managed idalib database in the IDA TUI.",
+ )
+ p.add_argument(
+ "binary",
+ nargs="*",
+ help="binary to open and analyze (several with --project "
+ "creates/extends that project)",
+ )
+ p.add_argument(
+ "--project",
+ metavar="FILE",
+ help="open a multi-binary project (created from the given "
+ "binaries if FILE doesn't exist)",
+ )
+ p.add_argument(
+ "--ttl",
+ type=int,
+ default=1800,
+ help="deprecated compatibility option (IDA Nexus uses leases)",
+ )
+ p.add_argument(
+ "--no-keepalive",
+ action="store_true",
+ help="deprecated compatibility option (the lease is the heartbeat)",
+ )
+ p.add_argument(
+ "--rpc",
+ metavar="PATH",
+ help="listen for RPC on this unix socket (puppeteer the TUI)",
+ )
+ p.add_argument(
+ "--trace",
+ metavar="FILE",
+ help="Tenet execution trace to explore alongside the binary",
+ )
g = p.add_argument_group(
"loading a headerless blob",
"An ELF/PE/Mach-O says what it is. A raw firmware dump doesn't, and IDA "
"falls back to x86 at address 0 — which analyses to nothing. These say "
- "how to read it, and are recorded per binary in a project.")
- g.add_argument("--processor", metavar="NAME",
- help="IDA processor: arm, armb (big-endian), mipsb, metapc, …")
- g.add_argument("--base", metavar="ADDR",
- help="load address, e.g. 0x8000000 (any base; NOT paragraphs)")
- g.add_argument("--ida-args", metavar="STR", dest="ida_args",
- help="legacy switches; only IDA Nexus-representable -p/-b/-T are accepted")
+ "how to read it, and are recorded per binary in a project.",
+ )
+ g.add_argument(
+ "--processor",
+ metavar="NAME",
+ help="IDA processor: arm, armb (big-endian), mipsb, metapc, …",
+ )
+ g.add_argument(
+ "--base",
+ metavar="ADDR",
+ help="load address, e.g. 0x8000000 (any base; NOT paragraphs)",
+ )
+ g.add_argument(
+ "--ida-args",
+ metavar="STR",
+ dest="ida_args",
+ help="legacy switches; only IDA Nexus-representable -p/-b/-T are accepted",
+ )
args = p.parse_args(argv)
load: dict = {}
@@ -112,6 +149,7 @@ def main(argv: list[str] | None = None) -> int:
binary = None
if args.project:
from .project import Project, ProjectError
+
ppath = os.path.abspath(os.path.expanduser(args.project))
try:
if os.path.isfile(ppath):
@@ -126,8 +164,10 @@ def main(argv: list[str] | None = None) -> int:
project.save()
_log(f"added {added} binary(ies) to {ppath}")
if dupes:
- _log(f"{dupes} already in the project (matched by path) "
- f"— left alone")
+ _log(
+ f"{dupes} already in the project (matched by path) "
+ f"— left alone"
+ )
elif args.binary:
project = Project.create(ppath, args.binary, load=load or None)
_log(f"created project {ppath} with {len(project.refs)} binaries")
@@ -154,7 +194,8 @@ def main(argv: list[str] | None = None) -> int:
key = os.path.normcase(os.path.realpath(binary))
registered = any(
key == os.path.normcase(os.path.realpath(str(item.get(field) or "")))
- for item in ready for field in ("exe_path", "idb_path")
+ for item in ready
+ for field in ("exe_path", "idb_path")
if item.get(field)
)
if not os.path.isfile(binary) and not registered:
@@ -171,8 +212,10 @@ def main(argv: list[str] | None = None) -> int:
else:
_log("several IDA Nexus databases are registered; pass one of these paths:")
for item in ready:
- _log(f" {item.get('exe_path') or item.get('idb_path')} "
- f"[{item.get('backend')}, {item.get('record_id')}]")
+ _log(
+ f" {item.get('exe_path') or item.get('idb_path')} "
+ f"[{item.get('backend')}, {item.get('record_id')}]"
+ )
return 2
# Hand off to the TUI (imported late so --help works without Textual). Code
@@ -190,16 +233,23 @@ def main(argv: list[str] | None = None) -> int:
# round trip, and only when attached to a tty.
try:
from . import kittygfx
+
kittygfx.supported()
except Exception: # noqa: BLE001 -- graphics are decoration, never fatal
pass
rpc_path = os.path.abspath(os.path.expanduser(args.rpc)) if args.rpc else None
- IdaTui(open_path=binary, keepalive=not args.no_keepalive,
- rpc_path=rpc_path, ttl=args.ttl, project=project,
- load_args=_load_args(load),
- trace_path=(os.path.abspath(os.path.expanduser(args.trace))
- if args.trace else "")).run()
+ IdaTui(
+ open_path=binary,
+ keepalive=not args.no_keepalive,
+ rpc_path=rpc_path,
+ ttl=args.ttl,
+ project=project,
+ load_args=_load_args(load),
+ trace_path=(
+ os.path.abspath(os.path.expanduser(args.trace)) if args.trace else ""
+ ),
+ ).run()
return 0