如何去除Android NDK编译的xlib.so符号以防止逆向分析?
解决Android NDK共享库符号暴露的逆向防护方法
当然可以搞定这个问题!要去掉这些暴露函数信息的符号标签,让反汇编结果只剩纯汇编指令,你可以通过编译配置+后处理工具的组合来实现,下面是具体的操作步骤:
1. 编译阶段提前控制符号可见性
首先在编译时就减少不必要的符号导出,这能从源头降低暴露风险:
- 如果用Android.mk,添加以下配置:
# 启用模块级符号剥离 LOCAL_STRIP_MODULE := true # 隐藏默认符号,仅显式导出必要函数 LOCAL_CFLAGS += -fvisibility=hidden -fvisibility-inlines-hidden # 开启最高级优化,进一步混淆指令结构 LOCAL_CFLAGS += -O3 - 如果用CMakeLists.txt,对应配置如下:
这里的# 隐藏默认符号 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -fvisibility-inlines-hidden") # 开启O3优化 set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3") # 链接时启用符号剥离 target_link_options(xlib PRIVATE -Wl,--strip-all)-fvisibility=hidden会把所有未显式标记为可见的函数/符号设为隐藏,只有你用__attribute__((visibility("default")))声明的必要函数才会被导出,大幅减少PLT表中的符号数量。
2. 用NDK的llvm-strip工具彻底剥离符号
编译完成后,再用NDK自带的llvm-strip工具做最终的符号清理,这一步能去掉所有残留的符号信息:
# 替换成你的NDK路径和主机平台(比如linux-x86_64、darwin-x86_64等) $NDK/toolchains/llvm/prebuilt/<your-host-platform>/bin/llvm-strip --strip-all xlib.so
--strip-all参数会移除so文件中的所有符号表、调试信息以及PLT表中的符号名称,之后用objdump反汇编时,就只能看到内存地址和纯汇编指令,不会再出现<_ZNSt6__ndk113__vector_func7_some_other_text@plt>这类函数标签了。
3. 进阶:Native代码混淆(可选)
如果想要进一步提升逆向难度,可以在编译时集成Native混淆工具,比如Obfuscator-LLVM(O-LLVM),它能对汇编指令做混淆变换(比如控制流平坦化、指令替换),即使有人拿到无符号的so,也很难分析出代码逻辑。你只需要在编译时添加O-LLVM的编译参数,就能自动完成混淆。
关键注意事项
- 剥离符号后,你自己调试这个so会变得困难,所以一定要保留一份带完整符号的调试版本,交付给用户的则是剥离后的版本。
- 如果你需要导出某些函数给Java层或其他so调用,必须在代码中显式标记可见性,比如:
否则这些导出函数会被隐藏,导致调用失败。extern "C" __attribute__((visibility("default"))) void Java_com_example_MyClass_nativeFunc(JNIEnv* env, jobject thiz) { // 函数实现 }
内容的提问来源于stack exchange,提问作者pilogo




