IDA Pro逆向so库:从JNI导出到反编译看加密逻辑
逆向系列继续,这次讲 Native 层。App 的关键逻辑如果放在 so 库里,Java 层 hook 搞不定,得用 IDA Pro 静态分析。一、准备工作
[*]IDA Pro 7.7+(支持 ARM64 反编译)
[*]目标 so 文件:从 APK 里解压 lib/arm64-v8a/ 目录下的 .so 文件
[*]可选:Frida 用于动态调试辅助验证
二、基本流程
[*]用 apktool 解包 APK,拿到 lib 目录下的 so 文件
[*]用 IDA 打开 so 文件,选 ARM64(或 ARM32 取决于目标架构)
[*]等 IDA 完成初始分析
[*]找到 JNI 导出函数(函数名以 Java_ 开头的)
[*]反编译看逻辑
[*]关键函数交叉验证
三、找关键函数
JNI 函数命名有规律:
Java_com_target_NativeUtil_encrypt
对应 Java 代码:
package com.target;
class NativeUtil {
native String encrypt(String input);
}
在 IDA 的 Exports 标签页搜索 "Java_",能看到所有 JNI 导出函数。双击进入看反编译结果。
四、看反编译代码
按 F5 切换到反编译视图(C 伪代码)。比如看到:
int __fastcall Java_com_target_NativeUtil_encrypt(
JNIEnv *env, jobject thiz, jstring input)
{
const char *str = (*env)->GetStringUTFChars(env, input, 0);
// 一堆位运算和异或
int result = str ^ 0x37;
result = (result << 3) | (result >> 5);
// ...
(*env)->ReleaseStringUTFChars(env, input, str);
return result;
}
看到异或(^)、移位(<< >>)、查表操作,基本就是加密逻辑。把伪代码翻译成 Python 就能验证。
五、常见技巧
[*]字符串搜索:Shift+F12 打开字符串窗口,搜关键 URL、错误信息、密钥常量
[*]交叉引用:在变量上按 X 看谁引用了它,顺藤摸瓜找到调用链
[*]动态调试:IDA 可以 attach 到 Android 进程,在 so 里下断点单步调试
[*]Frida 配合:用 Frida hook native 函数看输入输出,跟 IDA 的静态分析互相验证
六、反调试绕过
很多 so 会检测调试器:
[*]检测 ptrace:hook ptrace 返回 0
[*]检测 TracerPid:hook /proc/pid/status 的读取
[*]检测时间差:在关键函数前后读时钟,差值大就认为是调试
绕过思路:找到检测函数,用 Frida 在运行时 patch 返回值,或者直接在 IDA 里改 so 二进制(NOP 掉检测代码)。
七、实战要点
[*]IDA 反编译不完美,复杂函数会出乱码,结合汇编看
[*]so 可能有壳或 VM 保护,先脱壳再分析
[*]ARM 汇编看不懂的话,重点认 LDR/STR(读写内存)、BL/B(跳转)、CMP(比较)这几个指令
[*]加密函数的特征:大量异或、查表、循环移位
https://www.metk.cn/img/posts/reverse_ida.jpg
Native 逆向是硬骨头,但思路跟 Java 层一样:找到关键函数 → 看逻辑 → 验证。只是工具从 jadx 换成了 IDA,门槛高一些。 有个坑提醒,不同厂商ROM差异很大,通用性没有想象中那么强。 感谢分享,之前一直卡在这个点,看完豁然开朗。 步骤写得很清楚,跟着走了一遍,卡在第二步的环境配置上,后来装了老版本才好。 我这边环境是Mac,有些步骤要调整,回头补个差异说明。 照着试了一下,第一遍没成功,发现是权限问题,建议楼主补充个提示。 同求后续,想知道绕过之后怎么稳定保持,重签名这块一直搞不定。 这个思路让我想到另一个场景,回头试试能不能套用。 这个流程我在真机上验证过,确实可行,注意备份就行。 楼主有没有遇到过反调试?我这边一挂调试器就直接退出。