Skip to content

P2: UNSAFE backend scripting escape hatch (eval/exec)#211

Closed
mahaloz wants to merge 1 commit into
feat/cli-patchingfrom
feat/cli-backend-scripting
Closed

P2: UNSAFE backend scripting escape hatch (eval/exec)#211
mahaloz wants to merge 1 commit into
feat/cli-patchingfrom
feat/cli-backend-scripting

Conversation

@mahaloz

@mahaloz mahaloz commented Jul 17, 2026

Copy link
Copy Markdown
Member

What & why

The universal escape hatch for backend-specific work the abstracted API doesn't cover (IDALib's py_eval/py_exec_file). Kept explicitly unsafe and backend-specific — not portable, not sandboxed.

New capabilities

  • decompiler eval "<expr>" and decompiler exec "<code>" | --file <path>.
  • DecompilerInterface.backend_eval runs Python inside the backend process with the interface bound to deci: idaapi is importable, deci.flat_api (Ghidra), deci.project (angr), deci.bv (Binary Ninja). One generic base implementation serves every backend, routed through the server's main-thread dispatcher so it's safe on IDA/idalib.
  • eval returns the expression's repr; exec captures stdout and a result variable. Errors return a traceback and exit non-zero.

Example

$ decompiler eval "deci.name"
'ida'
$ decompiler eval "len(list(deci.functions.keys()))"
13
$ decompiler exec "print(hex(deci.binary_base_addr))"
0x400000
$ decompiler exec --file ./my_ida_script.py
$ decompiler eval "1/0"        # exits non-zero, prints traceback

Design note

The failure field is named traceback, not error, on purpose: the client/server wire protocol reserves a top-level error key for RPC failures, so a result dict with an error key made every successful call look like an RPC error. Renaming the key fixed it.

Tests

test_eval_expression, test_eval_has_backend_access (verifies deci is bound and the backend is reachable), test_exec_captures_stdout, test_exec_result_variable, test_eval_error_is_reported. All pass on IDA, Ghidra, and angr — the mechanism is backend-agnostic.


Eighth and final PR in the IDALib-parity series. Based on feat/cli-patching (#210).

This completes the gap-closing set: persistence, comments, globals/signatures, typed reads/addresses, search/imports, define/undefine, patching, and this scripting hatch.

🤖 Generated with Claude Code

https://claude.ai/code/session_01HfZHdprXg38re1XyKxzGg5

The universal escape hatch for backend-specific work the abstracted API
doesn't cover — kept explicitly unsafe and backend-specific, not portable.

- New `decompiler eval "<expr>"` and `decompiler exec "<code>"|--file <p>`.
- DecompilerInterface.backend_eval runs Python in the backend process with
  the interface bound to `deci` (idaapi importable, deci.flat_api on
  Ghidra, deci.project on angr, deci.bv on Binja). Generic — one base
  implementation serves every backend. Routed through the server's
  main-thread dispatcher, so it is safe on IDA/idalib.
- `eval` returns the expression repr; `exec` captures stdout and a
  `result` variable. Errors return a traceback and exit non-zero.
- The failure field is named `traceback` (not `error`) on purpose: the
  client/server wire protocol reserves a top-level `error` key for RPC
  failures, and colliding with it made every call look like an RPC error.
- Client proxy + tests (eval expr, backend access via `deci`, exec stdout,
  result var, error reporting) — all pass on IDA, Ghidra, and angr.
- SKILL.md / docs updated with prominent UNSAFE warnings.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HfZHdprXg38re1XyKxzGg5
@mahaloz

mahaloz commented Jul 17, 2026

Copy link
Copy Markdown
Member Author

Integrated into main as commit b8ad5e4. The stack got tangled when the bottom PRs (#204/#205) were squash-merged (#205 landed on feat/cli-persistence instead of main), so I reconciled by cherry-picking the whole series onto main linearly. The exact reviewed content of this PR is on main — closing this stacked PR as its changes are shipped.

@mahaloz mahaloz closed this Jul 17, 2026
@mahaloz
mahaloz deleted the feat/cli-backend-scripting branch July 17, 2026 16:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant