拿到两个AArch64安全模块时,file给出的第一印象很接近:都是64位共享库,都已经Strip,文件大小也只相差约0.36 MiB。NX、Full RELRO和BIND_NOW等基础安全项同样全部通过。
继续检查后,差异很快出现。FairGuard样本的节区表只覆盖文件的6.94%,.text仅16字节且全部为零;腾讯ACE样本的节区表覆盖率达到99.96%,还能恢复16,286条FDE记录。两份文件在常用ELF工具中的可读程度并不在一个水平线上。
本文用同一套静态口径,比较两份安全模块在ELF结构、动态符号、字符串、重定位、函数边界和局部熵分布上的表现,并给出可以复核的命令与量化结果。
样本与分析方式
| 项目 | FairGuard | 腾讯ACE |
|---|---|---|
| 游戏与版本 | 《闪烁之光》4.4.8 | 《火影忍者》1.79.79.9 |
| 安全模块 | libFairGuard.so |
libtersafe.so |
| SHA-256 | e34dd793cb58f360fc235e0375486a9a116154d664724ce5e688a46c611bf4fe |
517f1e3891e7a7c5dd8254bedcb09a5fe1d2acb0147cec757efb3a06ec5b2a10 |
| 架构 | AArch64 | AArch64 |
| 文件大小 | 5.16 MiB | 5.52 MiB |
| ELF类型 | 64位共享库 | 64位共享库 |
| Strip | 是 | 是 |
本次使用ChatGPT GPT-5.6 Sol,推理强度设置为"极高"。AI主要用于组织检查项、汇总命令输出、统计异常分布;涉及结构判断的数据,再回到ELF工具输出中复核。
基础信息可以直接通过以下命令重现:
bash
sha256sum libFairGuard.so libtersafe.so
file libFairGuard.so libtersafe.so
readelf -hW -lW -SW -sW -rW -dW libFairGuard.so
readelf -hW -lW -SW -sW -rW -dW libtersafe.so
readelf --debug-dump=frames libFairGuard.so
readelf --debug-dump=frames libtersafe.so
strings -a -n 8 libFairGuard.so
strings -a -n 8 libtersafe.so
节区覆盖率、最大无节区区间、字符串长度分档和64 KiB分块熵值,需要对上述结果继续做脚本统计。
1. ELF结构:工具能否直接建立代码地图
| 指标 | FairGuard | 腾讯ACE |
|---|---|---|
| 节区表覆盖文件比例 | 6.94% | 99.96% |
| 最大无节区描述区域 | 4,805,144字节 | 1,799字节 |
| 最大无节区区域占比 | 88.80% | 0.03% |
声明的.text大小 |
16字节 | 3,590,944字节 |
.text零字节比例 |
100% | 10.10% |
| RX段中可执行节区覆盖率 | 0.0039% | 65.74% |
FairGuard的.text只有16字节且全部为零,显然没有呈现实际代码主体。其ELF入口为0xfe00,落在节区表未描述的区域;文件内最大的无节区区间达到4,805,144字节,占比88.8%。
这种布局会直接影响IDA、Ghidra、radare2等工具的初始识别。分析者无法只依赖节区表确定代码范围,还要回到程序段、入口和加载逻辑中重新寻找有效内容。
腾讯ACE的节区表覆盖率为99.96%,.text、.rodata、.eh_frame、重定位表和版本表都能正常定位。常规工具打开文件后,更容易生成初始代码地图。
2. 符号与字符串:能留下多少定位线索
动态符号
| 指标 | FairGuard | 腾讯ACE |
|---|---|---|
| 动态符号总数 | 1,028 | 288 |
| 空名称符号 | 1,002(97.47%) | 1(0.35%) |
| 可读符号比例 | 2.24% | 99.65% |
| 可读导出接口 | 0 | 71 |
| 唯一导入函数名 | 4 | 216 |
| 4字节伪函数条目 | 999 | 2 |
| 不落在声明节区的符号 | 1,007 | 0 |
readelf一致性警告 |
10条 | 0 |
FairGuard虽然包含1,028个动态符号,但1,002个没有名称,999个函数条目的长度固定为4字节,另有1,007个符号地址与声明节区不一致。3个非空导出名称也是不可读字节序列,可读导出接口因此记为0。
腾讯ACE可以直接识别71个导出接口,包括JNI_OnLoad、tss_sdk_init、tss_sdk_encryptpacket和tss_sdk_decryptpacket等。部分名称来自公开SDK接口,但在逆向工具里仍是清晰的路标,可以沿交叉引用继续定位初始化、数据收发和加解密逻辑。
可打印字符串
| 指标 | FairGuard | 腾讯ACE |
|---|---|---|
| 长度≥8 | 427 | 4,224 |
| 长度≥16 | 27 | 1,624 |
| 长度≥32 | 12 | 370 |
.rodata可打印字符串 |
6 | 10,880 |
| 源码路径 | 0 | 6 |
明文JNI_OnLoad |
未发现 | 可见 |
为降低高熵数据随机形成短字符串带来的干扰,这里主要观察8字节以上的连续可打印ASCII内容。
腾讯ACE中长度达到16字符的字符串为1,624条,约为FairGuard的60倍,还能提取到NDK版本、Build ID及部分.cpp和LLVM编译路径。FairGuard主要保留依赖库名称与GCC 4.9编译痕迹,没有提取到可直接指向反调试、Hook或签名校验功能的明文关键词。
3. 重定位与FDE:函数边界还能恢复多少
| 指标 | FairGuard | 腾讯ACE |
|---|---|---|
| 重定位总数 | 93 | 25,380 |
| INIT/FINI目标 | 4 | 66 |
位于标准.text的INIT/FINI目标 |
0 | 66 |
| 位于无节区区域的INIT/FINI目标 | 4 | 0 |
| 可恢复FDE记录 | 0 | 16,286 |
.eh_frame零字节比例 |
100% | 32.51% |
.gcc_except_table零字节比例 |
100% | 38.33% |
FairGuard的4个构造与析构目标全部落在无节区描述区域。.eh_frame和.gcc_except_table虽然存在,内容却全部为零,readelf只能读出终止符,无法恢复有效FDE。
腾讯ACE可以恢复16,286条FDE记录。即便这些记录不包含函数名称,也能辅助逆向工具识别函数边界和栈展开关系。
重定位数量受代码规模和编译方式影响,单独比较意义有限。结合初始化入口、节区结构和FDE一起看,腾讯ACE保留了更多可被工具直接利用的交叉引用信息。
4. 熵值:整体数字低,不等于内容更透明
| 指标 | FairGuard | 腾讯ACE |
|---|---|---|
| 整体信息熵 | 4.626 | 6.456 |
| 文件零字节占比 | 54.43% | 21.89% |
| RX段中熵≥7.8的64 KiB块 | 35/83,42.17% | 4/84,4.76% |
| RX段中熵<1的64 KiB块 | 42/83,50.60% | 0/84 |
FairGuard的整体熵更低,原因是文件中存在大量零填充。若只对比整体熵值,很容易误判。
将RX段按64 KiB切分后,可以看到FairGuard同时包含大量高熵块与低熵零块。结合88.8%的无节区区域,这种分布更接近隐藏载荷、加密数据或自定义布局。腾讯ACE的数据分布较为连续,高熵分块数量也更少。
5. 基础安全项持平,量化差距来自静态信息隐藏
两份样本均通过NX Stack、GNU RELRO、BIND_NOW和Full RELRO检查,也都没有TEXTREL与RWX加载段。这部分没有拉开差距。
业内没有统一的SO加固百分制。下面采用本次专用的"静态抗分析强度"评分,将结构隐藏、信息暴露和工具可恢复程度汇总到同一张表中。总分适合快速查看,判断依据仍以原始指标为准。
| 评分维度 | 权重 | FairGuard | 腾讯ACE |
|---|---|---|---|
| ELF结构与节区隐藏 | 25 | 23 | 8 |
| 符号与接口信息隐藏 | 20 | 18 | 11 |
| 字符串与构建信息保护 | 15 | 14 | 8 |
| 初始化、重定位及FDE隐藏 | 15 | 14 | 7 |
| 数据不透明度与局部熵特征 | 15 | 13 | 9 |
| 基础ELF安全属性 | 10 | 10 | 10 |
| 总分 | 100 | 92 | 53 |
结论
在这套静态口径下,libFairGuard.so表现出更强的结构隐藏和信息收敛:实际内容没有通过常规节区完整呈现,动态符号中包含大量无名及固定长度条目,字符串、重定位和函数展开信息也更少。常规工具很难在打开文件后直接恢复有效代码地图。
libtersafe.so同样完成了Strip,基础ELF安全配置也比较完整,但整体保持标准共享库布局。符号、接口、字符串、重定位及FDE能够被常用工具较完整地提取,建立模块结构和选择后续分析入口会更直接。
这次AI辅助分析的价值主要体现在批量统计和异常筛选。GPT-5.6 Sol可以较快汇总节区覆盖率、无名符号、长字符串和FDE等数据,人仍需根据readelf等工具的原始输出复核口径与异常项。
如果要快速检查一份SO的静态抗分析程度,可以依次看五个位置:
- 节区表是否真实描述代码主体;
- 动态符号能否提供函数名和接口入口;
- 字符串中是否暴露功能名称与构建路径;
- 重定位和FDE能否帮助恢复交叉引用与函数边界;
- 局部熵分布是否与节区布局相互印证。
只看文件大小、Strip状态或单一熵值,都很难解释常用逆向工具中的实际分析阻力。