- 逆向工程
- 网络安全
【免费下载链接】radare2
UNIX-like reverse engineering framework and command-line toolset
导读:radare2 的功能被拆分为多个以
r_前缀命名的核心库(libr/下的 libr_*),它们之间的依赖关系决定了整个框架的构建顺序、插件机制与扩展方式。doc/rgraph.md 用一张 ASCII 关系图勾勒出这些 libr API 的相互依赖骨架。本文以该图为纲,结合仓库中的构建脚本(libr/libs.mk、libr/Makefile、libr/rules.mk)与依赖分析工具(libr/depgraph.pl、libr/symgraph.pl),逐层拆解 core、io、anal、debug、flag 等模块的职责边界与真实调用关系,读完你将对 radare2 的"分层 + 插件"架构形成完整认知,并能自行验证任意模块之间的依赖。
一、关系图总览
doc/rgraph.md的开篇即给出如下架构图(原文内容,完整保留):
+--------+ .-| config | / +--------+ +------+ +------+ +------+ +------+ | core |--| cons | | asm | | diff | +------+ | line | | bin | | sign | | \ +------+ | anal | | hash | ,_____. +----+ \ +---.--+ +--.---+ +._____.+ | io | +-------------'------/ | | +----+ | cmd, search, print |<------>| flags | | +------.-------------\ | meta | [ lib ] +----'----------+ +-`-----+ +._____.+ | .----| debug, bp, vm | | lang | | | | reg, syscall | | macro | +------'--+ | var, trace | +-------+ | plugins | +---------------+ | +-----.---+ | `---------------------------'作者在原文中特别注明这是 "Not-much-updated graph",即一张更新频率不高的历史性关系图。但正因如此,它恰好保留了 radare2 libr 层最稳定的架构骨架——图中几乎所有模块都能在当前仓库中找到对应目录,且依赖方向与构建脚本高度吻合。下面逐层解读这张图。
二、分层解读:从中央枢纽到基础支撑
1.core:一切命令的中枢
图中央是core(libr/core/),它向上承载radare2主程序(binr/radare2/radare2.c),向下依赖几乎所有其他库。这一点在头文件中体现得最为直观:libr/include/r_core.h 一口气包含了r_io.h、r_fs.h、r_egg.h、r_lang.h、r_asm.h、r_anal.h、r_cmd.h、r_cons.h、r_search.h、r_sign.h、r_debug.h、r_flag.h、r_config.h、r_bin.h、r_hash.h、r_util.h等头文件——这正是图中 core 向四方辐射出所有连线的原因。
core 还通过libr/core/p/(libr/core/p/)提供核心插件(core plugin),并在 libr/core/cplugin.c 中完成注册,其插件结构RCorePlugin定义在 r_core.h 中,包含init/fini/call生命周期回调。
2.io与plugins:读写与扩展的基石
图左侧显示io(libr/io/)直接挂在core之下,而io之下是[ lib ]与plugins。io负责一切底层输入输出抽象(文件、内存、远端、调试接口等),是上层分析的数据来源。
libr/io/p/(libr/io/p/)目录中包含 66 个.c文件,对应众多 io 插件(文件、gdb、winkd、bochs、qnx 等),它们正是图中plugins节点所指的插件体系;- 底层还会链接
shlr/(shared libraries,如 shlr/gdb/、shlr/java/、shlr/qnx/ 等),libr/Makefile 在合并libr.so时会将../shlr/gdb/lib/libgdbr、libr_java、libr_shlr一并链接进来。
3.config/cons:配置与输出的基础层
图上方是config(libr/config/),右侧是cons(libr/cons/)与line。它们属于"基础服务":
config提供全局配置项系统(RConfig、回调机制见 libr/config/callback.c);cons提供控制台输出、颜色、画布(canvas)、分页等交互能力;- 图中把
line(libr/cons/dietline.c、libr/cons/line.c)单独列出,因为它承担行编辑/提示符功能,是 r2 交互体验的基础。
4. 分析三件套:asm/bin/anal
图中core右侧第一组是asm、bin、anal,这是 radare2 的"分析核心三角":
asm(libr/asm/):汇编/反汇编抽象,依赖架构描述层arch(libr/arch/),并通过libr/asm/p/挂载 40 个左右的汇编插件;bin:二进制格式解析(ELF/PE/Mach-O 等),libr/include/r_bin.h 定义RBin相关接口;anal(libr/anal/):代码分析(函数、基本块、变量、类型、RTTI 等),其R2DEPS在 libr/anal/Makefile 中声明为r_util r_reg r_syscall r_search r_cons r_flag r_arch r_esil r_io,正好对应图中 anal 对 reg、syscall、esil、flag 等的依赖。
三者共享的依赖同样可从 libr/asm/Makefile 看到:r_syscall r_util r_esil r_muta r_flag r_cons r_reg r_arch。
5. 语义层:diff/sign/hash
图中 asm/bin/anal 下方是diff、sign、hash:
diff(代码/二进制比对,radiff2依赖 binr/radiff2/radiff2.c);sign(签名系统,核心命令z系列,见 libr/core/cmd_zign.inc.c 与 libr/anal/sign.c);hash(哈希算法,rahash2依赖 binr/rahash2/rahash2.c)。
这三者常与flag(命名地址/标签)配合工作,例如签名可以"命中"某个 flag 区域。
6. 命令与检索:cmd/search/print
图中部偏下是cmd, search, print这组,它们是 core 的"左右手":
cmd(libr/core/cmd.c 及 libr/core/cmd_*.inc.c 系列)解析并分发用户命令;search(libr/search/)提供字节/字符串/正则搜索能力;print(libr/util/r_print.h、libr/util/print.c)负责格式化输出。
7. 动态分析组:debug/bp/vm/reg/syscall/var/trace
图中左侧下方是debug, bp, vm与reg, syscall, var, trace的组合,对应动态调试与运行时状态:
debug(libr/debug/)与bp(libr/bp/)实现调试会话与断点(db命令);reg(libr/reg/)管理寄存器描述与读写;syscall(libr/syscall/)提供系统调用号与名称映射(数据在libr/syscall/d/的.txt中);var、trace属于 anal 与 debug 的产物(函数局部变量、执行轨迹),在图中的连线说明它们与调试/分析栈相互依赖。
8. 脚本与宏:lang/macro
图右侧下方是lang(libr/lang/)与macro:
lang是语言插件层(pipe、vala、dart 等,见 libr/lang/ 中的.c与.vala);macro对应命令宏((...)定义、.执行),由 libr/core/cmd_macro.inc.c 实现;- 图中 lang 指向 flags/meta 的虚线箭头,表示脚本/宏执行结果最终会写回 flag 与 meta(元数据)。
9. 数据底座:flags/meta
图右下角的,_____./+._____.+内是flags与meta,它们是所有分析结果的"命名空间与元数据"落点:
flags(libr/flag/)用RFlag维护地址↔名称映射,并支持 flag 空间(namespace)与标签(tags,见 libr/flag/tags.c);meta记录注释、类型、字符串引用等元信息,由 libr/anal/meta.c 与 libr/core/cmd_meta.inc.c 实现;- 图中 cmd/search/print 与 flags/meta 之间的
<------>双向箭头非常传神:命令与检索既读 flag/meta,又写 flag/meta。
三、源码印证:构建层级与真实依赖
1. 构建顺序即依赖顺序
libr/libs.mk 用LIBS0 ~ LIBS8定义了严格的构建层级,这与关系图的依赖方向完全一致:
LIBS0=util LIBS1=socket reg cons bp config muta syscall LIBS2=search flag esil io LIBS3=arch fs LIBS4=asm anal magic LIBS5=lang egg bin LIBS6=debug LIBS7=core LIBS8=main从下往上看:util是唯一的基础;随后是socket/reg/cons/bp/config/muta/syscall;再上是search/flag/esil/io;然后是架构层arch/fs;asm/anal/magic位于第四层;lang/egg/bin第五层;debug第六层;core第七层;main(libr/main/)最顶层。每个模块在 libr/Makefile 中按$(LIBS0) ... $(LIBS8)顺序递归构建,因此低层库绝不会反向依赖高层库。
2. R2DEPS:每个库显式声明的依赖
每个模块目录的Makefile通过R2DEPS显式声明依赖,例如:
- libr/anal/Makefile:
r_util r_reg r_syscall r_search r_cons r_flag r_arch r_esil r_io - libr/asm/Makefile:
r_syscall r_util r_esil r_muta r_flag r_cons r_reg r_arch - libr/arch/Makefile:
r_util r_reg r_esil r_muta
这些声明同时用于生成 pkg-config 文件(libr/rules.mk 的pkgcfg目标会把R2DEPS写入Requires:字段),因此pkg-config用户也能看到真实的库依赖链。
3. 合并库与符号导出
构建系统最终把各libr_*.a合并为统一的libr.a/libr.so(libr/Makefile),并设置-fvisibility=hidden只导出r_*符号。这说明图中所有模块对外呈现为统一的r_API 命名空间,符合"以 core 为枢纽、其余模块各司其职"的设计。
四、验证工具:如何自己画出并核对这张依赖图
doc/rgraph.md没有解释图的生成方式,但仓库提供了两套现成的验证脚本,可以复现、更新这张关系图。
1.depgraph.pl:从 Makefile 生成依赖图
libr/depgraph.pl 通过解析各模块Makefile中的DEPS/R2DEPS行生成图数据,支持三种输出格式:
perl depgraph.pl -h # 查看用法 perl depgraph.pl dot # 输出 Graphviz dot 格式 perl depgraph.pl gml # 输出 GML 格式 perl depgraph.pl r2 # 输出 radare2 图命令 (agn/age/agg)脚本注释给出的典型用法是:
perl depgraph.pl dot | dot -Tpng > deps.png而r2模式会输出agn(添加节点)、age(添加边)、agg(渲染图)命令序列,可直接粘贴进 radare2 的图查看器(V图形模式)中交互浏览模块依赖。
2.symgraph.pl:从二进制符号反推依赖
libr/symgraph.pl 使用rabin2对每个libr_*.so和binr/下的可执行文件做导入/导出符号分析:
rabin2 -i $1/libr_$1.so # 导入符号 (imports) rabin2 -s $1/libr_$1.so # 符号表 (symbols)最后把各库的导入、导出符号合并去重并排序:
cat $t/l/*.i $t/l/*.s $t/b/*.i | sort | uniq -c | sort -n | grep r_这样可以得到"哪个r_符号被多少个库/程序引用"的统计,从符号粒度验证依赖的真实性——比如r_util符号出现频次必然最高,对应它在LIBS0中的底层地位。
五、给读者的实操建议
- 快速定位模块:看到某个
r_xxxAPI 时,先到 libr/xxx/ 找同名目录,再到 libr/include/r_xxx.h 看接口定义; - 核对依赖关系:阅读某模块时,看该模块
Makefile的R2DEPS,或运行perl libr/depgraph.pl dot | dot -Tpng生成当前版本的真实依赖图——doc/rgraph.md是历史快照,构建脚本才是权威; - 理解扩展方式:几乎所有模块都有
p/(plugin)子目录,新增指令集、文件系统、调试后端都通过插件形式接入,这正是图中plugins节点存在的意义; - 从入口入手:想读源码时,优先读 libr/core/core.c 的
r_core_new与 binr/radare2/radare2.c,它们会依次初始化图中各模块,是理解依赖关系的"活文档"。
总而言之,doc/rgraph.md虽然简短,却精准概括了 radare2 二十年架构演进中最稳定的部分:core居中调度,io向下对接插件与底层资源,config/cons提供基础服务,asm/bin/anal完成静态分析,debug/bp/reg/syscall支撑动态调试,flags/meta沉淀一切分析结果,而cmd/search/print与lang/macro则负责交互与脚本化。理解这张图,就掌握了阅读 radare2 数万行源码的第一张地图。
- 逆向工程
- 网络安全
【免费下载链接】radare2
UNIX-like reverse engineering framework and command-line toolset
相关推荐
彻底搞懂deck.gl模块化架构:核心、图层与扩展的依赖关系全解析
彻底搞懂deck.gl模块化架构:核心、图层与扩展的依赖关系全解析 deck.gl作为WebGL2驱动的可视化框架,其模块化架构设计是实现高性能地理空间数据可视
前端数据可视化3D渲染图形学10分钟搞懂SeaTunnel源码架构:核心模块与依赖关系全解析
10分钟搞懂SeaTunnel源码架构:核心模块与依赖关系全解析 你是否在数据同步时遇到过系统卡顿、连接器不兼容、监控不到位的问题?作为下一代超高性能分布式数据
数据工程大数据批处理流处理UI-Router源码架构:核心模块与依赖关系解析
UI Router源码架构:核心模块与依赖关系解析 引言 UI Router作为AngularJS生态中最流行的路由解决方案,其源码架构设计体现了复杂单页应用
前端路由
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考