做网站建设的好处,wordpress自定义文章链接地址,校园网站建设的系统分析,域名注册好了怎么使用1、unidbg 入门 unidbg 是一款基于 unicorn 和 dynarmic 的逆向工具#xff0c; 可以直接调用 Android 和 IOS 的 so 文件#xff0c;无论是黑盒调用 so 层算法#xff0c;还是白盒 trace 输出 so 层寄存器值变化都是一把利器#xff5e; 尤其是动态 trace 方面堪比 ida tr… 1、unidbg 入门 unidbg 是一款基于 unicorn 和 dynarmic 的逆向工具 可以直接调用 Android 和 IOS 的 so 文件无论是黑盒调用 so 层算法还是白盒 trace 输出 so 层寄存器值变化都是一把利器 尤其是动态 trace 方面堪比 ida trace给用不起 ida 的我带来极大安慰
项目地址https://github.com/zhkl0228/unidbg
做脱机协议首先要找到关键的加密代码然而这些代码一般都在so里面因为逆向c/c的难度远比java大多了找到关键代码后一般情况下是逐行分析然后自己写代码复现整个加密过程。但是有些非标准的加密算法是由一个团队实现的整个过程非常复杂。逆向人员再去逐行分析和复现有点“不划算”怎么才能直接调用so里面的这些关键代码了可以通过前面的介绍的frida hook也可以通过今天介绍的这个so的模拟框架--unidbg官方的功能介绍如下
Emulation of the JNI Invocation API so JNI_OnLoad can be called.Support JavaVM, JNIEnv.Emulation of syscalls instruction.Support ARM32 and ARM64.Inline hook, thanks to Dobby.Android import hook, thanks to xHook.iOS fishhook and substrate and whale hook.unicorn backend support simple console debugger, gdb stub, instruction trace, memory read/write trace.Support iOS objc and swift runtime.Support dynarmic fast backend.Support Apple M1 hypervisor, the fastest ARM64 backend.Support Linux KVM backend with Raspberry Pi B4.
看着很多有点唬人实际并不复杂以本文分享的为例我们平时开发android app在Android studio配置好各种环境和参数后是能直接在java层调用so层函数的。那么在unidbg也能实现同样的功能即调用so层的函数这也是unidbg最核心的功能之一了具体该怎么操作了 步骤一当然是先去unidbg的官网下载unidbg的框架啦然后用intelij打开里面能看到作者已经写好的各种java的测试工程代码如下 IDEA导入unidbg工程
https://code.newban.cn/151.html
逆向工具之 unidbg在 pc 端模拟执行 so 文件中的函数 基本使用 创建模拟器创建虚拟机加载so调用so层函数简单罗列了一下基本的使用 十分好上手 // 创建模拟器实例,建议使用实际进程名可以规避进程名校验 emulator AndroidEmulatorBuilder.for64Bit().setProcessName(com.xxx.xxx).build(); // 创建模拟器内存接口 final Memory memory emulator.getMemory(); // 设置系统类库解析 memory.setLibraryResolver(new AndroidResolver(23)); // 创建 Android 虚拟机传入 APKunidbg 可以协助做一部分签名工作 vm emulator.createDalvikVM(new File(unidbg-android/src/test/java/com/xxx/xxx.apk)); // 加载 so 到虚拟内存,第二个参数的意思表示是否执行动态库的初始化代码 DalvikModule dm vm.loadLibrary(new File(unidbg-android/src/test/java/com/xxx/libxxx.so),true); // 获取 so 模块的句柄 module dm.getModule(); // 设置 JNI vm.setJni(this); // 打印日志 vm.setVerbose(true); // 调用 JNI_Onload dm.callJNI_OnLoad(emulator); // 构建函数参数格式 ListObject args new ArrayList(10); // 各种基本参数格式兼容 // 参数1JNIEnv *env args.add(vm.getJNIEnv()); // 参数2jobject或jclass 用不到直接填0即可 // 创建 jobject 如果没用到的话可以不写 // cNative vm.resolveClass(com/xxx/xxx); // DvmObject? cnative cNative.newObject(null); // args.add(cnative.hashCode()); args.add(0); // 参数3 字符串对象 String input abcdef; args.add(vm.addLocalObject(new StringObject(vm, input))); // 参数4 bytes 数组 String input abcdef; byte[] input_bytes input.getBytes(StandardCharsets.UTF_8); ByteArray input_byte_array new ByteArray(vm,input_bytes); args.add(vm.addLocalObject(input_byte_array)); // 参数5 bool // false 填 0true 填 1 args.add(1); // unidbg 主动调用函数 // 第二个参数是函数偏移量(thumb 记得1) // 第三个参数是参数列表 Number number module.callFunction(emulator,0x10618, args.toArray()); // unicorn trace贼好用堪比 ida trace String traceFile trace.txt; PrintStream traceStream null; try{ traceStream new PrintStream(new FileOutputStream(traceFile), true); } catch (FileNotFoundException e) { e.printStackTrace(); } // 核心 trace 开启代码也可以自己指定函数地址和偏移量 emulator.traceCode(module.base,module.basemodule.size).setRedirect(traceStream); // 获取最终返回值同时运行过程中的汇编代码和寄存器值会写入到文件中 return vm.getObject(number.intValue()).getValue().toString(); 输出结果 看看 trace log建议搭配 010 editor 使用 更香 示例
目录 unidbg-android/src/test/java 放置了很多示例足以支撑入门 这些测试的 demo 代码已经说明了 unidbg 的接口和核心功能了。今天就用 kanxue 提供的 so 来说明核心 api 和 调用流程 unidbg 调用so层函数 ( 普通的so方法、jni_onload调用、jni函数调用 )
1、选择执行引擎如果明确使用了以下代码那么unidbg使用dynarmic引擎否则默认使用unicorn引擎 static { DynarmicLoader.useDynarmic(); } 2、创建虚拟机/模拟器并执行虚拟机的类型是art还是dailvik AndroidARMEmulator emulator new AndroidARMEmulator(com.sun.jna,null,null); final Memory memory emulator.getMemory(); VM vm emulator.createDalvikVM(); vm.setVerbose(true);//这里如果是true后续调用jni_onload的时候就能打印日志 3、指定SDK的版本这里用23版本 LibraryResolver resolver new AndroidResolver(23); memory.setLibraryResolver(resolver); 4、开始加载so库了 Module unicorn08moduleemulator.loadLibrary(new File(D:\\xxxx\\unidbg-master\\unidbg-android\\src\\test\\java\\com\\unicorncourse08\\unicorn08.so)); 5、调用so层的导出函数这两个都是导出函数直接用符号名就行了 Number resultunicorn08module.callFunction(emulator,_Z3addii,1,2)[0];//导出函数直接用符号名就行了 System.out.println(_Z3addii result:result.intValue()); //_Z7add_sixiiiiii resultunicorn08module.callFunction(emulator,_Z7add_sixiiiiii,1,2,3,4,5,6)[0]; System.out.println(_Z7add_sixiiiiii resultresult.intValue()); 这个是打印的结果 _Z3addii result:3 _Z7add_sixiiiiii result21 6、这两个都是对字符串做操作的so层仅仅求了传入字符串的长度 MemoryBlock block1memory.malloc(10,true); UnidbgPointer str1_ptrblock1.getPointer(); str1_ptr.write(hello.getBytes()); String contentARM.readCString(emulator.getBackend(),str1_ptr.peer); System.out.println(_Z15getstringlengthPKc:str1_ptr.toString()---content); resultunicorn08module.callFunction(emulator,_Z15getstringlengthPKc,new PointerNumber(str1_ptr))[0]; Number r0valueemulator.getBackend().reg_read(ArmConst.UC_ARM_REG_R0); System.out.println(_Z15getstringlengthPKc result:result.intValue()----r0value); MemoryBlock block2memory.malloc(10,true); UnidbgPointer str2_ptrblock2.getPointer(); str2_ptr.write(666.getBytes()); String content2ARM.readCString(emulator.getBackend(),str2_ptr.peer); System.out.println(_Z16getstringlength2PKcS0_:str2_ptr.toString()---content2); resultunicorn08module.callFunction(emulator,_Z16getstringlength2PKcS0_,new PointerNumber(str1_ptr),new PointerNumber(str2_ptr))[0]; r0valueemulator.getBackend().reg_read(ArmConst.UC_ARM_REG_R0); System.out.println(_Z16getstringlength2PKcS0_ result:result.intValue()----r0value); 打印结果 _Z15getstringlengthPKc:RW0x4016b000---hello _Z15getstringlengthPKc result:5----5 _Z16getstringlength2PKcS0_:RW0x4016c000---666 _Z16getstringlength2PKcS0_ result:8----8 7、这核心的核心直接调用jni_onload vm.callJNI_OnLoad(emulator,unicorn08module); 打印结果这里可以看到分别在so的0x8c7、0xccb调用了FindClass和RegisterNative方法然后注册MainActivity这个类的stringFromJNI2方法该方法和so层中0xb35的方法是映射的 JNIEnv-FindClass(com/example/unicorncourse08/MainActivity) was called from RX0x40000c87[libnative-lib.so]0xc87 JNIEnv-RegisterNatives(com/example/unicorncourse08/MainActivity, unidbg0xbffff778, 1) was called from RX0x40000ccb[libnative-lib.so]0xccb RegisterNative(com/example/unicorncourse08/MainActivity, stringFromJNI2(Ljava/lang/String;)Ljava/lang/String;, RX0x40000b35[libnative-lib.so]0xb35) 去so的0xc87和0xccb查看果然是FindClass和RegisterNative方法unidbg 诚不我欺 作为逆向其实最重要的还是最后那个打印结果java层的stringFromJNI2方法就是和so层的这个方法是映射的 进入里面调用的各个函数仔细分析发现这个函数还是比较简单先接受传入的string再打印出来由于这个函数并未导出但是和java层的函数做了映射所以这里也可以直接通过java层的名字来直接调用代码如下 //调用jni函数对于动态注册的jni函数必须在完成地址的绑定才能调用 System.out.println(stringFromJNI1-------------------------); DvmClass MainActivity_dvmclassvm.resolveClass(com/example/unicorncourse08/MainActivity);//先把类找到这里的原理很像反射 DvmObject resultobjMainActivity_dvmclass.callStaticJniMethodObject(emulator,stringFromJNI1(Ljava/lang/String;)Ljava/lang/String;,helloworld);//再通过类去调用里面的函数 System.out.println(resultobj:resultobj); resultobjMainActivity_dvmclass.callStaticJniMethodObject(emulator,stringFromJNI1(Ljava/lang/String;)Ljava/lang/String;,new StringObject(vm, hellokanxue)); System.out.println(resultobj:resultobj); System.out.println(stringFromJNI1-------------------------); //动态注册的jni函数stringFromJNI2 resultobjMainActivity_dvmclass.callStaticJniMethodObject(emulator,stringFromJNI2(Ljava/lang/String;)Ljava/lang/String;,new StringObject(vm, hellostringFromJNI2)); System.out.println(resultobj:resultobj); System.out.println(stringFromJNI2-------------------------); DvmObject mainactivityMainActivity_dvmclass.newObject(null); mainactivity.callJniMethodObject(emulator,stringFromJNI2(Ljava/lang/String;)Ljava/lang/String;,new StringObject(vm, hellostringFromJNI2)); System.out.println(resultobj:resultobj); System.out.println(stringFromJNI2-------------------------); 打印的结果如下这里面除了我们显式调用println打印的日志还有unidbg这个框架自身打印的日志主要是JNIenv这个类的函数调用 stringFromJNI1------------------------- Find native function Java_com_example_unicorncourse08_MainActivity_stringFromJNI1(Ljava/lang/String;)Ljava/lang/String; RX0x40000a71[libnative-lib.so]0xa71 JNIEnv-GetStringUtfChars(helloworld) was called from RX0x40000b03[libnative-lib.so]0xb03 JNIEnv-NewStringUTF(helloworld) was called from RX0x40000b2f[libnative-lib.so]0xb2f resultobj:helloworld Find native function Java_com_example_unicorncourse08_MainActivity_stringFromJNI1(Ljava/lang/String;)Ljava/lang/String; RX0x40000a71[libnative-lib.so]0xa71 JNIEnv-GetStringUtfChars(hellokanxue) was called from RX0x40000b03[libnative-lib.so]0xb03 [main]I/stringFromJNI1: content:helloworld,length:10 [main]I/stringFromJNI1: content:hellokanxue,length:11 [main]I/stringFromJNI2: content:hellostringFromJNI2,length:19 [main]I/stringFromJNI2: content:hellostringFromJNI2,length:19 JNIEnv-NewStringUTF(hellokanxue) was called from RX0x40000b2f[libnative-lib.so]0xb2f resultobj:hellokanxue stringFromJNI1------------------------- Find native function Java_com_example_unicorncourse08_MainActivity_stringFromJNI2(Ljava/lang/String;)Ljava/lang/String; RX0x40000b35[libnative-lib.so]0xb35 JNIEnv-GetStringUtfChars(hellostringFromJNI2) was called from RX0x40000b03[libnative-lib.so]0xb03 JNIEnv-NewStringUTF(hellostringFromJNI2) was called from RX0x40000b2f[libnative-lib.so]0xb2f resultobj:hellostringFromJNI2 stringFromJNI2------------------------- Find native function Java_com_example_unicorncourse08_MainActivity_stringFromJNI2(Ljava/lang/String;)Ljava/lang/String; RX0x40000b35[libnative-lib.so]0xb35 JNIEnv-GetStringUtfChars(hellostringFromJNI2) was called from RX0x40000b03[libnative-lib.so]0xb03 JNIEnv-NewStringUTF(hellostringFromJNI2) was called from RX0x40000b2f[libnative-lib.so]0xb2f resultobj:hellostringFromJNI2 stringFromJNI2------------------------- 完整的代码 package com.unicorncourse08; import com.github.unidbg.LibraryResolver; import com.github.unidbg.Module; import com.github.unidbg.PointerNumber; import com.github.unidbg.arm.ARM; import com.github.unidbg.arm.backend.dynarmic.DynarmicLoader; import com.github.unidbg.linux.android.AndroidARMEmulator; import com.github.unidbg.linux.android.AndroidResolver; import com.github.unidbg.linux.android.dvm.DvmClass; import com.github.unidbg.linux.android.dvm.DvmObject; import com.github.unidbg.linux.android.dvm.StringObject; import com.github.unidbg.linux.android.dvm.VM; import com.github.unidbg.memory.Memory; import com.github.unidbg.memory.MemoryBlock; import com.github.unidbg.pointer.UnidbgPointer; import unicorn.ArmConst; import java.io.File; public class MainActivity { static { DynarmicLoader.useDynarmic(); } public static void main(String[] args) { AndroidARMEmulator emulator new AndroidARMEmulator(com.sun.jna,null,null); final Memory memory emulator.getMemory(); VM vm emulator.createDalvikVM(); vm.setVerbose(true); LibraryResolver resolver new AndroidResolver(23); memory.setLibraryResolver(resolver); Module unicorn08moduleemulator.loadLibrary(new File(D:\\xxxx\\unidbg-master\\unidbg-android\\src\\test\\java\\com\\unicorncourse08\\unicorn08.so)); Number resultunicorn08module.callFunction(emulator,_Z3addii,1,2)[0];//导出函数直接用符号名就行了 System.out.println(_Z3addii result:result.intValue()); //_Z7add_sixiiiiii resultunicorn08module.callFunction(emulator,_Z7add_sixiiiiii,1,2,3,4,5,6)[0]; System.out.println(_Z7add_sixiiiiii resultresult.intValue()); //_Z15getstringlengthPKc MemoryBlock block1memory.malloc(10,true); UnidbgPointer str1_ptrblock1.getPointer(); str1_ptr.write(hello.getBytes()); String contentARM.readCString(emulator.getBackend(),str1_ptr.peer); System.out.println(_Z15getstringlengthPKc:str1_ptr.toString()---content); resultunicorn08module.callFunction(emulator,_Z15getstringlengthPKc,new PointerNumber(str1_ptr))[0]; Number r0valueemulator.getBackend().reg_read(ArmConst.UC_ARM_REG_R0); System.out.println(_Z15getstringlengthPKc result:result.intValue()----r0value); MemoryBlock block2memory.malloc(10,true); UnidbgPointer str2_ptrblock2.getPointer(); str2_ptr.write(666.getBytes()); String content2ARM.readCString(emulator.getBackend(),str2_ptr.peer); System.out.println(_Z16getstringlength2PKcS0_:str2_ptr.toString()---content2); resultunicorn08module.callFunction(emulator,_Z16getstringlength2PKcS0_,new PointerNumber(str1_ptr),new PointerNumber(str2_ptr))[0]; r0valueemulator.getBackend().reg_read(ArmConst.UC_ARM_REG_R0); System.out.println(_Z16getstringlength2PKcS0_ result:result.intValue()----r0value); //调用jni_OnLoad函数 vm.callJNI_OnLoad(emulator,unicorn08module); //调用jni函数对于动态注册的jni函数必须在完成地址的绑定才能调用 System.out.println(stringFromJNI1-------------------------); DvmClass MainActivity_dvmclassvm.resolveClass(com/example/unicorncourse08/MainActivity);//先把类找到这里的原理很像反射 DvmObject resultobjMainActivity_dvmclass.callStaticJniMethodObject(emulator,stringFromJNI1(Ljava/lang/String;)Ljava/lang/String;,helloworld);//再通过类去调用里面的函数 System.out.println(resultobj:resultobj); resultobjMainActivity_dvmclass.callStaticJniMethodObject(emulator,stringFromJNI1(Ljava/lang/String;)Ljava/lang/String;,new StringObject(vm, hellokanxue)); System.out.println(resultobj:resultobj); System.out.println(stringFromJNI1-------------------------); //动态注册的jni函数stringFromJNI2 resultobjMainActivity_dvmclass.callStaticJniMethodObject(emulator,stringFromJNI2(Ljava/lang/String;)Ljava/lang/String;,new StringObject(vm, hellostringFromJNI2)); System.out.println(resultobj:resultobj); System.out.println(stringFromJNI2-------------------------); DvmObject mainactivityMainActivity_dvmclass.newObject(null); mainactivity.callJniMethodObject(emulator,stringFromJNI2(Ljava/lang/String;)Ljava/lang/String;,new StringObject(vm, hellostringFromJNI2)); System.out.println(resultobj:resultobj); System.out.println(stringFromJNI2-------------------------); } } 总结一下上述API包括了3种so函数的调用方法
普通的so方法jni_onload调用jni 函数调用
上面举例的这些内容相对简单并不涉及到so层调用java层的函数。如果遇到so层函数调用java层函数怎么办么我们如果自己在apk写java代码调用so层函数遇到so通过反射调用java层函数时需要自己补上java层对应的类、方法和变量因为这些需要执行的代码是绕不过去的unidbg是这么样的么 答案是肯定的 so 通过反射调用 java 层 ( 补环境 )
比如下面的这个so层的方法会在jni_onload中被调用这里需要获取java层普通变量、static变量后打印出来也会获取java层的普通方法然后调用这该怎么办了 上面说了so层调用java层的代码肯定是要补齐的如果直接简单粗暴改so层代码可能导致别人原来的逻辑错误 这里该怎么实操了 大概的思路是
自己补上缺失的方法当然java层的方法可以用jadx、jeb等反编译得到不用自己反编译smali这里缺失了base64方法需要补上自己补上缺失的变量方法同上重写getStaticObjectField、getObjectField、callObjectMethodV等方法然后检测传入的参数。一旦发现使用/调用的是java层变量、方法用自己补上的哪些代码替换原理像不像平时常用的hook
说了那么多完整的demo代码如下 package com.unicorncourse08; import com.github.unidbg.Module; import com.github.unidbg.linux.android.AndroidARMEmulator; import com.github.unidbg.linux.android.AndroidResolver; import com.github.unidbg.linux.android.dvm.*; import com.github.unidbg.linux.android.dvm.jni.ProxyClassFactory; import com.github.unidbg.memory.Memory; import com.github.unidbg.virtualmodule.android.AndroidModule; import com.github.unidbg.virtualmodule.android.JniGraphics; import org.apache.commons.codec.binary.Base64; import sun.applet.Main; import java.io.File; import java.lang.reflect.Field; public class MainActivitymethod1 extends AbstractJni { private static DvmClass MainActivityClass; Override /* * staticcontent是java层的静态变量getStaticObjectField一旦检测到so层引用这个变量那么自己返回这个变量的值 * */ public DvmObject? getStaticObjectField(BaseVM vm, DvmClass dvmClass, String signature) { System.out.println(getStaticObjectField-signature); if(signature.equals(com/example/testjni/MainActivity-staticcontent:Ljava/lang/String;)){ return new StringObject(vm,staticcontent);//源码 public static string staticcontent staticcontent } return super.getStaticObjectField(vm, dvmClass, signature); } Override /* * objcontent是java层的变量这里重写getObjectField方法一旦检测到so层引用这个变量那么自己返回这个变量的值 * */ public DvmObject? getObjectField(BaseVM vm, DvmObject? dvmObject, String signature) { System.out.println(getObjectField-signature); if(signature.equals(com/example/testjni/MainActivity-objcontent:Ljava/lang/String;)){ return new StringObject(vm,objcontent);//public string objcontent } return super.getObjectField(vm, dvmObject, signature); } /* * java层的方法这里需要复现否则不知道怎么执行 * */ public String base64(String arg3) { String resultBase64.encodeBase64String(arg3.getBytes()); return result; } Override /* * base64是java层的方法这里重写callObjectMethodV方法一旦发现调用的是java层的base64方法这里就用自己复现的base64方法替换 * */ public DvmObject? callObjectMethodV(BaseVM vm, DvmObject? dvmObject, String signature, VaList vaList) { System.out.println(callObjectMethodV-signature); if(signature.equals(com/example/testjni/MainActivity-base64(Ljava/lang/String;)Ljava/lang/String;)){ DvmObject dvmobjvaList.getObjectArg(0); String arg (String) dvmobj.getValue(); String resultbase64(arg); return new StringObject(vm,result); } return super.callObjectMethodV(vm, dvmObject, signature, vaList); } public static void main(String[] args) { MainActivitymethod1 mainActivitymethod1new MainActivitymethod1(); AndroidARMEmulator emulator new AndroidARMEmulator(org.telegram.messenger,null,null); final Memory memory emulator.getMemory(); memory.setLibraryResolver(new AndroidResolver(23)); VM vm emulator.createDalvikVM(); vm.setVerbose(true); vm.setJni(mainActivitymethod1); DalvikModule dm vm.loadLibrary(new File(D:\\xxxx\\unidbg-master\\unidbg-android\\src\\test\\java\\com\\unicorncourse08\\calljava.so), true); dm.callJNI_OnLoad(emulator); MainActivityClassvm.resolveClass(com/example/testjni/MainActivity); DvmObject objMainActivityClass.newObject(null); obj.callJniMethodObject(emulator,base64byjni(Ljava/lang/String;)Ljava/lang/String;,callbase64byjni); } } 整个逻辑其实并不复杂从main函数开始创建模拟器、创建虚拟机、加载so、调用so层函数打印的结果如下 JNIEnv-FindClass(com/example/testjni/MainActivity) was called from RX0x400009df[libnative-lib.so]0x9df JNIEnv-RegisterNatives(com/example/testjni/MainActivity, unidbg0xbffff768, 1) was called from RX0x40000f19[libnative-lib.so]0xf19 RegisterNative(com/example/testjni/MainActivity, stringFromJNI(Ljava/lang/String;)Ljava/lang/String;, RX0x40000cb1[libnative-lib.so]0xcb1) Find native function Java_com_example_testjni_MainActivity_base64byjni(Ljava/lang/String;)Ljava/lang/String; RX0x4000088d[libnative-lib.so]0x88d JNIEnv-FindClass(com/example/testjni/MainActivity) was called from RX0x400009df[libnative-lib.so]0x9df getStaticObjectField-com/example/testjni/MainActivity-staticcontent:Ljava/lang/String; JNIEnv-GetStaticObjectField(class com/example/testjni/MainActivity, staticcontent Ljava/lang/String; staticcontent) was called from RX0x40000aa5[libnative-lib.so]0xaa5 JNIEnv-GetStringUtfChars(staticcontent) was called from RX0x40000adb[libnative-lib.so]0xadb [main]I/stringFromJNI: staticcontent:staticcontent [main]I/stringFromJNI: objcontent:objcontent getObjectField-com/example/testjni/MainActivity-objcontent:Ljava/lang/String; JNIEnv-GetObjectField(com.example.testjni.MainActivity7b3300e5, objcontent Ljava/lang/String; objcontent) was called from RX0x40000b11[libnative-lib.so]0xb11 JNIEnv-GetStringUtfChars(objcontent) was called from RX0x40000adb[libnative-lib.so]0xadb JNIEnv-GetMethodID(com/example/testjni/MainActivity.base64(Ljava/lang/String;)Ljava/lang/String;) was called from RX0x40000b55[libnative-lib.so]0xb55 callObjectMethodV-com/example/testjni/MainActivity-base64(Ljava/lang/String;)Ljava/lang/String; JNIEnv-CallObjectMethodV(com.example.testjni.MainActivity7b3300e5, base64(callbase64byjni) Y2FsbGJhc2U2NGJ5am5p) was called from RX0x40000bb1[libnative-lib.so]0xbb1 JNIEnv-GetStringUtfChars(Y2FsbGJhc2U2NGJ5am5p) was called from RX0x40000adb[libnative-lib.so]0xadb JNIEnv-NewStringUTF(Y2FsbGJhc2U2NGJ5am5p) was called from RX0x40000c05[libnative-lib.so]0xc05 [main]I/stringFromJNI: base64result:Y2FsbGJhc2U2NGJ5am5p 大杀器Unidbg真正的威力
https://zhuanlan.zhihu.com/p/419170736 大杀器内置的HOOK框架
当然Unidbg还内置了多种HOOK框架,今天讲一个分析So比较实用的一款HookZz // 1. 获取HookZz对象 IHookZz hookZz HookZz.getInstance(emulator); // 加载HookZz支持inline hook文档看https://github.com/jmpews/HookZz // 2. enable hook hookZz.enable_arm_arm64_b_branch(); // 测试enable_arm_arm64_b_branch可有可无 index 0; hookZz.replace(module.findSymbolByName(lrand48), new ReplaceCallback() { Override public void postCall(Emulator? emulator, HookContext context) { ((EditableArm32RegisterContext)context).setR0(0x12345678); int ptrace_args0 context.getIntArg(0); System.out.println(lrand48 ptrace_args0); } },true); //aesdecode hook hookZz.wrap((module.base)0x396341, new WrapCallbackRegisterContext() { // inline wrap导出函数 UnidbgPointer addr null; Override // 4. 方法执行前 public void preCall(Emulator? emulator, RegisterContext ctx, HookEntryInfo info) { addr ctx.getPointerArg(0); UnidbgPointer pointerArg ctx.getPointerArg(1); UnidbgPointer pointer pointerArg.getPointer(12); int anInt pointerArg.getInt(8); byte[] byteArray pointer.getByteArray(0, anInt); String s xuzi1(byteArray); System.out.println(aes aesdecode s); } Override // 5. 方法执行后 public void postCall(Emulator? emulator, RegisterContext ctx, HookEntryInfo info) { byte[] aaaa addr.getPointer(0).getPointer(12).getByteArray(0,0x30); String s xuzi1(aaaa); System.out.println(aes aesdecode1 s); } }); 同理此框架也支持导出函数HOOK以及InlineHOOK 有了这个方法,在你分析一些函数的时候可以充当Log的效果或者强行改变一些函数的返回值让你更容易的分析比如本例中笔者改变了Lrand48的返回值,让函数每次都强行返回0x12345678这样在逆向分析的时候能让一些不确定性变成可控性。 拟执行某段子so实操教程
https://blog.csdn.net/fenfei331/article/details/117027797 github 上 unidbg 项目 https://github.com/search?qunidbg unidbgweb
https://github.com/zhaoboy9692/unidbgweb
unidbg的服务化毒、酷安、快手、小红书、马蜂窝、抖音、今日头条、美团、拼多多、启信宝、天眼查、封面新闻的相关so调用 unidbg_api
脱离安卓手机调用第三方.so文件,集成了spring boot框架提供web服务 可打成jar包一键部署 unidbg-local-server
https://github.com/gl953236368/uls
小红书最右拼多多携程bilibili轻小说美团......懂车帝