def context_code(self): nb_insn = self.get_setting("nb_lines_code") nb_insn_prev = self.get_setting("nb_lines_code_prev") cur_insn_color = unigdb.config.get("theme.disassemble_current_instruction") pc = int(unigdb.arch.CURRENT_ARCH.pc) # frame = gdb.selected_frame() arch_name = "{}:{}".format(unigdb.arch.CURRENT_ARCH.arch.lower(), unigdb.arch.CURRENT_ARCH.mode) self.context_title("code:{}".format(arch_name)) try: instruction_iterator = disass.capstone_disassemble # instruction_iterator = disass.ida_disassemble if use_ida else instruction_iterator for insn in instruction_iterator(pc, nb_insn, nb_prev=nb_insn_prev): line = [] is_taken = False target = None text = str(insn) if insn.address < pc: line += Color.grayify(" {}".format(text)) elif insn.address == pc: line += Color.colorify("{:s}{:s}".format(config_arrow_right.rjust(3), text), cur_insn_color) if unigdb.arch.CURRENT_ARCH.is_conditional_branch(insn): is_taken, reason = unigdb.arch.CURRENT_ARCH.is_branch_taken(insn) if is_taken: target = insn.operands[-1].split()[0] reason = "[Reason: {:s}]".format(reason) if reason else "" line += Color.colorify("\tTAKEN {:s}".format(reason), "bold green") else: reason = "[Reason: !({:s})]".format(reason) if reason else "" line += Color.colorify("\tNOT taken {:s}".format(reason), "bold red") elif unigdb.arch.CURRENT_ARCH.is_call(insn) and self.get_setting("peek_calls") is True: target = insn.operands[-1].split()[0] elif unigdb.arch.CURRENT_ARCH.is_ret(insn) and self.get_setting("peek_ret") is True: target = int(unigdb.arch.CURRENT_ARCH.get_ra(insn)) else: line += " {}".format(text) print("".join(line)) if target: try: target = int(target, 0) except TypeError: # Already an int pass except ValueError: # If the operand isn't an address right now we can't parse it continue for i, tinsn in enumerate(instruction_iterator(target, nb_insn)): text = " {} {}".format(unigdb.config.DOWN_ARROW if i == 0 else " ", str(tinsn)) print(text) break # except Exception as e: # message.error("Cannot disassemble from $PC: %s" % e) except Exception: import traceback print(traceback.format_exc()) return None
def print_registers(registers, ignored_registers=[], old_registers={}, flags=False): '''Print dereferenced registers Arguments: registers(list): List of printed registers ignored_registers(list): List of registers witch didn't printed old_registers(list): Old registers, needed for check if registers was changed flags(bool): Print flags Returns: A string representing pointers of each address and reference REG_NAME: 0x0804a10 —▸ 0x08061000 —▸ AAAA ''' widest = max(map(len, registers)) changed_color = unigdb.config.get("theme.registers_value_changed") regname_color = unigdb.config.get("theme.registers_register_name") line = '' # Print registers value for reg in registers: if reg in ignored_registers: continue try: r = unigdb.regs.get_register(reg) # if r.type.code == gdb.TYPE_CODE_VOID: # continue new_value_type_flag = False new_value = int(r) if r >= 0 else unigdb.arch.ptrmask + int(r) + 1 except Exception: # If this exception is triggered, it means that the current register # is corrupted. Just use the register "raw" value (not eval-ed) new_value = unigdb.regs.get_register(reg) new_value_type_flag = False except Exception: new_value = 0 new_value_type_flag = False old_value = old_registers.get(reg, 0) padreg = reg.ljust(widest, " ") value = new_value if value == old_value: line += "{}: ".format(Color.colorify(padreg, regname_color)) else: line += "{}: ".format(Color.colorify(padreg, changed_color)) if new_value_type_flag: line += "{:s} ".format(str(value)) else: line += unigdb.chain.format(value) print(line) line = "" # Print Flags if flags and unigdb.arch.CURRENT_ARCH.flags_table: print("Flags: {:s}".format( unigdb.arch.CURRENT_ARCH.flag_register_to_human()))
def initial_message(): msg = "{:s} for {:s} ready, type `{:s}' to start, `{:s}' to configure\n".format( Color.greenify("UniGDB"), get_os(), Color.colorify("self", "underline yellow"), Color.colorify("self config", "underline pink") ) ver = "{:d}.{:d}".format(sys.version_info.major, sys.version_info.minor) nb_cmds = len(unigdb.commands.__commands__) msg += "{:s} commands loaded using Python engine {:s}".format( Color.colorify(nb_cmds, "bold green"), Color.colorify(ver, "bold red")) return msg
def show_legend(self): if unigdb.config.get("self.disable_colors") is not True: str_color = unigdb.config.get("theme.dereference_string") code_addr_color = unigdb.config.get("theme.address_code") stack_addr_color = unigdb.config.get("theme.address_stack") heap_addr_color = unigdb.config.get("theme.address_heap") changed_register_color = unigdb.config.get("theme.registers_value_changed") print("[ Legend: {} | {} | {} | {} | {} ]".format( Color.colorify("Modified register", changed_register_color), Color.colorify("Code", code_addr_color), Color.colorify("Heap", heap_addr_color), Color.colorify("Stack", stack_addr_color), Color.colorify("String", str_color) )) return None
def invoke(self, args, from_tty): self.dont_repeat() if not os.access(unigdb.config.UNIGDB_RC, os.R_OK): return None quiet = args.lower() == "quiet" cfg = configparser.ConfigParser() cfg.read(unigdb.config.UNIGDB_RC) for section in cfg.sections(): if section == "aliases": # load the aliases for key in cfg.options(section): SelfAlias(key, cfg.get(section, key)) continue # load the other options for optname in cfg.options(section): try: key = "{:s}.{:s}".format(section, optname) _value, _doc = unigdb.config.get(key, get_all=True) new_value = cfg.get(section, optname) if isinstance(_value, bool): new_value = True if new_value == "True" else False new_value = int(new_value) if new_value.isdigit( ) or isinstance(_value, int) else new_value unigdb.config.set(key, new_value, _doc) except Exception: pass if not quiet: message.success("Configuration from '{:s}' restored".format( Color.colorify(unigdb.config.UNIGDB_RC, "bold blue"))) return None
def format(value, limit=LIMIT, code=True): """ Recursively dereferences an address into string representation, or convert the list representation of address dereferences into string representation. Arguments: value(int|list): Either the starting address to be sent to get, or the result of get (a list) limit(int): Number of valid pointers code(bool): Hint that indicates the value may be an instruction offset(int): Offset into the address to get the next pointer hard_stop(int): Value to stop on hard_end: Value to append when hard_stop is reached: null, value of hard stop, a string. Returns: A string representing pointers of each address and reference Strings format: 0x0804a10 —▸ 0x08061000 ◂— 0x41414141 """ limit = int(limit) # Get config params base_address_color = unigdb.config.get("theme.dereference_base_address") string_color = unigdb.config.get("theme.dereference_string") config_arrow_right = unigdb.config.get("theme.chain_arrow_right") # Allow results from get function to be passed to format if isinstance(value, list): chain = value else: chain = examine_mem_value(value, limit) # Set arrow separate arrow_right = ' %s ' % config_arrow_right # Colorize the chain rest = [] for link in chain: if isinstance(link, int): rest.append(Color.colorify('%#x' % link, base_address_color)) if isinstance(link, str): rest.append(Color.colorify('"{:s}"'.format(link), string_color)) # symbol = unigdb.symbol.get(link) or None # if symbol: # symbol = '%#x (%s)' % (link, symbol) # rest.append(M.get(link, symbol)) return arrow_right.join(rest)
def load(self, initial=False): """Load all the commands and functions defined by UNIGDB into GDB.""" nb_missing = 0 self.commands = [(x._cmdline_, x) for x in unigdb.commands.__commands__] # load all of the functions for function_class_name in unigdb.functions.__functions__: self.loaded_functions.append(function_class_name()) def is_loaded(x): return any(filter(lambda u: x == u[0], self.loaded_commands)) for cmd, class_name in self.commands: if is_loaded(cmd): continue try: self.loaded_commands.append((cmd, class_name, class_name())) if hasattr(class_name, "_aliases_"): aliases = getattr(class_name, "_aliases_") for alias in aliases: SelfAlias(alias, cmd) except Exception as reason: self.missing_commands[cmd] = reason nb_missing += 1 # sort by command name self.loaded_commands = sorted(self.loaded_commands, key=lambda x: x[1]._cmdline_) if initial: print( "{:s} for {:s} ready, type `{:s}' to start, `{:s}' to configure" .format(Color.greenify("UNIGDB"), get_os(), Color.colorify("self", "underline yellow"), Color.colorify("self config", "underline pink"))) ver = "{:d}.{:d}".format(sys.version_info.major, sys.version_info.minor) nb_cmds = len(self.loaded_commands) print("{:s} commands loaded for GDB {:s} using Python engine {:s}". format(Color.colorify(nb_cmds, "bold green"), Color.colorify(gdb.VERSION, "bold yellow"), Color.colorify(ver, "bold red"))) if nb_missing: message.warn( "{:s} command{} could not be loaded, run `{:s}` to know why." .format(Color.colorify(nb_missing, "bold red"), "s" if nb_missing > 1 else "", Color.colorify("self missing", "underline pink"))) return None
def do_theme(self, args: argparse.Namespace): if not args.key: for setting in sorted(self.settings): value = self.get_setting(setting) value = Color.colorify(value, value) print("{:40s}: {:s}".format(setting, value)) return None setting = args.key if not self.has_setting(setting): message.error("Invalid key") return None if not args.value: value = self.get_setting(setting) value = Color.colorify(value, value) print("{:40s}: {:s}".format(setting, value)) return None val = [x for x in args.value.split() if x in Color.colors] self.add_setting(setting, " ".join(val)) return None
def print_setting(self, plugin_name, verbose=False): res = unigdb.config.get(plugin_name, get_all=True) string_color = unigdb.config.get("theme.dereference_string") misc_color = unigdb.config.get("theme.dereference_base_address") if not res: return None _value, _desc = res _setting = Color.colorify(plugin_name, "green") _type = type(_value).__name__ if isinstance(_value, str): _value = '"{:s}"'.format(Color.colorify(_value, string_color)) else: _value = Color.colorify(_value, misc_color) print("{:s} ({:s}) = {:s}".format(_setting, _type, _value)) if verbose: print(Color.colorify("\nDescription:", "bold underline")) print("\t{:s}".format(_desc)) return None
def context_title(self, m): line_color = unigdb.config.get("theme.context_title_line") msg_color = unigdb.config.get("theme.context_title_message") if not m: print(Color.colorify(unigdb.config.HORIZONTAL_LINE * self.tty_columns, line_color)) return None trail_len = len(m) + 6 title = "" title += Color.colorify( "{:{padd}<{width}} ".format( "", width=max(self.tty_columns - trail_len, 0), padd=unigdb.config.HORIZONTAL_LINE ), line_color ) title += Color.colorify(m, msg_color) title += Color.colorify(" {:{padd}<4}".format("", padd=unigdb.config.HORIZONTAL_LINE), line_color) print(title) return None
def __load_extra_plugins(self): nb_added = -1 try: nb_inital = len(self.loaded_commands) directories = unigdb.config.get("self.extra_plugins_dir") if directories: for directory in directories.split(";"): directory = os.path.realpath(os.path.expanduser(directory)) if os.path.isdir(directory): sys.path.append(directory) for fname in os.listdir(directory): if not fname.endswith(".py"): continue fpath = "{:s}/{:s}".format(directory, fname) if os.path.isfile(fpath): gdb.execute("source {:s}".format(fpath)) nb_added = len(self.loaded_commands) - nb_inital if nb_added > 0: message.success("{:s} extra commands added from '{:s}'".format( Color.colorify(nb_added, "bold green"), Color.colorify(directory, "bold blue"))) except gdb.error as e: message.error("failed: {}".format(str(e))) return nb_added
def print_guessed_arguments(self, function_name): """When no symbol, read the current basic block and look for "interesting" instructions.""" def __get_current_block_start_address(): pc = int(unigdb.arch.CURRENT_ARCH.pc) try: block_start = gdb.block_for_pc(pc).start except RuntimeError: # if stripped, let's roll back 5 instructions block_start = disass.gdb_get_nth_previous_instruction_address(pc, 5) return block_start parameter_set = set() pc = int(unigdb.arch.CURRENT_ARCH.pc) block_start = __get_current_block_start_address() instruction_iterator = disass.capstone_disassemble function_parameters = unigdb.arch.CURRENT_ARCH.function_parameters arg_key_color = unigdb.config.get("theme.registers_register_name") insn_count = (pc - block_start) // unigdb.arch.CURRENT_ARCH.instruction_length if unigdb.arch.current == 'mips': insn_count += 1 # for branch delay slot for insn in instruction_iterator(block_start, insn_count): if not insn.operands: continue if unigdb.arch.current == 'i386': if insn.mnemonic == "push": parameter_set.add(insn.operands[0]) else: op = "$" + insn.operands[0] if op in function_parameters: parameter_set.add(op) if unigdb.arch.current == 'x86-64': # also consider extended registers extended_registers = {"$rdi": ["$edi", "$di"], "$rsi": ["$esi", "$si"], "$rdx": ["$edx", "$dx"], "$rcx": ["$ecx", "$cx"], } for exreg in extended_registers: if op in extended_registers[exreg]: parameter_set.add(exreg) # cicle end if unigdb.arch.current == 'i386': nb_argument = len(parameter_set) else: nb_argument = 0 for p in parameter_set: nb_argument = max(nb_argument, function_parameters.index(p) + 1) args = [] for i in range(nb_argument): _key, _value = unigdb.arch.CURRENT_ARCH.get_ith_parameter(i) _value = unigdb.chain.format(int(_value)) args.append("{} = {}".format(Color.colorify(_key, arg_key_color), _value)) self.context_title("arguments (guessed)") print("{} (".format(function_name)) if args: print(" " + ",\n ".join(args)) print(")") return None
def flag_register_to_human(self, val=None): return Color.colorify("No flag register", "yellow underline")