前言
本案例分析仅用于学习交流,禁止用于非法用途
这个app是我在最近的逆向学习中,对自己来说比较困难的一个案例,其中涉及到frida检测,unidbg补环境,ollvm分析等一些之前不太熟悉的操作,在此记录一下自己的学习过程。
抓包
我们第一步对该app进行抓包分析,可以看到上传的参数全部被加密,看不出任何有效参数

frida检测与脱壳
在查看app的信息的时候,显示是360加固

尝试使用frida-dexdump,直接报错,应该是有frida检测

查看是加载哪个so时退出,发现是libmsaoaidsec.so,应该有多线程检测

hook一波clone函数后直接绕过
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| function nop_64(addr) { Memory.protect(addr, 4 , 'rwx'); var w = new Arm64Writer(addr); w.putRet(); w.flush(); w.dispose(); }
function hook_clone(soname) { var clone = Module.findExportByName('libc.so', 'clone'); Interceptor.attach(clone, { onEnter: function(args) { if(args[3] != 0){ var addr = args[3].add(96).readPointer() var so_name = Process.findModuleByAddress(addr).name; var so_base = Module.getBaseAddress(so_name); var offset = (addr - so_base); if(so_name.indexOf(soname) >= 0) { console.log("===============>", so_name, addr,offset, offset.toString(16)); nop_64(addr) } } }, onLeave: function(retval) { } }); } setImmediate(hook_clone, "libmsaoaidsec.so")
|

将上述代码添加到frida-dexdump的源码中即可成功脱壳

算法分析
算法定位
对java层的代码分析,不难找到参数的加密方法

hook该函数,可以看到加密前后的代码已经实现了加密

接下来定位该方法在哪个so文件中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| function find_function() { console.log("==== 0")
Java.perform(function () {
var process_Obj_Module_Arr = Process.enumerateModules(); for(var i = 0; i < process_Obj_Module_Arr.length; i++) { if(process_Obj_Module_Arr[i].path.indexOf("lib")!=-1) { console.log("模块名称:",process_Obj_Module_Arr[i].name);
var libname = process_Obj_Module_Arr[i].name frida_Module_import(libname) } } }) }
function frida_Module_import(libname) { Java.perform(function () { const hooks = Module.load(libname); var Imports = hooks.enumerateExports(); for(var i = 0; i < Imports.length; i++) { if (Imports[i].name.indexOf('sub_0515') != -1) { console.log("type:",Imports[i].type); console.log("name:",Imports[i].name); console.log("module:",Imports[i].module); console.log("address:",Imports[i].address); } } }); }
|
最后发现是在libumejni.so中

ida打开发现是经过了ollvm混淆,非常难看

unidbg补环境
unidbg去执行这个函数,不出意外程序进行了一些反射调用,需要进行补环境

这里需要补的环境并不算多,一些敏感参数还要配合frida hook来查找
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| @Override public DvmObject<?> callObjectMethod(BaseVM vm, DvmObject<?> dvmObject, String signature, VarArg varArg) { switch (signature) { case "hanglvzongheng/MainActivity->getPackageManager()Landroid/content/pm/PackageManager;": return vm.resolveClass("android/content/pm/PackageManager").newObject(null); case "hanglvzongheng/MainActivity->getPackageName()Ljava/lang/String;": return new StringObject(vm, "com.umetrip.android.msky.app"); } return super.callObjectMethod(vm, dvmObject, signature, varArg); }
@Override public DvmObject<?> callStaticObjectMethod(BaseVM vm, DvmClass dvmClass, String signature, VarArg varArg) { switch (signature){ case "com/umetrip/android/umehttp/security/SignUtil->getFingerprint(Landroid/content/Context;)Ljava/lang/String;": { return new StringObject(vm, "---------------------------------------"); } } return super.callStaticObjectMethod(vm, dvmClass, signature, varArg); }
@Override public DvmObject<?> getStaticObjectField(BaseVM vm, DvmClass dvmClass, String signature) { switch (signature) { case "com/umetrip/android/msky/app/BuildConfig->umSElga4:Ljava/lang/String;": return new StringObject(vm, "------"); } return super.getStaticObjectField(vm, dvmClass, signature); }
|
最终成功执行,并与抓包和hook出来的结果一致

算法分析
先随便构造一个简单的输入,然后开始trace,最终是60w行的trace代码

接下来就是慢慢调试分析了,最终分析得到的是算法是一个黑盒aes ecb加密与rc4加密,这里就不详细展开了
最终效果
