Skip to content

fix(tools/reversing): tolerate extra Ghidra fields; brace-safe script templates; drop dead return#422

Open
VoidChecksum wants to merge 2 commits into
mainfrom
fix/reversing-robustness
Open

fix(tools/reversing): tolerate extra Ghidra fields; brace-safe script templates; drop dead return#422
VoidChecksum wants to merge 2 commits into
mainfrom
fix/reversing-robustness

Conversation

@VoidChecksum
Copy link
Copy Markdown
Collaborator

Summary

  • ghidra.py: GhidraFunction(**f) crashed with TypeError when Ghidra MCP/headless JSON included keys beyond the dataclass's five fields (e.g. thunk, namespace). Added _GHIDRA_FUNC_KEYS = frozenset(f.name for f in dataclasses.fields(GhidraFunction)) and filter each dict to known keys before unpacking — applied to both the MCP path and the headless path in ghidra_analyze_binary.
  • scripts.py: ghidra_recon_script / r2_recon_script called .format() with caller-supplied binary and script_name. A path containing { or } raised KeyError/ValueError. Replaced .format() with chained .replace() calls; emitted script text is identical for normal paths.
  • tools.py: bin_r2_script had two consecutive identical return statements; the second was unreachable dead code. Removed the duplicate.

Test plan

  • TestGhidraFunctionExtraKeys.test_extra_keys_do_not_raise — constructs GhidraFunction from a dict with extra keys (thunk, namespace, unknown field); asserts no raise and known fields populated
  • TestGhidraFunctionExtraKeys.test_ghidra_analysis_with_extra_function_fields — exercises the full list-comprehension path in ghidra_analyze_binary with extra-keyed dicts
  • TestScriptsBracePath.test_ghidra_recon_script_brace_in_binary — binary path /tmp/{evil}/target{x} does not raise
  • TestScriptsBracePath.test_r2_recon_script_brace_in_binary — same for r2 template
  • TestScriptsBracePath.test_scripts_normal_path_preserved — normal paths still appear in output
  • TestBinR2ScriptNoDeadReturn.test_returns_json_with_source_keybin_r2_script returns valid JSON with source key
  • uv run pytest packages/decepticon/tests/unit/reversing -q36 passed

… templates; drop dead return

ghidra.py: real-world Ghidra MCP/headless output includes keys beyond
the five in GhidraFunction (e.g. thunk, namespace). Constructing
GhidraFunction(**f) would raise TypeError on any such dict. Added
_GHIDRA_FUNC_KEYS (frozenset derived from dataclasses.fields) and
filter each dict to known keys before unpacking. Applied to both the
MCP path and the headless path in ghidra_analyze_binary.

scripts.py: ghidra_recon_script and r2_recon_script called .format()
with caller-supplied binary/script_name. A path containing { or }
raised KeyError/ValueError. Replaced .format() with chained .replace()
calls so untrusted content is never treated as a format spec. The
emitted script text is identical for normal paths.

tools.py: bin_r2_script had two identical consecutive return statements;
the second was unreachable dead code. Removed the duplicate.

tests: added test_reversing_robustness.py covering all three fixes with
no real binary or Ghidra instance required.
…cript

Folds in the crash fix from #395: the Ghidra recon template iterated 'for a in f.getEntryPoint()', but Function.getEntryPoint() returns a single non-iterable Address, so the generated script raised at runtime. The line was also dead (addrs unused). Removes it; the entry point is still printed. Adds a regression test. Consolidates #395 into this PR.
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