class CrashGraph: def __init__(self, object, file_name): """" Initialized the object's internal data. Args: object: Crash object file_name: png output file name """ self.r2_obj = object.r2_obj self.r2_dbg_obj = object.r2_dbg_obj self.r2_stand_obj = object.r2_stand_obj self.graph_obj = Graph() self.count = 1 self.file_name = file_name def crash_graph(self): """ Graph generation """ self.r2_stand_obj.analyze() self.arch_obj = Arch(self.r2_obj) self.r2_dbg_obj.debug_setenv("dbg.btdepth", "256") #afl func_list = self.r2_stand_obj.aflqj() if not func_list: print("No functions") sys.exit(-1) #set bps for function in func_list: self.r2_dbg_obj.debug_break(function) self.node_list = [] self.range_list = [] first = True while True: # continue self.r2_dbg_obj.debug_continue() get_info = self.r2_dbg_obj.debug_infoj() signal = get_info["signal"] self.r2_dbg_obj.debug_dmmSy() self.pc = self.arch_obj.get_reg("program_counter") self.pdj = self.r2_dbg_obj.debug_pdj_single(self.pc) bt = self.r2_dbg_obj.debug_dbt() # check access violation signal if Checks.check_signal(signal): regs = self.r2_dbg_obj.debug_registers() node_name = "crash_node" message = "" is_exploitable = False if self.pdj[0]["type"] == "invalid": print("ERROR: Function crash_graph, the type is invalid!") return False opcode = self.pdj[0]["opcode"] crash_address = self.pdj[0]["offset"] is_exploitable = CrashAnal.exploitable(signal, self.r2_dbg_obj) if is_exploitable: exploitable_message = "PROBABLY EXPLOITABLE" message = "crash details" else: exploitable_message = "PROBABLY NOT EXPLOITABLE" message = "details" label = "Exploitable: " + exploitable_message + " \n " + "crash instruction: \n" + str( hex(crash_address) ) + " - " + str( opcode ) + " \nbacktrace: \n " + bt + " \n " + "registers: \n" + regs + " \n " self.node = self.graph_obj.create_node(node_name, "green", label) self.node_list.append(self.node) # create edge try: caller_address = bt.splitlines()[1].split()[1] except Exception as ex: print("WARNING: caller address - backtrace error: %s" % ex) caller_address = "0x0" self.create_edge(int(caller_address, 16), message) break if signal != "SIGTRAP": break if first: self.create_node("gold") first = False continue self.create_node("gold") try: caller_address = self.pdj[0]["xrefs"][0]["addr"] except Exception as ex: print("WARNING: caller address - xref not there: %s" % ex) try: caller_address = bt.splitlines()[1].split()[1] except Exception as ex: print("WARNING: caller address - backtrace erro: %s" % ex) continue # create edge self.create_edge(caller_address, self.count) # create png self.graph_obj.create_png(self.file_name) def create_node(self, color): function_address = self.pdj[0]["fcn_addr"] func_address_end = self.pdj[0]["fcn_last"] r = range(function_address, func_address_end) self.range_list.append(r) func_name = self.pdj[0]["flags"][0] node_name = func_name label = func_name + " [ " + str(hex(function_address)) + " - " + str( hex(func_address_end)) + " ] " self.node = self.graph_obj.create_node(node_name, color, label) self.node_list.append(self.node) def create_edge(self, caller_address, label): for range_addr in self.range_list: if caller_address in range_addr: for single_node in self.node_list: a = range_addr[0] b = single_node.obj_dict["attributes"]["label"].split()[2] if int(range_addr[0]) == int(b, 16): self.graph_obj.create_edge(single_node, self.node, label) self.count += 1 return
class Parse: def __init__(self, input_file, filename): """" Initialized the object's internal data. """ self.input_file = input_file self.graph_obj = Graph() self.filename = filename self.count = 0 self.disass = [] self.last_node = "" self.start_address = "" self.end_address = "" self.pc = "" self.name_function = None self.args_label = "" self.ret = None self.args = [] def read_file(self): with open(self.input_file) as fp: line = fp.readline() while line: self.parse(line, fp) line = fp.readline() # create pdf self.graph_obj.create_pdf(self.filename) def parse(self, line, fp): if "[ADDR]" in line: line = line.split() self.parse_addr(line, fp) elif "[NOSYM]" in line: self.parse_nosym(line, fp) elif "[ARG]" in line: self.parse_args(line, fp) self.generate_ret_args() elif "[RET]" in line: self.parse_ret(line) self.generate_ret_args() else: return def parse_addr(self, line, fp): self.start_address = line[3] self.end_address = line[6] self.pc = line[8] self.name_function = line[10] new_line = fp.readline() if "TAG" in new_line: self.parse_disass(new_line, fp) if self.count < 600: self.generate_graph(True) def parse_disass(self, line, fp): self.disass = [] self.bb_start = line.split()[1] while "END" not in line: line = fp.readline() a = line[52:] self.disass.append(a) fp.readline() def parse_nosym(self, line, fp): self.pc = line.split()[2] self.name_function = self.pc self.start_address = line.split()[6] self.end_address = line.split()[10] new_line = fp.readline() if "TAG" in new_line: self.parse_disass(new_line, fp) self.generate_graph(False) def parse_args(self, line, fp): self.wrap_function = line.split()[2] arg = "Arg: " + line.split()[5] + "\n" self.args.append(arg) line = fp.readline() while "ARG" in line: arg = "Arg: " + line.split()[5] + "\n" self.args.append(arg) def parse_ret(self, line): self.ret = "Return value: " + line.split()[4] def generate_ret_args(self): node_name = self.wrap_function color = "Orange" if not self.args_label: self.args_label = "Function: " + self.wrap_function + " [ " + self.start_address + " - " + self.end_address + " ] \n" if self.args: self.args_label += "".join(self.args) self.args = [] if self.ret: self.args_label += "\n" + self.ret self.ret = None node_id = node_name self.graph_obj.create_node(node_id, color, self.args_label) self.args_label = "" def generate_graph(self, no_sym): color = "Green" label = "" node_name = self.pc if no_sym: label += self.name_function else: label = "BB" label += " [ " + self.start_address + " - " + self.end_address + " ] " label += "\n PC: " + self.pc + "\n" if self.disass: label += "".join(self.disass) self.disass = [] color = "yellow" node_id = node_name if self.count == 0: # first node self.node = self.graph_obj.create_node(node_id, color, label) self.last_node = self.node self.count = self.count + 1 else: self.node = self.graph_obj.create_node(node_id, color, label) self.graph_obj.create_edge(self.last_node, self.node, self.count) self.count = self.count + 1 self.last_node = self.node
class Parse: def __init__(self, input_file, filename, crash_desc): """" Initialized the object's internal data. """ self.input_file = input_file self.graph_obj = Graph() self.filename = filename self.count = 0 self.disass = [] self.last_node = "" self.start_address = "" self.end_address = "" self.pc = "" self.name_function = "" self.args_label = "" self.ret = "" self.signal = "" self.signal_num = "" self.args = [] self.crash_desc = crash_desc def read_file(self): with open(self.input_file) as fp: line = fp.readline() while line: new_line = self.parse(line, fp) if new_line == None: line = fp.readline() else: line = new_line # create pdf self.graph_obj.create_pdf(self.filename) def parse(self, line, fp): if "[FUNC]" in line: self.parse_line(line, True) new_line = self.parse_addr(fp) return new_line elif "[NOFUNC]" in line: self.parse_line(line, False) new_line = self.parse_nosym(fp) return new_line elif "[ARG]" in line: new_line = self.parse_args(line, fp) self.generate_ret_args() return new_line elif "[RET]" in line: new_line = self.parse_ret(line, fp) self.generate_ret_args() return new_line elif "[CRASH]" in line: self.parse_crash(line) self.generate_crash() else: return None def parse_line(self, line, func): line = line.split(";") self.start_address = line[1] self.end_address = line[2] self.pc = line[3] if func: self.name_function = line[4] else: self.name_function = self.pc def parse_crash(self, line): line = line.split(";") self.signal_num = line[1] self.signal = line[2] self.pc = line[3] def parse_addr(self, fp): new_line = fp.readline() if "TAG" in new_line: self.parse_disass(new_line, fp) new_line = None if self.count < 60000: self.generate_graph(True) else: print( "It is not possible to generate the graph! (In pydot.py the call subprocess.Popen never end)" ) sys.exit() return new_line def parse_disass(self, line, fp): self.disass = [] self.bb_start = line.split()[1] while "END" not in line: line = fp.readline() a = line[52:] self.disass.append(a) fp.readline() def parse_nosym(self, fp): new_line = fp.readline() if "TAG" in new_line: self.parse_disass(new_line, fp) new_line = None if self.count < 60000: self.generate_graph(False) else: print( "It is not possible to generate the graph! (In pydot.py the call subprocess.Popen never end)" ) sys.exit() return new_line def parse_args(self, line, fp): line = line.split(";") self.wrap_function = line[1] self.pc = line[2] self.arg_num = line[3] arg = "Arg" + self.arg_num + ": " + line[5] + "\n" self.args.append(arg) new_line = fp.readline() if "DUMP" in new_line: new_line = new_line.split(";") arg = "DUMP: " + new_line[2] + "\n" self.args.append(arg) new_line = None return new_line def parse_ret(self, line, fp): line = line.split(";") self.wrap_function = line[1] self.pc = line[2] self.ret = " Return value: " + line[3] + "\n" new_line = fp.readline() if "DUMP" in new_line: new_line = new_line.split(";") ret = "DUMP: " + new_line[2] + "\n" self.ret += ret new_line = None return new_line def generate_ret_args(self): node_name = str(self.wrap_function) color = "Orange" if not self.args_label: self.args_label = "Function: " + self.wrap_function + " [ " + self.start_address + " - " + self.end_address + " ] \n" if self.args: self.args_label += "".join(self.args) self.args = [] if self.ret: self.args_label += "\nFunction: " + self.wrap_function + self.ret self.ret = None node_id = node_name self.graph_obj.create_node(node_id, color, self.args_label) self.args_label = "" def generate_graph(self, no_sym): color = "Green" label = "" node_name = str(self.pc) if no_sym: label += self.name_function else: label = "BB" label += " [ " + self.start_address + " - " + self.end_address + " ] " label += "\n PC: " + self.pc + "\n" if self.disass: label += "".join(self.disass) self.disass = [] color = "yellow" node_id = node_name if self.count == 0: # first node self.graph_obj.create_node(node_id, color, label) self.last_node = node_id self.count = self.count + 1 else: self.graph_obj.create_node(node_id, color, label) self.graph_obj.create_edge(self.last_node, node_id, self.count) self.count = self.count + 1 self.last_node = node_id def generate_crash(self): node_name = str(self.pc) self.crash_desc += "\nCrash at: " + self.pc + "Signal: " + self.signal_num + " [" + self.signal + "]" self.graph_obj.create_node(node_name, "Red", self.crash_desc) self.graph_obj.create_edge(self.last_node, node_name, self.count)