intellicrack.bridges.ghidra
Ghidra bridge for static analysis and decompilation.
This module provides integration with Ghidra for advanced static analysis, decompilation, and reverse engineering capabilities using ghidra_bridge.
- prepare_remote_script(code)[source]
Dedent a Jython script and rewrite it to capture its trailing result as a sentinel.
The Ghidra bridge transports user scripts to a remote Jython interpreter where they are run via Python’s
exec(), which discards the value of any trailing expression statement. This helper rewrites such scripts so the trailing result is preserved on the remote interpreter as a uniquely named global variable, suitable for retrieval via a follow-upremote_eval.Two shapes are recognised:
The final top-level statement is a bare expression (
ast.Expr), such as a trailing variable reference or literal. It is rewritten in place into an assignment to the sentinel, preserving evaluation order and side effects exactly.The final top-level statement is an
if/elsechain or atryblock whose tail, on every reachable path, assigns the same single variable (see_find_trailing_result_name()). Asentinel = <variable>assignment is appended after the script so that variable’s final value is captured without altering the script’s original control flow.
- class GhidraBridge[source]
Bases:
_GhidraBridgeAnalysisMixinBridge for Ghidra reverse engineering suite.
Composed from the
_GhidraBridgeBasecore class together with topical mixin classes that inherit linearly so cross-references resolve through normal MRO. Each mixin groups one surface area (core lifecycle and binary loading, bookmarking and structure editing, call-tree analysis and references) so no single class definition exceeds the public method limit. The final class exposes the full Ghidra feature set including call-tree exploration, decompiler configuration, program metadata, external references, thunk handling, and bookmark/label management.- async shutdown()[source]
Shutdown Ghidra and cleanup resources.
Closes the active ghidra_bridge RPC client (preventing socket leaks), terminates the headless subprocess, closes the kill-on-close job object handle created for it in
start_headless(), joins the stdout/stderr drain threads, and removes the bridge script under a process-wide lock to prevent races with concurrentstart_headlessinvocations.- Return type:
None
- async get_function_body(address)[source]
Get address ranges, thunk status, and size for a function.
- async get_call_tree(address, direction='callees', depth=3)[source]
Get recursive call tree for callees, callers, or both.
- Parameters:
- Returns:
Recursive call tree dict with function, address, direction, and children.
- Return type:
- Raises:
ToolError – If Ghidra is not connected.
- async get_instruction_pcode(address)[source]
Get raw per-instruction P-code ops, independent of decompilation.
Reads P-code directly off the
Instructionobject in theListingviaInstruction.getPcode(), so it is available even when full decompilation fails, times out, or the function has no recognized boundaries at all.
- async disassemble_range(start_address, end_address)[source]
Convert undefined bytes into instructions over an address range.
Wraps Ghidra’s
DisassembleCommand, the programmatic form of the Listing’s “Disassemble” (D) action, following flows the same way the GUI action does.- Parameters:
- Returns:
Dict with start, end, instructions_created, and success.
- Return type:
- Raises:
ToolError – If Ghidra is not connected or the command is rejected by Ghidra.
- async clear_code_bytes(start_address, end_address)[source]
Undefine instructions back to raw bytes over an address range.
Wraps
Listing.clearCodeUnits, the programmatic form of the Listing’s “Clear Code Bytes” (C) action. Clearing an already-undefined range is a harmless no-op in Ghidra, so this still reports success in that case.
- async create_data_type(category, name, type_kind, fields=None)[source]
Create a new data type in the type manager.
- Parameters:
- Returns:
Dict with name, kind, size, and success.
- Return type:
- Raises:
ToolError – If Ghidra is not connected or type creation fails.
- async get_data_type_tree(category_path=None, max_depth=32)[source]
Browse the full Data Type Manager tree: categories and every data type kind.
Unlike
get_structures(), which only surfaces structures viaDataTypeManager.getAllStructures(), this walks the category tree itself (Category.getCategories()/Category.getDataTypes()) so enums, unions, typedefs, and function-definitions are included alongside structures.- Parameters:
- Returns:
Recursive dict of categories, subcategories, and data types of every kind.
- Return type:
- Raises:
ToolError – If Ghidra is not connected or
category_pathdoes not name an existing category.
- async import_c_header(header_path, include_paths=None)[source]
Parse a C header file and add its declared types to the program’s data type manager.
Dispatches to Ghidra’s
CParserUtils.parseHeaderFileswith the current program’s ownDataTypeManageras the parse target, so every type the header declares is added directly to the open program instead of to a separate archive. The supplied path is lexically normalised and verified to exist as a regular file before any value is forwarded to Ghidra, and the parse runs inside a Ghidra transaction that is rolled back if parsing fails. A non-Noneresult fromparseHeaderFilesdoes not by itself mean the parse succeeded, so the returnedCParseResultsrecord’s ownsuccessful()accessor is read explicitly rather than treating “no exception raised” as success.- Parameters:
- Returns:
Dict with path, types_added, and success.
- Return type:
- Raises:
ToolError – If Ghidra is not connected,
header_pathis empty, cannot be resolved, does not exist, is not a regular file, or Ghidra fails to parse the header.
- async export_data_type_archive(archive_path)[source]
Export every data type in the program’s type manager to a new .gdt archive file.
Creates a new
FileDataTypeManagerarchive and copies every data type from the current program’s ownDataTypeManagerinto it viaDataTypeManager.addDataType, then saves and closes the archive. The current program is never mutated by this operation (only read from), so no Ghidra transaction is opened against it; the archive’s own internal transaction handling insideaddDataType/save()is sufficient.
- async import_data_type_archive(archive_path)[source]
Import every data type from an existing .gdt archive file into the program’s type manager.
Opens the archive read-only via
FileDataTypeManager.openFileArchiveand copies every data type it contains into the current program’s ownDataTypeManagerviaaddDataType. The copy runs inside a Ghidra transaction against the current program; the archive itself is opened read-only and is never written back to.
- async create_data(address, data_type)[source]
Create a data item at an address using a named data type.
- async configure_analysis(analyzer_name, *, enabled, options=None)[source]
Enable or disable a Ghidra analyzer and optionally set options.
- Parameters:
- Returns:
Dict with analyzer, enabled, and success.
- Return type:
- Raises:
ToolError – If Ghidra is not connected or configuration fails.
- async set_decompiler_options(simplification=None, max_instructions=None, *, extra=None)[source]
Configure decompiler simplification style and/or instruction limit.
Stores supplied values on the bridge instance so subsequent decompilation calls reuse the same configuration for the life of the session, or until overwritten by another call to this method. Passing
Nonefor a value leaves the previously stored value in place. Additional key/value options can be supplied viaextraand are persisted and applied verbatim toDecompileOptions.setOptionwhen present.- Parameters:
simplification (str | None) – Simplification style name (e.g. ‘normalize’, ‘jumptable’, ‘decompile’). When
Nonethe currently stored value is preserved.max_instructions (int | None) – Maximum instructions per function for decompiler. When
Nonethe currently stored value is preserved.extra (dict[str, Any] | None) – Optional dict of additional key/value decompiler options. Keys and values are merged into the persisted configuration and then applied to Ghidra.
- Returns:
Dict with simplification, max_instructions, extra options, and success.
- Return type:
- Raises:
ToolError – If Ghidra is not connected or configuration fails.
- property decompiler_options: dict[str, Any]
The persisted decompiler options configured on this bridge.
- async create_memory_block(name, start, size, permissions='r')[source]
Create a new initialized memory block.
- Parameters:
- Returns:
Dict with name, start, size, permissions, and success.
- Return type:
- Raises:
ToolError – If Ghidra is not connected or block creation fails.
- async split_memory_block(name, split_address)[source]
Split a memory block into two blocks at an address.
The original block is truncated to end just before
split_address, and a new block covering the remainder is created by Ghidra’sMemory.split.- Parameters:
- Returns:
Dict with name, split_address, and success.
- Return type:
- Raises:
ToolError – If Ghidra is not connected, no block with
nameexists,split_addressis not inside the block, or the split fails.
- async move_memory_block(name, new_start)[source]
Move a memory block to a different start address.
- Parameters:
- Returns:
Dict with name, new_start, and success.
- Return type:
- Raises:
ToolError – If Ghidra is not connected, no block with
nameexists, or the move fails (e.g. the target range overlaps an existing block).
- async rename_memory_block(name, new_name)[source]
Rename an existing memory block.
- Parameters:
- Returns:
Dict with name, previous_name, and success.
- Return type:
- Raises:
ToolError – If Ghidra is not connected, no block with
nameexists, or the rename fails (e.g. renaming an overlay block without exclusive access).
- async set_memory_block_comment(name, comment)[source]
Set or replace the comment on an existing memory block.
- async join_memory_blocks(name1, name2)[source]
Join two contiguous memory blocks into one.
- Parameters:
- Returns:
Dict with the joined block name and success.
- Return type:
- Raises:
ToolError – If Ghidra is not connected, either block does not exist, or the join fails (e.g. blocks are not contiguous or compatible).
- async create_program_tree(tree_name)[source]
Create an additional named program tree.
Wraps
Listing.createRootModule(treeName). The new root module’s own name defaults to the program’s name (nottree_name) per the Ghidra API –tree_nameis purely the tree’s identifier as used byListing.getRootModule/getTreeNameselsewhere in this bridge.
- async get_program_tree()[source]
Get the program tree module and fragment hierarchy.
Recursively walks every module under every root, returning the complete tree of submodules and fragments, plus each fragment’s address ranges so callers can navigate the layout without issuing additional RPC calls. A depth cap prevents runaway recursion on pathological inputs.
- Returns:
Dict with
treeslist. Each tree hasnameandroot(recursive module node). A module node hasname,type(“module”), andchildren. A fragment node hasname,type(“fragment”), andranges(list of{start, end}offsets).- Return type:
- Raises:
ToolError – If Ghidra is not connected or the RPC fails.
- async edit_program_tree(tree_name, operation, parent_module, child_name, new_name=None)[source]
Create, delete, rename, or reparent a module/fragment in a program tree.
Wraps
ProgramModule.createModule,ProgramModule.createFragment,ProgramModule.reparent,ProgramModule.removeChild, andGroup.setNameto give write access to the program tree hierarchy thatget_program_tree()only reads.move_childis implemented withProgramModule.reparent, notProgramModule.moveChild: the latter only reorders a child that is already directly under the module it is called on and never changes that child’s parent, so it cannot move a child across parents.- Parameters:
tree_name (str) – Name of the program tree to modify (as returned by
get_program_tree’strees[].name).operation (str) – One of
create_module,create_fragment,move_child,delete, orrename.create_module/create_fragmentcreatechild_nameas a new child ofparent_module.move_childlooks up every module that currently parents the existing module or fragment namedchild_name(a child may legitimately have more than one parent in a program tree) and reparents it underparent_module, removing it from each of those other parents so it ends up a direct child ofparent_moduleand nowhere else.deleteremoves the existing module or fragment namedchild_namefrom its direct parentparent_module.renamerenames the existing module or fragment namedchild_nametonew_name.parent_module (str) – Name of the existing module that will contain (or already contains, for
move_child/delete) the child.child_name (str) – Name of the module/fragment to create, move, delete, or rename.
new_name (str | None) – New name for the child when
operationisrename; required forrename, unused otherwise.
- Returns:
Dict with tree_name, operation, child_name, and success. Also includes
new_namewhenoperationisrename.- Return type:
- Raises:
ToolError – If Ghidra is not connected,
operationis unrecognized,new_nameis missing forrename, the tree does not exist,parent_moduledoes not exist or names a fragment rather than a module,child_namedoes not exist, namesparent_moduleitself, would create a cycle by moving a module under one of its own descendants, names the tree’s parentless root module,deletetargets a non-empty module, or the mutation otherwise fails.
- async diff_programs(other_program_path)[source]
Compare the current program with another program file.
- async set_color(address, color)[source]
Set a background color on a code unit at an address.
Uses Ghidra’s
ColorizingServicewhen available so the color participates in Ghidra’s persistent colorization store, falling back to anIntPropertyMapentry in the user property manager so the color survives reload even when no colorizing service is registered.In headless mode (
SystemUtilities.isInHeadlessMode()true), theIntPropertyMapfallback has no visual effect and no consumer in the Ghidra UI - it would be a silent no-op. This method therefore raisesToolErrorwhen theColorizingServiceis not available and the bridge is running headless, instead of returningsuccess: True.- Parameters:
- Returns:
Dict with address, color, backend used, and success.
- Return type:
- Raises:
ToolError – If Ghidra is not connected, neither colorization backend can persist the color, or the bridge is running headless without an interactive
ColorizingService.
- async set_program_metadata(name=None, image_base=None)[source]
Set program name and/or image base address.
After
Program.setName/Program.setImageBasereturn, the bridge re-queriesgetName()andgetImageBase().getOffset()viaremote_evaland verifies each requested change is observable on the live program.- Parameters:
- Returns:
Dict with name, image_base, and success.
- Return type:
- Raises:
ToolError – If Ghidra is not connected, the write fails, or the readback does not reflect the requested changes.
- async execute_script_with_params(code, params=None)[source]
Execute Jython code with a JSON params dict injected as a local variable.
- async create_function_tag(name, comment='')[source]
Create a function tag in the program’s tag manager.
- async set_function_tags(address, tag_name, operation)[source]
Add or remove a function tag on a specific function.
- Parameters:
- Returns:
Dict with address, tag_name, operation, and success.
- Return type:
- Raises:
ToolError – If Ghidra is not connected,
operationis unrecognized, the function is not found, or the mutation fails.
- async get_function_tags(address=None)[source]
List function tags: every tag in the program, or one function’s tags.
- async add_external_function(library, name, address=None)[source]
Add an external function to the external symbol table.
- async add_bookmark(address, category, comment, bookmark_type='Note')[source]
Add a bookmark at an address (explicit mutator alias).
Mirrors
create_bookmark()while wrapping the call in a Ghidra transaction so the mutation can be rolled back if the bookmark manager rejects the request.- Parameters:
- Returns:
Dict with address, category, comment, bookmark_type, and success.
- Return type:
- Raises:
ToolError – If Ghidra is not connected or the RPC fails.
- async remove_bookmark(address, category=None, bookmark_type=None)[source]
Remove one or more bookmarks at an address.
When
categoryand/orbookmark_typeare provided, only bookmarks matching those fields are removed. When both areNone, every bookmark at the address is removed.- Parameters:
- Returns:
Dict with address, number of bookmarks removed, and success.
- Return type:
- Raises:
ToolError – If Ghidra is not connected, the RPC fails, or no matching bookmark existed.
- async promote_symbol_to_primary(address, name)[source]
Promote an already-existing symbol at an address to primary.
Looks up the named symbol among every symbol already defined at
addressand callsSymbol.setPrimary()on it – the programmatic form of the Symbol Table window’s “Set Primary” action. Unlikeadd_label()’s creation-timeprimary=Trueflag, this method never creates a symbol; it only acts on oneSymbolTable.getSymbolsalready returns.- Parameters:
- Returns:
Dict with address, name, already_primary, and success.
- Return type:
- Raises:
ToolError – If Ghidra is not connected, the RPC fails, or no symbol named
nameexists ataddress.
- async add_thunk(address, thunked_address)[source]
Mark a function as a thunk forwarding to another function.
- Parameters:
- Returns:
Dict with address, thunked_address, and success.
- Return type:
- Raises:
ToolError – If Ghidra is not connected, either function does not exist, or the operation fails.
- async add_external_reference(from_addr, library, name)[source]
Add an external reference from an address to a named symbol.
- Parameters:
- Returns:
Dict with from_addr, library, name, and success.
- Return type:
- Raises:
ToolError – If Ghidra is not connected or the reference cannot be added.