用Unidbg在PC上跑通Android的SO:逆向Native算法环境
为什么用Unidbg逆向Android Native算法最头疼的不是算法本身,是把它从so库里抠出来单独跑。Frida hook要真机,IDA静态分析看不到运行时数据,Unidbg是个折中——在JVM里模拟ARM指令,直接调so里的函数,传参拿返回值,连真机都省了。我上周用它跑通了一个App的sign算法,记一下流程。
[*]装环境:JDK 1.8加Maven,clone unidbg仓库。README写支持JDK 11,但实际跑11会有报错,1.8最稳。
[*]定位函数:用IDA打开libxxx.so,找到目标JNI函数地址,记下偏移。
[*]写调用类:继承from UnicornContext,加载so,call函数,打印结果。
[*]补环境:so里调JNI方法(FindClass、GetStaticMethodID等)会缺,要实现这些hook。
最难的是第4步。一个商业App的sign函数通常调5到10个JNI方法,每个都要在Unidbg里模拟返回值。比如GetStringUTFChars要返回传入的字符串,GetByteArrayElements要返回一个内存指针。我那个项目调了8个JNI方法,补了3天才跑通。
跑通的标志是输入相同字符串,Unidbg输出的sign和真机hook出来的一致。不一致就是补环境补错了,最常见的是某个JNIEnv方法返回NULL导致后续逻辑短路。
代码骨架贴一下:
import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.linux.android.AndroidEmulatorBuilder;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.memory.Memory;
AndroidEmulator emulator = AndroidEmulatorBuilder.for32Bit().build();
Memory memory = emulator.getMemory();
memory.setLibraryResolver(new AndroidResolver(23));
emulator.getSyscallHook().setVerbose(false);
DalvikModule dm = emulator.loadLibrary(new File("libxxx.so"));
dm.callJNI_OnLoad(emulator);
Module module = dm.getModule();
long addr = module.base + 0x1234;
Object[] args = { "input_string" };
Object result = runAddress(emulator, addr, args, false);
System.out.println(result);
性能上Unidbg比Frida慢10倍,但胜在可重复,跑通了能直接集成到批量请求里。我的方案是Unidbg算sign,Python起50个协程并发请求,日处理200万次签名,跑了半年没崩过。
https://www.metk.cn/img/posts/unidbg_native_emulator.jpg 试了下你说的第二种方法,成功率更高,推荐。 想请教一下,你用的这个版本是哪个?我这边跑起来报错。 我这边环境是Mac,有些步骤要调整,回头补个差异说明。 这个技术本身是中性工具,关键看用途,楼主的态度挺正的。 同意楼主的判断,现在加固手段越来越多,纯手工成本太高了。 照着试了一下,第一遍没成功,发现是权限问题,建议楼主补充个提示。 楼主的排版可以再优化下,代码块用起来会更清楚。 这个思路让我想到另一个场景,回头试试能不能套用。 这篇干货,比那些只有命令没有解释的强太多了。