爬⾍⼯程师的unidbg⼊门教程
现在很多的app使⽤了so加密,以后会越来越多。爬⾍⼯程师可能会直接逆向app,看java代码,完成java层的算法破解,但是如果遇到so该怎么办呢?可能你会直接破解so,但是真的会有很多爬⾍⼯程师会去并且会破解so吗?有时候我们可以不⽤破解so,利⽤很多⼤佬写好的轮⼦即可完成so的调⽤。
说到调⽤,就有很多⽅法了,⽐如⽤frida的rpc、xposed+andserver、再者就是unicorn+web框架等等,今天要说的并不是这些,⽽是unidbg,这框架有什么好的地⽅呢?看看介绍。
介绍(来⾃逸飞)
unidbg 是⼀个基于 unicorn 的逆向⼯具,可以⿊盒调⽤安卓和 iOS 中的 so ⽂件。unidbg 是⼀个标准的 java 项⽬。
由于现在的⼤多数 app 把签名算法已经放到了 so ⽂件中,所以要想破解签名算法,必须能够破解 so ⽂件。但是我们知道,C++ 的逆向远⽐ Java 的逆向要难得多了,所以好多时候是没法破解的,那么这个时候还可以采⽤ hook 的⽅法,直接读取程序中算出来的签名,但是这样的话,需要实际运⾏这个应⽤,需要模拟器或者真机,效率⼜不是很⾼。
unidbg 就是⼀个很巧妙地解决⽅案,他不需要直接运⾏ app,也⽆需逆向 so ⽂件,⽽是通过在 app 中
到对应的 JNI 接⼝,然后⽤unicorn 引擎直接执⾏这个 so ⽂件,所以效率也⽐较⾼。
这⾥重要的是⽬前利⽤unidbg+springboot做成了web服务。
⾷⽤
上个代码看着⽐较⽅便,代码中有很多注释
public class du extends AbstractJni {
//ARM模拟器
private final ARMEmulator emulator;
//vm
private final VM vm;
//载⼊的模块
private final Module module;
private final DvmClass TTEncryptUtils;
//初始化
public du() throws IOException {
//创建app进程,这⾥其实可以不⽤写的,我这⾥是随便写的,使⽤app本⾝的进程就可以绕过进程检测
emulator = new AndroidARMEmulator("com.du.du");
Memory memory = Memory();
//作者⽀持19和23两个sdk
memory.setLibraryResolver(new AndroidResolver(23));
memory.setCallInitFunction();
//创建DalvikVM,利⽤apk本⾝,可以为null
/
/如果⽤apk⽂件加载so的话,会⾃动处理签名⽅⾯的jni,具体可看AbstractJni,利⽤apk加载的好处,
//        vm = ateDalvikVM(new File("src/test/resources/du/du4160.apk"));
我这⾥没有⽤到apk,主要是没有检测其他因素。
vm = ateDalvikVM(null);
//加载so,使⽤armv8-64速度会快很多,这⾥是so的⽂件路径,其实也可以利⽤apk⾃⾝的。
DalvikModule dm = vm.loadLibrary(new File("src/test/resources/du/libJNIEncrypt.so"), false);
//调⽤jni
dm.callJNI_OnLoad(emulator);
module = dm.getModule();
//加载so的那个类
TTEncryptUtils = vm.resolveClass("com/duapp/aesjni/AESEncrypt");
}
//关闭模拟器
private void destroy() throws IOException {
emulator.close();
System.out.println("destroy");
}
public static void main(String[] args) throws IOException {
du t = new du();
t.destroy();
}
private String encodeByte() {
//调试
// 这⾥还⽀持gdb调试,
//emulator.attach(DebuggerType.GDB_SERVER);
//附加调试器
//        emulator.attach(DebuggerType.SIMPLE);
//        aceCode();
//这⾥是打断点,原地址0x00005028->新地址0x40005028 新地址需要改成0x4
//        emulator.attach().addBreakPoint(null, 0x40001188);//encode地址
//        emulator.attach().addBreakPoint(null, 0x40000D10);
Number ret = TTEncryptUtils.callStaticJniMethod(emulator, "getByteValues()Ljava/lang/String;");
long hash = ret.intValue() & 0xffffffffL;
StringObject st1 = vm.getObject(hash);
//*这⾥要处理下字符串
String byteString = Value();
StringBuilder builder = new StringBuilder(byteString.length());
for (int i = 0; i < byteString.length(); i++) {
if (byteString.charAt(i) == '0') {
builder.append('1');
} else {
builder.append('0');
}
}
//获取encodeByte地址
ret = TTEncryptUtils.callStaticJniMethod(emulator, "encodeByte(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
//传参,这⾥需要两个字符串,所以就传⼊两个参数
vm.addLocalObject(new StringObject(vm, "要加密的值")),
vm.addLocalObject(new StringObject(vm, String())));
//ret 返回的是地址,
hash = ret.intValue() & 0xffffffffL;
//获得其值
StringObject str = vm.getObject(hash);
图片爬虫appSystem.out.Value());
Value();
}
}
上边代码有jni的类是哪⼀个需要知道,就是下⾯这个类,这个其实是和加载so有关系的。
TTEncryptUtils = vm.resolveClass("com/*/aesjni/AESEncrypt");
我们需要逆向app,这⾥不细说如何在app中寻加载so的类。如下图,encodeByte是该app调⽤native层加密的⼊⼝,loadLibrary是java加载so的⽅法,这个类就是上述代码中填写的。
然后再看"encodeByte(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"这⾥,这是smali写法,不补基础,后⾯跟上需要传的参数,getByteValues这个⽅法是毒获取的⼀个01字符串,并且在java层进⾏了处理,然后再传进encodeByte⾥⾯,encodeByte这个⽅法最后获取的其实
并不是最终需要的,需要md5才是最后的newSign。可以验证⼀下下。
测试结果通过。
最后
启动java⽂件时候注意这个改成⾃⼰的平台
VM options: -Djava.library.path=prebuilt/os -Djna.library.path=prebuilt/os
Where os may: linux64, win32, win64, osx64

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。