Crusader_Decomp/.github/skills/pyghidra-ghidra-ops/SKILL.md

7.9 KiB

PyGhidra Ghidra Ops

Use this skill when Ghidra MCP is missing a needed operation and you need native CPython access to the Ghidra API for the local Crusader project.

Use Cases

  • Create or delete functions in CRUSADER-RAW.EXE.
  • Apply small batched repairs driven by verified addresses.
  • Add comments or rename functions by address from a repeatable JSON plan.
  • Decompile or disassemble functions without switching back to the MCP server.
  • Query function metadata, search by name, and inspect xrefs from the same local CLI.
  • Inspect project root files to confirm the program name/path before running edits.

Workspace Defaults

  • Ghidra install dir: I:\Apps\ghidra_11.3.2_PUBLIC
  • Ghidra project dir: repo root
  • Ghidra project name: Crusader
  • Default program: CRUSADER-RAW.EXE
  • Local Python env: .venv-pyghidra311
  • CLI entrypoint: .\.venv-pyghidra311\Scripts\python.exe -m tools.pyghidra_crusader

Constraints

  • Stay conservative. Use the same rename and batch-size rules as the main Ghidra workflow.
  • Prefer one focused plan or 1-5 direct edits at a time.
  • Write operations require the project to be openable for modification. If Crusader.lock is present because the GUI owns the project, close Ghidra first or work on a copy.
  • Keep crusader_decompilation_notes.md updated after verified repair batches.

Commands

List root project files:

.\.venv-pyghidra311\Scripts\python.exe -m tools.pyghidra_crusader project-files

Delete a bad function object:

.\.venv-pyghidra311\Scripts\python.exe -m tools.pyghidra_crusader delete-function --entry 0007:5b6f

Create a repaired function with an explicit body:

.\.venv-pyghidra311\Scripts\python.exe -m tools.pyghidra_crusader create-function \
  --entry 0007:5a90 \
  --name seg043_func_0090 \
  --body-start 0007:5a90 \
  --body-end 0007:5b79 \
  --plate-comment "Recovered from standalone seg043 boundary scan"

Rename a function by entry address:

.\.venv-pyghidra311\Scripts\python.exe -m tools.pyghidra_crusader rename-function --entry 0006:02cc --name entity_class_get_flag20

MCP-style read/query commands are also available from the same CLI:

.\.venv-pyghidra311\Scripts\python.exe -m tools.pyghidra_crusader get-function-by-address --address 000a:48ff
.\.venv-pyghidra311\Scripts\python.exe -m tools.pyghidra_crusader get_function_by_address --address 000a:48ff
.\.venv-pyghidra311\Scripts\python.exe -m tools.pyghidra_crusader get-function-containing --address 000a:4901
.\.venv-pyghidra311\Scripts\python.exe -m tools.pyghidra_crusader decompile-function-by-address --address 000a:48ff
.\.venv-pyghidra311\Scripts\python.exe -m tools.pyghidra_crusader disassemble-function --address 000a:48ff
.\.venv-pyghidra311\Scripts\python.exe -m tools.pyghidra_crusader read-region --start 000a:48ff --end 000a:4912
.\.venv-pyghidra311\Scripts\python.exe -m tools.pyghidra_crusader search-functions-by-name --query rng_
.\.venv-pyghidra311\Scripts\python.exe -m tools.pyghidra_crusader list-methods --limit 20
.\.venv-pyghidra311\Scripts\python.exe -m tools.pyghidra_crusader list_methods --limit 20
.\.venv-pyghidra311\Scripts\python.exe -m tools.pyghidra_crusader list-strings --limit 20
.\.venv-pyghidra311\Scripts\python.exe -m tools.pyghidra_crusader list-imports --limit 20
.\.venv-pyghidra311\Scripts\python.exe -m tools.pyghidra_crusader list-exports --limit 20
.\.venv-pyghidra311\Scripts\python.exe -m tools.pyghidra_crusader list-namespaces --limit 20
.\.venv-pyghidra311\Scripts\python.exe -m tools.pyghidra_crusader list-segments --limit 20
.\.venv-pyghidra311\Scripts\python.exe -m tools.pyghidra_crusader list-data-items --limit 20
.\.venv-pyghidra311\Scripts\python.exe -m tools.pyghidra_crusader list-classes --limit 20
.\.venv-pyghidra311\Scripts\python.exe -m tools.pyghidra_crusader get-xrefs-to --address 000a:48ff
.\.venv-pyghidra311\Scripts\python.exe -m tools.pyghidra_crusader get-function-xrefs --name rng_next_modulo

All commands also support structured output for scripting:

.\.venv-pyghidra311\Scripts\python.exe -m tools.pyghidra_crusader --format json get-function-by-address --address 000a:48ff

JSON output now uses a stable envelope:

{
  "schema_version": "1.0",
  "command": "get-function-by-address",
  "ok": true,
  "schema": { "type": "object", "properties": { "name": { "type": "string" } } },
  "data": {
    "name": "rng_next_modulo",
    "signature": "undefined rng_next_modulo()",
    "entry": "000a:48ff",
    "body_start": "000a:48ff",
    "body_end": "000a:4912"
  }
}

The CLI also accepts exact MCP-style underscore command aliases, so local automation can often swap MCP names directly with little or no translation.

For ad hoc investigation, prefer run-script over multiline python -c or pasted PowerShell here-strings. It avoids leaving the shared shell stuck in an unfinished string/block state:

.\.venv-pyghidra311\Scripts\python.exe -m tools.pyghidra_crusader run-script --script .\pyghidra_plans\inspect_rng.py --read-only

Script globals available inside run-script:

config
project
program
helpers["get_function"]
helpers["get_function_containing"]
helpers["decompile_function"]
helpers["disassemble_function"]
helpers["get_xrefs_to"]
helpers["get_xrefs_from"]
helpers["read_region_bytes"]
helpers["rename_function"]
helpers["set_comment"]

Write-side MCP-style aliases are available too:

.\.venv-pyghidra311\Scripts\python.exe -m tools.pyghidra_crusader rename-function-by-address --entry 000a:48ff --name rng_next_modulo
.\.venv-pyghidra311\Scripts\python.exe -m tools.pyghidra_crusader set-decompiler-comment --address 000a:48ff --text "Returns RNG output modulo the requested bound."
.\.venv-pyghidra311\Scripts\python.exe -m tools.pyghidra_crusader set-disassembly-comment --address 000a:48ff --text "Modulo wrapper around rng_advance_state"

Apply a small JSON plan:

{
  "transaction": "Repair seg043 boundaries",
  "remove_functions": [
    "0007:5b6f"
  ],
  "create_functions": [
    {
      "entry": "0007:5a90",
      "name": "seg043_func_0090",
      "body_start": "0007:5a90",
      "body_end": "0007:5b79",
      "comment": "Recovered from standalone seg043 boundary scan"
    },
    {
      "entry": "0007:5b7a",
      "name": "seg043_func_017a",
      "body_start": "0007:5b7a",
      "body_end": "0007:5c1b"
    },
    {
      "entry": "0007:5c1c",
      "name": "seg043_func_021c",
      "body_start": "0007:5c1c",
      "body_end": "0007:5c80"
    }
  ],
  "comments": [
    {
      "address": "0007:5b6f",
      "text": "Old auto-created split overlaps the earlier seg043:0090..0179 routine.",
      "type": "plate"
    }
  ]
}
.\.venv-pyghidra311\Scripts\python.exe -m tools.pyghidra_crusader apply-plan --plan .\seg043_repair.json

Dry-run a plan before touching the project:

.\.venv-pyghidra311\Scripts\python.exe -m tools.pyghidra_crusader apply-plan --plan .\seg043_repair.json --dry-run

Implementation Notes

  • Address strings accept raw SSSS:OOOO form or plain integers such as 0x75a90.
  • The CLI tries a few root folder path variants when opening the program so it can tolerate minor project path differences.
  • Plan files support remove_functions, rename_functions, create_functions, comments, and assert_functions.
  • set-decompiler-comment maps to a pre-comment and set-disassembly-comment maps to an EOL comment.
  • Read/query commands open the program read-only; create/rename/comment/plan commands still require the project to be writable.
  • run-script --read-only is the safest way to do one-off inspection without getting the shared PowerShell session stuck in a multiline Python string.
  • read-region now reads bytes one address at a time instead of relying on a bulk getBytes path that produced misleading all-zero results in this project under PyGhidra.
  • PyGhidra startup now suppresses the noisy local GhidraMCP Module.manifest warnings during normal CLI operation.