You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何去除Android NDK .so文件中的符号?解决nm检测异常问题

如何去除Android .so文件中嵌入的硬编码符号

从你的命令输出能看出来,这些符号并不是存放在ELF的符号表(.symtab.dynsym)里的——这就是为什么nm检测不到符号,strip也毫无作用的原因。你用strings看到的符号,其实是硬编码在代码段(比如.text)里的字符串常量,大概率是编译时编译器保留的名字(比如C++名字修饰后的函数名,可能用于异常信息、运行时类型识别(RTTI)或者日志输出)。

第一步:确认符号的存储位置

先验证这个判断,用Android NDK里的readelfobjdump工具:

# 查看.so的段信息,确认符号是否在.text或其他非符号表段
arm-linux-androideabi-readelf -S libMeow.so

# 反汇编代码段,搜索目标符号,看是否作为字符串嵌入
arm-linux-androideabi-objdump -d libMeow.so | grep _ZN11SecretClass14SecretFunctionERKS_

如果输出里能看到这个符号出现在指令流旁边的字符串注释里,那就能确定是硬编码的字符串了。

第二步:去除这些符号的方法

方法1:从编译阶段彻底避免生成这类符号

这是最稳妥的方式,从根源解决问题:

  • 关闭RTTI和异常:如果你的C++代码不需要运行时类型识别和异常处理,编译时添加-fno-rtti-fno-exceptions选项,编译器就不会生成包含类/函数名的字符串常量。
  • 启用字符串混淆:使用支持代码混淆的编译工具,比如O-LLVM(Obfuscated LLVM),它可以将字符串常量替换为加密后的内容,运行时再解密,避免明文符号暴露。
  • 自定义名字修饰:对于C代码,用extern "C"包裹不需要C名字修饰的函数,或者手动修改类/函数名,减少敏感符号的出现。

方法2:对已编译的.so文件进行二进制替换

如果已经拿到编译好的.so,只能手动处理,但要注意必须保持字符串长度一致,否则会破坏二进制结构导致程序崩溃:

  1. 用十六进制编辑器打开libMeow.so,找到目标符号字符串(比如_ZN11SecretClass14SecretFunctionERKS_)。
  2. 用等长度的无意义字符替换(比如用XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,长度要和原符号完全相同)。
  3. 批量替换所有类似的符号,完成后保存文件,记得测试.so是否还能正常加载运行。

也可以用脚本自动化这个过程,比如用sed处理二进制文件(注意指定二进制模式):

# 替换目标符号为等长度的X,注意替换后的字符串长度必须和原符号一致
arm-linux-androideabi-sed -i 's/_ZN11SecretClass14SecretFunctionERKS_/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/' libMeow.so

提示:替换前一定要备份原文件,并且替换后必须测试.so的可用性,任何长度变化都会导致程序崩溃。

为什么strip和nm没用?

最后补充解释下:nm只读取ELF文件的符号表(.symtab用于调试符号,.dynsym用于导出动态符号),如果符号不是存放在这些段里,nm就检测不到。而strip的作用是移除符号表中的调试符号和未使用的动态符号,对嵌入在代码段里的硬编码字符串完全没有影响。

内容的提问来源于stack exchange,提问作者Myria

火山引擎 最新活动