def add_fast_dict_from_all_vuln_func(self): mgr_t = FESinkFuncMgr() for func_name, xref_list in mgr_t.gen_sink_func_xref(): if not func_name in self.vuln_func_fast_dict: tag = SINK_FUNC[func_name]['tag'] print('func_name: ', func_name) print('xref_list: ', len(xref_list)) if tag == FUNC_TAG['PRINTF']: items = printf_func_analysis(func_name, xref_list) self.add_fast_dict_from_items(items) elif tag == FUNC_TAG['STRING']: items = str_func_analysis(func_name, xref_list) self.add_fast_dict_from_items(items) elif tag == FUNC_TAG['SCANF']: items = scanf_func_analysis(func_name, xref_list) self.add_fast_dict_from_items(items) elif tag == FUNC_TAG['SYSTEM']: items = system_func_analysis(func_name, xref_list) self.add_fast_dict_from_items(items) elif tag == FUNC_TAG['MEMORY']: items = mem_func_analysis(func_name, xref_list) self.add_fast_dict_from_items(items) else: FELogger.info("未支持函数%s" % func_name) else: continue
def btn_get_one_sink_func_xref(self, code=0): """ 查看某个危险函数调用地址 """ tgt_t = ida_kernwin.ask_str('', 0, '请输入要查看的危险函数名') if tgt_t in SINK_FUNC: cols = [['', 0 | ida_kernwin.Choose.CHCOL_DEC], ['函数名', 10 | ida_kernwin.Choose.CHCOL_PLAIN], ['函数地址', 10 | ida_kernwin.Choose.CHCOL_HEX]] items = [] mgr_t = FESinkFuncMgr() xref_list = mgr_t.get_one_func_xref(tgt_t) if not xref_list: FELogger.warn("未找到函数%s" % tgt_t) return tmp_list = [] for xref_addr in xref_list: data = AnalysisChooseData(vuln=0, name=tgt_t, ea=xref_addr) items.append(data) tmp_list.append(xref_addr) self.sink_func_xref_dict[tgt_t] = tmp_list chooser = AnalysisChooser(title='危险函数调用地址', cols=cols, item=items) chooser.Show() else: FELogger.warn("未支持函数")
def btn_imp_ghidra_funcs(self, code=0): """ 导入Ghidra函数列表 """ ghidra_filepath = os.path.join(os.getcwd(), 'ghidra_func_addrs.csv') ghidra_path = ida_kernwin.ask_str(ghidra_filepath, 0, '导入的Ghidra导出函数文件路径') func_addrs = list(idautils.Functions()) make_func_addrs = [] if ghidra_path and ghidra_path != '': if os.path.exists(ghidra_path): with open(ghidra_path, 'rb') as f: next(f) reader = csv.reader(f) for row in reader: addr = int(row[0].strip('\"'), 16) if ida_funcs.add_func(addr) == True: make_func_addrs.append(addr) else: if addr not in func_addrs: FELogger.info("创建函数%s失败" % hexstr(addr)) FELogger.info("Ghidra导出函数文件:%s,已导入" % ghidra_path) else: FELogger.erro("未找到Ghidra导出函数文件:%s" % ghidra_path) else: FELogger.warn("请输入Ghidra导出函数文件路径") FELogger.info("成功创建%d个新函数" % len(make_func_addrs))
def btn_del_all_vuln_bpt(self, code=0): """删除断点 所有危险函数漏洞地址""" for xref_addr_t in reduce(lambda x, y: x + y, self.vuln_func_fast_dict.values()): ida_dbg.del_bpt(xref_addr_t) FELogger.info('已删除断点:危险函数漏洞分析(全部)')
def btn_add_all_vuln_bpt(self, code=0): """添加断点 所有危险函数漏洞地址""" self.add_fast_dict_from_all_vuln_func() for xref_addr_t in reduce(lambda x, y: x + y, self.vuln_func_fast_dict.values()): ida_dbg.add_bpt(xref_addr_t, 0, idc.BPT_DEFAULT) FELogger.info('已添加断点:危险函数漏洞分析(全部)')
def btn_del_one_vuln_bpt(self, code=0): """删除断点 某个危险函数漏洞地址""" tgt_t = ida_kernwin.ask_str('', 0, '请输入危险函数名') if tgt_t in SINK_FUNC: if tgt_t in self.vuln_func_fast_dict: for xref_addr_t in self.vuln_func_fast_dict[tgt_t]: ida_dbg.del_bpt(xref_addr_t) FELogger.info("已删除断点:危险函数漏洞分析(%s)" % tgt_t) else: FELogger.warn("未支持函数")
def trace_next(self, blk, node, reg): """ 下一轮回溯 """ for ref_addr in self.get_all_ref(blk.start_ea): block = self.get_blk(ref_addr) if block: FELogger.info("基本块跳转\t"+hexstr(ref_addr)+"\t"+idc.generate_disasm_line(ref_addr, 0)) node_t = self.create_tree_node(ref_addr, prev=node) self.dfs(node_t, reg, block)
def btn_del_tmp_func_bpt(self, code=0): """删除临时函数断点""" tgt_t = ida_kernwin.ask_str('', 0, '请输入任意函数名') try: if tgt_t in self.tmp_func_dict: for xref_addr_t in self.tmp_func_dict[tgt_t]: ida_dbg.del_bpt(xref_addr_t) CUSTOM_FUNC.pop(tgt_t) FELogger.info("已删除断点:指定函数调用地址 %s" % tgt_t) except Exception: FELogger.warn("请输入函数名")
def add_tmp_func(self, info_only=False): """ 添加临时sink函数 info_only: 在添加函数信息的同时是否添加断点 """ input_str = ida_kernwin.ask_text( 0, '', "请输入任意函数名/函数地址,及各参数类型(none, int, str),可输入多行\n例如:\nstrcmp str str") try: rules = [x.strip() for x in input_str.strip().split('\n')] for rule in rules: tgt_t = rule.split(' ')[0].strip() args_rule = [x.strip() for x in rule.split(' ')[1:]] if not tgt_t in self.tmp_func_dict: if tgt_t.startswith('0x'): addr_t = int(tgt_t, 16) addr_hexstr = hexstr(addr_t) CUSTOM_FUNC[addr_hexstr] = {'args_rule': args_rule} self.tmp_func_dict[addr_hexstr] = [addr_t] if info_only == False: ida_dbg.add_bpt(addr_t, 0, idc.BPT_DEFAULT) else: for func_addr_t in idautils.Functions(): func_name_t = ida_funcs.get_func_name(func_addr_t) if func_name_t == tgt_t: CUSTOM_FUNC[func_name_t] = { 'args_rule': args_rule } self.tmp_func_dict[func_name_t] = [] for xref_addr_t in idautils.CodeRefsTo( func_addr_t, 0): self.tmp_func_dict[func_name_t].append( xref_addr_t) if info_only == False: ida_dbg.add_bpt( xref_addr_t, 0, idc.BPT_DEFAULT) else: continue break else: continue else: CUSTOM_FUNC[tgt_t] = {'args_rule': args_rule} for xref_addr_t in self.tmp_func_dict[tgt_t]: if info_only == False: ida_dbg.add_bpt(xref_addr_t, 0, idc.BPT_DEFAULT) else: continue FELogger.info("已添加断点:%s" % rule) except Exception as e: FELogger.info("输入信息有误:%s" % e)
def jump_in_hex(self): ea = self.ea if not ea or not ida_bytes.is_loaded(ea): FELogger.warn("地址错误") return widget = self.find_hex_view() if not widget: FELogger.warn("无法找到十六进制窗口") return self.jumpto_in_view(widget, ea)
def jump_in_new_window(self): ea = self.ea if not ea or not ida_bytes.is_loaded(ea): FELogger.warn("地址错误") return window_name = "D-0x%x" % ea widget = ida_kernwin.open_disasm_window(window_name) if widget: self.jumpto_in_view(widget, ea) else: FELogger.warn("创建新窗口失败")
def jump_in_disassembly(self): ea = self.ea if not ea or not ida_bytes.is_loaded(ea): FELogger.warn("地址错误") return widget = self.find_disass_view() if not widget: FELogger.warn("无法找到反汇编窗口") return self.jumpto_in_view(widget, ea)
def get_all_bpt_list(self): """ 获取所有断点的地址列表 """ bpt_list = [] bpt_num = ida_dbg.get_bpt_qty() bpt_t = ida_dbg.bpt_t() for i in range(bpt_num): if ida_dbg.getn_bpt(i, bpt_t) == True: bpt_list.append(bpt_t.ea) else: FELogger.info("获取断点失败 %d" % i) return bpt_list
def activate(self, ctx): if self.get_xdbg_hook_status(): FELogger.info('关闭调试事件记录') self.dbg_hook.unhook() else: FELogger.info('启用调试事件记录') if ida_kernwin.ask_yn(0, '是否单步调试?') == 1: self.dbg_hook.step_dbg = True else: self.dbg_hook.step_dbg = False self.dbg_hook.hook() self.set_xdbg_hook_status()
def system_func_analysis(func_name, xref_list): """ system系列函数漏洞分析 """ vuln_flag = 0 addr1 = 0 str1 = '' func_name_t = func_name xref_list_t = xref_list items = [] vuln_rule = SINK_FUNC[func_name_t]['vuln_rule'] vuln_reg = vuln_rule[0]['vuln_regs'][0] FELogger.info('检测%s漏洞' % vuln_rule[0]['vuln_type']) for xref_addr_t in xref_list_t: FELogger.info("从%s回溯来源地址%s" % (hexstr(xref_addr_t), vuln_reg)) tracer = FEArgsTracer(xref_addr_t, vuln_reg) source_addr = tracer.run() print('source_addr: ', source_addr) # 判断是否找到目标地址 if source_addr == []: FELogger.info("目标地址未找到%s" % hexstr(xref_addr_t)) vuln_flag = 1 else: for cmd_addr in source_addr: addr1 = cmd_addr # 判断字符串是否来自内存 if idc.get_operand_type(cmd_addr, 1) == ida_ua.o_mem: cmd_str = FEStrMgr.get_mem_string(cmd_addr) # 判断是否找到字符串 if cmd_str == []: FELogger.info("硬编码命令未找到%s" % hexstr(xref_addr_t)) vuln_flag = 1 else: vuln_flag = 0 str1 = cmd_str[0] else: FELogger.info("命令来自外部%s" % hexstr(xref_addr_t)) vuln_flag = 1 data = AnalysisChooseData(vuln=vuln_flag, name=func_name_t, ea=xref_addr_t, addr1=addr1, str1=str1) items.append(data) return items
def btn_import_all_bpt_addr(self, code=0): """ 导入离线断点 """ cur_workpath = os.getcwd() csv_filepath = os.path.join( cur_workpath, '%s_bpt.csv' % ida_nalt.get_root_filename()) if os.path.exists(csv_filepath): with open(csv_filepath, 'r') as f: next(f) reader = csv.reader(f) for row in reader: ida_dbg.add_bpt(int(row[0], 16), 0, idc.BPT_DEFAULT) FELogger.info("导入断点完成:%s" % csv_filepath) else: FELogger.warn("文件不存在:%s" % csv_filepath)
def btn_export_all_bpt_addr(self, code=0): """ 导出离线断点 """ cur_workpath = os.getcwd() csv_filepath = os.path.join( cur_workpath, '%s_bpt.csv' % ida_nalt.get_root_filename()) bpt_list = self.get_all_bpt_list() bpt_list = [[format(bpt, '#010x')[2:]] for bpt in bpt_list] header = ['breakpoints'] with open(csv_filepath, 'w', newline='') as f: ff = csv.writer(f) ff.writerow(header) ff.writerows(bpt_list) FELogger.info("导出断点完成:%s" % csv_filepath)
def get_after_run_info(self, args_rule): """ 获取某函数执行后的返回值 # TODO 添加参数的变化 """ runtime_info = {} args = self.get_xdbg_reg_var() rv = ida_idd.regval_t() ida_dbg.get_reg_val('PC', rv) FELogger.console('PC: %s' % hexstr(rv.ival)) arg_v = args[arm_regset.ret].ival #str_t = FEStrMgr.get_string_from_mem(arg_v) #runtime_info[arm_regset.ret] = [hexstr(arg_v), repr(str_t)] #FELogger.console('ret: %s => %s' % (hexstr(arg_v), repr(str_t))) FELogger.console('%s: %s' % (arm_regset.ret, hexstr(arg_v))) return runtime_info
def btn_dfs_test_2(self, code=0): tgt_t = ida_kernwin.ask_str('', 0, '请输入函数名') reg_t = ida_kernwin.ask_str('', 0, '请输入回溯寄存器') if (tgt_t and tgt_t != '') and (reg_t and reg_t != ''): for func_addr_t in idautils.Functions(): func_name_t = ida_funcs.get_func_name(func_addr_t) if func_name_t == tgt_t: for xref_addr_t in idautils.CodeRefsTo(func_addr_t, 0): if ida_funcs.get_func(xref_addr_t): FELogger.info("从地址%s回溯寄存器%s" % (hexstr(xref_addr_t), reg_t)) tracer = FEArgsTracer(xref_addr_t, reg_t, max_node=256) source_addr = tracer.run() print('source_addr: ', source_addr) break else: FELogger.warn("请输入函数名和寄存器")
def dfs(self, node, reg, blk): """深度优先搜索 node: 当前节点 reg: 回溯寄存器 blk: 当前基本块 """ blk_t = blk if self.get_node_nums() < self.max_node: # 避免路径爆炸 if self.push_cache_node(node['addr'], reg): # 避免重复,加快速度 cur_t, reg_t = self.trace_block(blk_t, node, reg) if reg_t: # 如果返回一个新的寄存器,开启下一轮回溯 self.trace_next(blk_t, node, reg_t) else: self.cache['addr'].add(cur_t) else: FELogger.info("该块已经回溯,取消操作") else: FELogger.info("超出最大回溯块数量")
def add_or_del_all_xref_bpt(self, is_add): if is_add == True: action = idc.add_bpt act_info = '添加' else: action = idc.del_bpt act_info = '删除' if self.sink_func_xref_dict == {}: mgr_t = FESinkFuncMgr() for func_name, xref_list in mgr_t.gen_sink_func_xref(): tmp_list = [] for xref_addr_t in xref_list: tmp_list.append(xref_addr_t) action(xref_addr_t) self.sink_func_xref_dict[func_name] = tmp_list else: for xref_addr_t in reduce(lambda x, y: x + y, self.sink_func_xref_dict.values()): action(xref_addr_t) FELogger.info('已%s断点:危险函数调用地址(全部)' % act_info)
def fix_len_args_run_info(self, args_rule, args): """ 获取定长参数函数的寄存器信息 """ run_info = {} for idx in range(len(args_rule)): str_reg = 'R%s' % idx arg_t = args_rule[idx] if arg_t == 'none': # 跳过无关的参数 continue elif arg_t == 'int': run_info[str_reg] = [hexstr(args[str_reg].ival), None] FELogger.console('%s: %s' % (str_reg, hexstr(args[str_reg].ival))) elif arg_t == 'str': arg_v = args[str_reg].ival if arg_v != 0: str_t = FEStrMgr.get_string_from_mem(arg_v) else: str_t = '' run_info[str_reg] = [hexstr(arg_v), repr(str_t)] FELogger.console('%s: %s => %s' % (str_reg, hexstr(arg_v), repr(str_t))) else: run_info[str_reg] = [hexstr(args[str_reg].ival), None] FELogger.console('%s: %s' % (str_reg, hexstr(args[str_reg].ival))) return run_info
def add_or_del_one_xref_bpt(self, is_add): if is_add == True: action = idc.add_bpt act_info = '添加' else: action = idc.del_bpt act_info = '删除' tgt_t = ida_kernwin.ask_str('', 0, '请输入危险函数名') if tgt_t in SINK_FUNC: if not tgt_t in self.sink_func_xref_dict: mgr_t = FESinkFuncMgr() xref_list = mgr_t.get_one_func_xref(tgt_t) if not xref_list: FELogger.warn("未找到函数%s" % tgt_t) return tmp_list = [] for xref_addr in xref_list: tmp_list.append(xref_addr) action(xref_addr) self.sink_func_xref_dict[tgt_t] = tmp_list else: for xref_addr_t in self.sink_func_xref_dict[tgt_t]: action(xref_addr_t) FELogger.info("已%s断点:危险函数调用地址(%s)" % (act_info, tgt_t)) else: FELogger.warn("未支持函数")
def get_before_run_info(self, args_rule): """ 获取某函数执行前的寄存器信息 """ runtime_info = {} args = self.get_xdbg_reg_var() rv = ida_idd.regval_t() ida_dbg.get_reg_val('PC', rv) FELogger.console('PC: %s' % hexstr(rv.ival)) # 判断是否包含变长参数 if args_rule[-1] == '...': runtime_info = self.var_len_args_run_info(args_rule, args) elif args_rule[-1] == 'va_list': # TODO 支持va_list参数解析,暂时同“...” runtime_info = self.var_len_args_run_info(args_rule, args) else: runtime_info = self.fix_len_args_run_info(args_rule, args) return runtime_info
def btn_add_one_vuln_bpt(self, code=0): """添加断点 某个危险函数漏洞地址""" tgt_t = ida_kernwin.ask_str('', 0, '请输入危险函数名') if tgt_t in SINK_FUNC: if not tgt_t in self.vuln_func_fast_dict: mgr_t = FESinkFuncMgr() xref_list = mgr_t.get_one_func_xref(tgt_t) tag = SINK_FUNC[tgt_t]['tag'] if not xref_list: FELogger.warn("未找到函数%s" % tgt_t) return if tag == FUNC_TAG['PRINTF']: items = printf_func_analysis(tgt_t, xref_list) self.add_fast_dict_from_items(items) elif tag == FUNC_TAG['STRING']: items = str_func_analysis(tgt_t, xref_list) self.add_fast_dict_from_items(items) elif tag == FUNC_TAG['SCANF']: items = scanf_func_analysis(tgt_t, xref_list) self.add_fast_dict_from_items(items) elif tag == FUNC_TAG['SYSTEM']: items = system_func_analysis(tgt_t, xref_list) self.add_fast_dict_from_items(items) elif tag == FUNC_TAG['MEMORY']: items = mem_func_analysis(tgt_t, xref_list) self.add_fast_dict_from_items(items) else: FELogger.info("未支持函数%s" % tgt_t) if tgt_t in self.vuln_func_fast_dict: for xref_addr_t in self.vuln_func_fast_dict[tgt_t]: ida_dbg.add_bpt(xref_addr_t, 0, idc.BPT_DEFAULT) FELogger.info('已添加断点:危险函数漏洞分析(%s)' % tgt_t) else: FELogger.warn("未支持函数")
def btn_dfs_test_1(self, code=0): addr_t = ida_kernwin.ask_str('', 0, '请输入回溯起点地址') reg_t = ida_kernwin.ask_str('', 0, '请输入回溯寄存器') if (addr_t and addr_t != '') and (reg_t and reg_t != ''): try: addr_t = int(addr_t, 16) except Exception: FELogger.warn("无效地址") return FELogger.info("从地址%s回溯寄存器%s" % (hexstr(addr_t), reg_t)) tracer = FEArgsTracer(addr_t, reg_t) source_addr = tracer.run() print('source_addr: ', source_addr) else: FELogger.warn("请输入起点地址和寄存器")
def do_export(): st = ida_auto.set_ida_state(idc.IDA_STATUS_WORK) xml = XmlExporter(1) try: try: xml.export_xml() FELogger.info("已导出IDA数据到XML") except Cancelled: ida_kernwin.hide_wait_box() FELogger.warn("已取消XML导出") except Exception as e: ida_kernwin.hide_wait_box() FELogger.warn("导出XML失败 %s" % e) finally: xml.cleanup() ida_auto.set_ida_state(st)
def check_src_reg(xref_addr_t, src_reg, siz_addr_t=0): vuln_flag = 0 addr1 = 0 str1 = '' if siz_addr_t == 0: str_siz_addr = '' else: str_siz_addr = hexstr(siz_addr_t) FELogger.info("从%s回溯来源地址%s" % (hexstr(xref_addr_t), src_reg)) src_tracer = FEArgsTracer(xref_addr_t, src_reg) src_source_addr = src_tracer.run() print('src_source_addr: ', src_source_addr) # 判断是否找到字符串来源地址 if src_source_addr == []: FELogger.info("未找到目标地址%s" % hexstr(xref_addr_t)) vuln_flag = 1 else: for src_addr in src_source_addr: addr1 = src_addr src_str = FEStrMgr.get_mem_string(src_addr) # 判断是否找到字符串 if src_str == []: FELogger.info('来源字符串未找到%s' % hexstr(xref_addr_t)) vuln_flag = 1 else: # 判断来源地址是否为内存 str1 = src_str[0] if idc.get_operand_type(src_addr, 1) != ida_ua.o_mem: vuln_flag = 1 else: vuln_flag = 0 data = AnalysisChooseData(vuln=vuln_flag, name=func_name_t, ea=xref_addr_t, addr1=addr1, str1=str1, other1=str_siz_addr) items.append(data)
def PLUGIN_ENTRY(): try: return Firmeye() except Exception as e: FELogger.erro(e.__str__())
def banner(self): FELogger.console(PLUGIN_HELP) FELogger.console(BANNER_MSG)