def invoke(self, arg, from_tty): breakpoints = arg current_pc_int = int( SysUtils.extract_address(str(gdb.parse_and_eval("$pc"))), 16) try: disas_output = gdb.execute("disas $pc-30,$pc", to_string=True) # Just before the line "End of assembler dump" last_instruction = disas_output.splitlines()[-2] previous_pc_address = SysUtils.extract_address(last_instruction) except: previous_pc_address = hex(current_pc_int) global track_watchpoint_dict try: count = track_watchpoint_dict[breakpoints][current_pc_int][0] + 1 except KeyError: if breakpoints not in track_watchpoint_dict: track_watchpoint_dict[breakpoints] = OrderedDict() count = 1 register_info = ScriptUtils.get_general_registers() register_info.update(ScriptUtils.get_flag_registers()) register_info.update(ScriptUtils.get_segment_registers()) float_info = ScriptUtils.get_float_registers() disas_info = gdb.execute("disas " + previous_pc_address + ",+40", to_string=True).replace("=>", " ") track_watchpoint_dict[breakpoints][current_pc_int] = [ count, previous_pc_address, register_info, float_info, disas_info ] track_watchpoint_file = SysUtils.get_track_watchpoint_file( pid, breakpoints) pickle.dump(track_watchpoint_dict[breakpoints], open(track_watchpoint_file, "wb"))
def invoke(self, arg, from_tty): arg_list = arg.split(",") breakpoint_number = arg_list.pop() register_expressions = arg_list global track_breakpoint_dict if not breakpoint_number in track_breakpoint_dict: track_breakpoint_dict[breakpoint_number] = OrderedDict() for register_expression in register_expressions: if not register_expression: continue if not register_expression in track_breakpoint_dict[ breakpoint_number]: track_breakpoint_dict[breakpoint_number][ register_expression] = OrderedDict() try: address = SysUtils.extract_address( gdb.execute("p/x " + register_expression, from_tty, to_string=True)) except: address = None if address: if address not in track_breakpoint_dict[breakpoint_number][ register_expression]: track_breakpoint_dict[breakpoint_number][ register_expression][address] = 1 else: track_breakpoint_dict[breakpoint_number][ register_expression][address] += 1 track_breakpoint_file = SysUtils.get_track_breakpoint_file( pid, breakpoint_number) pickle.dump(track_breakpoint_dict[breakpoint_number], open(track_breakpoint_file, "wb"))
def invoke(self, arg, from_tty): breakpoints = arg current_pc_int = int(SysUtils.extract_address(str(gdb.parse_and_eval("$pc"))), 16) try: disas_output = gdb.execute("disas $pc-30,$pc", to_string=True) # Just before the line "End of assembler dump" last_instruction = disas_output.splitlines()[-2] previous_pc_address = SysUtils.extract_address(last_instruction) except: previous_pc_address = hex(current_pc_int) global track_watchpoint_dict try: count = track_watchpoint_dict[breakpoints][current_pc_int][0] + 1 except KeyError: if breakpoints not in track_watchpoint_dict: track_watchpoint_dict[breakpoints] = OrderedDict() count = 1 register_info = ScriptUtils.get_general_registers() register_info.update(ScriptUtils.get_flag_registers()) register_info.update(ScriptUtils.get_segment_registers()) float_info = ScriptUtils.get_float_registers() disas_info = gdb.execute("disas " + previous_pc_address + ",+40", to_string=True).replace("=>", " ") track_watchpoint_dict[breakpoints][current_pc_int] = [count, previous_pc_address, register_info, float_info, disas_info] track_watchpoint_file = SysUtils.get_track_watchpoint_file(pid, breakpoints) pickle.dump(track_watchpoint_dict[breakpoints], open(track_watchpoint_file, "wb"))
def invoke(self, arg, from_tty): breakpoint, max_trace_count, stop_condition, step_mode, stop_after_trace,collect_general_registers,\ collect_flag_registers, collect_segment_registers, collect_float_registers = eval(arg) gdb.execute("delete " + breakpoint) regex_ret = re.compile(r":\s+ret") # 0x7f71a4dc5ff8 <poll+72>: ret regex_call = re.compile( r":\s+call") # 0x7f71a4dc5fe4 <poll+52>: call 0x7f71a4de1100 contents_send = type_defs.TraceInstructionsTree() for x in range(max_trace_count): line_info = gdb.execute("x/i $pc", to_string=True).split(maxsplit=1)[1] collect_dict = OrderedDict() if collect_general_registers: collect_dict.update(ScriptUtils.get_general_registers()) if collect_flag_registers: collect_dict.update(ScriptUtils.get_flag_registers()) if collect_segment_registers: collect_dict.update(ScriptUtils.get_segment_registers()) if collect_float_registers: collect_dict.update(ScriptUtils.get_float_registers()) contents_send.add_child( type_defs.TraceInstructionsTree(line_info, collect_dict)) status_info = (type_defs.TRACE_STATUS.STATUS_TRACING, line_info + " (" + str(x + 1) + "/" + str(max_trace_count) + ")") trace_status_file = SysUtils.get_trace_instructions_status_file( pid, breakpoint) pickle.dump(status_info, open(trace_status_file, "wb")) if regex_ret.search(line_info): if contents_send.parent is None: new_parent = type_defs.TraceInstructionsTree() contents_send.set_parent(new_parent) new_parent.add_child(contents_send) contents_send = contents_send.parent elif step_mode == type_defs.STEP_MODE.SINGLE_STEP: if regex_call.search(line_info): contents_send = contents_send.children[-1] if stop_condition: try: if str(gdb.parse_and_eval(stop_condition)) == "1": break except: pass if step_mode == type_defs.STEP_MODE.SINGLE_STEP: gdb.execute("stepi", to_string=True) elif step_mode == type_defs.STEP_MODE.STEP_OVER: gdb.execute("nexti", to_string=True) trace_instructions_file = SysUtils.get_trace_instructions_file( pid, breakpoint) pickle.dump(contents_send.get_root(), open(trace_instructions_file, "wb")) status_info = (type_defs.TRACE_STATUS.STATUS_FINISHED, "Tracing has been completed") trace_status_file = SysUtils.get_trace_instructions_status_file( pid, breakpoint) pickle.dump(status_info, open(trace_status_file, "wb")) if not stop_after_trace: gdb.execute("c")
def data(self, QModelIndex, int_role=None): if not QModelIndex.isValid(): return QVariant() if int_role == Qt.BackgroundColorRole: address = self.current_address + QModelIndex.row() * self.column_count + QModelIndex.column() if SysUtils.modulo_address(address, GDB_Engine.inferior_arch) in self.breakpoint_list: return QVariant(QColor(Qt.red)) elif int_role != Qt.DisplayRole: return QVariant() if self.data_array is None: return QVariant() return QVariant( SysUtils.aob_to_str(self.data_array[QModelIndex.row() * self.column_count + QModelIndex.column()]))
def refresh(self, int_address, offset, data_array=None, breakpoint_info=None): int_address = SysUtils.modulo_address(int_address, GDB_Engine.inferior_arch) self.breakpoint_list.clear() if data_array is None: self.data_array = GDB_Engine.hex_dump(int_address, offset) else: self.data_array = data_array if breakpoint_info is None: breakpoint_info = GDB_Engine.get_breakpoint_info() for breakpoint in breakpoint_info: breakpoint_address = int(breakpoint.address, 16) for i in range(breakpoint.size): self.breakpoint_list.add(SysUtils.modulo_address(breakpoint_address + i, GDB_Engine.inferior_arch)) self.current_address = int_address self.layoutChanged.emit()
def invoke(self, arg, from_tty): searched_str, case_sensitive, enable_regex = eval(arg) if enable_regex: try: if case_sensitive: regex = re.compile(searched_str) else: regex = re.compile(searched_str, re.IGNORECASE) except Exception as e: print("An exception occurred while trying to compile the given regex\n", str(e)) return str_dict = shelve.open(SysUtils.get_referenced_calls_file(pid), "r") returned_list = [] for index, item in enumerate(str_dict): symbol = ScriptUtils.examine_expression(item).all if not symbol: continue if enable_regex: if not regex.search(symbol): continue else: if case_sensitive: if symbol.find(searched_str) == -1: continue else: if symbol.lower().find(searched_str.lower()) == -1: continue returned_list.append((symbol, len(str_dict[item]))) str_dict.close() send_to_pince(returned_list)
def write_address(address, value_index, value): if not type(address) == int: try: address = int(address, 16) except: print(str(address) + " is not a valid address") return write_data = SysUtils.parse_string(value, value_index) if write_data is None: return encoding, option = type_defs.string_index_to_encoding_dict.get( value_index, (None, None)) if encoding is None: if value_index is type_defs.VALUE_INDEX.INDEX_AOB: write_data = bytearray(write_data) else: data_type = type_defs.index_to_struct_pack_dict.get( value_index, -1) write_data = struct.pack(data_type, write_data) else: write_data = write_data.encode(encoding, option) FILE = open(mem_file, "rb+") try: FILE.seek(address) FILE.write(write_data) FILE.close() except (OSError, ValueError): print("Can't access the memory at address " + hex(address) + " or offset " + hex(address + len(write_data)))
def set_single_address(address, value_index, value): if not type(address) == int: try: address = int(address, 16) except: print(str(address) + " is not a valid address") return write_data = SysUtils.parse_string(value, value_index) if write_data is None: return encoding, option = type_defs.string_index_to_encoding_dict.get( value_index, (None, None)) if encoding is None: if value_index is type_defs.VALUE_INDEX.INDEX_AOB: write_data = bytearray(write_data) else: data_type = type_defs.index_to_struct_pack_dict.get( value_index, -1) write_data = struct.pack(data_type, write_data) else: write_data = bytearray(write_data, encoding, option) FILE = open(mem_file, "rb+") # Check SetMultipleAddresses class in GDBCommandExtensions.py to see why we moved away the try/except block FILE.seek(address) FILE.write(write_data) FILE.close()
def invoke(self, arg, from_tty): searched_str, case_sensitive, enable_regex = eval(arg) if enable_regex: try: if case_sensitive: regex = re.compile(searched_str) else: regex = re.compile(searched_str, re.IGNORECASE) except Exception as e: print( "An exception occurred while trying to compile the given regex\n", str(e)) return str_dict = shelve.open(SysUtils.get_referenced_calls_file(pid), "r") returned_list = [] for index, item in enumerate(str_dict): symbol = ScriptUtils.examine_expression(item).all if not symbol: continue if enable_regex: if not regex.search(symbol): continue else: if case_sensitive: if symbol.find(searched_str) == -1: continue else: if symbol.lower().find(searched_str.lower()) == -1: continue returned_list.append((symbol, len(str_dict[item]))) str_dict.close() send_to_pince(returned_list)
def data(self, QModelIndex, int_role=None): if not QModelIndex.isValid(): return QVariant() elif int_role != Qt.DisplayRole: return QVariant() if self.data_array is None: return QVariant() return QVariant( SysUtils.aob_to_ascii( self.data_array[QModelIndex.row() * self.column_count + QModelIndex.column()]))
def refresh(self, int_address, offset, data_array=None, breakpoint_info=None): int_address = SysUtils.modulo_address(int_address, GDB_Engine.inferior_arch) self.breakpoint_list.clear() if data_array is None: self.data_array = GDB_Engine.hex_dump(int_address, offset) else: self.data_array = data_array if breakpoint_info is None: breakpoint_info = GDB_Engine.get_breakpoint_info() for breakpoint in breakpoint_info: breakpoint_address = int(breakpoint.address, 16) for i in range(breakpoint.size): self.breakpoint_list.add( SysUtils.modulo_address(breakpoint_address + i, GDB_Engine.inferior_arch)) self.current_address = int_address self.layoutChanged.emit()
def invoke(self, arg, from_tty): stack_info_list = [] if ScriptUtils.current_arch == type_defs.INFERIOR_ARCH.ARCH_64: chunk_size = 8 int_format = "Q" stack_register = "rsp" result = gdb.execute("p/x $rsp", from_tty, to_string=True) else: chunk_size = 4 int_format = "I" stack_register = "esp" result = gdb.execute("p/x $esp", from_tty, to_string=True) stack_address = int(SysUtils.extract_address(result), 16) # $6 = 0x7f0bc0b6bb40 with open(ScriptUtils.mem_file, "rb") as FILE: try: old_position = FILE.seek(stack_address) except (OSError, ValueError): send_to_pince(stack_info_list) return for index in range(int(4096 / chunk_size)): current_offset = chunk_size * index stack_indicator = hex(stack_address + current_offset ) + "(" + stack_register + "+" + hex( current_offset) + ")" try: FILE.seek(old_position) read = FILE.read(chunk_size) except (OSError, ValueError): print("Can't access the stack after address " + stack_indicator) break old_position = FILE.tell() int_addr = struct.unpack_from(int_format, read)[0] hex_repr = hex(int_addr) try: FILE.seek(int_addr) read_pointer = FILE.read(20) except (OSError, ValueError): pointer_data = "" else: result = gdb.execute("x/b " + hex_repr, to_string=True) result = common_regexes.plain_symbol.search(result) if not result: pointer_data = "(str)" + read_pointer.decode( "utf-8", "ignore") else: pointer_data = "(ptr)" + result.group(0) stack_info_list.append( [stack_indicator, hex_repr, pointer_data]) send_to_pince(stack_info_list)
def data(self, QModelIndex, int_role=None): if not QModelIndex.isValid(): return QVariant() if int_role == Qt.BackgroundColorRole: if QModelIndex.row() * self.column_count + QModelIndex.column( ) in self.breakpoint_list: return QVariant(QColor(Qt.red)) elif int_role != Qt.DisplayRole: return QVariant() if self.data_array is None: return QVariant() return QVariant( SysUtils.aob_to_str( self.data_array[QModelIndex.row() * self.column_count + QModelIndex.column()]))
def set_single_address(address, value_index, value): try: address = int(address, 16) except: print(str(address) + " is not a valid address") return write_data = SysUtils.parse_string(value, value_index) if write_data is None: return if value_index is INDEX_STRING: write_data = bytearray(write_data, "utf-8", "replace") elif value_index is INDEX_AOB: write_data = bytearray(write_data) else: data_type = index_to_struct_pack_dict.get(value_index, -1) write_data = struct.pack(data_type, write_data) FILE = open(mem_file, "rb+") # Check SetMultipleAddresses class in GDBCommandExtensions.py to see why we moved away the try/except block FILE.seek(address) FILE.write(write_data) FILE.close()
def invoke(self, arg, from_tty): arg_list = arg.split(",") breakpoint_number = arg_list.pop() register_expressions = arg_list global track_breakpoint_dict if not breakpoint_number in track_breakpoint_dict: track_breakpoint_dict[breakpoint_number] = OrderedDict() for register_expression in register_expressions: if not register_expression: continue if not register_expression in track_breakpoint_dict[breakpoint_number]: track_breakpoint_dict[breakpoint_number][register_expression] = OrderedDict() try: address = ScriptUtils.examine_expression(register_expression).address except: address = None if address: if address not in track_breakpoint_dict[breakpoint_number][register_expression]: track_breakpoint_dict[breakpoint_number][register_expression][address] = 1 else: track_breakpoint_dict[breakpoint_number][register_expression][address] += 1 track_breakpoint_file = SysUtils.get_track_breakpoint_file(pid, breakpoint_number) pickle.dump(track_breakpoint_dict[breakpoint_number], open(track_breakpoint_file, "wb"))
def invoke(self, arg, from_tty): stacktrace_info_list = [] if ScriptUtils.current_arch == type_defs.INFERIOR_ARCH.ARCH_64: sp_register = "rsp" result = gdb.execute("p/x $rsp", from_tty, to_string=True) else: sp_register = "esp" result = gdb.execute("p/x $esp", from_tty, to_string=True) stack_pointer_int = int(SysUtils.extract_address(result), 16) # $6 = 0x7f0bc0b6bb40 result = gdb.execute("bt", from_tty, to_string=True) max_frame = common_regexes.max_frame_count.findall(result)[-1] # +1 because frame numbers start from 0 for item in range(int(max_frame) + 1): result = gdb.execute("info frame " + str(item), from_tty, to_string=True) frame_address = common_regexes.frame_address.search(result).group( 1) difference = hex(int(frame_address, 16) - stack_pointer_int) frame_address_with_difference = frame_address + "(" + sp_register + "+" + difference + ")" return_address = common_regexes.return_address.search(result) if return_address: try: result = gdb.execute("x/b " + return_address.group(1), from_tty, to_string=True) except: break return_address_with_info = common_regexes.return_address_with_info.search( result).group(1) else: return_address_with_info = "<unavailable>" stacktrace_info_list.append( [return_address_with_info, frame_address_with_difference]) send_to_pince(stacktrace_info_list)
def invoke(self, arg, from_tty): breakpoint, max_trace_count, stop_condition, step_mode, stop_after_trace, collect_general_registers, \ collect_flag_registers, collect_segment_registers, collect_float_registers = eval(arg) gdb.execute("delete " + breakpoint) trace_status_file = SysUtils.get_trace_instructions_status_file( pid, breakpoint) regex_ret = re.compile(r":\s+ret") # 0x7f71a4dc5ff8 <poll+72>: ret regex_call = re.compile( r":\s+call") # 0x7f71a4dc5fe4 <poll+52>: call 0x7f71a4de1100 tree_root = last_node = current_node = [("", None), None, []] for x in range(max_trace_count): try: output = pickle.load(open(trace_status_file, "rb")) if output[0] == type_defs.TRACE_STATUS.STATUS_CANCELED: break except: pass line_info = gdb.execute("x/i $pc", to_string=True).split(maxsplit=1)[1] collect_dict = OrderedDict() if collect_general_registers: collect_dict.update(ScriptUtils.get_general_registers()) if collect_flag_registers: collect_dict.update(ScriptUtils.get_flag_registers()) if collect_segment_registers: collect_dict.update(ScriptUtils.get_segment_registers()) if collect_float_registers: collect_dict.update(ScriptUtils.get_float_registers()) current_node[2].append( ((line_info, collect_dict), current_node, [])) status_info = (type_defs.TRACE_STATUS.STATUS_TRACING, line_info + " (" + str(x + 1) + "/" + str(max_trace_count) + ")") pickle.dump(status_info, open(trace_status_file, "wb")) if regex_ret.search(line_info): if current_node == tree_root: tree_root = (("", None), [], [tree_root]) current_node = last_node elif step_mode == type_defs.STEP_MODE.SINGLE_STEP: if regex_call.search(line_info): last_node = current_node current_node = current_node[2][-1] if stop_condition: try: if str(gdb.parse_and_eval(stop_condition)) == "1": break except: pass if step_mode == type_defs.STEP_MODE.SINGLE_STEP: gdb.execute("stepi", to_string=True) elif step_mode == type_defs.STEP_MODE.STEP_OVER: gdb.execute("nexti", to_string=True) status_info = (type_defs.TRACE_STATUS.STATUS_PROCESSING, "Processing the collected data") pickle.dump(status_info, open(trace_status_file, "wb")) trace_instructions_file = SysUtils.get_trace_instructions_file( pid, breakpoint) pickle.dump(tree_root, open(trace_instructions_file, "wb")) status_info = (type_defs.TRACE_STATUS.STATUS_FINISHED, "Tracing has been completed") pickle.dump(status_info, open(trace_status_file, "wb")) if not stop_after_trace: gdb.execute("c")
def invoke(self, arg, from_tty): if ScriptUtils.current_arch == type_defs.INFERIOR_ARCH.ARCH_64: disas_option = distorm3.Decode64Bits else: disas_option = distorm3.Decode32Bits referenced_strings_dict = shelve.open( SysUtils.get_referenced_strings_file(pid), writeback=True) referenced_jumps_dict = shelve.open( SysUtils.get_referenced_jumps_file(pid), writeback=True) referenced_calls_dict = shelve.open( SysUtils.get_referenced_calls_file(pid), writeback=True) region_list, discard_invalid_strings = receive_from_pince() dissect_code_status_file = SysUtils.get_dissect_code_status_file(pid) region_count = len(region_list) self.memory = open(ScriptUtils.mem_file, "rb") buffer = 0x130000 # Has the best record of 13.6 sec. Tested on 0ad with Intel i7-4702MQ CPU and 8GB RAM ref_str_count = len(referenced_strings_dict) ref_jmp_count = len(referenced_jumps_dict) ref_call_count = len(referenced_calls_dict) for region_index, region in enumerate(region_list): region_info = region.addr, "Region " + str( region_index + 1) + " of " + str(region_count) start_addr, end_addr = region.addr.split("-") start_addr = int( start_addr, 16 ) # Becomes address of the last disassembled instruction later on end_addr = int(end_addr, 16) region_finished = False while not region_finished: remaining_space = end_addr - start_addr if remaining_space < buffer: offset = remaining_space region_finished = True else: offset = buffer status_info = region_info + ( hex(start_addr) + "-" + hex(start_addr + offset), ref_str_count, ref_jmp_count, ref_call_count) pickle.dump(status_info, open(dissect_code_status_file, "wb")) try: self.memory.seek(start_addr) except (OSError, ValueError): break code = self.memory.read(offset) disas_data = distorm3.Decode(start_addr, code, disas_option) if not region_finished: last_disas_addr = disas_data[-4][0] for index in range(4): del disas_data[ -1] # Get rid of last 4 instructions to ensure correct bytecode translation else: last_disas_addr = 0 for (instruction_offset, size, instruction, hexdump) in disas_data: if isinstance(instruction, bytes): instruction = instruction.decode() if instruction.startswith("J") or instruction.startswith( "LOOP"): found = common_regexes.dissect_code_valid_address.search( instruction) if found: referenced_address_str = common_regexes.hex_number.search( found.group(0)).group(0) referenced_address_int = int( referenced_address_str, 16) if self.is_memory_valid(referenced_address_int): instruction_only = common_regexes.alphanumerics.search( instruction).group(0).casefold() try: referenced_jumps_dict[ referenced_address_str][ instruction_offset] = instruction_only except KeyError: referenced_jumps_dict[ referenced_address_str] = {} referenced_jumps_dict[ referenced_address_str][ instruction_offset] = instruction_only ref_jmp_count += 1 elif instruction.startswith("CALL"): found = common_regexes.dissect_code_valid_address.search( instruction) if found: referenced_address_str = common_regexes.hex_number.search( found.group(0)).group(0) referenced_address_int = int( referenced_address_str, 16) if self.is_memory_valid(referenced_address_int): try: referenced_calls_dict[ referenced_address_str].add( instruction_offset) except KeyError: referenced_calls_dict[ referenced_address_str] = set() referenced_calls_dict[ referenced_address_str].add( instruction_offset) ref_call_count += 1 else: found = common_regexes.dissect_code_valid_address.search( instruction) if found: referenced_address_str = common_regexes.hex_number.search( found.group(0)).group(0) referenced_address_int = int( referenced_address_str, 16) if self.is_memory_valid(referenced_address_int, discard_invalid_strings): try: referenced_strings_dict[ referenced_address_str].add( instruction_offset) except KeyError: referenced_strings_dict[ referenced_address_str] = set() referenced_strings_dict[ referenced_address_str].add( instruction_offset) ref_str_count += 1 start_addr = last_disas_addr self.memory.close()
def invoke(self, arg, from_tty): (breakpoint, max_trace_count, stop_condition, step_mode, stop_after_trace, collect_general_registers, collect_flag_registers, collect_segment_registers, collect_float_registers) = eval(arg) gdb.execute("delete " + breakpoint) trace_status_file = SysUtils.get_trace_instructions_status_file( pid, breakpoint) # The reason we don't use a tree class is to make the tree json-compatible # tree format-->[node1, node2, node3, ...] # node-->[(line_info, register_dict), parent_index, child_index_list] tree = [] current_index = 0 # Avoid calling len() current_root_index = 0 root_index = 0 # Root always be an empty node, it's up to you to use or delete it tree.append([("", None), None, []]) for x in range(max_trace_count): try: output = pickle.load(open(trace_status_file, "rb")) if output[0] == type_defs.TRACE_STATUS.STATUS_CANCELED: break except: pass line_info = gdb.execute("x/i $pc", to_string=True).split(maxsplit=1)[1] collect_dict = OrderedDict() if collect_general_registers: collect_dict.update(ScriptUtils.get_general_registers()) if collect_flag_registers: collect_dict.update(ScriptUtils.get_flag_registers()) if collect_segment_registers: collect_dict.update(ScriptUtils.get_segment_registers()) if collect_float_registers: collect_dict.update(ScriptUtils.get_float_registers()) current_index += 1 tree.append([(line_info, collect_dict), current_root_index, []]) tree[current_root_index][2].append(current_index) # Add a child status_info = (type_defs.TRACE_STATUS.STATUS_TRACING, line_info + " (" + str(x + 1) + "/" + str(max_trace_count) + ")") pickle.dump(status_info, open(trace_status_file, "wb")) if common_regexes.trace_instructions_ret.search(line_info): if tree[current_root_index][1] is None: # If no parents exist current_index += 1 tree.append([("", None), None, [current_root_index]]) tree[current_root_index][ 1] = current_index # Set new parent current_root_index = current_index # current_node=current_node.parent root_index = current_root_index # set new root else: current_root_index = tree[current_root_index][ 1] # current_node=current_node.parent elif step_mode == type_defs.STEP_MODE.SINGLE_STEP: if common_regexes.trace_instructions_call.search(line_info): current_root_index = current_index if stop_condition: try: if str(gdb.parse_and_eval(stop_condition)) == "1": break except: pass if step_mode == type_defs.STEP_MODE.SINGLE_STEP: gdb.execute("stepi", to_string=True) elif step_mode == type_defs.STEP_MODE.STEP_OVER: gdb.execute("nexti", to_string=True) status_info = (type_defs.TRACE_STATUS.STATUS_PROCESSING, "Processing the collected data") pickle.dump(status_info, open(trace_status_file, "wb")) trace_instructions_file = SysUtils.get_trace_instructions_file( pid, breakpoint) json.dump((tree, root_index), open(trace_instructions_file, "w")) status_info = (type_defs.TRACE_STATUS.STATUS_FINISHED, "Tracing has been completed") pickle.dump(status_info, open(trace_status_file, "wb")) if not stop_after_trace: gdb.execute("c")
def test_split_symbol(self): self.assertListEqual(SysUtils.split_symbol("func(param)@plt"), ["func", "func(param)", "func(param)@plt"])
import gdb, pickle, json, sys, re, struct, io, ctypes, os, shelve, distorm3 from collections import OrderedDict # This is some retarded hack gdbvalue = gdb.parse_and_eval("$PINCE_PATH") PINCE_PATH = gdbvalue.string() sys.path.append( PINCE_PATH ) # Adds the PINCE directory to PYTHONPATH to import libraries from PINCE from libPINCE.gdb_python_scripts import ScriptUtils from libPINCE import SysUtils, type_defs, common_regexes inferior = gdb.selected_inferior() pid = inferior.pid recv_file = SysUtils.get_IPC_from_PINCE_file(pid) send_file = SysUtils.get_IPC_to_PINCE_file(pid) lib = None # Format of info_list: [count, previous_pc_address, register_info, float_info, disas_info] # Format of watchpoint_dict: {address1:info_list1, address2:info_list2, ...} # Format of watchpoint_numbers: str([1,2,3,4,..]) # Format: {watchpoint_numbers1:watchpoint_dict1, watchpoint_numbers2:track_watchpoint_dict2, ...} track_watchpoint_dict = {} # Format of expression_info_dict: {value1:count1, value2:count2, ...} # Format of register_expression_dict: {expression1:expression_info_dict1, expression2:expression_info_dict2, ...} # Format: {breakpoint_number1:register_expression_dict1, breakpoint_number2:register_expression_dict2, ...} track_breakpoint_dict = {}
def get_selected_address(self): ci = self.currentIndex() current_address = self.model().current_address + ci.row() * self.model().columnCount() + ci.column() return SysUtils.modulo_address(current_address, GDB_Engine.inferior_arch)
desc = 'Runs all unit tests by creating or attaching to a process' ex = 'Example of Usage:' \ + '\n\tsudo python3 run_tests.py -a kmines' \ + '\n\tsudo python3 run_tests.py -c /usr/games/kmines -o="-v"' parser = argparse.ArgumentParser(description=desc, epilog=ex, formatter_class=argparse.RawDescriptionHelpFormatter) parser.add_argument("-a", metavar="process_name", type=str, help="Attaches to the process with given name") parser.add_argument("-c", metavar="file_path", type=str, help="Creates a new process with given path") parser.add_argument("-o", metavar="options", type=str, default="", help="Arguments that'll be passed to the inferior, only can be used with -c, optional") parser.add_argument("-l", metavar="ld_preload_path", type=str, default="", help="Path of the preloaded .so file, only can be used with -c, optional") args = parser.parse_args() if args.a: process_list = SysUtils.search_in_processes_by_name(args.a) if not process_list: parser.error("There's no process with the name " + args.a) if len(process_list) > 1: for p in process_list: try: name = p.name() except psutil.NoSuchProcess: print("Process with pid", p.pid, "does not exist anymore") continue print(name) print("There are more than one process with the name " + args.a) exit() pid = process_list[0].pid if not GDB_Engine.can_attach(pid): parser.error("Failed to attach to the process with pid " + str(pid))
def get_selected_address(self): ci = self.currentIndex() current_address = self.model().current_address + ci.row() * self.model( ).columnCount() + ci.column() return SysUtils.modulo_address(current_address, GDB_Engine.inferior_arch)
from collections import OrderedDict # This is some retarded hack gdbvalue = gdb.parse_and_eval("$PINCE_PATH") PINCE_PATH = gdbvalue.string() sys.path.append( PINCE_PATH ) # Adds the PINCE directory to PYTHONPATH to import libraries from PINCE from libPINCE.gdb_python_scripts import ScriptUtils from libPINCE import SysUtils from libPINCE import type_defs inferior = gdb.selected_inferior() pid = inferior.pid recv_file = SysUtils.get_ipc_from_PINCE_file(pid) send_file = SysUtils.get_ipc_to_PINCE_file(pid) lib = None # Format of info_list: [count, previous_pc_address, register_info, float_info, disas_info] # Format of watchpoint_dict: {address1:info_list1, address2:info_list2, ...} # Format of watchpoint_numbers: str([1,2,3,4,..]) # Format: {watchpoint_numbers1:watchpoint_dict1, watchpoint_numbers2:track_watchpoint_dict2, ...} track_watchpoint_dict = {} # Format of expression_info_dict: {value1:count1, value2:count2, ...} # Format of register_expression_dict: {expression1:expression_info_dict1, expression2:expression_info_dict2, ...} # Format: {breakpoint_number1:register_expression_dict1, breakpoint_number2:register_expression_dict2, ...} track_breakpoint_dict = {}
def invoke(self, arg, from_tty): if ScriptUtils.current_arch == type_defs.INFERIOR_ARCH.ARCH_64: disas_option = distorm3.Decode64Bits else: disas_option = distorm3.Decode32Bits referenced_strings_dict = shelve.open(SysUtils.get_referenced_strings_file(pid), writeback=True) referenced_jumps_dict = shelve.open(SysUtils.get_referenced_jumps_file(pid), writeback=True) referenced_calls_dict = shelve.open(SysUtils.get_referenced_calls_file(pid), writeback=True) region_list, discard_invalid_strings = receive_from_pince() dissect_code_status_file = SysUtils.get_dissect_code_status_file(pid) region_count = len(region_list) self.memory = open(ScriptUtils.mem_file, "rb") buffer = 0x130000 # Has the best record of 13.6 sec. Tested on 0ad with Intel i7-4702MQ CPU and 8GB RAM ref_str_count = len(referenced_strings_dict) ref_jmp_count = len(referenced_jumps_dict) ref_call_count = len(referenced_calls_dict) for region_index, region in enumerate(region_list): region_info = region.addr, "Region " + str(region_index + 1) + " of " + str(region_count) start_addr, end_addr = region.addr.split("-") start_addr = int(start_addr, 16) # Becomes address of the last disassembled instruction later on end_addr = int(end_addr, 16) region_finished = False while not region_finished: remaining_space = end_addr - start_addr if remaining_space < buffer: offset = remaining_space region_finished = True else: offset = buffer status_info = region_info + (hex(start_addr) + "-" + hex(start_addr + offset), ref_str_count, ref_jmp_count, ref_call_count) pickle.dump(status_info, open(dissect_code_status_file, "wb")) try: self.memory.seek(start_addr) except (OSError, ValueError): break code = self.memory.read(offset) disas_data = distorm3.Decode(start_addr, code, disas_option) if not region_finished: last_disas_addr = disas_data[-4][0] for index in range(4): del disas_data[-1] # Get rid of last 4 instructions to ensure correct bytecode translation else: last_disas_addr = 0 for (instruction_offset, size, instruction, hexdump) in disas_data: if isinstance(instruction, bytes): instruction = instruction.decode() if instruction.startswith("J") or instruction.startswith("LOOP"): found = common_regexes.dissect_code_valid_address.search(instruction) if found: referenced_address_str = common_regexes.hex_number.search(found.group(0)).group(0) referenced_address_int = int(referenced_address_str, 16) if self.is_memory_valid(referenced_address_int): instruction_only = common_regexes.alphanumerics.search(instruction).group(0).casefold() try: referenced_jumps_dict[referenced_address_str][instruction_offset] = instruction_only except KeyError: referenced_jumps_dict[referenced_address_str] = {} referenced_jumps_dict[referenced_address_str][instruction_offset] = instruction_only ref_jmp_count += 1 elif instruction.startswith("CALL"): found = common_regexes.dissect_code_valid_address.search(instruction) if found: referenced_address_str = common_regexes.hex_number.search(found.group(0)).group(0) referenced_address_int = int(referenced_address_str, 16) if self.is_memory_valid(referenced_address_int): try: referenced_calls_dict[referenced_address_str].add(instruction_offset) except KeyError: referenced_calls_dict[referenced_address_str] = set() referenced_calls_dict[referenced_address_str].add(instruction_offset) ref_call_count += 1 else: found = common_regexes.dissect_code_valid_address.search(instruction) if found: referenced_address_str = common_regexes.hex_number.search(found.group(0)).group(0) referenced_address_int = int(referenced_address_str, 16) if self.is_memory_valid(referenced_address_int, discard_invalid_strings): try: referenced_strings_dict[referenced_address_str].add(instruction_offset) except KeyError: referenced_strings_dict[referenced_address_str] = set() referenced_strings_dict[referenced_address_str].add(instruction_offset) ref_str_count += 1 start_addr = last_disas_addr self.memory.close()
def invoke(self, arg, from_tty): (breakpoint, max_trace_count, stop_condition, step_mode, stop_after_trace, collect_general_registers, collect_flag_registers, collect_segment_registers, collect_float_registers) = eval(arg) gdb.execute("delete " + breakpoint) trace_status_file = SysUtils.get_trace_instructions_status_file(pid, breakpoint) # The reason we don't use a tree class is to make the tree json-compatible # tree format-->[node1, node2, node3, ...] # node-->[(line_info, register_dict), parent_index, child_index_list] tree = [] current_index = 0 # Avoid calling len() current_root_index = 0 root_index = 0 # Root always be an empty node, it's up to you to use or delete it tree.append([("", None), None, []]) for x in range(max_trace_count): try: output = pickle.load(open(trace_status_file, "rb")) if output[0] == type_defs.TRACE_STATUS.STATUS_CANCELED: break except: pass line_info = gdb.execute("x/i $pc", to_string=True).split(maxsplit=1)[1] collect_dict = OrderedDict() if collect_general_registers: collect_dict.update(ScriptUtils.get_general_registers()) if collect_flag_registers: collect_dict.update(ScriptUtils.get_flag_registers()) if collect_segment_registers: collect_dict.update(ScriptUtils.get_segment_registers()) if collect_float_registers: collect_dict.update(ScriptUtils.get_float_registers()) current_index += 1 tree.append([(line_info, collect_dict), current_root_index, []]) tree[current_root_index][2].append(current_index) # Add a child status_info = (type_defs.TRACE_STATUS.STATUS_TRACING, line_info + " (" + str(x + 1) + "/" + str(max_trace_count) + ")") pickle.dump(status_info, open(trace_status_file, "wb")) if common_regexes.trace_instructions_ret.search(line_info): if tree[current_root_index][1] is None: # If no parents exist current_index += 1 tree.append([("", None), None, [current_root_index]]) tree[current_root_index][1] = current_index # Set new parent current_root_index = current_index # current_node=current_node.parent root_index = current_root_index # set new root else: current_root_index = tree[current_root_index][1] # current_node=current_node.parent elif step_mode == type_defs.STEP_MODE.SINGLE_STEP: if common_regexes.trace_instructions_call.search(line_info): current_root_index = current_index if stop_condition: try: if str(gdb.parse_and_eval(stop_condition)) == "1": break except: pass if step_mode == type_defs.STEP_MODE.SINGLE_STEP: gdb.execute("stepi", to_string=True) elif step_mode == type_defs.STEP_MODE.STEP_OVER: gdb.execute("nexti", to_string=True) status_info = (type_defs.TRACE_STATUS.STATUS_PROCESSING, "Processing the collected data") pickle.dump(status_info, open(trace_status_file, "wb")) trace_instructions_file = SysUtils.get_trace_instructions_file(pid, breakpoint) json.dump((tree, root_index), open(trace_instructions_file, "w")) status_info = (type_defs.TRACE_STATUS.STATUS_FINISHED, "Tracing has been completed") pickle.dump(status_info, open(trace_status_file, "wb")) if not stop_after_trace: gdb.execute("c")
def invoke(self, arg, from_tty): global referenced_jumps_dict global referenced_calls_dict global referenced_strings_dict regex_valid_address = re.compile( r"(\s+|\[|,)0x[0-9a-fA-F]+(\s+|\]|,|$)") regex_hex = re.compile(r"0x[0-9a-fA-F]+") regex_instruction = re.compile(r"\w+") region_list = receive_from_pince() dissect_code_status_file = SysUtils.get_dissect_code_status_file(pid) region_count = len(region_list) self.memory = open(ScriptUtils.mem_file, "rb") for region_index, region in enumerate(region_list): status_info = region.addr, "Region " + str(region_index + 1) + " of " + str(region_count), \ len(referenced_strings_dict), len(referenced_jumps_dict), len(referenced_calls_dict) pickle.dump(status_info, open(dissect_code_status_file, "wb")) start_addr, end_addr = region.addr.split("-") start_addr = "0x" + start_addr end_addr = "0x" + end_addr disas_data = gdb.execute("disas " + start_addr + "," + end_addr, to_string=True) lines = disas_data.splitlines() del lines[0], lines[ -1] # Get rid of "End of assembler dump" and "Dump of assembler code..." texts for line in lines: referrer_address, opcode = line.split(":", maxsplit=1) opcode = opcode.strip() opcode = ScriptUtils.remove_disas_comment(opcode) if opcode.startswith("j") or opcode.startswith("loop"): found = regex_valid_address.search(opcode) if found: referenced_int_address = int( regex_hex.search(found.group(0)).group(0), 16) if self.is_memory_valid(referenced_int_address): instruction = regex_instruction.search( opcode).group(0) referrer_int_address = int( regex_hex.search(referrer_address).group(0), 16) if not referenced_int_address in referenced_jumps_dict: referenced_jumps_dict[ referenced_int_address] = {} referenced_jumps_dict[referenced_int_address][ referrer_int_address] = instruction if opcode.startswith("call"): found = regex_valid_address.search(opcode) if found: referenced_int_address = int( regex_hex.search(found.group(0)).group(0), 16) if self.is_memory_valid(referenced_int_address): referrer_int_address = int( regex_hex.search(referrer_address).group(0), 16) if not referenced_int_address in referenced_calls_dict: referenced_calls_dict[ referenced_int_address] = set() referenced_calls_dict[referenced_int_address].add( referrer_int_address) else: found = regex_valid_address.search(opcode) if found: referenced_int_address = int( regex_hex.search(found.group(0)).group(0), 16) if self.is_memory_valid(referenced_int_address): referrer_int_address = int( regex_hex.search(referrer_address).group(0), 16) if not referenced_int_address in referenced_strings_dict: referenced_strings_dict[ referenced_int_address] = set() referenced_strings_dict[ referenced_int_address].add( referrer_int_address) self.memory.close()
along with this program. If not, see <http://www.gnu.org/licenses/>. """ import gdb, pickle, json, sys, re, struct, io, ctypes, os, shelve, distorm3 from collections import OrderedDict # This is some retarded hack gdbvalue = gdb.parse_and_eval("$PINCE_PATH") PINCE_PATH = gdbvalue.string() sys.path.append(PINCE_PATH) # Adds the PINCE directory to PYTHONPATH to import libraries from PINCE from libPINCE.gdb_python_scripts import ScriptUtils from libPINCE import SysUtils, type_defs, common_regexes inferior = gdb.selected_inferior() pid = inferior.pid recv_file = SysUtils.get_IPC_from_PINCE_file(pid) send_file = SysUtils.get_IPC_to_PINCE_file(pid) lib = None # Format of info_list: [count, previous_pc_address, register_info, float_info, disas_info] # Format of watchpoint_dict: {address1:info_list1, address2:info_list2, ...} # Format of watchpoint_numbers: str([1,2,3,4,..]) # Format: {watchpoint_numbers1:watchpoint_dict1, watchpoint_numbers2:track_watchpoint_dict2, ...} track_watchpoint_dict = {} # Format of expression_info_dict: {value1:count1, value2:count2, ...} # Format of register_expression_dict: {expression1:expression_info_dict1, expression2:expression_info_dict2, ...} # Format: {breakpoint_number1:register_expression_dict1, breakpoint_number2:register_expression_dict2, ...} track_breakpoint_dict = {}
metavar="options", type=str, default="", help= "Arguments that'll be passed to the inferior, only can be used with -c, optional" ) parser.add_argument( "-l", metavar="ld_preload_path", type=str, default="", help="Path of the preloaded .so file, only can be used with -c, optional") args = parser.parse_args() if args.a: process_list = SysUtils.search_in_processes_by_name(args.a) if not process_list: parser.error("There's no process with the name " + args.a) if len(process_list) > 1: for item in process_list: print(item.name()) print("There are more than one process with the name " + args.a) exit() pid = process_list[0].pid if not GDB_Engine.can_attach(pid): parser.error("Failed to attach to the process with pid " + str(pid)) GDB_Engine.attach(pid) elif args.c: if not GDB_Engine.create_process(args.c, args.o, args.l): parser.error("Couldn't create the process with current args") else:
def invoke(self, arg, from_tty): referenced_strings_dict = shelve.open( SysUtils.get_referenced_strings_file(pid), writeback=True) referenced_jumps_dict = shelve.open( SysUtils.get_referenced_jumps_file(pid), writeback=True) referenced_calls_dict = shelve.open( SysUtils.get_referenced_calls_file(pid), writeback=True) regex_valid_address = re.compile( r"(\s+|\[|,)0x[0-9a-fA-F]+(\s+|\]|,|$)") regex_hex = re.compile(r"0x[0-9a-fA-F]+") regex_instruction = re.compile(r"\w+") region_list = receive_from_pince() dissect_code_status_file = SysUtils.get_dissect_code_status_file(pid) region_count = len(region_list) self.memory = open(ScriptUtils.mem_file, "rb") buffer = 0x10000 for region_index, region in enumerate(region_list): region_info = region.addr, "Region " + str( region_index + 1) + " of " + str(region_count) start_addr, end_addr = region.addr.split("-") start_addr = int(start_addr, 16) end_addr = int(end_addr, 16) remaining_space = end_addr - start_addr while remaining_space > 0: if remaining_space < buffer: offset = start_addr + remaining_space else: offset = start_addr + buffer start_addr_str = hex(start_addr) offset_str = hex(offset) status_info = region_info + (start_addr_str + "-" + offset_str, len(referenced_strings_dict), len(referenced_jumps_dict), len(referenced_calls_dict)) pickle.dump(status_info, open(dissect_code_status_file, "wb")) disas_data = gdb.execute("disas " + start_addr_str + "," + offset_str, to_string=True) start_addr = offset remaining_space -= buffer lines = disas_data.splitlines() del lines[0], lines[ -1] # Get rid of "End of assembler dump" and "Dump of assembler code..." texts for line in lines: referrer_address, opcode = line.split(":", maxsplit=1) opcode = opcode.strip() opcode = ScriptUtils.remove_disas_comment(opcode) if opcode.startswith("j") or opcode.startswith("loop"): found = regex_valid_address.search(opcode) if found: referenced_address_str = regex_hex.search( found.group(0)).group(0) referenced_address_int = int( referenced_address_str, 16) if self.is_memory_valid(referenced_address_int): instruction = regex_instruction.search( opcode).group(0) referrer_address = regex_hex.search( referrer_address).group(0) try: referenced_jumps_dict[ referenced_address_str][ referrer_address] = instruction except KeyError: referenced_jumps_dict[ referenced_address_str] = {} if opcode.startswith("call"): found = regex_valid_address.search(opcode) if found: referenced_address_str = regex_hex.search( found.group(0)).group(0) referenced_address_int = int( referenced_address_str, 16) if self.is_memory_valid(referenced_address_int): referrer_address = regex_hex.search( referrer_address).group(0) try: referenced_calls_dict[ referenced_address_str].add( referrer_address) except KeyError: referenced_calls_dict[ referenced_address_str] = set() else: found = regex_valid_address.search(opcode) if found: referenced_address_str = regex_hex.search( found.group(0)).group(0) referenced_address_int = int( referenced_address_str, 16) if self.is_memory_valid(referenced_address_int): referrer_address = regex_hex.search( referrer_address).group(0) try: referenced_strings_dict[ referenced_address_str].add( referrer_address) except KeyError: referenced_strings_dict[ referenced_address_str] = set() self.memory.close()