From 63e4a26268d2f912922596e3511da49e1ca08349 Mon Sep 17 00:00:00 2001 From: hugsy Date: Wed, 13 May 2020 16:57:58 -0700 Subject: [PATCH] All the old features are now working again --- __init__.py | 125 +++++++++++++++++++++++++++++++--------------------- gef.py | 94 ++++++++++++++++++++++++++------------- helpers.py | 48 ++++++++------------ 3 files changed, 156 insertions(+), 111 deletions(-) diff --git a/__init__.py b/__init__.py index d4a6c81..85e38de 100644 --- a/__init__.py +++ b/__init__.py @@ -45,8 +45,7 @@ info, err, dbg, - add_gef_breakpoint, - delete_gef_breakpoint, + RunInBackground, ) from .constants import ( @@ -64,28 +63,50 @@ ) -__service_started = False __service_thread = None +__gef_instance = None +def is_service_started(): + global __service_thread + return __service_thread is not None + + +def gef_add_breakpoint(bv, addr): + global __gef_instance + if __gef_instance is None: + return False + return __gef_instance.add_breakpoint(bv, addr) + -def create_binja_menu(): +def gef_del_breakpoint(bv, addr): + global __gef_instance + if __gef_instance is None: + return False + return __gef_instance.delete_breakpoint(bv, addr) + + +def register_gef_breakpoint_menu(): # Binja does not really support menu in its GUI just yet PluginCommand.register_for_address( - "gef : add breakpoint", + "GEF\\Set breakpoint", "Add a breakpoint in gef at the specified location.", - add_gef_breakpoint + gef_add_breakpoint, + is_valid = lambda view, addr: is_service_started() ) PluginCommand.register_for_address( - "gef : delete breakpoint", + "GEF\\Delete breakpoint", "Remove a breakpoint in gef at the specified location.", - delete_gef_breakpoint + gef_del_breakpoint, + is_valid = lambda view, addr: is_service_started() ) return def start_service(host, port, bv): + """ Starting the service """ + global __gef_instance info("Starting service on {}:{}".format(host, port)) server = xmlrpc.server.SimpleXMLRPCServer( (host, port), @@ -94,7 +115,8 @@ def start_service(host, port, bv): allow_none=True ) server.register_introspection_functions() - server.register_instance(Gef(server, bv)) + __gef_instance = Gef(server, bv) + server.register_instance(__gef_instance) dbg("Registered {} functions.".format( len(server.system_listMethods()) )) while True: if hasattr(server, "shutdown") and server.shutdown==True: break @@ -102,63 +124,64 @@ def start_service(host, port, bv): return -def gef_start(bv): - global __service_thread, __service_started - __service_thread = threading.Thread(target=start_service, args=(HOST, PORT, bv)) - __service_thread.daemon = True - __service_thread.start() - dbg("Started new thread '{}'".format(__service_thread.name)) - - if not __service_started: - create_binja_menu() - __service_started = True - return +def shutdown_service(): + try: + cli = xmlrpc.client.ServerProxy("http://{:s}:{:d}".format(HOST, PORT)) + cli.shutdown() + except socket.error: + pass -def gef_stop(bv): +def stop_service(): + """ Stopping the service """ global __service_thread + dbg("Trying to stop service thread") + shutdown_service() __service_thread.join() __service_thread = None info("Server stopped") return -def gef_start_stop(bv): - if __service_thread is None: - dbg("Trying to start service thread") - gef_start(bv) - show_message_box( - "GEF", - "Service successfully started, you can now have gef connect to it", - MessageBoxButtonSet.OKButtonSet, - MessageBoxIcon.InformationIcon - ) - - else: - dbg("Trying to stop service thread") - try: - cli = xmlrpc.client.ServerProxy("http://{:s}:{:d}".format(HOST, PORT)) - cli.shutdown() - except socket.error: - pass - - gef_stop(bv) - show_message_box( - "GEF", - "Service successfully stopped", - MessageBoxButtonSet.OKButtonSet, - MessageBoxIcon.InformationIcon - ) +def gef_start(bv): + global __service_thread + dbg("Starting background service...") + __service_thread = threading.Thread(target=start_service, args=(HOST, PORT, bv)) + __service_thread.daemon = True + __service_thread.start() + register_gef_breakpoint_menu() + show_message_box( + "GEF", + "Service successfully started, you can now have gef connect to it", + MessageBoxButtonSet.OKButtonSet, + MessageBoxIcon.InformationIcon + ) return +def gef_stop(bv): + "Stopping background service... " + stop_service() + show_message_box( + "GEF", + "Service successfully stopped", + MessageBoxButtonSet.OKButtonSet, + MessageBoxIcon.InformationIcon + ) + return - +PluginCommand.register( + "GEF\\Start service", + "Start the service for communicating with gef", + gef_start, + is_valid = lambda view: not is_service_started() +) PluginCommand.register( - "Start/stop server GEF interaction", - "Start/stop the XMLRPC server for communicating with gef", - gef_start_stop + "GEF\\Stop service", + "Stop the service for communicating with gef", + gef_stop, + is_valid = lambda view: is_service_started() ) \ No newline at end of file diff --git a/gef.py b/gef.py index 3484d28..c6834e6 100644 --- a/gef.py +++ b/gef.py @@ -6,13 +6,13 @@ core_version, log_info, highlight, - ) from .constants import ( PAGE_SIZE, DEBUG, HL_NO_COLOR, + HL_BP_COLOR, HL_CUR_INSN_COLOR, ) @@ -23,11 +23,6 @@ expose, is_exposed, ishex, - g_breakpoints, - g_current_instruction, - hl, - add_gef_breakpoint, - delete_gef_breakpoint, ) from xmlrpc.server import ( @@ -50,7 +45,11 @@ def __init__(self, server, bv, *args, **kwargs): self.view = bv self.base = bv.entry_point & ~(PAGE_SIZE-1) self._version = ("Binary Ninja", core_version()) - self.old_bps = set() + self.__old_bps = set() + self.__breakpoints = set() + tag_type = bv.tag_types["Breakpoints"] + self.__bp_tag = bv.create_tag(tag_type, "GEF Breakpoint", True) + self.__current_instruction = 0 return @@ -108,16 +107,21 @@ def version(self): def jump(self, address): """ Jump(int addr) => None Move the EA pointer to the address pointed by `addr`. - Example: binaryninja Jump 0x4049de + Example: binaryninja jump 0x4049de """ - addr = int(address, 0) - return self.view.file.navigate(self.view.file.view, addr) + try: + addr = int(address, 0) + self.view.offset = addr + return True + except: + pass + return False @expose def makecomm(self, address, comment): """ MakeComm(int addr, string comment) => None Add a comment at the location `address`. - Example: binaryninja MakeComm 0x40000 "Important call here!" + Example: binaryninja makecomm 0x40000 "Important call here!" """ addr = int(address, 0) start_addr = self.view.get_previous_function_start_before(addr) @@ -128,57 +132,87 @@ def makecomm(self, address, comment): def setcolor(self, address, color='0xff0000'): """ SetColor(int addr [, int color]) => None Set the location pointed by `address` with `color`. - Example: binaryninja SetColor 0x40000 0xff0000 + Example: binaryninja setcolor 0x40000 0xff0000 """ addr = int(address, 0) color = int(color, 0) R,G,B = (color >> 16)&0xff, (color >> 8)&0xff, (color&0xff) color = highlight.HighlightColor(red=R, blue=G, green=B) - return hl(self.view, addr, color) + return self.highlight(addr, color) @expose def sync(self, off, added, removed): """ Sync(off, added, removed) => None - Synchronize debug info with gef. This is an internal function. It is - not recommended using it from the command line. + Synchronize debug info with gef. This is an internal function. It is not recommended using it from the command line. + Example: binaryninja sync """ - global g_current_instruction - off = int(off, 0) pc = self.base + off - if DEBUG: log_info("[*] current_pc=%#x , old_pc=%#x" % (pc, g_current_instruction)) + if DEBUG: log_info("[*] current_pc=%#x , old_pc=%#x" % (pc, self.__current_instruction)) # unhighlight the _current_instruction - if g_current_instruction > 0: - hl(self.view, g_current_instruction, HL_NO_COLOR) - hl(self.view, pc, HL_CUR_INSN_COLOR) + if self.__current_instruction > 0: + self.highlight(self.__current_instruction, HL_NO_COLOR) + self.highlight(pc, HL_CUR_INSN_COLOR) # update the _current_instruction - g_current_instruction = pc - + self.__current_instruction = pc + self.jump(self.__current_instruction) dbg("pre-gdb-add-breakpoints: %s" % (added,)) dbg("pre-gdb-del-breakpoints: %s" % (removed,)) - dbg("pre-binja-breakpoints: %s" % (g_breakpoints)) + dbg("pre-binja-breakpoints: %s" % (self.__breakpoints)) - bn_added = [ x-self.base for x in g_breakpoints if x not in self.old_bps ] - bn_removed = [ x-self.base for x in self.old_bps if x not in g_breakpoints ] + bn_added = [ x-self.base for x in self.__breakpoints if x not in self.__old_bps ] + bn_removed = [ x-self.base for x in self.__old_bps if x not in self.__breakpoints ] for bp in added: - add_gef_breakpoint(self.view, self.base + bp) + self.add_breakpoint(self.view, self.base + bp) for bp in removed: - delete_gef_breakpoint(self.view, self.base + bp) + self.delete_breakpoint(self.view, self.base + bp) - self.old_bps = copy.deepcopy(g_breakpoints) + self.__old_bps = copy.deepcopy(self.__breakpoints) dbg("post-gdb-add-breakpoints: %s" % (bn_added,)) dbg("post-gdb-del-breakpoints: %s" % (bn_removed,)) - dbg("post-binja-breakpoints: %s" % (g_breakpoints,)) + dbg("post-binja-breakpoints: %s" % (self.__breakpoints,)) return [bn_added, bn_removed] + def highlight(self, addr, color): + dbg("hl(%#x, %s)" % (addr, color)) + start_addr = self.view.get_previous_function_start_before(addr) + func = self.view.get_function_at(start_addr) + if func is None: + return + func.set_user_instr_highlight(addr, color) + return + + + def add_breakpoint(self, bv, addr): + if addr in self.__breakpoints: + return False + + self.__breakpoints.add(addr) + info("Breakpoint {:#x} added".format(addr)) + self.highlight(addr, HL_BP_COLOR) + self.view.add_user_data_tag(addr, self.__bp_tag) + return True + + + def delete_breakpoint(self, bv, addr): + if addr not in self.__breakpoints: + return False + + self.__breakpoints.discard(addr) + info("Breakpoint {:#x} removed".format(addr)) + self.highlight(addr, HL_NO_COLOR) + self.view.remove_user_data_tag(addr, self.__bp_tag) + return True + + class BinjaGefRequestHandler(SimpleXMLRPCRequestHandler): rpc_paths = ("/RPC2",) \ No newline at end of file diff --git a/helpers.py b/helpers.py index 876797d..d8d3b57 100644 --- a/helpers.py +++ b/helpers.py @@ -2,6 +2,7 @@ log_info, log_debug, log_error, + BackgroundTaskThread, ) from .constants import ( @@ -11,11 +12,6 @@ ) -g_breakpoints = set() - -g_current_instruction = 0 - - def expose(f): "Decorator to set exposed flag on a function." f.exposed = True @@ -42,29 +38,21 @@ def dbg(x): log_debug("[*] {:s}".format(x)) -def hl(bv, addr, color): - dbg("hl(%#x, %s)" % (addr, color)) - start_addr = bv.get_previous_function_start_before(addr) - func = bv.get_function_at(start_addr) - if func is None: + +class RunInBackground(BackgroundTaskThread): + def __init__(self, target, cancel_cb=None, *args, **kwargs): + BackgroundTaskThread.__init__(self, '', cancel_cb is not None) + self.target = target + self.args = args + self.kwargs = kwargs + self.cancel_cb = cancel_cb + return + + def run(self): + self.target(self, *self.args, **self.kwargs) + return + + def cancel(self): + self.cancel_cb() return - func.set_user_instr_highlight(addr, color) - return - - -def add_gef_breakpoint(bv, addr): - global g_breakpoints - if addr in g_breakpoints: return False - g_breakpoints.add(addr) - info("Breakpoint {:#x} added".format(addr)) - hl(bv, addr, HL_BP_COLOR) - return True - - -def delete_gef_breakpoint(bv, addr): - global g_breakpoints - if addr not in g_breakpoints: return False - g_breakpoints.discard(addr) - info("Breakpoint {:#x} removed".format(addr)) - hl(bv, addr, HL_NO_COLOR) - return True \ No newline at end of file +