ghidra::scripting

tool ghidra java · python
SetupUI tipsJava API PythonHeadlessCTF patterns
01Setup & Script Manager
Script Manager
# Open: Window → Script Manager  (or Shift+F2)
# Run a script: double-click or click Run
# Script directories: Script Manager → Manage Script Dirs
# Default: ~/ghidra_scripts/

# Script types:
# .java  → Java (GhidraScript subclass, most API examples)
# .py    → Jython (Python 2.7 with Java interop)
# .py    → Python 3 via pyhidra (newer, external)

# Run script from console (Script Manager → Console tab)
# Output visible in Script Manager console

# Headless: analyzeHeadless (see section 05)

# Useful built-in scripts:
# FindStrings.java      → find all strings
# RecoverClassesFromRTTIScript.java → C++ RTTI
# DecompileAllFunctions.java
Key UI shortcuts
ActionShortcut
Go to addressG
Rename symbolL
Retype variableCtrl+L
Cross-referencesCtrl+Shift+F (xrefs to) / X (inline)
Search stringsSearch → For Strings
Search memorySearch → Memory
DecompilerWindow → Decompiler
Function graphWindow → Function Graph
Script ManagerWindow → Script Manager
Re-analyzeAnalysis → Auto Analyze
Patch bytesRight-click → Patch Bytes
Comments; (EOL) / Shift+; (plate)
02Java Script API
Core objects & access
// In a GhidraScript subclass (Java):
// Available globals: currentProgram, currentAddress,
// currentLocation, currentSelection, state, monitor

Program prog = currentProgram;
Listing listing = prog.getListing();
SymbolTable symTable = prog.getSymbolTable();
Memory mem = prog.getMemory();
FunctionManager funcMgr = prog.getFunctionManager();
ReferenceManager refMgr = prog.getReferenceManager();
AddressFactory addrFactory = prog.getAddressFactory();

// Address from hex string
Address addr = toAddr("0x401234");
Address addr = currentAddress;  // cursor position

// Print to console
println("Found: " + addr);
printf("Value: %d\n", value);
Functions & symbols
// Get function at address
Function func = getFunctionAt(toAddr("0x401234"));
Function func = getFunctionContaining(currentAddress);

// Iterate all functions
for (Function f : funcMgr.getFunctions(true)) {
    println(f.getName() + " @ " + f.getEntryPoint());
}

// Find function by name
for (Symbol s : symTable.getSymbols("main")) {
    println(s.getAddress().toString());
}

// Get function variables
Variable[] locals = func.getLocalVariables();
Parameter[] params = func.getParameters();

// Rename function
func.setName("check_password", SourceType.USER_DEFINED);

// Rename variable (in decompiler context)
// Use API: HighFunction / DecompInterface
Memory & bytes
// Read bytes
byte[] bytes = new byte[16];
mem.getBytes(toAddr("0x401234"), bytes);
for (byte b : bytes) printf("%02x ", b & 0xff);

// Read integer
int val = mem.getInt(toAddr("0x404060"));
long val = mem.getLong(toAddr("0x404060"));

// Write bytes (program must be open for writing)
mem.setBytes(toAddr("0x401234"), new byte[]{0x90, 0x90});

// Find bytes pattern
Address found = mem.findBytes(
    mem.getMinAddress(),
    new byte[]{0x48, 0x31, (byte)0xff},
    null,   // mask (null = exact)
    true, monitor
);
println("Found at: " + found);
Strings & data
// Iterate all defined strings
DataIterator it = listing.getDefinedData(true);
while (it.hasNext()) {
    Data d = it.next();
    if (d.getDataType().getName().contains("string")) {
        println(d.getAddress() + ": " + d.getValue());
    }
}

// Cross-references TO an address
Reference[] xrefs = getReferencesTo(toAddr("0x402010"));
for (Reference r : xrefs) {
    println("xref from: " + r.getFromAddress());
}

// Cross-references FROM a function
ReferenceIterator refs = refMgr.getReferencesFromIterator(
    func.getBody(), true);
while (refs.hasNext()) {
    Reference r = refs.next();
    println(r.getToAddress().toString());
}
03Python (Jython) API
Python basics (Jython 2.7)
# Jython: Python 2.7 with full Java API access
# Same objects as Java scripts, Python syntax

# Core objects (same as Java, auto-imported)
prog    = currentProgram
listing = prog.getListing()
symtab  = prog.getSymbolTable()
mem     = prog.getMemory()
funcmgr = prog.getFunctionManager()

# Print
print("hello")   # Python 2 print statement

# Address
addr = toAddr("0x401234")
addr = currentAddress

# All functions
for f in funcmgr.getFunctions(True):
    print(f.getName(), f.getEntryPoint())

# Find function by name
for sym in symtab.getSymbols("win"):
    print(sym.getAddress())
pyhidra (Python 3)
# pyhidra: Python 3 Ghidra bindings (external)
pip install pyhidra

# Analyze binary from Python 3 script
import pyhidra

with pyhidra.open_program("./challenge") as flat_api:
    # All Ghidra functions available via flat_api
    func = flat_api.getFunctionAt(flat_api.toAddr("0x401234"))
    print(func.getName())

    # Iterate functions
    prog = flat_api.getCurrentProgram()
    for f in prog.getFunctionManager().getFunctions(True):
        print(f.getName(), hex(f.getEntryPoint().getOffset()))

# Full analysis mode
with pyhidra.open_program("./challenge",
        analyze=True) as flat_api:
    # Binary fully analyzed, all functions detected
    pass
04Headless Mode
analyzeHeadless
# Location: $GHIDRA_HOME/support/analyzeHeadless

# Analyze binary + run script, no GUI
analyzeHeadless /tmp/ghidra_proj myproject \
  -import ./challenge \
  -postScript MyScript.java

# With script arguments
analyzeHeadless /tmp/ghidra_proj myproject \
  -import ./challenge \
  -postScript MyScript.java arg1 arg2

# Reuse existing project (no re-import)
analyzeHeadless /tmp/ghidra_proj myproject \
  -process challenge \
  -postScript MyScript.java

# Python script headless
analyzeHeadless /tmp/proj myproj \
  -import ./challenge \
  -postScript extract_strings.py

# Disable auto analysis (faster for simple scripts)
analyzeHeadless /tmp/proj myproj \
  -import ./challenge -noanalysis \
  -postScript MyScript.java
05CTF Script Patterns
Extract XOR-encoded strings (Python)
# Find XOR decode loops and extract strings
# Pattern: data array XORed with key byte

data_addr = toAddr("0x404060")
key = 0x42
length = 20

result = []
for i in range(length):
    b = mem.getByte(data_addr.add(i)) & 0xff
    result.append(chr(b ^ key))
print("".join(result))
Decompile all functions (Python)
from ghidra.app.decompiler import DecompInterface

decomp = DecompInterface()
decomp.openProgram(currentProgram)

for func in currentProgram.getFunctionManager().getFunctions(True):
    results = decomp.decompileFunction(func, 30, monitor)
    if results and results.decompileCompleted():
        code = results.getDecompiledFunction().getC()
        if "flag" in code.lower() or "key" in code.lower():
            print("===", func.getName(), "===")
            print(code)
Patch bytes via script
# NOP out a check (patch JNE → NOP NOP)
from ghidra.program.model.mem import MemoryAccessException

addr = toAddr("0x401234")

# Start transaction
tid = currentProgram.startTransaction("Patch")
try:
    mem.setBytes(addr, [0x90, 0x90])   # NOP NOP
    currentProgram.endTransaction(tid, True)
    print("Patched!")
except Exception, e:
    currentProgram.endTransaction(tid, False)
    print("Error:", e)
Find all strcmp calls
# Find all functions that call strcmp
strcmp_sym = None
for sym in symtab.getSymbols("strcmp"):
    strcmp_sym = sym
    break

if strcmp_sym:
    strcmp_addr = strcmp_sym.getAddress()
    xrefs = getReferencesTo(strcmp_addr)
    for r in xrefs:
        func = getFunctionContaining(r.getFromAddress())
        if func:
            print(func.getName(), "calls strcmp at", r.getFromAddress())
QUICK REFERENCE →  ① Script Manager: Window → Script Manager or Shift+F2  ② Headless: analyzeHeadless /tmp/proj p -import ./bin -postScript S.py  ③ toAddr("0x401234") address from string  ④ getFunctionAt(addr) / getFunctionContaining(addr)  ⑤ getReferencesTo(addr) cross-references  ⑥ DecompInterface for pseudo-C in scripts  ⑦ pyhidra for Python 3 automation