def _async_change_current_state(bv, address): global _running if not __check_executor(): return state = executor.fringe.get_deferred_by_address(address) if state is None: log_alert("no such deferred state") return def f(tb): global _running disable_widgets() executor.set_current_state(state) sync_ui(bv, delta=False) enable_widgets() _running = False if not _running: _running = True background_task = TaskInBackground(bv, "seninja: changing current state", f) background_task.start()
def _async_start_se(bv, address): if globs.executor is not None: log_alert("seninja is already running") return False def f(tb): try: globs.executor = SymbolicExecutor(bv, address) except SENinjaError as e: sys.stderr.write(e.message + "\n") globs._running = False return globs.dfs_searcher = searcher.DFSSearcher(globs.executor) globs.bfs_searcher = searcher.BFSSearcher(globs.executor) globs._running = False if not globs._running: globs._running = True background_task = TaskInBackground( bv, "seninja: starting symbolic execution", f) background_task.start() background_task.join() if not __check_executor(): # something wrong return initialize_ui() sync_ui(bv) enable_widgets()
def _async_run_bfs_searcher(bv): if not __check_executor(): return if not globs.bfs_searcher.ready_to_run(): log_alert("no target set for searcher") return def f(tb): def callback(s): tb.progress = "seninja: running BFS @ %s" % hex(s.get_ip()) if globs._stop: globs._stop = False return False return True globs.bfs_searcher.run(callback) enable_widgets() sync_ui(bv, globs.executor._last_error == None) globs._running = False if not globs._running: disable_widgets() globs._running = True background_task = TaskInBackground(bv, "seninja: running BFS", f) background_task.start()
def get_debugger_argument(bv): """ Pops up a window that lets the user set the debugger arguments. Implemented using the native Binja GUI, so we don't have the option of showing a command history""" mode = ChoiceField("Mode", choices) text = TextLineField("") get_form_input([mode, SeparatorField(), text], "Set Run Arguments") if mode.result is None: mode = 'raw' else: mode = mode.choices[mode.result] text = str(text.result).strip() if mode == 'raw': return text try: if mode == 'hex': return text.decode('hex') if mode == 'b64': return b64decode(text) if mode == 'py2': return eval(text) except: log_alert("Failed to decode input") return ""
def _async_run_dfs_searcher_findall(bv): if not __check_executor(): return if not globs.dfs_searcher.ready_to_run(): log_alert("no target set for searcher") return timeout = globs.executor.bncache.get_setting("exploration_timeout") timeout = int(timeout) def f(tb): start = time.time() def callback(s): tb.progress = "seninja: running DFS @ %s" % hex(s.get_ip()) if timeout > 0 and time.time() - start > timeout: # Timeout elapsed print("[!] Timeout elapsed (%d sec)" % timeout) return False if globs._stop: globs._stop = False return False return True globs.dfs_searcher.run(step_callback=callback, findall=True) enable_widgets() sync_ui(bv, globs.executor._last_error == None) globs._running = False if not globs._running: disable_widgets() globs._running = True background_task = TaskInBackground(bv, "seninja: running DFS", f) background_task.start()
def _async_start_se(bv, address): global _running if executor is not None: log_alert("seninja is already running") return False def f(tb): global executor, _running try: executor = SymbolicExecutor(bv, address) except Exception as e: print("!ERROR!") print(traceback.format_exc()) _running = False return initialize_ui() sync_ui(bv) enable_widgets() _running = False if not _running: _running = True background_task = TaskInBackground( bv, "seninja: starting symbolic execution", f) background_task.start()
def _async_merge_states(bv, address): # merge all states at address and put them in current state. Current state must be at address if not __check_executor(): return if globs.executor.state.get_ip() != address: log_alert("current state is not at this address") return to_be_merged = globs.executor.fringe.get_all_deferred_by_address(address) if to_be_merged is None: log_alert("no deferred state at this address") return def f(tb): disable_widgets() tot = len(to_be_merged) i = 0 for s in to_be_merged: globs.executor.state.merge(s) i += 1 tb.progress = "seninja: merging states %d/%d" % (i, tot) sync_ui(bv) enable_widgets() globs._running = False if not globs._running: globs._running = True background_task = TaskInBackground(bv, "seninja: merging states", f) background_task.start()
def start_se(bv, address): if globs.executor is not None: log_alert("seninja is already running") return False globs.executor = SymbolicExecutor(bv, address) globs.dfs_searcher = searcher.DFSSearcher(globs.executor) globs.bfs_searcher = searcher.BFSSearcher(globs.executor)
def create_bookmark(self): if not bookmarks: return bookmarks.create_bookmark(self.bv, self.bv.offset) try: with open(self.default_bookmarks_file, "w") as bookmarks_file: pickle.dump(self.bv.file.session_data['bookmarks'], bookmarks_file) except: bn.log_alert("Error Saving Bookmarks")
def find_constructor(bv): constructor_list = [(c.short_name, c.address) for c in bv.symbols.values() if re.match(r'([A-Za-z0-9_]+)\:\:\1', c.short_name)] if not len(constructor_list): log_alert("No constructors found!") constructor = get_choice_input('Choose a constructor', 'Constructors:', [x[0] for x in constructor_list]) if constructor is not None: return bv.get_function_at(constructor_list[constructor][1]) return None
def change_current_state(address_or_state): # take only the first one at the given address. TODO if not __check_executor(): return if not isinstance(address_or_state, State): state = executor.fringe.get_deferred_by_address(address_or_state) else: state = address_or_state if state is None: log_alert("no such deferred state") return executor.set_current_state(state)
def decode(self, encoded): """ Takes the input from the text box and decodes it using the parameter set in the combobox """ mode = self._encodings[self._decoder.currentIndex()] if mode == 'raw': return str(encoded) try: if mode == 'hex': return encoded.decode('hex') if mode == 'b64': return b64decode(encoded) if mode == 'py2': return eval(encoded) except: log_alert("Failed to decode input") return None
def _async_merge_states(bv, address): # merge all states at address and put them in current state. Current state must be at address if not __check_executor(): return if globs.executor.state.get_ip() != address: log_alert("current state is not at this address") return to_be_merged_all = globs.executor.fringe.get_all_deferred_by_address( address) if to_be_merged_all is None: log_alert("no deferred state at this address") return mergeable, not_mergeable = globs.executor.extract_mergeable_with_current_state( to_be_merged_all) if len(not_mergeable) > 0: print( "WARNING: %d states was not merged since they deviate from the current state after executing the current instruction" % len(not_mergeable)) globs.executor.fringe._deferred[address] = not_mergeable if len(mergeable) == 0: return to_be_merged = mergeable def f(tb): disable_widgets() tot = len(to_be_merged) i = 0 for s in to_be_merged: globs.executor.state.merge(s) i += 1 tb.progress = "seninja: merging states %d/%d" % (i, tot) globs.executor.delete_comment_for_address(address) sync_ui(bv) enable_widgets() globs._running = False if not globs._running: globs._running = True background_task = TaskInBackground(bv, "seninja: merging states", f) background_task.start()
def navigate_to_virtual_function(bv, addr): constructor = find_constructor(bv) if constructor is None: return vtable = find_vtable(bv, constructor.low_level_il) if vtable is None: log_alert("Couldn't find vtable for {}".format( constructor.symbol.full_name)) return function_pointer = find_function_offset(vtable, bv, addr) if function_pointer is None: log_alert("Couldn't find vtable offset for this call!") return bv.file.navigate(bv.file.view, function_pointer)
def _async_change_current_state(bv, address): if not __check_executor(): return states = globs.executor.fringe.get_list_deferred_by_address(address) if len(states) == 0: log_alert("no such deferred state") return if len(states) == 1: state = globs.executor.fringe.get_deferred_by_address(address) else: state_idx = get_choice_input("Select state", "states", list(map(str, states))) state = globs.executor.fringe.get_deferred_by_address( address, state_idx) disable_widgets() globs.executor.delete_comment_for_address(address) globs.executor.set_current_state(state) sync_ui(bv, delta=False) enable_widgets()
def enable_dynamics(bv): """ Does first time setup for everything. See show_message calls for more explanation. Not sure how well this handles being called twice... """ global main_window, reg_prefix, reg_width if (bv.arch.name == 'x86_64'): pass elif (bv.arch.name == 'x86'): reg_width = 32 reg_prefix = 'e' else: log_alert("Architecture not supported!") # Maybe msp430 someday? return show_message("Syncing with Voltron") if not sync(bv): show_message("Could not Sync with Voltron, spawning debugger terminal") terminal_wrapper(bv) for _ in range( 5): # Give up if the sync doesn't work after five seconds if (sync(bv)): break sleep(1) show_message("Attempting to set breakpoint at main") funcs = [f for f in filter(lambda b: b.name == 'main', bv.functions)] if (len(funcs) != 0): set_breakpoint(bv, funcs[0].start) navigate_to_address(bv, funcs[0].start) else: log_alert("No main function found, so no breakpoints were set") show_message("Placing windows") # Set the binary view the toolbar should pass to everything it calls set_bv(bv) show_register_window(bv) show_memory_window(bv) show_traceback_window(bv) if ('gdb' in debugger): show_terminal_window(bv) # Tell GDB to hand off io from the binary to our pseudoterminal set_tty(bv, main_window.term_window.tty) main_window.messagebox.hide()
def update_registers(registers, derefs): """ Updates the value and dereference string for each register in the OrderedDict passed in the registers parameter. """ global main_window if main_window is not None: dereferences = OrderedDict() if (len(registers.keys()) == 0): log_alert( "Got a response from Voltron, but no registers. The process has probably exited." ) return # Update registers in order, build an OrderedDict of derefs so the order # for those is preserved too. for reg in reglist: try: main_window.regwindow.update_single_register( reg, registers[reg]) dereferences[reg] = derefs[reg] except KeyError: log_error("Voltron did not return a register called " + reg) main_window.regwindow.update_derefs(dereferences) main_window.regwindow.highlight_dirty()
def _async_start_se(bv, address): if globs.executor is not None: log_alert("seninja is already running") return False def f(tb): globs.executor = SymbolicExecutor(bv, address) globs.dfs_searcher = searcher.DFSSearcher(globs.executor) globs.bfs_searcher = searcher.BFSSearcher(globs.executor) globs._running = False if not globs._running: globs._running = True background_task = TaskInBackground( bv, "seninja: starting symbolic execution", f) background_task.start() background_task.join() initialize_ui() sync_ui(bv) enable_widgets()
def _async_toggle_state_history(bv): if not __check_executor(): return if globs.executor.state is None: return if globs.executor.bncache.get_setting("save_state_history") == "false": log_alert( "State history is not saved. This can be changed in settings") return if len(globs.highlighted_state_history) > 0: # Remove highlight ui_reset_state_history_highlight() else: # Set highlight for insn in globs.executor.state.insn_history: globs.highlighted_state_history.append(insn) func = globs.executor.bncache.get_function(insn) func.set_auto_instr_highlight(insn, HIGHLIGHTED_HISTORY_COLOR)
def start_se(bv, address): global executor if executor is not None: log_alert("seninja is already running") return False executor = SymbolicExecutor(bv, address)
def update_wrapper(wrapped, bv): global executing_on_stack, stack_bv, lowest_stack """ Runs each time a button on the toolbar is pushed. Updates the live displays of program information """ # Call wrapped function wrapped(bv) # Handle Register Updates reg, derefs = get_registers( bv) # derefs will have the error message if something goes wrong try: update_registers(reg, derefs) except AttributeError: # reg was None if ( derefs == 'Target busy' ): # Probably living in kernel-land, which could be for a number of reasons. # We make the hopeful assumption that the reason is the program is waiting for user input. main_window.term_window.bring_to_front() log_info( "The target was busy, preventing us from retrieving the register state. It may be waiting for input from you." ) elif (derefs == 'No such target'): # Usually happens when the inferior process has exited log_alert( "Couldn't get register state. The process may not be running.") else: # Maybe you didn't run the binary yet? log_alert( "Couldn't get register state. Please consult the log for more information" ) # If something went wrong with the last update, we register a callback that will get run # the next time we have a sucessful sync. We partially apply the arguments on the callback # so we don't lose our reference to the binary view. See docstring on signal_sync_done for more register_sync_callback(partial(signal_sync_done, bv), should_delete=True) return # Handle Memory Updates procname = filename.split( "/")[-1] if filename is not None else bv.file.filename.split( "/")[-1].replace(".bndb", "") # Iterate through the processes on the system to find the right memory map for proc in psutil.process_iter(): if proc.name() == procname: # Found debugged process maps = proc.memory_maps(grouped=False) for m in maps: # Update Stack if (m.path.strip("[]") == 'stack'): addr = m.addr.split("-") high = int(addr[1], 16) sp, bp, ip = reg[reg_prefix + 'sp'], reg[reg_prefix + 'bp'], reg[reg_prefix + 'ip'] # Lock out the top of the memory to an even multiple of 32 so we don't # get confusing column-wise shifts in the display memtop = min([sp, lowest_stack]) memtop = memtop if (memtop % 32 == 0) else (memtop + (32 - memtop % 32) - 32) lowest_stack = memtop mem = get_memory(bv, memtop, high - memtop) if mem is None: log_error("No memory returned!") return # Display memory from the base of the stack (high addresses) # to the stack pointer (low addresses) main_window.hexv.update_display('stack', memtop, mem) main_window.hexv.highlight_stack_pointer(sp, width=reg_width / 8) main_window.hexv.highlight_base_pointer(bp, width=reg_width / 8) # If the instruction pointer is on the stack, highlight it in the memory viewer # and try to display it in the Binary Ninja window. if (ip > memtop and ip <= high): main_window.hexv.highlight_instr_pointer(ip) if not executing_on_stack: executing_on_stack = True # Ideally we'd like to get the stack view inline using something like # stack_bv = BinaryViewType.get_view_of_file('/dev/null'), # but that doesn't actually work because Binary Ninja really only supports # getting active binary views via callbacks, for now. if stack_bv is not None: # because of the way .write is implemented, this works if we jump to the stack # exactly one time and stay there. If we go to the stack, leave, and come back, # we end up creating multiple overlapping segments, which will probably break things. stack_bv.write(memtop, mem) stack_bv.add_function( ip, plat=bv.arch.standalone_platform) print(stack_bv) else: executing_on_stack = False # Update BSS try: bss = bv.sections['.bss'] bssmem = get_memory(bv, bss.start, bss.length) main_window.hexv.update_display( 'bss', bss.start, bssmem) except KeyError: log_info('Binary has no bss section') # Repaint the viewer once (much faster than the 8 times we used to do) main_window.hexv.redraw() # Update traceback main_window.tb_window.update_frames(get_backtrace(bv)) # Update return address try: ret = calculate_return_addr_pos(sp, bp, ip, bv) ret_add_offset = (ret - memtop) if ( ret is not None) else (bp - memtop + (reg_width / 8)) main_window.hexv.highlight_retn_addr( (ret) if (ret is not None) else (bp + (reg_width / 8)), width=reg_width / 8) retrieved = mem[ret_add_offset:ret_add_offset + (reg_width / 8)][::-1].encode('hex') if (len(retrieved) > 0): ret_add = int(retrieved, 16) main_window.tb_window.update_ret_address(ret_add) except ValueError: log_error( "Tried to find the return address before the stack was set up. Carry on." ) break break
def __check_executor(): if globs.executor is None: log_alert("seninja not running") return False return True
def visit_LLIL_NORET(self, expr): log_alert("VM Halted.")