radare2 libr 架构解析:一张图看懂核心库 API 依赖关系
2026/9/20 17:25:49 网站建设 项目流程
  • 逆向工程
  • 网络安全

【免费下载链接】radare2

UNIX-like reverse engineering framework and command-line toolset

项目地址:https://gitcode.com/gh_mirrors/ra/radare2
点击查看免费下载

导读: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.hr_fs.hr_egg.hr_lang.hr_asm.hr_anal.hr_cmd.hr_cons.hr_search.hr_sign.hr_debug.hr_flag.hr_config.hr_bin.hr_hash.hr_util.h等头文件——这正是图中 core 向四方辐射出所有连线的原因。

core 还通过libr/core/p/(libr/core/p/)提供核心插件(core plugin),并在 libr/core/cplugin.c 中完成注册,其插件结构RCorePlugin定义在 r_core.h 中,包含init/fini/call生命周期回调。

2.ioplugins:读写与扩展的基石

图左侧显示io(libr/io/)直接挂在core之下,而io之下是[ lib ]pluginsio负责一切底层输入输出抽象(文件、内存、远端、调试接口等),是上层分析的数据来源。

  • 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/libgdbrlibr_javalibr_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右侧第一组是asmbinanal,这是 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 下方是diffsignhash

  • 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, vmreg, syscall, var, trace的组合,对应动态调试与运行时状态:

  • debug(libr/debug/)与bp(libr/bp/)实现调试会话与断点(db命令);
  • reg(libr/reg/)管理寄存器描述与读写;
  • syscall(libr/syscall/)提供系统调用号与名称映射(数据在libr/syscall/d/.txt中);
  • vartrace属于 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

图右下角的,_____./+._____.+内是flagsmeta,它们是所有分析结果的"命名空间与元数据"落点:

  • 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/fsasm/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_*.sobinr/下的可执行文件做导入/导出符号分析:

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中的底层地位。

五、给读者的实操建议

  1. 快速定位模块:看到某个r_xxxAPI 时,先到 libr/xxx/ 找同名目录,再到 libr/include/r_xxx.h 看接口定义;
  2. 核对依赖关系:阅读某模块时,看该模块MakefileR2DEPS,或运行perl libr/depgraph.pl dot | dot -Tpng生成当前版本的真实依赖图——doc/rgraph.md是历史快照,构建脚本才是权威;
  3. 理解扩展方式:几乎所有模块都有p/(plugin)子目录,新增指令集、文件系统、调试后端都通过插件形式接入,这正是图中plugins节点存在的意义;
  4. 从入口入手:想读源码时,优先读 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/printlang/macro则负责交互与脚本化。理解这张图,就掌握了阅读 radare2 数万行源码的第一张地图。

  • 逆向工程
  • 网络安全

【免费下载链接】radare2

UNIX-like reverse engineering framework and command-line toolset

项目地址:https://gitcode.com/gh_mirrors/ra/radare2
点击查看免费下载

相关推荐

上一篇:如何高效使用Stable Video Infinity:专业级视频修复实战指南
下一篇:Intel RealSense在Jetson Orin Nano上的设备检测问题分析与解决方案

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询