Recipes
Short, complete snippets for what agents and tools do all day.
Each recipe is a whole task in a few lines, with a link to the page that explains it.
Ask an analysed project a question
Open the project read-only (no lock, no copy), find the program by hash, and check you're answering about the right build.
1import hashlib, ghidra_session as gs2 3digest = hashlib.sha256(open("target.exe", "rb").read()).hexdigest()4with gs.connect(client="triage", harness="codex") as s:5 s.call("open_project", path="/re/Game")6 hit = s.call("list", sha256=digest, programsOnly=True)["entries"][0]7 s.call("open_program", path=hit["key"])8 assert s.call("info")["sha256"] == digest9 print(s.call("decompile", address="rva:0x5d53a0")["c"])More in Projects.
Test a hypothesis without touching anyone's view
Rename and retype a function in a private overlay, decompile it to see if the result reads right, and promote it into a working copy only if it does.
1s.call("open_program", path="p1:/game.exe", overlay="tick")2s.call("apply_overlay", overlay="tick", ops=[3 {"op": "rename", "address": "rva:0x67bc40", "name": "PlayerTick"},4 {"op": "signature", "address": "rva:0x67bc40",5 "signature": "void PlayerTick(void *self, float dt)"},6])7print(s.call("decompile", overlay="tick", address="rva:0x67bc40")["c"])8 9s.call("promote_overlay", overlay="tick", fork={"path": "/work/tick"}) # or drop_overlayMore in Overlays.
Two agents annotating one program
Both open it in shared mode. expect turns a silent overwrite into a conflict that names who got there first.
1s.call("open_program", path="game.exe", writable=True, share=True)2try:3 s.call("rename", address="rva:0x1a2b30", name="g_playerList", expect="DAT_1401a2b30")4except gs.SessionError as e:5 if e.code == "conflict":6 print("changed by", e.details["lastEdit"]) # re-read, then decide7s.call("save")More in Shared writing.
A long export that can be watched and cancelled
Scripts that write big files run on the long lane, report progress, and stop at the next monitor check when cancelled.
1rid = s.send("script", script="ExportJsonl.java", args=[out], artifact=out,2 parallel=True, maxChars=1000)3print(s.call("status")["clients"]) # progress of every unanswered request4s.call("cancel", target=rid, parallel=True) # leaves out + ".part", valid up to its last lineMore in Scheduling.
Handle a busy program like a colleague would
Errors say who holds what and suggest the next step. A ready request is often attached.
1try:2 s.call("rename", address="rva:0x1000", name="Init")3except gs.SessionError as e:4 d = e.details5 if e.code == "busy":6 print("held by", d["holder"], "- retry or raise wait")7 elif e.code == "not_owner":8 s.call(**d["overlaySuggestion"]) # annotate privately insteadMore in Error codes.
From a shell script, without Python code
A private session over stdin: one process, one sequence of requests, no daemon.
1python $GS stdio <<'EOF'2{"id": 1, "cmd": "open_project", "path": "/re/MyProject"}3{"id": 2, "cmd": "open_program", "path": "target.exe"}4{"id": 3, "cmd": "functions", "contains": "crypt", "limit": 20}5EOFMore in CLI.