☰
OWASP MASTG 安卓逆向实践:从 Android ELF 二进制中提取调试信息与符号表
2026/10/9 1:34:02 网站建设 项目流程
  • 文档
  • 教程
  • 网络安全

【免费下载链接】mastg

The OWASP Mobile Application Security Testing Guide (MASTG) is a comprehensive manual for mobile app security testing and reverse engineering. It describes technical processes for verifying the OWASP Mobile Security Weakness Enumeration (MASWE) weaknesses, which are in alignment with the OWASP MASVS.

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

导读

在 Android 应用的逆向工程与漏洞分析中,native 层(.so动态库)往往是安全测试的关键战场,而符号与调试信息则是解读 native 代码的第一把钥匙:它们能直接暴露函数名、变量名、源文件行号,甚至还原出 JNI 桥接函数的完整签名。本文基于 OWASP Mobile Application Security Testing Guide(MASTG)的 MASTG-TECH-0140,系统讲解如何利用 radare2、objdump、nm 三套工具判断 ELF 二进制是否被 strip(剥离符号),并从中提取调试符号、导入/导出符号与 JNI 符号。读完本文,你将掌握一套不依赖任何图形界面、可复现的纯命令行符号提取工作流,能够快速判断一个 Android native 库的"可读性",为后续反汇编与动态调试打下基础。

背景:为什么符号信息对 Android 逆向如此重要

Android 的 native 代码(C/C++)被编译为 ELF 格式的动态库(.so),并由 Java 层通过System.loadLibrary在运行时加载。这些库中的符号表记录了函数与全局变量的名称、类型、绑定属性(GLOBAL/WEAK/LOCAL)以及地址信息。对于逆向分析者而言:

  • 未剥离(unstripped)的二进制保留了完整的符号表,Java_sg_vantagepoint_helloworldjni_MainActivity_stringFromJNI这类 JNI 符号可以直接告诉我们 Java 方法与 native 函数的对应关系;
  • 剥离(stripped)的二进制删除了符号表,只剩下地址和指令流,分析难度显著上升。

因此,拿到一个 APK 后,第一步往往不是直接反汇编,而是先回答三个问题:这个.so是否被 strip?它保留了哪些符号?行号信息是否还在?这正是本文要解决的核心问题。

MASTG 仓库提供了可直接用于实验的样本 Samples/Android/01_HelloWorld-JNI/HelloWord-JNI.apk,其lib/armeabi-v7a/libnative-lib.so中导出的Java_sg_vantagepoint_helloworldjni_MainActivity_stringFromJNI是贯穿全文的示例符号(该样本的完整反汇编分析见 MASTG-TECH-0018)。

方法一:radare2 符号检查与导出符号枚举

radare2(r2)是 MASTG 推荐的通用二进制分析框架,支持 Android 的 DEX、ELF(可执行文件、.so、ART)及 Java(JNI 与 Java 类)等多种格式,详见工具页 MASTG-TOOL-0028。它既能以r2交互式 shell 使用,也能通过rabin2等独立 CLI 工具完成信息提取(MASTG-TOOL-0129)。

快速判断二进制是否被 strip

在 r2 shell 中加载目标库后,执行以下命令即可一次性查看三项关键属性:

[0x0003e360]> i~stripped,linenum,lsyms linenum true lsyms true stripped false

对输出逐项解读:

  • stripped为false,表示调试符号存在,二进制未被剥离;
  • linenum为true,表示行号信息可用(即编译时保留了与源文件的对应关系);
  • lsyms为true,表示本地(局部)符号存在。

这三个字段全部来自 ELF 文件头与符号段(.symtab/.dynsym)的元信息,r2 在加载文件时即可解析,无需执行耗时的代码分析。

用is枚举导入/导出符号

r2 的is命令用于列出从 ELF 符号表解析出的导入与导出符号。先使用-A参数加载并分析示例库,再执行is:

r2 -A libnative-lib.so [0x00000e3c]> is nth paddr vaddr bind type size lib name demangled ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― 3 0x00000e78 0x00000e78 GLOBAL FUNC 16 Java_sg_vantagepoint_helloworldjni_MainActivity_stringFromJNI 4 0x00001578 0x00001578 GLOBAL FUNC 4 __aeabi_unwind_cpp_pr0 5 ---------- 0x00003004 GLOBAL NOTYPE 0 _edata 6 ---------- 0x00003004 GLOBAL NOTYPE 0 _end 7 ---------- 0x00003004 GLOBAL NOTYPE 0 __bss_start 10 0x0000157c 0x0000157c WEAK FUNC 4 __aeabi_unwind_cpp_pr1 11 0x00001580 0x00001580 WEAK FUNC 4 __aeabi_unwind_cpp_pr2 13 0x000017dc 0x000017dc GLOBAL FUNC 0 __gnu_Unwind_Restore_VFP_D ...

输出列的含义:

  • nth:符号在符号表中的序号;
  • paddr/vaddr:物理地址(文件偏移)与虚拟地址(加载后地址);
  • bind:绑定类型,GLOBAL(全局)、WEAK(弱)等;
  • type:符号类型,FUNC(函数)、NOTYPE(无类型,如段边界标记);
  • size:符号占用的字节大小;
  • name:符号名,本例中的Java_sg_vantagepoint_helloworldjni_MainActivity_stringFromJNI正是 JNI 层导出的入口函数。

注意_edata、_end、__bss_start这类 NOTYPE 符号是链接器生成的段边界标记,并非业务函数,分析时可将其与__aeabi_unwind_cpp_pr*等运行时辅助函数一并忽略。

聚焦 JNI 符号

逆向 Android 应用时,JNI 符号的价值最高——它直接揭示 Java 类与方法与 native 函数的映射。r2 支持用~管道符对命令输出做过滤,~JNI即可只保留含 "JNI" 的行:

[0x00000e3c]> is~JNI

同样的需求也可以直接在 shell 中使用rabin2 -s完成:

rabin2 -s libnative-lib.so | grep JNI

MASTG-TECH-0018 中给出了该命令在 HelloWorld-JNI 样本上的实际输出,可与 r2 内部结果互相印证:

$ rabin2 -s HelloWord-JNI/lib/armeabi-v7a/libnative-lib.so | grep -i Java 003 0x00000e78 0x00000e78 GLOBAL FUNC 16 Java_sg_vantagepoint_helloworldjni_MainActivity_stringFromJNI

提示:rabin2是 radare2 框架中的独立二进制信息提取工具,支持 ELF、Mach-O、PE、Java CLASS 等多种格式,能输出符号导入/导出、库依赖、字符串、交叉引用、入口点与架构类型等信息,输出格式可与 radare2 及其他工具对接(MASTG-TOOL-0129)。

方法二:objdump 检查调试符号

GNU binutils 中的objdump提供--syms选项,用于展示 ELF 文件的符号表。对比两个示例文件的输出,可以直观看出"有无符号"的差别:

objdump --syms libnative-lib.so libnative-lib.so: file format elf32-littlearm SYMBOL TABLE:

libnative-lib.so的符号表为空,说明该二进制已被 strip,没有任何可用的调试符号。

再看未剥离的版本:

objdump --syms libunstripped.so libunstripped.so: file format elf32-littlearm SYMBOL TABLE: 00000000 l df *ABS* 00000000 crtbegin_so.c 000315d8 l .text 00000000 $a.0 000315e8 l .text 00000000 $a.2 0003161c l .text 00000000 $a.4 000315e4 l .text 00000000 $d.1 00031614 l .text 00000000 $d.3 ...

这里l表示局部(local)符号,df表示调试文件(debug file),后面的crtbegin_so.c等源文件名直接证明调试符号(含源文件信息)仍然存在。

方法三:nm 提取符号表并对比判断剥离状态

nm是 GNU binutils 中专门显示二进制符号表(name list)的工具,MASTG 为其建立了独立的工具页 MASTG-TOOL-0003。它可以从 ELF 文件中检索符号表,并区分全局可见符号与仅存在于.symtab中的本地(static)符号。

对已剥离的库,nm直接报告无符号:

nm libnative-lib.so libnative-lib.so: no symbols

如果二进制保留符号,nm会列出全局可见的函数名与变量名;而nm -a会额外显示所有符号,包括本地(static)符号——但前提是.symtab段仍然存在。因此,比较nm与nm -a的输出差异,是判断"是否剥离了调试符号"的经典方法:

diff <(nm libnative-lib.so) <(nm -a libnative-lib.so)
  • 如果输出为空:调试符号已被剥离;
  • 如果出现带函数名或源文件引用的条目:符号仍然存在。

对未剥离库执行同样的比较,差异行会包含源文件信息,例如:

diff <(nm libunstripped.so) <(nm -a libunstripped.so) | tail 3871a31083,31086 > 00000000 a stdexcept.cpp > 00000000 a stdlib_exception.cpp > 00000000 a stdlib_stdexcept.cpp > 00000000 a stdlib_typeinfo.cpp 3875a31091 > 00000000 a string.cpp 3888a31105,31106 > 00000000 a system_error.cpp > 00000000 a thread.cpp

输出中a表示绝对符号(absolute symbol),这些*.cpp条目是 C++ 标准库的源文件引用,它们的出现说明.symtab中保留了丰富的调试符号信息。

三种方法的选型与互补

工具命令典型用途优势
radare2(i)i~stripped,linenum,lsyms一键判断剥离状态、行号、本地符号交互式,可无缝衔接后续反汇编
radare2(is)/ rabin2is/rabin2 -s枚举导入/导出符号,过滤 JNI 符号与反汇编工作流一体
objdumpobjdump --syms查看完整符号表(含局部符号)GNU binutils 自带,无需额外安装
nmnm与nm -a对比区分全局/本地符号、判断是否剥离输出简洁,便于脚本化

三者都只做静态解析,成本低、速度快,适合在开始正式反汇编之前快速"摸清"目标库的底细。radare2 的优势在于它是完整的逆向框架,拿到符号信息后可直接在同一 shell 中继续反汇编;objdump 与 nm 则适合在 shell 脚本或自动化检查中批量使用。

实战要点与仓库内延伸阅读

  • 实验样本:使用 Samples/Android/01_HelloWorld-JNI/HelloWord-JNI.apk 可完整复现本文所有命令。该 APK 的lib目录下按 ABI(armeabi、armeabi-v7a、arm64-v8a 等)分目录存放libnative-lib.so,各架构版本编译自同一份源码,功能一致;若计划后续在真机调试,建议优先选择 ARM 架构版本(详见 MASTG-TECH-0018)。
  • 符号信息与安全特性检查:符号表不仅能帮助逆向,还能用于安全测试。例如 MASTG-TEST-0044 使用rabin2 -I检查 native 库的canary(栈保护)与pic(位置无关代码)加固属性,这与符号提取属于同一类"二进制元信息审计"思路。
  • 下一步:反汇编:确认符号存在后,可在 r2 中继续使用pd/pdf查看反汇编,或进入 Visual Mode、Graph Mode 追踪代码流程(参见 MASTG-TOOL-0028 与 MASTG-TECH-0018)。

小结

判定一个 Android ELF 库的"可读性"并不需要复杂的工具链:radare2 的i与is、objdump 的--syms、nm 的-a对比,三套方案互相印证,即可完整回答"是否被 strip、保留哪些符号、是否含行号信息"这三个核心问题。掌握这一工作流,是 Android native 逆向的第一步,也是评估应用加固与混淆效果(剥离符号是最基础的缓解手段)的重要依据。

  • 文档
  • 教程
  • 网络安全

【免费下载链接】mastg

The OWASP Mobile Application Security Testing Guide (MASTG) is a comprehensive manual for mobile app security testing and reverse engineering. It describes technical processes for verifying the OWASP Mobile Security Weakness Enumeration (MASWE) weaknesses, which are in alignment with the OWASP MASVS.

项目地址:https://gitcode.com/gh_mirrors/ow/mastg
点击查看免费下载
上一篇:Kaggler数据I/O:高效处理CSV、LibSVM和HDF5格式的终极指南 🚀
下一篇:5 分钟在终端跑起 AI 编程助手:OpenCode 快速部署完整指南

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

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

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

立即咨询