def _print_context(self, uc, pc): self.register_module.registers('mem_invalid') print(utils.titlify('disasm')) self.asm_module.internal_disassemble(uc.mem_read(pc - 0x16, 0x32), pc - 0x16, pc) if self.mem_access_result is not None: val = utils.red_bold("\t0x%x" % self.mem_access_result[1]) ad = utils.green_bold("\t> 0x%x" % self.mem_access_result[0]) print(utils.titlify("memory access")) print(utils.white_bold("WRITE") + val + ad) self.hook_mem_access = None self.mem_access_result = None
def exec(self, func_name, *args): print(utils.titlify('help')) print(utils.green_bold('usage: ') + self.command_map['executors']['usage']) r = [] for key, value in self.executors_map.items(): id = value['id'] cmd_count = str(len(value['cmd_list'])) r.append([str(id), key, cmd_count]) h = [utils.white_bold_underline('id'), utils.white_bold_underline('name'), utils.white_bold_underline('commands')] print(utils.titlify('executors')) print(tabulate(r, h, tablefmt="simple"))
def dbg_hook_code(self, uc, address, size, user_data): """ Unicorn instructions hook """ try: self.current_address = address hit_soft_bp = False should_print_instruction = self.trace_instructions > 0 if self.soft_bp: self.hook_mem_access = True self.soft_bp = False hit_soft_bp = True if address != self.last_bp and \ (address in self.core_module.get_breakpoints_list() or self.has_soft_bp): if self.skip_bp_count > 0: self.skip_bp_count -= 1 else: self.breakpoint_count += 1 should_print_instruction = False uc.emu_stop() self.last_bp = address print(utils.titlify('breakpoint')) print('[' + utils.white_bold(str(self.breakpoint_count)) + ']' + ' hit ' + utils.red_bold('breakpoint') + ' at: ' + utils.green_bold(hex(address))) self._print_context(uc, address) elif address == self.last_bp: self.last_bp = 0 self.has_soft_bp = hit_soft_bp if self.current_address + size == self.exit_point: should_print_instruction = False self._print_context(uc, address) print( utils.white_bold("emulation") + " finished with " + utils.green_bold("success")) if should_print_instruction: self.asm_module.internal_disassemble( uc.mem_read(address, size), address) except KeyboardInterrupt as ex: # If stuck in an endless loop, we can exit here :). TODO: does that mean ctrl+c never works for targets? print(utils.titlify('paused')) self._print_context(uc, address) uc.emu_stop()
def list(self, func_name, *args): print(utils.titlify('mappings')) h = [ utils.white_bold_underline('path'), utils.white_bold_underline('address'), utils.white_bold_underline('length') ] print('') print(tabulate(self.mappings, h, tablefmt="simple")) print('')
def dbg_hook_mem_invalid(self, uc: Uc, access, address, size, value, userdata): """ Unicorn mem invalid hook """ if size < 2: size = self.last_mem_invalid_size self.last_mem_invalid_size = size self.register_module.registers('mem_invalid') print(utils.titlify('disasm')) start = max(0, self.pc - 0x16) self.asm_module.internal_disassemble(uc.mem_read(start, 0x32), start, address)
def registers(self, func_name, *args): print(utils.titlify('registers')) arch = self.core_instance.unicorndbg_instance.arch mode = self.core_instance.unicorndbg_instance.mode regtable = getRegStringTable(getArchString(arch, mode)) r = [] for regcode in regtable: r.append(self.reg(regtable[regcode], regcode)) h = [ utils.white_bold_underline('register'), utils.white_bold_underline('hex'), utils.white_bold_underline('decimal') ] print(tabulate(r, h, tablefmt="simple"))
def find(self, func_name, *args): where = utils.u_eval(self.core_instance, args[0]) what = bytes.fromhex(args[1]) match = re.compile(what) result = [] map_start = 0 start = 0 size = 0 mappings = self.core_instance.get_module( 'mappings_module').get_mappings() if isinstance(where, str): for map in mappings: if map[0] == where: start = int(map[1], 16) map_start = start size = map[2] else: for map in mappings: if int(map[1], 16) <= where < (int(map[1], 16) + map[2]): map_start = int(map[1], 16) start = where size = map[2] b = self.core_instance.get_emu_instance().mem_read( start, size - (map_start - start)) for match_obj in match.finditer(b): offset = match_obj.start() + map_start result.append([hex(offset)]) print(utils.titlify('find')) if len(result) == 0: print('Nothing found.') else: h = [utils.white_bold_underline('offset')] print('') print(tabulate(result, h, tablefmt="simple")) print('')
def print_command_list(self, com_obj): """ print the command list of the com_obj reference passed (could be root or even a sub_command reference) :param com_obj: command object reference :return: """ try: com_array = [] for com in com_obj: # if a short reference is present print (short) # if the command is a ref, ignore it if "ref" not in com_obj[com]: com_array.append(com) # sort the list of commands and print it com_array.sort() command_table_arr = [] for com in com_array: com_t = [utils.green_bold(com)] have_shorts = "short" in com_obj[com] if have_shorts: com_t.append(com_obj[com]["short"]) else: com_t.append('') com_t.append(self.print_usage(com_obj[com], only_get=True)) command_table_arr.append(com_t) print(utils.titlify('help')) print( tabulate(command_table_arr, [ utils.white_bold_underline('command'), utils.white_bold_underline('short'), utils.white_bold_underline('usage') ], tablefmt="simple")) except Exception as e: print(utils.error_format('print_command_list', str(e)))
def exec_command(self, command, args): """ the core method of commands exec, it tries to fetch the requested command, bind to the right context and call the associated function TODO: :param command: requested command :param args: arguments array :return: """ # save the found command and sub_command array complete_command_array = [command] try: if command == '': return if command in self.commands_map: # if we found the command but has the "ref" property, # so we need to reference to another object. Ex. short command q --references--> quit if 'ref' in self.commands_map[command]: com = self.commands_map[self.commands_map[command]['ref']] else: com = self.commands_map[command] # if we have no arguments no sub_command exist, else save the first argument last_function = False if len(args) > 0: possible_sub_command = args[0] else: possible_sub_command = None # now iterate while we have a valid sub_command, # when we don't find a valid sub_command exit and the new command will be the sub_command # save the sub_command parent prev_command = com while last_function is False: # if the sub command is a ref, catch the right command if 'ref' in com: com = prev_command['sub_commands'][com['ref']] if 'sub_commands' in com and possible_sub_command: if possible_sub_command in com['sub_commands']: prev_command = com com = com['sub_commands'][possible_sub_command] # pop the found sub_command so we can iterate on the remanings arguments complete_command_array.append(args.pop(0)) command = possible_sub_command # if there are arguments left if len(args) > 0: # take the first args (the next sub_command) possible_sub_command = args[0] else: last_function = True else: last_function = True else: last_function = True # if the sub_command is a reference to another associated sub_command if 'ref' in com: com = prev_command['sub_commands'][com['ref']] # if we have a function field just fetch the context and the function name, # bind them and call the function passing the arguments if 'function' in com: if 'args' in com['function']: args_check, args_error = utils.check_args(com['function']['args'], args) if args_check is False: raise Exception(args_error) context = self.context_map[com["function"]["context"]] funct = com["function"]["f"] call_method = getattr(context, funct) # we pass the command name (could be useful for the called function) # and possible arguments to the function call_method(command, *args) else: # if we have no method implementation of the command # print the help of the command # passing all the arguments list to help function (including the command) in a unique array self.exec_command('help', complete_command_array) else: print("command '" + command + "' not found") except Exception as e: if isinstance(e, UcError): print(utils.titlify('uc error')) print(str(e)) else: print(utils.error_format('exec_command', str(e))) self.exec_command('help', complete_command_array)
def help(self, func_name, *args): """ print the help and command usage of the requested command (and sub_command too) help command_to_get_help [sub_command_to_get_help1 sub_command_to_get_help2] :param func_name: :param args: :return: """ # we need at least 1 command to get the help if args: try: # h will keep the command dictionary iteration # c will keep the deep of the sub_command iteration h = None c = 0 prev_h = None # iterate for every command and sub_command in args for arg in args: c += 1 # keep a reference (useful for errors) of command\sub_command name command = arg # if we already fetched the first main command if h: # if we have a sub_command save the reference so we can iterate into it if "sub_commands" in h: if len(h["sub_commands"]) is not 0: # save the parent command prev_h = h h = h["sub_commands"][arg] else: raise Exception else: raise Exception # if is the first fetch of the main command just search it on the commands_map dict # and save the reference. We will start the command root from here else: # if the requested command is a "ref" to another command, just keep the right reference if "ref" in self.core_instance.commands_map[arg]: h = self.core_instance.commands_map[ self.core_instance.commands_map[arg]["ref"]] else: h = self.core_instance.commands_map[arg] # keep a reference to parent command prev_h = h if c > 0: # if the sub_command is a reference to another associated sub_command if "ref" in h: h = prev_h['sub_commands'][h['ref']] # print help and usage passing h, the command object reference print(utils.titlify(command)) print(h["help"]) self.print_usage(h) # if there are sub_commands print a list of them if "sub_commands" in h: self.print_command_list(h["sub_commands"]) except Exception as e: print(utils.error_format(func_name, str(e))) print("no help for command '" + command + "'" + ' found') # if we have no args (so no commands) just print the commands list else: self.print_command_list(self.core_instance.commands_map)
def dbg_hook_code(self, uc, address, size, user_data): """ Unicorn instructions hook """ try: # 设置当前地址 self.current_address = address # 命中软断点 hit_soft_bp = False # 打印指令? should_print_instruction = self.trace_instructions > 0 # 如果软断点 if self.soft_bp: # 内存访问hook self.hook_mem_access = True # 软断点 self.soft_bp = False # 命中软断点置位 hit_soft_bp = True # 地址不是上一个断点 and (地址在断点列表中 or 有软断点) if address != self.last_bp and \ (address in self.core_module.get_breakpoints_list() or self.has_soft_bp): # 略过断点 if self.skip_bp_count > 0: self.skip_bp_count -= 1 else: # 断点数加一 self.breakpoint_count += 1 # 应该打印指令 should_print_instruction = False # 模拟停止 uc.emu_stop() # 上一个断点 self.last_bp = address # 打印一些东西 print(utils.titlify('breakpoint')) print('[' + utils.white_bold(str(self.breakpoint_count)) + ']' + ' hit ' + utils.red_bold('breakpoint') + ' at: ' + utils.green_bold(hex(address))) self._print_context(uc, address) # 地址是上一个断点 elif address == self.last_bp: self.last_bp = 0 # 有软断点 self.has_soft_bp = hit_soft_bp if self.current_address + size == self.exit_point: # 到达退出点 should_print_instruction = False self._print_context(uc, address) print( utils.white_bold("emulation") + " finished with " + utils.green_bold("success")) if should_print_instruction: # 反汇编 self.asm_module.internal_disassemble( uc.mem_read(address, size), address) except KeyboardInterrupt as ex: # If stuck in an endless loop, we can exit here :). TODO: does that mean ctrl+c never works for targets? print(utils.titlify('paused')) self._print_context(uc, address) uc.emu_stop()
def exec_command(self, command, args): # 执行命令 """ the core method of commands exec, it tries to fetch the requested command, 执行命令核心方法,提取请求的命令 bind to the right context and call the associated function 绑定到正确的上下文中,调用相应的函数 TODO: :param command: requested command :param args: arguments array :return: """ # save the found command and sub_command array # complete_command_array 保存找到的命令和子命令的数组 complete_command_array = [command] try: # 如果是空命令直接返回 if command == '': return # 如果命令位于 commands_map if command in self.commands_map: # if we found the command but has the "ref" property, # 如果找到了命令但是有 ref(指向)属性 # so we need to reference to another object. Ex. short command q --references--> quit # 需要引用另一个实例,比如命令简称 if 'ref' in self.commands_map[command]: # 新com指向ref指向的命令 com = self.commands_map[self.commands_map[command]['ref']] else: # 否则命令就是它自己内部保存的命令 com = self.commands_map[command] # if we have no arguments no sub_command exist, else save the first argument last_function = False if len(args) > 0: # 没有子命令,子命令就是 第一个选项 args[0],可能的子命令? possible_sub_command = args[0] else: possible_sub_command = None # now iterate while we have a valid sub_command, # 当有子命令的时候遍历 # when we don't find a valid sub_command exit and the new command will be the sub_command # 当没有找到有效的子命令,退出,新的命令是sub_command # save the sub_command parent # 保存子命令的母命令 prev_command = com while last_function is False: # if the sub command is a ref, catch the right command # 如果子命令中有引用,com保存它正确命令 if 'ref' in com: com = prev_command['sub_commands'][com['ref']] if 'sub_commands' in com and possible_sub_command: # 如果possible_sub_command存在,com中有sub_commands项 if possible_sub_command in com['sub_commands']: prev_command = com # com用它里边的子命令possible_sub_command答题 com = com['sub_commands'][possible_sub_command] # pop the found sub_command so we can iterate on the remanings arguments # 完成命令数组加入 args.pop(0) complete_command_array.append(args.pop(0)) # 命令是possible_sub_command command = possible_sub_command # if there are arguments left if len(args) > 0: # take the first args (the next sub_command) possible_sub_command = args[0] else: last_function = True else: last_function = True else: last_function = True # if the sub_command is a reference to another associated sub_command # 如果 sub_command是另一个相关子命令的引用 if 'ref' in com: com = prev_command['sub_commands'][com['ref']] # if we have a function field just fetch the context and the function name, # 如果有函数域,提取它和函数名字 # bind them and call the function passing the arguments # 绑定他们,调用函数,传递参数 if 'function' in com: if 'args' in com['function']: # 检查参数 args_check, args_error = utils.check_args( com['function']['args'], args) if args_check is False: # 检查失败 raise Exception(args_error) # 函数上下文,根据context_map context = self.context_map[com["function"]["context"]] # 函数 funct = com["function"]["f"] # 调用方法,直接getattr call_method = getattr(context, funct) # we pass the command name (could be useful for the called function) # and possible arguments to the function # 直接调用这个函数 call_method(command, *args) else: # if we have no method implementation of the command # print the help of the command # passing all the arguments list to help function (including the command) in a unique array # 如果没有实现这个函数,打印帮助信息 self.exec_command('help', complete_command_array) else: # 没有找到这个命令 print("command '" + command + "' not found") except Exception as e: if isinstance(e, UcError): print(utils.titlify('uc error')) print(str(e)) else: print(utils.error_format('exec_command', str(e))) self.exec_command('help', complete_command_array)