应用安全 --- IDA Pro 函数头批量导出

news/2025/10/15 14:03:49/文章来源:https://www.cnblogs.com/GKLBB/p/19143202

应用安全 --- IDA Pro 函数头批量导出

使用ida内置的识别方法导出

"""
IDA Pro Hex-Rays Function Header Exporter
功能:批量导出所有函数的Hex-Rays反编译函数头
"""

import idaapi
import idc
import idautils
import ida_funcs
import ida_hexrays
import ida_name
import ida_typeinf
from datetime import datetimeclass HexRaysHeaderExporter(idaapi.plugin_t):flags = idaapi.PLUGIN_UNLcomment = "导出Hex-Rays函数头"help = "批量导出所有函数的反编译函数头"wanted_name = "Hex-Rays Header Exporter"wanted_hotkey = "Ctrl-Shift-H"def init(self):# 检查Hex-Rays是否可用if not ida_hexrays.init_hexrays_plugin():idaapi.msg("[!] Hex-Rays decompiler 未安装或不可用\n")return idaapi.PLUGIN_SKIPidaapi.msg("Hex-Rays Header Exporter 已加载\n")idaapi.msg("按 Ctrl+Shift+H 导出函数头\n")return idaapi.PLUGIN_OKdef run(self, arg):exporter = HeaderExporterCore()exporter.export_all_headers()def term(self):passclass HeaderExporterCore:def __init__(self):self.headers = []self.failed = []def check_hexrays(self):"""检查Hex-Rays是否可用"""if not ida_hexrays.init_hexrays_plugin():idaapi.warning("Hex-Rays decompiler 不可用!\n请确保已安装对应架构的反编译器。")return Falsereturn Truedef get_function_header(self, func_ea):"""获取函数的反编译头"""try:# 尝试反编译cfunc = ida_hexrays.decompile(func_ea)if not cfunc:return None# 方法1: 从伪代码中提取第一行(最准确)sv = cfunc.get_pseudocode()if sv and len(sv) > 0:# 第一行通常是函数声明first_line = ida_lines.tag_remove(sv[0].line)# 清理多余空格和换行first_line = ' '.join(first_line.split())return first_line# 方法2: 从类型信息构造func_type = cfunc.typeif func_type:# 获取函数名func_name = ida_name.get_name(func_ea)# 生成函数声明declaration = ida_typeinf.print_tinfo('', 0, 0, ida_typeinf.PRTYPE_1LINE, func_type, func_name, '')return declarationreturn Noneexcept Exception as e:return Nonedef get_function_header_simple(self, func_ea):"""备用方法:使用类型信息生成函数头"""try:func_name = ida_name.get_name(func_ea)# 获取函数类型tif = ida_typeinf.tinfo_t()if not ida_typeinf.guess_tinfo(tif, func_ea):return None# 打印类型result = ida_typeinf.print_tinfo('', 0, 0, ida_typeinf.PRTYPE_1LINE, tif, func_name, '')if result:return resultreturn Noneexcept:return Nonedef export_all_headers(self):"""导出所有函数头"""if not self.check_hexrays():return# 询问导出选项choice = idaapi.ask_yn(1, "选择导出模式:\n\n""YES - 仅导出成功反编译的函数\n""NO - 同时导出失败信息\n""CANCEL - 取消")if choice == -1:returninclude_failed = (choice == 0)# 选择保存路径filepath = idaapi.ask_file(1, "*.txt", "保存函数头")if not filepath:returnidaapi.msg("\n[*] 开始导出函数头...\n")idaapi.show_wait_box("正在导出函数头...")self.headers = []self.failed = []# 获取所有函数funcs = list(idautils.Functions())total = len(funcs)for idx, func_ea in enumerate(funcs):if idx % 50 == 0:idaapi.replace_wait_box(f"进度: {idx}/{total}")idaapi.msg(f"[*] 进度: {idx}/{total}\n")func_name = ida_name.get_name(func_ea)# 尝试获取函数头header = self.get_function_header(func_ea)if header:self.headers.append({'address': func_ea,'name': func_name,'header': header})else:# 尝试备用方法header = self.get_function_header_simple(func_ea)if header:self.headers.append({'address': func_ea,'name': func_name,'header': header})else:self.failed.append({'address': func_ea,'name': func_name})idaapi.hide_wait_box()# 写入文件self.write_to_file(filepath, include_failed)# 显示结果msg = f"导出完成!\n\n"msg += f"成功: {len(self.headers)} 个函数\n"msg += f"失败: {len(self.failed)} 个函数\n"msg += f"文件: {filepath}"idaapi.info(msg)idaapi.msg(f"\n[+] {msg}\n")def write_to_file(self, filepath, include_failed):"""写入文件"""with open(filepath, 'w', encoding='utf-8') as f:# 写入文件头f.write("=" * 80 + "\n")f.write("IDA Pro Hex-Rays 函数头导出\n")f.write(f"导出时间: {datetime.now()}\n")f.write(f"二进制文件: {idaapi.get_input_file_path()}\n")f.write(f"成功导出: {len(self.headers)} 个函数\n")f.write(f"失败: {len(self.failed)} 个函数\n")f.write("=" * 80 + "\n\n")# 写入成功的函数头f.write("=" * 80 + "\n")f.write("函数声明列表\n")f.write("=" * 80 + "\n\n")for item in self.headers:# 格式: 地址 | 函数头f.write(f"// Address: 0x{item['address']:X}\n")f.write(f"{item['header']}\n\n")# 如果需要,写入失败的函数if include_failed and self.failed:f.write("\n" + "=" * 80 + "\n")f.write("反编译失败的函数\n")f.write("=" * 80 + "\n\n")for item in self.failed:f.write(f"0x{item['address']:X} - {item['name']}\n")def PLUGIN_ENTRY():return HexRaysHeaderExporter()# 独立运行
if __name__ == "__main__":exporter = HeaderExporterCore()exporter.export_all_headers()

 

自己实现的函数参数头导出

"""
IDA Pro Function Parameter Analyzer (兼容版本)
修复了 get_func_flags 的兼容性问题
"""

import idaapi
import idc
import idautils
import ida_funcs
import ida_typeinf
import ida_name
import json
import csv
from datetime import datetimeclass FunctionParamAnalyzer(idaapi.plugin_t):flags = idaapi.PLUGIN_UNLcomment = "批量分析函数参数并导出"help = "分析所有函数的参数个数和类型"wanted_name = "Function Parameter Analyzer"wanted_hotkey = "Ctrl-Shift-P"def init(self):idaapi.msg("Function Parameter Analyzer 已加载\n")idaapi.msg("按 Ctrl+Shift+P 启动分析\n")return idaapi.PLUGIN_OKdef run(self, arg):analyzer = ParamAnalyzerCore()analyzer.show_menu()def term(self):passclass ParamAnalyzerCore:def __init__(self):self.functions_data = []def show_menu(self):"""显示操作菜单"""choice = idaapi.ask_yn(1, "函数参数分析器\n\n""YES - 导出为JSON\n""NO - 导出为CSV\n""CANCEL - 导出为TXT")if choice == -1:export_type = "txt"elif choice == 0:export_type = "csv"else:export_type = "json"self.analyze_all_functions()self.export_results(export_type)def analyze_all_functions(self):"""分析所有函数"""idaapi.msg("\n[*] 开始分析函数参数...\n")self.functions_data = []func_count = 0for func_ea in idautils.Functions():func_count += 1current = 0for func_ea in idautils.Functions():current += 1if current % 100 == 0:idaapi.msg(f"[*] 进度: {current}/{func_count}\n")func_info = self.analyze_function(func_ea)if func_info:self.functions_data.append(func_info)idaapi.msg(f"[+] 分析完成!共分析 {len(self.functions_data)} 个函数\n")def get_function_flags(self, func_ea, func_obj):"""获取函数标志(兼容多版本)"""try:# 方法1: 通过func对象if func_obj and hasattr(func_obj, 'flags'):return func_obj.flagsexcept:passtry:# 方法2: 使用idcflags = idc.get_func_attr(func_ea, idc.FUNCATTR_FLAGS)if flags is not None and flags != idc.BADADDR:return flagsexcept:passtry:# 方法3: 使用ida_funcs (老版本)if hasattr(ida_funcs, 'get_func_flags'):return ida_funcs.get_func_flags(func_ea)except:passreturn 0def is_library_function(self, func_ea, func_obj):"""判断是否为库函数(兼容多版本)"""try:flags = self.get_function_flags(func_ea, func_obj)if flags:return (flags & ida_funcs.FUNC_LIB) != 0except:pass# 备用方法:通过函数名判断try:func_name = ida_name.get_name(func_ea)# 常见库函数前缀lib_prefixes = ['_', 'j_', '__', 'std::', 'strcpy', 'strcmp', 'malloc', 'free', 'printf', 'scanf']for prefix in lib_prefixes:if func_name.startswith(prefix):return Trueexcept:passreturn Falsedef analyze_function(self, func_ea):"""分析单个函数"""try:func_name = ida_name.get_name(func_ea)if not func_name:func_name = f"sub_{func_ea:X}"# 获取函数对象func = ida_funcs.get_func(func_ea)if not func:return None# 获取函数类型信息tif = ida_typeinf.tinfo_t()has_tif = ida_typeinf.guess_tinfo(tif, func_ea)func_data = {'address': f"0x{func_ea:X}",'name': func_name,'param_count': 0,'params': [],'return_type': 'unknown','calling_convention': 'unknown','is_library': self.is_library_function(func_ea, func)}# 如果有类型信息if has_tif and tif.is_func():func_details = ida_typeinf.func_type_data_t()tif.get_func_details(func_details)# 参数数量func_data['param_count'] = func_details.size()# 调用约定cc = func_details.cccc_map = {ida_typeinf.CM_CC_CDECL: '__cdecl',ida_typeinf.CM_CC_STDCALL: '__stdcall',ida_typeinf.CM_CC_FASTCALL: '__fastcall',ida_typeinf.CM_CC_THISCALL: '__thiscall',}func_data['calling_convention'] = cc_map.get(cc, 'unknown')# 返回类型ret_type = func_details.rettypefunc_data['return_type'] = str(ret_type)# 参数详情for i in range(func_details.size()):param = func_details[i]param_info = {'index': i,'name': param.name if param.name else f"arg_{i}",'type': str(param.type),'size': param.type.get_size()}func_data['params'].append(param_info)else:# 尝试从栈帧分析参数func_data['param_count'] = self.estimate_param_count(func_ea)return func_dataexcept Exception as e:# 静默处理错误,避免大量输出return Nonedef estimate_param_count(self, func_ea):"""估算参数数量(当没有类型信息时)"""try:frame = ida_funcs.get_frame(func_ea)if not frame:return 0param_count = 0for member in idautils.StructMembers(frame.id):offset, name, size = memberif offset > 0 and offset < 0x100:param_count += 1return param_countexcept:return 0def export_results(self, export_type):"""导出结果"""if not self.functions_data:idaapi.warning("没有可导出的数据!")return# 选择保存路径filepath = idaapi.ask_file(1, f"*.{export_type}", f"保存为 {export_type.upper()}")if not filepath:idaapi.msg("[!] 取消导出\n")returntry:if export_type == "json":self.export_json(filepath)elif export_type == "csv":self.export_csv(filepath)elif export_type == "txt":self.export_txt(filepath)idaapi.msg(f"[+] 成功导出到: {filepath}\n")idaapi.info(f"分析结果已导出到:\n{filepath}\n\n共 {len(self.functions_data)} 个函数")except Exception as e:idaapi.warning(f"导出失败: {str(e)}")def export_json(self, filepath):"""导出为JSON格式"""output = {'analysis_time': datetime.now().isoformat(),'binary': idaapi.get_input_file_path(),'total_functions': len(self.functions_data),'functions': self.functions_data}with open(filepath, 'w', encoding='utf-8') as f:json.dump(output, f, indent=2, ensure_ascii=False)def export_csv(self, filepath):"""导出为CSV格式"""with open(filepath, 'w', newline='', encoding='utf-8') as f:writer = csv.writer(f)writer.writerow(['Address', 'Function Name', 'Param Count', 'Return Type', 'Calling Convention', 'Parameters', 'Is Library'])for func in self.functions_data:params_str = '; '.join([f"{p['name']}:{p['type']}" for p in func['params']]) if func['params'] else 'N/A'writer.writerow([func['address'],func['name'],func['param_count'],func['return_type'],func['calling_convention'],params_str,func['is_library']])def export_txt(self, filepath):"""导出为TXT格式"""with open(filepath, 'w', encoding='utf-8') as f:f.write("=" * 80 + "\n")f.write("函数参数分析报告\n")f.write(f"分析时间: {datetime.now()}\n")f.write(f"二进制文件: {idaapi.get_input_file_path()}\n")f.write(f"函数总数: {len(self.functions_data)}\n")f.write("=" * 80 + "\n\n")for func in self.functions_data:f.write(f"函数: {func['name']}\n")f.write(f"  地址: {func['address']}\n")f.write(f"  参数数量: {func['param_count']}\n")f.write(f"  返回类型: {func['return_type']}\n")f.write(f"  调用约定: {func['calling_convention']}\n")f.write(f"  库函数: {'是' if func['is_library'] else '否'}\n")if func['params']:f.write("  参数列表:\n")for p in func['params']:f.write(f"    [{p['index']}] {p['name']}: {p['type']} (size: {p['size']})\n")else:f.write("  参数列表: 无类型信息\n")f.write("\n" + "-" * 80 + "\n\n")def PLUGIN_ENTRY():return FunctionParamAnalyzer()# 独立运行
if __name__ == "__main__":analyzer = ParamAnalyzerCore()analyzer.show_menu()

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/937492.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2025年液压阀块厂家最新推荐排行榜,液压阀块加工,阀块零件机加工,液压阀加工,各种液压阀块专业制造商实力解析

2025年液压阀块厂家最新推荐排行榜,液压阀块加工,阀块零件机加工,液压阀加工,各种液压阀块专业制造商实力解析液压传动系统作为现代工业装备的核心组成部分,其性能优劣直接影响整个设备的运行效率与可靠性。在液压…

线程的状态对比:等待、驻留、监视

目录线程的状态对比:等待、驻留、监视等待(waiting)和监视(blocked)的区别等待(waiting)和监视(blocked)都算是阻塞吗?线程池没有任务来时,所有核心线程会是等待(waiting)状态?不同类型的等待总结等待(…

‌Keepalived‌是一个轻量级的高可用解决方案

‌Keepalived‌是一个轻量级的高可用解决方案回到顶部 什么是keepalived? ‌Keepalived‌是一个轻量级的高可用解决方案,主要用于Linux系统。它的主要功能是通过虚拟路由冗余协议(VRRP)实现高可用性,确保服务的持…

[论文阅读] AI + 软件工程(Debug)| 告别 “猜 bug”:TreeMind 用 LLM+MCTS 破解 Android 不完整报告复现难题 - 实践

[论文阅读] AI + 软件工程(Debug)| 告别 “猜 bug”:TreeMind 用 LLM+MCTS 破解 Android 不完整报告复现难题 - 实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !importa…

2025 年上海金蝶软件代理推荐榜:上海金蝶精斗云代理商聚焦数字化适配,这家核心代理商值得选

随着企业数字化转型进入深水区,小微企业对轻量化云服务的需求、中大型企业对全流程 ERP 系统的诉求持续攀升,金蝶软件作为国内企业管理软件领域的领军品牌,其代理商的选择成为企业数字化落地的关键一环。2025 年,市…

2025年法兰保护罩厂家最新推荐排行榜:管道法兰保护罩,设备法兰保护罩,耐腐蚀法兰保护罩,定制法兰保护罩公司推荐

2025年法兰保护罩厂家最新推荐排行榜:管道法兰保护罩,设备法兰保护罩,耐腐蚀法兰保护罩,定制法兰保护罩公司推荐行业背景与发展趋势在工业设备维护领域,法兰保护罩作为关键的防护部件,正发挥着日益重要的作用。随…

曝光骗子游小龙被多个用户举报QQ3595441998,骗取订金、不发货

曝光骗子游小龙被多个用户举报QQ3595441998,骗取订金、不发货曝光骗子游小龙被多个用户举报QQ3595441998,骗取订金、不发货--------------------------------------骗子实名: 游小龙 (深圳) 手机: 13243884907…

栈的基本函数

include include<stdlib.h> define MaxSize using namespace std; typedef int ElemType; typedef struct {ElemType data[MaxSize];int top; }SqStack;void InitSqStack(SqStack *&s) {s=(SqStack *)malloc…

软件开发初学

1 SQL基础 1.1 数据类型 1.1.1 定义 数据:是一个信息集合,以某种数据类型保存在数据库里。数据包括姓名、数字、货币、文本、图形、小数、计算、统计等,几乎涵盖能够想象到的任何东西。 数据可以保存为大写、小写或大…

DevExpress WinForms v25.2新功能预览 - 报表组件方面的全新升级

DevExpress WinForms v25.2新功能预览 - 报表组件方面的全新升级DevExpress WinForms 拥有180+组件和UI库,能为Windows Forms平台创建具有影响力的业务解决方案。DevExpress WinForms能完美构建流畅、美观且易于使用的…

2025年振动电机厂家最新权威推荐榜:高频/防爆/低噪声/卧式/直流/节能/侧板式/三段式全系列深度解析与选购指南

2025年振动电机厂家最新权威推荐榜:高频/防爆/低噪声/卧式/直流/节能/侧板式/三段式全系列深度解析与选购指南行业背景与发展趋势振动电机作为工业生产中不可或缺的核心动力设备,其技术发展与制造业升级息息相关。近…

测试面试官亲述:打动我的不是技能,而是这种思维

请记住,我手中的Pass卡,永远留给那些手握船桨,更懂得看罗盘的航海家。那个让我“心头一亮”的瞬间 大家好,我是一名在互联网大厂做了近8年的测试开发工程师,也作为面试官参与了上百场测试岗位的招聘。 我看过太多…

分布式架构下的信息一致性、幂等性与缓存设计实战:以库存下单为例(Cache-Aside、分布式锁、幂等键)

分布式架构下的信息一致性、幂等性与缓存设计实战:以库存下单为例(Cache-Aside、分布式锁、幂等键)2025-10-15 13:51 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: norma…

大数据分析之MySQL学习1

学习内容: 一、SQL 语言分类DQL(数据查询语言):用于数据查询,包含SELECT语句,可结合FROM(表或视图)、WHERE(查询条件)等进行字段、表或视图的查询。 DML(数据操作语言):用于数据操作,包含INSERT(插入)…

实用指南:开源 | 充电桩 运维 管理平台(IoT+运维工单平台)功能清单 - 慧知开源充电桩平台

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

2025年GEO(AI搜索优化)源头厂家终极口碑推荐榜

摘要 随着AI技术的快速发展,GEO(AI搜索优化)行业在2025年迎来爆发式增长,企业对于精准、高效的搜索优化需求激增。本文基于市场调研和用户反馈,为您呈现2025年GEO源头厂家排名榜单,帮助加盟商和企业快速选择可靠…

2025年GEO(AI搜索优化)源头厂家Top10权威推荐榜

摘要 随着人工智能技术的迅猛发展,GEO(AI搜索优化)在2025年成为企业提升在线可见性和营销效率的核心工具。行业数据显示,AI搜索优化市场年增长率达30%,企业通过优化技术可实现搜索曝光量提升200%以上。本文基于市…

2025 年丝杆升降机厂家行业推荐榜:螺旋丝杆升降机/蜗杆丝杆升降机/蜗轮丝杆升降机/聚焦精准传动需求,德州德特机械设备有限公司成优选

随着制造业自动化、智能化升级加速,丝杆升降机作为实现精准传动、负载控制的核心部件,应用场景已从传统重工业逐步拓展至机械制造、自动化生产线、物流仓储设备、新能源装备等多个领域,2025 年市场需求预计持续增长…

073_尚硅谷_其它进制转二进制

073_尚硅谷_其它进制转二进制1.八进制转换成二进制2.十六进制转换成二进制

深度解读:2025中国太阳能板TOP10榜单背后的格局颠覆与逻辑

摘要 随着全球能源转型加速,太阳能板行业在2025年迎来爆发式增长,行业规模预计突破5000亿元。面对市场上数百家太阳能板制造商,如何选择可靠供应商成为行业痛点。本文基于技术参数、用户口碑、服务能力等维度,为您…