ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

ida-pro-mcp 中的 ida_gdl:IDA Pro 控制流图与调用图生成 API 全解析

ida-pro-mcp 中的 ida_gdl:IDA Pro 控制流图与调用图生成 API 全解析 逆向工程MCP 服务AI 应用【免费下载链接】ida-pro-mcpAI-powered reverse engineering assistant that bridges IDA Pro with language models through MCP.项目地址https://gitcode.com/gh_mirrors/id/ida-pro-mcp点击查看免费下载本指南以 skills/idapython/docs/ida_gdl.rst 为骨架系统讲解 IDA Pro IDAPython 中ida_gdl模块的全部能力从底层gdl_graph_t图数据结构、qflow_chart_t流程图构建器到高层 Pythonic 的FlowChart/BasicBlock封装再到.dot/.gdl文件生成与 wingraph32 图形化展示。文中还结合 ida-pro-mcp 仓库源码展示FlowChart如何被真实项目用于基本块枚举、圈复杂度计算与控制流分析帮助你直接把这套 API 用进自己的逆向工程脚本。模块定位ida_gdl到底是什么ida_gdl是 IDA Pro 提供的一组底层图绘制操作Low level graph drawing operations核心职责有两个控制流图flow chart构建把函数或地址范围切分成基本块建立块与块之间的前驱/后继pred/succ关系调用图call graph构建与输出生成简单调用图simple call chart和复杂交叉引用图complex call chart并可导出为.dotGraphviz或.gdlGDL 图描述语言文件或调用 wingraph32 图形化显示。在 ida-pro-mcp 的 IDAPython skill 中ida_gdl被列为Flow graphs流程图能力的核心模块对应的典型类型是FlowChart与BasicBlock见 skills/idapython/SKILL.md 中的模块速查表。提示官方文档建议若想以更简洁、类型提示更完善的 API 完成常见图操作可参考 IDA Domain API 的ida_domain.functions模块而ida_gdl本身则保留为底层、可完全掌控的 IDAPython 接口适合高级定制场景。流程图构建核心FlowChart与BasicBlockFlowChartPythonic 的流程图入口FlowChart(fNone, boundsNone, flags0)是官方推荐的 Python 层封装用于确定一个函数或地址范围的基本块划分f目标函数func_t。为None时使用bounds指定地址范围boundsrange_t地址范围flags流程图标志见下文 Flow chart flagssize流程图中基本块的总数refresh()刷新流程图函数被修改、重新分析后重新计算块划分可直接迭代for bb in fc: ...每次迭代返回一个BasicBlock。文档原话指出查看示例用法请参考官方示例ex_gdl_qflow_chart.py。BasicBlock基本块的统一视图BasicBlock(id, bb, fc)由FlowChart迭代产生暴露以下字段与方法成员说明id基本块编号Block IDstart_ea基本块起始地址end_ea基本块结束地址type块类型取值见fc_block_type_t枚举fcb_*系列preds()迭代前驱块列表succs()迭代后继块列表实战示例枚举函数全部基本块import idaapi from ida_gdl import FlowChart func idaapi.get_func(idaapi.get_name_ea(idaapi.BADADDR, main)) if func is None: raise RuntimeError(function main not found) fc FlowChart(func) print(ftotal blocks: {fc.size}) for bb in fc: print( fblock #{bb.id}: {bb.start_ea:x}-{bb.end_ea:x} ftype{bb.type} succs{[hex(s.start_ea) for s in bb.succs()]} )圈复杂度一张流程图能算出的关键指标利用FlowChart的前驱/后继关系可以很自然地计算函数的圈复杂度cyclomatic complexity。ida-pro-mcp 的 src/ida_pro_mcp/ida_mcp/api_composite.py 中_basic_block_info()就是这么做的fc idaapi.FlowChart(func) nodes 0 edges 0 for block in fc: nodes 1 for _ in block.succs(): edges 1 return {count: nodes, cyclomatic_complexity: edges - nodes 2}即V(G) E - N 2仅靠FlowChart迭代与block.succs()即可完成无需任何额外图算法依赖。底层流程图构建器qflow_chart_t与cancellable_graph_t当需要更底层的控制例如按地址范围建图、追加块、自定义打印时使用qflow_chart_t。它继承自cancellable_graph_t后者又继承自gdl_graph_t并提供cancelled: bool属性表示构建是否被用户中止。qflow_chart_t 关键成员title图标题strbounds整个实例的总体范围range_tpfn本实例所基于的函数func_t*flags流程图标志nproper属于指定范围内的基本块数量create(title, pfn, ea1, ea2, flags)基于函数构建流程图签名create(_title: str, _pfn: func_t *, _ea1: ea_t, _ea2: ea_t, _flags: int) - Nonecreate(title, ranges, flags)基于多地址范围rangevec_t构建流程图签名create(_title: str, ranges: const rangevec_t , _flags: int) - Noneappend_to_flowchart(ea1, ea2)向已有流程图追加一个范围由此产生FC_APPND多范围流程图refresh()刷新流程图calc_block_type(blknum)计算指定块的类型返回fc_block_type_tis_ret_block(blknum)/is_noret_block(blknum)判断块是否返回 / 是否永不返回nsucc(node)/npred(node)后继 / 前驱数量succ(node, i)/pred(node, i)取第 i 个后继 / 前驱size()块总数print_names()打印块名受FC_PRINT标志控制。官方建议常规 Python 脚本优先使用高层FlowChartqflow_chart_t仅在需要精细控制时使用。底层图数据结构gdl_graph_t、node_ordering_t、edge_tgdl_graph_t通用有向图容器gdl_graph_t是所有图构建器cancellable_graph_t、qflow_chart_t的基类提供完整的图遍历与打印接口size()/node_qty()节点数量empty()图是否为空exists(node)节点是否存在entry()/exit()图的入口 / 出口节点nsucc(node)/npred(node)后继 / 前驱数量succ(node, i)/pred(node, i)按序取后继 / 前驱nedge(node, ispred)/edge(node, i, ispred)以ispred区分前驱/后继方向的边访问get_node_label(n)取节点标签char*get_node_color(n)/get_edge_color(i, j)节点 / 边颜色bgcolor_tfront()图前端节点begin()/end()返回node_iterator支持 C 风格迭代打印族print_graph_attributes(fp)、print_node(fp, n)、print_edge(fp, i, j)、print_node_attributes(fp, n)。node_ordering_t节点排序辅助用于记录节点访问顺序接口包括clear()清空resize(n)/size()调整 / 查询容量set(node, num)为节点设定顺序号clr(node) - bool清除节点顺序号node(order) - int由顺序号取节点order(node) - int由节点取顺序号。edge_t 与 EDGE_* 边类型edge_t(x: int 0, y: int 0)表示一条边src为源节点号dst为目标节点号edgevec_t为边的容器vector。EDGE_*系列常量描述边的图论角色常量含义EDGE_NONE无类型边EDGE_TREE树边EDGE_FORWARD前向边EDGE_BACK回边后向边EDGE_CROSS交叉边EDGE_SUBGRAPH子图边块的类型体系fc_block_type_tfcb_* 常量fc_block_type_t枚举定义在 skills/idapython/docs/ida_gdl.rst 中BasicBlock.type与qflow_chart_t.calc_block_type()的返回值都来自该枚举常量含义fcb_normal普通块fcb_indjump以间接跳转结尾的块fcb_ret返回块returnfcb_cndret条件返回块fcb_noret不返回块noreturnfcb_enoret外部不返回块不属于本函数fcb_extern外部普通块fcb_error执行越过函数末尾的块错误配合两个判定函数使用is_noret_block(btype: fc_block_type_t) - bool该块是否永不返回is_ret_block(btype: fc_block_type_t) - bool该块是否返回。流程图构建标志FC_* 系列qflow_chart_t.create()与FlowChart(f, bounds, flags)的flags参数取值标志说明FC_PRINT打印块名仅被display_flow_chart()使用FC_NOEXT不计算外部块。默认情况下跳出函数的跳转目标会以单指令块的形式出现在流程图中设置该标志可阻止这类块进入流程图FC_RESERVED原FC_PREDS的保留位值 0已废弃FC_APPND多范围流程图由append_to_flowchart设置FC_CHKBREAKbuild_qflow_chart()可被用户中止FC_CALL_ENDS调用指令终止基本块call 指令作为块边界FC_NOPREDS不计算前驱列表仅保留后继关系节省内存FC_OUTLINES包含 outlined 代码配合FUNC_OUTLINE实践建议只想分析函数的“块内指令 → 调用目标”关系而无需反向追踪时可组合FC_NOPREDS跳过前驱计算需要把每个 call 指令切成独立块时使用FC_CALL_ENDS不关心跳出函数的跳转目标时用FC_NOEXT精简图规模。图生成与展示gen_* 系列函数与 CHART_* 标志ida_gdl提供三个高层“一键生成”函数它们的共同规则是gflags中若未指定CHART_GEN_DOT、CHART_GEN_GDL、CHART_WINGRAPH三者中的任何一个函数直接返回False失败时会弹出警告消息。gen_gdl 与 display_gdl最底层的输出原语gen_gdl(g: gdl_graph_t, fname: str) - None把图对象g序列化为 GDL 文件。display_gdl(fname: str) - int调用wingraph32展示 GDL 文件。grapher 的确切名称从配置文件读取由setup_graph_subsystem()完成设置。fname应指向临时文件当 wingraph32 成功显示后该输入文件会被自动删除返回值为操作系统错误码0表示成功。gen_flow_graph流程图的文件输出gen_flow_graph(filename: str, title: str, pfn, ea1, ea2, gflags: int) - boolfilename输出文件名扩展名不生效由标志决定会强制为.dot或.gdl可为Nonetitle图标题pfn要绘制的函数func_t*ea1/ea2当pfn None时用作地址范围gflags流程图构建标志 输出标志。import idaapi from ida_gdl import gen_flow_graph func idaapi.get_func(idaapi.get_name_ea(idaapi.BADADDR, main)) ok gen_flow_graph( /tmp/main_flow, # 扩展名无效最终被强制为 .dot / .gdl main flow graph, func, # 也可以传 None改用 ea1/ea2 指定范围 func.start_ea, func.end_ea, idaapi.CHART_GEN_DOT, # 只生成 Graphviz .dot 文件 ) print(generated:, ok)gen_simple_call_chart简单调用图gen_simple_call_chart(filename: str, wait: str, title: str, gflags: int) - boolwait构建过程中显示给用户的提示消息gflagsCHART_NOLIBFUNCS与流程图构建标志的组合。gen_complex_call_chart复杂交叉引用图gen_complex_call_chart(filename, wait, title, ea1, ea2, flags, recursion_depth: int -1) - boolea1/ea2地址范围flags调用图构建标志 流程图构建标志的组合recursion_depth递归深度限制默认-1表示不限制。CHART_* 输出与筛选标志标志说明CHART_PRINT_NAMES是否打印每个块的标签CHART_GEN_DOT生成.dot文件扩展名强制为.dotCHART_GEN_GDL生成.gdl文件扩展名强制为.gdlCHART_WINGRAPH调用 grapher 图形化显示CHART_NOLIBFUNCS不把库函数纳入图中CHART_REFERENCING绘制对列表中地址的引用引用方CHART_REFERENCED绘制列表中地址发出的引用被引用方CHART_RECURSIVE对新增块继续递归分析CHART_FOLLOW_DIRECTION只沿发现当前块的引用方向分析新增块的引用CHART_IGNORE_XTRN忽略外部符号引用CHART_IGNORE_DATA_BSS忽略数据段 / BSS 段引用CHART_IGNORE_LIB_TO忽略对库函数的引用CHART_IGNORE_LIB_FROM忽略来自库函数的引用CHART_PRINT_COMMENTS打印注释CHART_PRINT_DOTS在超出递归深度范围存在 xref 时打印省略点dots组合示例生成包含外部符号、递归展开、排除库函数的复杂调用图.gdl文件from ida_gdl import gen_complex_call_chart import idaapi ok gen_complex_call_chart( /tmp/callgraph, # 输出文件扩展名被强制为 .gdl building call graph..., # 构建提示消息 complex call chart, 0x401000, 0x404000, # 地址范围 idaapi.CHART_GEN_GDL | idaapi.CHART_REFERENCING | idaapi.CHART_REFERENCED | idaapi.CHART_RECURSIVE | idaapi.CHART_NOLIBFUNCS, recursion_depth3, )仓库实战印证FlowChart 在 ida-pro-mcp 中的真实用法ida-pro-mcp 在多个模块中直接消费ida_gdl.FlowChart可作为这套 API 的标准用法样板1. 函数画像基本块数量统计src/ida_pro_mcp/ida_mcp/api_analysis.py 的_profile_function()通过sum(1 for _ in idaapi.FlowChart(func))一行统计函数基本块总数并连同指令数、调用者/被调用者数量、字符串与常量引用等一起组成函数画像FuncProfileItem。2. CFG 分页导出basic_blocks 工具同文件中的basic_blocks工具tool idasync签名见 api_analysis.py把FlowChart迭代结果映射为结构化BasicBlock定义于 utils.py 的 TypedDict支持max_blocks默认 1000上限 10000与offset分页并返回cursor游标供 MCP 客户端持续拉取flowchart idaapi.FlowChart(func) for block in flowchart: all_blocks.append(BasicBlock( starthex(block.start_ea), endhex(block.end_ea), sizeblock.end_ea - block.start_ea, typeblock.type, successors[hex(succ.start_ea) for succ in block.succs()], predecessors[hex(pred.start_ea) for pred in block.preds()], ))注意这里对succs()/preds()的用法对每个后继/前驱调用.start_ea取得块起始地址正是BasicBlock迭代器的标准消费方式。3. 圈复杂度E - N 2api_composite.py 的_basic_block_info()用FlowChart统计节点数与边数block.succs()计数按edges - nodes 2计算圈复杂度用于函数复杂度评级。4. 测试侧的使用tests/binary_info.py 在收集二进制信息时同样迭代idaapi.FlowChart(func)提取main函数的基本块start/end/size/successors验证了该 API 在无人值守自动化环境下的可用性。常见问题与使用要点gen_*函数返回False多半是gflags里既没有CHART_GEN_DOT也没有CHART_GEN_GDL/CHART_WINGRAPH。三者至少要指定一个。输出扩展名不对filename的扩展名被忽略.dot/.gdl由标志强制决定请勿在文件名里自行拼接扩展名。display_gdl后文件消失这是预期行为——wingraph32 成功显示后输入临时文件会被自动删除若需要保留副本请自行另存。外部跳转块太多若流程图里出现大量不属于本函数的单指令块使用FC_NOEXT阻止外部块进入。前驱计算开销大大函数可加FC_NOPREDS跳过前驱列表此时preds()/npred()不再可用。flowchart.refresh()场景函数被 patch、重新定义或自动分析更新后调用refresh()重新计算块划分而不是重建FlowChart对象。参考资料ida_gdl 完整 API 文档本指南的原始依据IDAPython skill 总览与模块速查表仓库实际用例api_analysis.py、api_composite.py、utils.py、tests/binary_info.py赞分享逆向工程MCP 服务AI 应用【免费下载链接】ida-pro-mcpAI-powered reverse engineering assistant that bridges IDA Pro with language models through MCP.项目地址https://gitcode.com/gh_mirrors/id/ida-pro-mcp点击查看免费下载相关推荐3大突破性优化IINA如何通过FFmpeg实现macOS视频播放的极致性能3大突破性优化IINA如何通过FFmpeg实现macOS视频播放的极致性能 IINA作为macOS平台最受欢迎的开源视频播放器其核心优势在于深度集成了FFm逆向工程MCP 服务AI 应用IDA Pro 逆向工程栈帧操控指南ida_frame 模块深度解析与 ida-pro-mcp 实战IDA Pro 逆向工程栈帧操控指南ida_frame 模块深度解析与 ida pro mcp 实战 函数栈帧Function Stack Frame是逆逆向工程MCP 服务AI 应用Vibe-Trading 实战Tushare 沪深股通十大成交股hsgt_top10接口全解析与北向资金信号构建Vibe Trading 实战Tushare 沪深股通十大成交股hsgt_top10接口全解析与北向资金信号构建 本篇技术指南聚焦 Vibe Tradin逆向工程MCP 服务AI 应用上一篇iOSAppHook常见问题解决重签名失败、dylib注入错误的7种排查方法下一篇Snips NLU 数据模型与核心概念解析创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表