def test_address_comparison(self): with ghidra_bridge.GhidraBridge( namespace=globals(), connect_to_port=ghidra_bridge_port.DEFAULT_SERVER_PORT): test_address = currentAddress.add(1) self.assertFalse(test_address < currentAddress) self.assertTrue(test_address > currentAddress)
def __init__(self) -> None: import ghidra_bridge namespace = {} self._bridge = ghidra_bridge.GhidraBridge(namespace) self._cuf = ghidra.program.model.listing.CodeUnitFormat.DEFAULT self._diss = ghidra.app.util.PseudoDisassembler(currentProgram)
def test_interactive_getState_fix(self): """ confirm that getState is updated, and doesn't cause a reset to old values when interactive mode is enabled """ with ghidra_bridge.GhidraBridge( namespace=globals(), connect_to_port=bridge.DEFAULT_SERVER_PORT, interactive_mode=True): if state.getTool() is None: self.skipTest( "Interactive mode tests not supported against headless (no tool)" ) else: # record the current address as an int curr_addr = currentAddress.getOffset() # move the current address state.setCurrentAddress(currentAddress.add(0x10)) # call getState new_state = getState() # check the new address has changed (not sure exactly what it's changed to, because instruction alignments might change exactly where we go) self.assertNotEqual(curr_addr, currentAddress.getOffset()) # check that the state address matches self.assertEqual(currentAddress.getOffset(), new_state.getCurrentAddress().getOffset())
def test_non_interactive_currentAddress(self): """ confirm that the current address (and ideally, the other current* vars - TODO) are NOT updated when interactive mode is disabled """ with ghidra_bridge.GhidraBridge( namespace=globals(), connect_to_port=bridge.DEFAULT_SERVER_PORT, interactive_mode=False): if state.getTool() is None: self.skipTest( "This test isn't supported against headless/no tool ghidra, because of how we try to get the most up to date addresses" ) else: listing_panel = ghidra_bridge.ghidra_bridge.get_listing_panel( state.getTool(), ghidra) # get the actual current address actual_current_addr = listing_panel.getProgramLocation( ).getAddress().getOffset() # record the "current" address as an int curr_addr = currentAddress.getOffset() # move the current address state.setCurrentAddress(currentAddress.add(0x10)) # check the address has changed new_actual_current_addr = listing_panel.getProgramLocation( ).getAddress().getOffset() self.assertNotEqual(actual_current_addr, new_actual_current_addr) # check the currentAddress hasn't changed self.assertEqual(curr_addr, currentAddress.getOffset())
def test_namespace_cleanup(self): with ghidra_bridge.GhidraBridge( namespace=globals(), connect_to_port=bridge.DEFAULT_SERVER_PORT): self.assertTrue("currentAddress" in globals()) self.assertTrue("currentAddress" not in globals())
def test_isinstance_fix(self): """ check that we automatically fix up isinstance when using namespace, so we can isinstance bridged objects """ with ghidra_bridge.GhidraBridge( namespace=globals(), connect_to_port=bridge.DEFAULT_SERVER_PORT): self.assertTrue( isinstance(currentAddress, ghidra.program.model.address.Address))
def test_array_creation_without_forced_unicode(self): """ Check that we can instatiate an array.array without the error about it wanting a plain string as the first argument. Depends on jfx_bridge 0.8.0 """ b = ghidra_bridge.GhidraBridge(namespace=globals()) array = b.remote_import("array") test = array.array("b", b"\0" * 10) self.assertIsNotNone(test)
def test_readme_remote_eval_example_backcompat(self): """ Test the example from the readme, in its old version, before we changed GhidraBridge to inherit BridgeClient """ b = ghidra_bridge.GhidraBridge(namespace=globals()) func = currentProgram.getFunctionManager().getFunctions(True).next() mnemonics = b.bridge.remote_eval( "[ i.getMnemonicString() for i in currentProgram.getListing().getInstructions(f.getBody(), True)]", f=func, )
def test_readme_remote_eval_example(self): """ Test the example from the readme """ b = ghidra_bridge.GhidraBridge(namespace=globals()) func = currentProgram.getFunctionManager().getFunctions(True).next() mnemonics = b.remote_eval( "[ i.getMnemonicString() for i in currentProgram.getListing().getInstructions(f.getBody(), True)]", f=func, )
def run_script(server_host, server_port): import ghidra_bridge # load something ghidra doesn't have import networkx print("Running inside the bridge!") # create the bridge and load the flat API/ghidra modules into the namespace with ghidra_bridge.GhidraBridge(connect_to_host=server_host, connect_to_port=server_port, namespace=globals()): # grab the current function function = currentProgram.getFunctionManager().getFunctionContaining(currentAddress) if function is None: raise Exception( "Current address {} not within a function".format(currentAddress)) print("Graphing {}:{}".format(function, function.getEntryPoint())) model = ghidra.program.model.block.BasicBlockModel(currentProgram) # get the first code block in the function code_block = model.getFirstCodeBlockContaining( function.getEntryPoint(), monitor) graph = networkx.DiGraph() # step through the code blocks, adding them to a networkx graph to_visit_list = [code_block] visited_list = [] while len(to_visit_list) > 0: visit_block = to_visit_list.pop() src_block_address = visit_block.getFirstStartAddress().getOffset() # mark as visited visited_list.append(src_block_address) dest_it = visit_block.getDestinations(monitor) dest_ref = dest_it.next() while dest_ref is not None: dest_block = dest_ref.getDestinationBlock() dest_address = dest_block.getFirstStartAddress().getOffset() # add an edge graph.add_edge(src_block_address, dest_address) # add the destination to the visit list, if we haven't already visited it if dest_address not in visited_list and dest_address not in [block.getFirstStartAddress().getOffset() for block in to_visit_list]: to_visit_list.append(dest_block) dest_ref = dest_it.next() # visits completed # can now perform graph analysis on the graph... or just print the edges print(graph.edges)
def test_namespace_cleanup_with_interactive(self): """ check that we can still remove if the values we add have been updated by interactive mode """ with ghidra_bridge.GhidraBridge(namespace=globals(), connect_to_port=ghidra_bridge_port.DEFAULT_SERVER_PORT, interactive_mode=True): self.assertTrue("currentAddress" in globals()) # cause currentAddress to change # move the current address state.setCurrentAddress(currentAddress.add(0x10)) # add a little sleep, so there's enough time for the update to make it back to us (interactive_mode isn't meant to be scripted...) time.sleep(1) # make sure it's no longer present self.assertTrue("currentAddress" not in globals())
def test_hook_import(self): with ghidra_bridge.GhidraBridge( namespace=globals(), connect_to_port=ghidra_bridge_port.DEFAULT_SERVER_PORT, hook_import=True, ): import ghidra self.assertTrue("ghidra" in str(ghidra)) from ghidra.framework.model import ToolListener import docking.widgets.indexedscrollpane.IndexScrollListener import java.math.BigInteger bi = java.math.BigInteger(str(10))
def main(mapdir): read_combined(mapdir) with ghidra_bridge.GhidraBridge(namespace=globals()) as b: print(hex(getState().getCurrentAddress().getOffset())) # Find all the functions whose name is a default name, i.e. FUN_BAADF00D (where BAADF00D is an 8-digit hexadecimal address) name_list = b.remote_eval( "[(f.getName(), int(str(f.getEntryPoint()), 16),) for f in currentProgram.getFunctionManager().getFunctionsNoStubs(True) if f.getName()[0:4] in ['FUN_', 'LAB_'] and f.getName().endswith(str(f.getEntryPoint()))]" ) print(len(name_list)) newnames = [] count_addr, count_syms = 0, 0 for _, addr in name_list: # symbol name is "garbage" anyway if addr in bsp_addr: count_addr += 1 print("addr: ", count_addr)
def test_interactive_currentAddress(self): """ confirm that the current address (and ideally, the other current* vars - TODO) are updated when interactive mode is enabled """ with ghidra_bridge.GhidraBridge(namespace=globals(), connect_to_port=ghidra_bridge_port.DEFAULT_SERVER_PORT, interactive_mode=True): if state.getTool() is None: self.skipTest( "Interactive mode tests not supported against headless (no tool)") else: # record the current address as an int curr_addr = currentAddress.getOffset() # move the current address state.setCurrentAddress(currentAddress.add(0x10)) # add a little sleep, so there's enough time for the update to make it back to us (interactive_mode isn't meant to be scripted...) time.sleep(1) # check the new address has changed (not sure exactly what it's changed to, because instruction alignments might change exactly where we go) self.assertNotEqual(curr_addr, currentAddress.getOffset())
def __init__(self, widget, args): # Load configuration self.config_file = os.path.join(self.get_temp_dir(), "pe_tree_ghidra.ini") super(GhidraRuntime, self).__init__(widget, args) # Initialise Ghidra bridge try: self.bridge = ghidra_bridge.GhidraBridge(connect_to_host=self.args.server, connect_to_port=self.args.port, namespace=globals(), response_timeout=20) except ConnectionRefusedError: print("Please run ghidra_bridge_server_background.py under Ghidra -> Window -> Script Manager") exit() state = getState() currentProgram = state.getCurrentProgram() self.address_factory = currentProgram.getAddressFactory() self.function_manager = currentProgram.getFunctionManager() self.data_type_manager = currentProgram.getDataTypeManager() self.listing = currentProgram.getListing() self.memory = currentProgram.getMemory() self.address_space = currentProgram.getAddressFactory().getDefaultAddressSpace()
def main(code_path, target_addr, shellcode_addr, amount, savefile=None, initial_storage_file=None, initial_balance=None, flags=None): savefilebase = savefile or code_path if code_path.endswith('.json'): with open(code_path, 'rb') as f: jd = json.load(f) p = Project.from_json(jd) else: with open(code_path) as infile: inbuffer = infile.read().rstrip() code = bytes.fromhex(inbuffer) p = Project(code) with open('%s.project.json' % savefilebase, 'w') as f: json.dump(p.to_json(), f) amount_check = '+' amount = amount.strip() if amount[0] in ('=', '+', '-'): amount_check = amount[0] amount = amount[1:] amount = int(amount) initial_storage = dict() if initial_storage_file: with open(initial_storage_file, 'rb') as f: initial_storage = { int(k, 16): int(v, 16) for k, v in json.load(f).items() } flags = flags or {'CALL', 'CALLCODE', 'DELEGATECALL', 'SELFDESTRUCT'} result = combined_exploit(p, int(target_addr, 16), int(shellcode_addr, 16), amount, amount_check, initial_storage, initial_balance, flags=flags) if result: call, r, model = result print(model) with open('%s.exploit.json' % savefilebase, 'w') as f: json.dump( { 'paths': [{ 'index': i, 'path': [ ins for ins in res.state.trace if ins in p.cfg.bb_addrs or ins == res.state.trace[-1] ] } for i, res in enumerate(r.results)], 'calls': [{ 'index': i, 'call': hex_encode(c) } for i, c in enumerate(call)] }, f) for i, res in enumerate(r.results): yes = query_yes_no("Found vulnerable path, mark it in Ghidra?") print('%d: %s' % (i, '->'.join( '%x' % i for i in res.state.trace if i in p.cfg.bb_addrs or i == res.state.trace[-1]))) if (yes): b = ghidra_bridge.GhidraBridge(namespace=globals(), response_timeout=1000) tid = currentProgram.startTransaction("ghidrda evm") memory = currentProgram.getMemory() ram = memory.getBlock("ram") ram_size = ram.getSize() ram_addr = ram.getStart() for i in res.state.trace: if i in p.cfg.bb_addrs or i == res.state.trace[-1]: print(hex(i)) Color = b.remote_import("java.awt.Color") setBackgroundColor(ram_addr.add(i), Color.YELLOW) currentProgram.endTransaction(tid, True) print(call) print for c in call: if c['caller'] == c['origin']: print( 'eth.sendTransaction({from:"0x%040x", data:"0x%s", to:"0x4000000000000000000000000000000000000000"%s, gasPrice:0})' % (c['origin'], c.get('payload', b'').hex(), ", value:%d" % c['value'] if c.get('value', 0) else '')) else: print( 'eth.sendTransaction({from:"0x%040x", data:"0x%s", to:"0x%040x"%s, gasPrice:0})' % (c['origin'], c.get('payload', b'').hex(), c['caller'], ", value:%d" % c['value'] if c.get('value', 0) else '')) return True return False
len(generic_name), generic_name, 0, ) archive = BytesIO() with ZipFile(archive, "w") as zfile: item = ZipInfo("FOLDER_ITEM") zfile.write(item, folder_item) length = len(archive.getbuffer()) return header + struct.pack(">Q", length) + archive.getvalue() try: import ghidra_bridge b = ghidra_bridge.GhidraBridge(namespace=locals()) except ImportError: secho("ghidra_bridge package not found", fg="red") except AttributeError: secho("ghidra_bridge is not started", fg="red") except ConnectionRefusedError: secho("ghidra_bridge connection error", fg="red") else: if conf.config is None: conf.config = conf.Config() if conf.config.Ghidra.manager == "program": dtm = currentProgram.getDataTypeManager() if conf.VERBOSE: secho("ghidra_bridge connection with data type manager %s" % dtm, fg="blue") tr = dtm.startTransaction("ccrawl")
def test_memory_callable_iterable(self): """ Test that we handle the ghidra.program.model.mem.Memory class - it's callable and iterable """ with ghidra_bridge.GhidraBridge( namespace=globals(), connect_to_port=bridge.DEFAULT_SERVER_PORT): self.assertNotEqual(None, ghidra.program.model.mem.Memory)
DANGEROUS_INSTRUCTIONS = ["CALL", "SELFDESTRUCT", "CALLCODE", "DELEGATECALL"] # main print("""\ _ _ _ __ _| |__ (_) __| |_ __ __ _ _____ ___ __ ___ / _` | '_ \| |/ _` | '__/ _` |_____ / _ \ \ / / '_ ` _ \ | (_| | | | | | (_| | | | (_| |_____| __/\ V /| | | | | | \__, |_| |_|_|\__,_|_| \__,_| \___| \_/ |_| |_| |_| v.0.1 |___/ """) # creates the bridge and loads the flat API into the global namespace b = ghidra_bridge.GhidraBridge(namespace=globals(), response_timeout=1000) tid = currentProgram.startTransaction("ghidrda evm") memory = currentProgram.getMemory() ram = memory.getBlock("ram") ram_size = ram.getSize() ram_addr = ram.getStart() print("[*] Reading RAM:", ram_size, "bytes", "at", ram_addr) i = getInstructionAt(ram_addr) print("[*] Searching dangerous instructions...")
def test_str_javapackage(self): """ Test that we can now call str on javapackage objects """ with ghidra_bridge.GhidraBridge( namespace=globals(), connect_to_port=bridge.DEFAULT_SERVER_PORT): self.assertTrue("java package ghidra" in str(ghidra))
filename_input = sys.argv[1] if filename_input.endswith('.evm'): with open(filename_input, 'rb') as f: evm_code = f.read() print(binascii.hexlify(evm_code)) elif filename_input.endswith('.evm_h'): with open(filename_input, 'r') as f: evm_code = f.read() print(evm_code) else: print("[!] Imposible to read bytecode") exit(0) b = ghidra_bridge.GhidraBridge( namespace=globals(), response_timeout=1000 ) # creates the bridge and loads the flat API into the global namespace tid = currentProgram.startTransaction("ghidrda evm") memory = currentProgram.getMemory() ram = memory.getBlock("ram") addr = ram.getStart() size = ram.getSize() print("[*] Setting analysis options....") setAnalysisOption(currentProgram, "Embedded Media", "false") setAnalysisOption(currentProgram, "ASCII Strings", "false") setAnalysisOption(currentProgram, "Create Address Tables", "false")
logFormatter = logging.Formatter("%(asctime)s [%(threadName)-12.12s] [%(levelname)-5.5s] %(message)s") rootLogger = logging.getLogger() rootLogger.setLevel(logging.DEBUG) #fileHandler = logging.FileHandler("{0}/{1}.log".format(logPath, fileName)) #fileHandler.setFormatter(logFormatter) #rootLogger.addHandler(fileHandler) consoleHandler = logging.StreamHandler() consoleHandler.setFormatter(logFormatter) rootLogger.addHandler(consoleHandler) if __name__ == '__main__': init_logger() b = ghidra_bridge.GhidraBridge(namespace=globals()) # creates the bridge and loads the flat API into the global namespace cfg = Control_Flow_Graph() cfg.print_cfg() """ For tests in interpreter: b = ghidra_bridge.GhidraBridge(namespace=globals()) block_model_iterator = ghidra.program.model.block.BasicBlockModel(currentProgram) function = getFirstFunction() function_addresses = function.getBody() code_blocks_iterator = block_model_iterator.getCodeBlocksContaining(function_addresses, monitor) block = code_blocks_iterator.next() new_block = dict()
def run_server(host=ghidra_bridge.bridge.DEFAULT_HOST, server_port=ghidra_bridge.bridge.DEFAULT_SERVER_PORT, client_port=ghidra_bridge.bridge.DEFAULT_CLIENT_PORT): server = ghidra_bridge.GhidraBridge(host=host, local_server_port=server_port, ghidra_server_port=client_port) server.bridge.start()
parser = argparse.ArgumentParser( description='Dirty script to parse headers into Ghidra Data Type Archives') parser.add_argument('header_file', help='The header file to parse') parser.add_argument('--output', '-o', help='Path of the output file (must not exist yet!)') #parser.add_argument('--overwrite', '-f', help="Overwrite the output file if it already exists", action='store_true') args = parser.parse_args() import logging print("Connecting to bridge") import ghidra_bridge b = ghidra_bridge.GhidraBridge(namespace=globals()) java = b.bridge.remote_import("java") ghidra = b.bridge.remote_import("ghidra") print("Creating parser") if args.output: full_path = os.path.abspath(args.output) dtm = ghidra.program.model.data.FileDataTypeManager.createFileArchive( java.io.File(full_path)) cparser = ghidra.app.util.cparser.C.CParser(dtm, True, None) else: cparser = ghidra.app.util.cparser.C.CParser() print("Finished parsing")