返回列表 发新帖

《安卓逆向这档事》二十三、黑盒魔法之Unidbg

  [复制链接]

91

主题

3807

回帖

2万

积分

博士后

萌新

Rank: 8Rank: 8

金币
10363
好评
335
信誉
278

考神MT论坛帅哥MT论坛最佳新人MT论坛活跃会员

QQ
发表于 2024-12-31 10:20:38 | 显示全部楼层 | 阅读模式  来自 福建
本帖最后由 正己 于 2025-1-3 16:05 编辑



一、课程目标
1.了解unicorn与unidbg
2.源码学习unidbg的常用api
3.了解unidbg_hook
4.了解unidbg_patch
二、工具

1.教程Demo
2.IDEA
3.IDA
三、课程内容

一.unicorn&unidbg
1.什么是unicorn

开源地址
Unicorn 是一个由新加坡南洋理工大学团队在2015年开源的CPU模拟器框架,它支持多种架构,包括X86/X64/ARM/ARM64/MIPS等。Unicorn 的主要特点是:
1. **多架构支持**:它能够模拟不同架构的CPU指令,这使得它在跨平台分析和测试中非常有用。
2. **高性能**:Unicorn 通过使用JIT(Just-In-Time)编译技术,将模拟的指令翻译成宿主机的本地指令,从而提高了执行效率。
3. **丰富的接口**:Unicorn 提供了多种语言的绑定,包括Python、Java、C#等,使得在不同编程环境中都能方便地使用。
4. **Hook和拦截功能**:Unicorn 允许用户在模拟执行过程中设置Hook,拦截和处理特定的指令或内存访问,这对于逆向工程和动态分析非常有用。
5. **专注于CPU模拟**:与一些既模拟CPU又模拟操作系统的模拟器不同,Unicorn 专注于CPU指令的模拟,提供了简单的Hook接口、内存操作接口和指令执行接口,而不涉及操作系统层面的模拟。

2.什么是unidbg?
开源地址
Unidbg(Unicorn Debugger)是一个开源的轻量级模拟器,主要设计用于模拟执行Android平台上的Native代码。它由凯神在2019年开源,基于Maven构建,使用Java语言编写,可以在IDE中打开和运行。Unidbg能够模拟Android Native函数的执行,让逆向工程师和安全研究人员能够分析和理解二进制文件的运行行为。它支持模拟系统调用和JNI调用,使得可以在模拟环境中执行依赖这些调用的代码。Unidbg基于Unicorn项目,Unidbg的优势在于它提供了一种隐蔽的监控手段,可以模拟复杂的Native环境,帮助用户进行深入的动态分析。由于其开源特性,Unidbg得到了社区的广泛支持和持续更新,成为了Android Native逆向分析领域中一个强有力的工具。
竞争者: AndroidNativeEmu 和继任者 ExAndroidNativeEmu     (Unidbg优点:模拟实现了更多的系统调用和 JNI)

3.unidbg的使用场景与优缺点


二.初试unidbg

1.配置资源文件
1.下载idea
社区版下载链接
2.下载源代码,并用idea打开,并配置好sdk
3.文件结构解析:

  1. ├── README.md                     [b][size=5]项目介绍和使用指南[/size][/b]
  2. ├── LICENSE                       [b][size=5]开源许可证文件[/size][/b]
  3. ├── .gitignore                    [b][size=5]Git 忽略文件配置[/size][/b]
  4. ├── pom.xml                       [b][size=5]Maven 配置文件,定义了项目的依赖和构建配置[/size][/b]
  5. ├── mvnw                          [b][size=5]脚本文件,用于 Maven Wrapper (Linux/Mac)[/size][/b]
  6. ├── mvnw.cmd                      [b][size=5]脚本文件,用于 Maven Wrapper (Windows)[/size][/b]
  7. ├── test.sh                       [b][size=5]测试脚本 (Linux/Mac)[/size][/b]
  8. ├── test.cmd                      [b][size=5]测试脚本 (Windows)[/size][/b]
  9. ├── .mvn/                         [b][size=5]Maven 配置目录[/size][/b]
  10. │   └── wrapper/                  [b][size=5]Maven Wrapper 相关配置[/size][/b]
  11. ├── assets/                       [b][size=5]存放模拟过程中使用的资源文件[/size][/b]
  12. │   ├── *.dll                     [b][size=5]Windows 动态链接库文件[/size][/b]
  13. │   └── *.so                      [b][size=5]Linux/Android 动态链接库文件[/size][/b]
  14. ├── backend/                      [b][size=5]后端逻辑实现,包含核心模拟功能[/size][/b]
  15. ├── unidbg-api/                   [b][size=5]核心接口和抽象类模块[/size][/b]
  16. │   └── src/                      [b][size=5]API 模块的源代码目录[/size][/b]
  17. ├── unidbg-ios/                   [b][size=5]iOS 应用模拟模块[/size][/b]
  18. │   └── src/                      [b][size=5]iOS 模拟模块的源代码目录[/size][/b]
  19. ├── unidbg-android/               [b][size=5]Android 应用模拟模块[/size][/b]
  20. │   ├── pom.xml                   [b][size=5]Maven 构建文件[/size][/b]
  21. │   ├── pull.sh                   [b][size=5]拉取 Android 模拟所需依赖文件的脚本[/size][/b]
  22. │   └── src/                      [b][size=5]unidbg-android 模块的源代码目录[/size][/b]
  23. │       ├── main/
  24. │       │   ├── java/             [b][size=5]核心 Java 源代码[/size][/b]
  25. │       │   │   └── com/github/unidbg/  [b][size=5]包含核心模拟器、文件系统、虚拟机组件[/size][/b]
  26. │       │   │   └── net/fornwall/jelf   [b][size=5]ELF 文件格式解析实现[/size][/b]
  27. │       │   └── resources/        [b][size=5]资源文件,封装了 JNI 库、Android 系统库等[/size][/b]
  28. │       ├── test/
  29. │       │   ├── java/             [b][size=5]单元测试代码[/size][/b]
  30. │       │   ├── native/android/   [b][size=5]测试 Android 原生库的 C/C++ 源代码[/size][/b]
  31. │       │   └── resources/        [b][size=5]测试资源文件,包含预编译的二进制文件(log4j.properties这个是日志相关配置,可以对open,syscall这类的系统调用进行trace)[/size][/b]
  32. └── .mvn/                         [b][size=5]Maven Wrapper 相关配置目录[/size][/b]

复制代码

  1. java
  2. log4j.logger.com.github.unidbg.linux.file=DEBUG //把INFO改成DEBUG
复制代码


2.项目式学习
  1. java
  2. package com.kanxue.test2;

  3. import com.github.unidbg.AndroidEmulator;
  4. import com.github.unidbg.Module;
  5. import com.github.unidbg.arm.backend.DynarmicFactory;
  6. import com.github.unidbg.linux.android.AndroidEmulatorBuilder;
  7. import com.github.unidbg.linux.android.AndroidResolver;
  8. import com.github.unidbg.linux.android.dvm.DalvikModule;
  9. import com.github.unidbg.linux.android.dvm.DvmObject;
  10. import com.github.unidbg.linux.android.dvm.ProxyDvmObject;
  11. import com.github.unidbg.linux.android.dvm.VM;
  12. import com.github.unidbg.memory.Memory;

  13. import java.io.File;

  14. public class MainActivity {

  15.     private final AndroidEmulator emulator; // 定义Android模拟器实例
  16.     private final VM vm; // 定义Dalvik虚拟机实例

  17.     public MainActivity() {
  18.         // 创建32位Android模拟器实例,使用Dynarmic后端
  19.         emulator = AndroidEmulatorBuilder.for32Bit()
  20.                 .addBackendFactory(new DynarmicFactory(true))
  21.                 .build();

  22.         // 获取模拟器的内存管理接口
  23.         Memory memory = emulator.getMemory();
  24.         // 设置系统类库
  25.         LibraryResolver resolver = new AndroidResolver(23);
  26.         memory.setLibraryResolver(resolver);

  27.         // 创建Dalvik虚拟机实例
  28.         vm = emulator.createDalvikVM();
  29.         // 设置是否输出详细的JNI调用日志
  30.         vm.setVerbose(false);

  31.         // 加载指定路径的SO库文件,不自动调用JNI_OnLoad函数
  32.         DalvikModule dm = vm.loadLibrary(new File("unidbg-android/src/test/resources/example_binaries/armeabi-v7a/libnative-lib.so"), false);
  33.         // 手动调用JNI_OnLoad方法
  34.         dm.callJNI_OnLoad(emulator);
  35.     }

  36.     public void crack() {
  37.         // 创建一个vm对象,模拟Java层的对象传递给JNI层
  38.         DvmObject<?> obj = ProxyDvmObject.createObject(vm, this);

  39.         // 记录开始时间
  40.         long start = System.currentTimeMillis();

  41.         // 遍历所有可能的三字符组合,尝试破解
  42.         for (char a : LETTERS) {
  43.             for (char b : LETTERS) {
  44.                 for (char c : LETTERS) {
  45.                     String str = "" + a + b + c;
  46.                     // 调用JNI方法,传入当前组合,判断是否成功
  47.                     boolean success = obj.callJniMethodBoolean(emulator, "jnitest(Ljava/lang/String;)Z", str);
  48.                     if (success) {
  49.                         // 如果成功,输出结果并结束
  50.                         System.out.println("Found: " + str + ", off=" + (System.currentTimeMillis() - start) + "ms");
  51.                         return;
  52.                     }
  53.                 }
  54.             }
  55.         }
  56.     }

  57.     private static final char[] LETTERS = {  
  58.         'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',  
  59.         'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',  
  60.         'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',  
  61.         'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'  
  62.         }; // 定义字母表

  63.     public static void main(String[] args) {
  64.             //记录开始时间
  65.             long start = System.currentTimeMillis();  
  66.         // 创建MainActivity实例
  67.         MainActivity main = new MainActivity();
  68.         //输出调用结果
  69.         System.out.println("load offset=" + (System.currentTimeMillis() - start) + "ms");  
  70.         // 调用破解方法
  71.         main.crack();
  72.     }
  73. }


复制代码

  1. java
  2. emulator = AndroidEmulatorBuilder.for32Bit()
  3.             .addBackendFactory(new DynarmicFactory(true))
  4.             .build();
复制代码

- 1.for32Bit()的意思是创建32位Android模拟器实例,for64Bit()则是创建64位,apk lib 里只有armeabi-v7a,那就只能选择 32 位,apk lib 里只有arm64-v8a,就选择 64 位。区别:64位的执行速度较快,浮动10%左右;Unidbg 对 ARM32 的支持和完善程度高于 ARM64
- 2.Unidbg 支持了数个后端,目前共五个 Backend,分别是 Unicorn、Unicorn2、Dynarmic(执行速度较快)、Hypervisor、KVM。new DynarmicFactory(true)中的true,标志着在出现异常时是否使用默认后端unicorn。

  1. java
  2. .setRootDir() //设置虚拟机的根目录,可以实现io重定向,例如:app读取/data/data/123.txt,rootDir设置为E:/unidbg,那么真正的目录是E:/unidbg/data/data/123.txt,
复制代码


#1.emulator常用Api



  1. java
  2.     LibraryResolver resolver = new AndroidResolver(23);
  3.     memory.setLibraryResolver(resolver);
复制代码

23 和 19 分别对应于 sdk23(Android 6.0) 和 sdk19(Android 4.4)的运行库环境,处理 64 位 SO 时只能选择 SDK23。

#2.memory常用Api


`vm常用Api`
  1. java
  2.         // 创建Dalvik虚拟机实例
  3.         vm = emulator.createDalvikVM();
  4.         // 设置是否输出详细的JNI调用日志
  5.         vm.setVerbose(false);
  6.         // 加载指定路径的SO库文件,不自动调用JNI_OnLoad函数
  7.         DalvikModule dm = vm.loadLibrary(new File("unidbg-android/src/test/resources/example_binaries/armeabi-v7a/libnative-lib.so"), false);
  8.         // 手动调用JNI_OnLoad方法
  9.         dm.callJNI_OnLoad(emulator);
复制代码




- 1.`VM dalvikVM = emulator.createDalvikVM(new File("apk file path"))`-创建虚拟机并指定APK文件,加载指定APK文件,unidbg可以帮我们完成一些小操作,例如:解析 Apk 基本信息,Apk 的版本名、版本号、包名、 Apk 签名等信息,减少补环境操作;解析和管理 Apk 资源文件,加载 Apk 后可以通过 `openAsset`获取 APK `assets`目录下的文件。
- 2.`loadLibrary`三个重载方法
  1. java
  2. /**
  3. * 加载指定名称的库文件。
  4. * @param libname 库文件的名称,不包括前缀 "lib" 和后缀 ".so"(例如 "example" 对应 "libexample.so")。
  5. * @param forceCallInit 是否强制调用库的初始化函数(如 JNI_OnLoad)。
  6. * [url=home.php?mod=space&uid=134981]@Return[/url] 加载后的 DalvikModule 对象,封装了加载的库模块。
  7. */
  8. DalvikModule loadLibrary(String libname, boolean forceCallInit);

  9. /**
  10. * 从原始字节数组中加载指定的库文件。
  11. * @param libname 库文件的名称,仅用于标识该库,与文件路径无关。
  12. * @param 传入buffer方便解析elf
  13. */
  14. DalvikModule loadLibrary(String libname, byte[] raw, boolean forceCallInit);

  15. /**
  16. * 从指定路径的加载ELF。
  17. * @param elfFile 表示库的 ELF 文件,必须是有效的 ELF 格式文件。例如:new File("unidbg-android/src/test/resources/example_binaries/armeabi-v7a/libnative-lib.so")
  18. * @param forceCallInit 是否强制调用库的初始化函数(如 JNI_OnLoad)。
  19. */
  20. DalvikModule loadLibrary(File elfFile, boolean forceCallInit);

复制代码


#3.jni函数的调用

  1. java
  2. //第一个参数传入模拟器实例
  3. //第二个参数传入要调用的函数在java层方法签名信息
  4. //第三个参数传入可变参数列表,这里的参数在旧版本有很多需要自己封装,新版则帮我们封装好了,详细看callJniMethod方法
  5. boolean success = obj.callJniMethodBoolean(emulator, "jnitest(Ljava/lang/String;)Z", str);

  6. /**
  7. * 调用 JNI 方法的辅助函数。
  8. *
  9. * @param emulator   模拟器实例。
  10. * @param vm         Dalvik 虚拟机实例。
  11. * @param objectType 调用方法的类(DvmClass)。
  12. * @param thisObj    方法调用的对象实例(DvmObject)。
  13. * @param method     要调用的方法签名(例如 "methodName(参数类型)返回类型")。
  14. * @param args       方法的可变参数列表。
  15. * @return           方法执行后的返回值(Number 类型),可能是整数或浮点数。
  16. */
  17. protected static Number callJniMethod(Emulator<?> emulator, VM vm, DvmClass objectType, DvmObject<?> thisObj, String method, Object... args) {
  18.     // 查找对应的本地函数指针(Native 方法)
  19.     UnidbgPointer fnPtr = objectType.findNativeFunction(emulator, method);
  20.     // 将当前对象添加到本地引用表,防止被垃圾回收
  21.     vm.addLocalObject(thisObj);
  22.     // 创建用于存放函数参数的列表,初始容量为10
  23.     List<Object> list = new ArrayList<>(10);
  24.     // 添加 JNI 环境指针(JNIEnv*)
  25.     list.add(vm.getJNIEnv());
  26.     // 添加 this 对象的引用(jobject)
  27.     list.add(thisObj.hashCode());
  28.     // 处理传入的参数列表
  29.     if (args != null) {
  30.         for (Object arg : args) {
  31.             if (arg instanceof Boolean) {
  32.                 // 如果参数是布尔值,转换为 JNI_TRUE 或 JNI_FALSE
  33.                 list.add((Boolean) arg ? VM.JNI_TRUE : VM.JNI_FALSE);
  34.                 continue;
  35.             } else if (arg instanceof Hashable) {
  36.                 // 如果参数实现了 Hashable 接口,表示是 DvmObject 或其子类
  37.                 list.add(arg.hashCode()); // 添加对象引用(jobject)
  38.                 if (arg instanceof DvmObject) {
  39.                     // 将 DvmObject 对象添加到本地引用表
  40.                     vm.addLocalObject((DvmObject<?>) arg);
  41.                 }
  42.                 continue;
  43.             } else if (arg instanceof DvmAwareObject ||
  44.                     arg instanceof String ||
  45.                     arg instanceof byte[] ||
  46.                     arg instanceof short[] ||
  47.                     arg instanceof int[] ||
  48.                     arg instanceof float[] ||
  49.                     arg instanceof double[] ||
  50.                     arg instanceof Enum) {
  51.                 // 如果参数是 DvmAwareObject、字符串、数组或枚举等类型
  52.                 // 创建一个代理 DvmObject 对象
  53.                 DvmObject<?> obj = ProxyDvmObject.createObject(vm, arg);
  54.                 // 添加对象引用(jobject)
  55.                 list.add(obj.hashCode());
  56.                 // 将对象添加到本地引用表
  57.                 vm.addLocalObject(obj);
  58.                 continue;
  59.             }

  60.             // 对于其他类型的参数,直接添加到参数列表
  61.             list.add(arg);
  62.         }
  63.     }
  64.     // 调用本地函数,传入参数列表,并返回结果
  65.     return Module.emulateFunction(emulator, fnPtr.peer, list.toArray());
  66. }

复制代码

基本类型直接传递,int、long、boolean、double 等。
- 下面几种对象类型unidbg也帮我们封装好了
- String
- byte 数组
- short 数组
- int 数组
- float 数组
- double 数组
- Enum 枚举类型
#4.特殊参数构造
对于其他数据类型需要借助`resolveClass`构造,例如`Context`
  1. java
  2. DvmObject<?> context = vm.resolveClass("android/content/Context").newObject(null);
复制代码


#5.符号调用与偏移调用
`符号调用`
  1. java
  2. Symbol symbol = module.findSymbolByName("导出符号");  
  3. if (symbol != null){  
  4.         //第一个模拟器实例,第二个jnienv,第三个jclass,第四个可变参数
  5.     Number numbers = symbol.call(emulator, vm.getJNIEnv(), vm.addLocalObject(实例类), 可变参数);  
  6.     int result = numbers.intValue();
  7.     System.out.println(result);  
  8.     //如果返回值是string,可以通过vm.getObject(retval)获取
  9.     System.out.println(vm.getObject(result).getValue());
  10. }else {  
  11.     System.out.println("符号未找到");  
  12. }
复制代码

`偏移调用`
  1. java
  2. //第一个模拟器实例,第二个偏移地址(thumb记得+1),第三个jnienv,第四个jclass,第五个可变参数
  3. Number number = module.callFunction(emulator, 0x11240, vm.getJNIEnv(),vm.addLocalObject(SecurityUtils),vm.addLocalObject(new StringObject(vm, "超级")));
  4. DvmObject<?> object = vm.getObject(number.intValue());  
  5. System.out.println("result:" + object.getValue());
复制代码


已有2人评分好评 金币 理由
zlnxlzht + 1 + 1 很给力!
秋枫Mod + 1 + 1 支持大佬

查看全部评分 总评分:好评 +2  金币 +2 

回复

使用道具 举报

91

主题

3807

回帖

2万

积分

博士后

萌新

Rank: 8Rank: 8

金币
10363
好评
335
信誉
278

考神MT论坛帅哥MT论坛最佳新人MT论坛活跃会员

QQ
发表于 2024-12-31 10:21:59 | 显示全部楼层  来自 福建
剩下内容放二楼
3.unidbg之hook


#1.HookZz&Dobby
  1. java
  2. // 获取 HookZz 实例,用于后续的 Hook 操作
  3. IHookZz hookZz = HookZz.getInstance(emulator);
  4. // 使用 HookZz 的 wrap 方法对导出函数 "ss_encrypt" 进行 Inline Hook
  5. hookZz.wrap(module.findSymbolByName("ss_encrypt"), new WrapCallback<RegisterContext>() {
  6.     @Override
  7.     public void preCall(Emulator<?> emulator, RegisterContext ctx, HookEntryInfo info) {
  8.         // 在函数调用前执行的操作
  9.         // 获取第三个参数的指针
  10.         Pointer pointer = ctx.getPointerArg(2);
  11.         // 获取第四个参数的整数值
  12.         int length = ctx.getIntArg(3);
  13.         // 读取指针指向的内存内容,获取密钥数据
  14.         byte[] key = pointer.getByteArray(0, length);
  15.         // 使用 Inspector 工具输出密钥内容,便于调试和分析
  16.         Inspector.inspect(key, "ss_encrypt key");
  17.     }

  18.     @Override
  19.     public void postCall(Emulator<?> emulator, RegisterContext ctx, HookEntryInfo info) {
  20.         // 在函数调用后执行的操作
  21.         // 输出函数返回值的值
  22.         System.out.println("ss_encrypt.postCall R0=" + ctx.getLongArg(0));
  23.     }
  24. });
复制代码

**1.获取 HookZz 实例**:
  1. java
  2. IHookZz hookZz = HookZz.getInstance(emulator);
复制代码

**2.wrap_hook函数**:
  1. java
  2. hookZz.wrap(functionAddress, new WrapCallback<RegisterContext>() {
  3.     @Override
  4.     public void preCall(Emulator<?> emulator, RegisterContext context, HookEntryInfo info) {
  5.         // 函数调用前的操作
  6.         UnidbgPointer input = ctx.getPointerArg(2);  
  7.                 System.out.println("preCall:"+vm.getObject(input.toIntPeer()));
  8.         
  9.     }

  10.     @Override
  11.     public void postCall(Emulator<?> emulator, RegisterContext context, HookEntryInfo info) {
  12.         // 函数调用后的操作
  13.         //获取整数型的返回值
  14.         System.out.println("postCall:" + ctx.getLongArg(0));
  15.         //获取jstr
  16.                 UnidbgPointer input = ctx.getPointerArg(0);  
  17.                 System.out.println("postCall:"+vm.getObject(input.toIntPeer()));
  18.     }
  19. });
复制代码

`wrap`函数有两个重载,一个基于符号寻址,一个基于地址寻址,本质没区别,符号寻址的最终也是会调用`symbol.getAddress()`
参数里的WrapCallback的泛型接口有三个`RegisterContext(函数 Hook)`、`HookZzArm32RegisterContext(针对ARM32位)`和`HookZzArm64RegisterContext(针对ARM64位)`因为可以访问某个寄存器的值,所以适用于inline hook

而在`HookZzArm64RegisterContext`中则是通过以下的方法去获取对应的寄存器的值

**3.instrument_inline_hook函数**
  1. java
  2. // 使用 HookZz 的 instrument 方法对特定地址的指令进行 Inline Hook, thumb记得+1
  3. hookZz.instrument(module.base + 0x11470, new InstrumentCallback<Arm64RegisterContext>() {  
  4.     @Override  
  5.     public void dbiCall(Emulator<?> emulator, Arm64RegisterContext ctx, HookEntryInfo info) {
  6.             // 在指定指令执行时触发的操作
  7.         // 输出 W0 寄存器的值
  8.         System.out.println("W0=" + ctx.getXInt(0));  
  9.     }  
  10. });
复制代码

**4.replace替换函数***
  1. java
  2. // 使用 dobby 的 replace 方法替换 "Java_com_zj_wuaipojie_util_SecurityUtil_diamondNum" 函数的实现
  3. Dobby dobby = Dobby.getInstance(emulator);  
  4. dobby.replace(module.findSymbolByName("Java_com_zj_wuaipojie_util_SecurityUtil_diamondNum"), new ReplaceCallback() { // 使用Dobby inline hook导出函数  
  5.     @Override  
  6.     public HookStatus onCall(Emulator<?> emulator, HookContext context, long originFunction) {  
  7.                 //替换整数型
  8.         return HookStatus.LR(emulator,888888);  
  9.         //字符串
  10.         return HookStatus.LR(emulator, vm.addLocalObject(new StringObject(vm, "超级")));
  11.     }  
  12. });

复制代码


#2.Unicorn_Hook
  1. java
  2. emulator.getBackend().hook_add_new(new CodeHook() {  
  3.     @Override  
  4.     public void hook(Backend backend, long address, int size, Object user) {  
  5.         Arm64RegisterContext context = emulator.getContext();  
  6.         if (address == module.base + 0x11330) {  
  7.             int x0=emulator.getBackend().reg_read(Arm64Const.UC_ARM64_REG_X0).intValue();  
  8.             System.out.println("x0:"+vm.getObject(x0));  
  9.             emulator.getBackend().reg_write(Arm64Const.UC_ARM64_REG_X0,vm.addLocalObject(new StringObject(vm, "超级")));  
  10.         }  
  11.     }  
  12.     @Override  
  13.     public void onAttach(UnHook unHook) {  
  14.     }  
  15.     @Override  
  16.     public void detach() {  
  17.     }  
  18. }, module.base + 0x11240,module.base + 0x11340,null);  
  19. StringObject Result = SecurityUtils.callStaticJniMethodObject(emulator, "vipLevel(Ljava/lang/String;)Ljava/lang/String;", "123");
  20. System.out.println("Result: " + Result.getValue());
复制代码

#3.Console Debugge
Console Debugger(控制台调试器)是 Unidbg 提供的一个强大工具,允许用户在模拟执行过程中设置断点、单步调试、查看和修改内存及寄存器等操作,从而深入分析目标程序的行为。
  1. java
  2. Debugger attach = emulator.attach();  
  3. attach.addBreakPoint(module.base + 0x11070); //下断地址
  4. //调用
  5. Number number = module.callFunction(emulator, 0x11014, vm.getJNIEnv(),vm.addLocalObject(SecurityUtils),vm.addLocalObject(new StringObject(vm, "123456")));  
  6. System.out.println("result:" + number.intValue());
复制代码


`替换返回值`
  1. java
  2. emulator.attach().addBreakPoint(module.findSymbolByName("verifyApkSign").getAddress(), new BreakPointCallback() {
  3.         @Override
  4.         public boolean onHit(Emulator<?> emulator, long address) {
  5.             System.out.println("替换函数 verifyApkSign");
  6.             RegisterContext registerContext = emulator.getContext();
  7.             emulator.getBackend().reg_write(ArmConst.UC_ARM_REG_PC, registerContext.getLRPointer().peer);
  8.             emulator.getBackend().reg_write(ArmConst.UC_ARM_REG_R0, 0);
  9.             return true;
  10.         }
  11.     });

复制代码


4.unidbg之patch
Patch 就是直接对二进制文件进行修改,Patch本质上只有两种形式
- patch 二进制文件
- 在内存里 patch
Patch的应用场景很多,在一些场景比Hook更好用,这就是需要介绍它的原因。Patch 二进制文件的形式是大多数人所熟悉的,在IDA中使用KeyPatch打补丁的体验很友好。这里主要介绍unidbg的内存Patch。
`借助Keystone 汇编引擎`
  1. java
  2. UnidbgPointer pointer = UnidbgPointer.pointer(emulator,module.base + 0x1146C);  
  3. //在进行 Patch 操作前,需确保已正确定位目标函数的地址和指令集类型(如 ARM 或 Thumb)
  4. //如果是32位的,代码如下:Keystone keystone = new Keystone(KeystoneArchitecture.Arm, KeystoneMode.ArmThumb);
  5. Keystone keystone = new Keystone(KeystoneArchitecture.Arm64, KeystoneMode.LittleEndian);  
  6. String s = "MOV W0, #0x99";  //具体要修改的汇编指令
  7. byte[] machineCode = keystone.assemble(s).getMachineCode();   //转换为机器码
  8. pointer.write(machineCode); //写入内存

复制代码
回复

使用道具 举报

91

主题

3807

回帖

2万

积分

博士后

萌新

Rank: 8Rank: 8

金币
10363
好评
335
信誉
278

考神MT论坛帅哥MT论坛最佳新人MT论坛活跃会员

QQ
发表于 2024-12-31 10:22:28 | 显示全部楼层  来自 福建
表哥们点点关注
回复

使用道具 举报

20

主题

1万

回帖

2万

积分

博士后

Rank: 8Rank: 8

金币
2644
好评
9
信誉
96

考神

发表于 2024-12-31 10:28:54 来自手机  | 显示全部楼层  来自 河北
看看隐藏
回复

使用道具 举报

0

主题

1214

回帖

3367

积分

大学生

Rank: 5Rank: 5

金币
2550
好评
0
信誉
100

MT论坛新人MT论坛最佳新人考神

发表于 2024-12-31 10:31:43 来自手机  | 显示全部楼层  来自 山西
看看隐藏
回复

使用道具 举报

1

主题

2389

回帖

6201

积分

硕士生

Rank: 6Rank: 6

金币
829
好评
1
信誉
104

考神MT论坛新人MT论坛最佳新人MT论坛帅哥

发表于 2024-12-31 10:33:44 来自手机  | 显示全部楼层  来自 云南
看看隐藏
回复

使用道具 举报

85

主题

7249

回帖

2万

积分

博士后

Rank: 8Rank: 8

金币
777
好评
96
信誉
147

考神MT论坛活跃会员MT论坛新人MT论坛最佳新人MT论坛帅哥MT论坛侠客挂机大佬

发表于 2024-12-31 10:38:15 来自手机  | 显示全部楼层  来自 新疆
看看教程
回复

使用道具 举报

18

主题

601

回帖

3199

积分

大学生

Rank: 5Rank: 5

金币
1028
好评
3
信誉
102

MT论坛最佳新人

发表于 2024-12-31 10:43:19 来自手机  | 显示全部楼层  来自 河南
过来看看
回复

使用道具 举报

0

主题

2759

回帖

6263

积分

硕士生

Rank: 6Rank: 6

金币
2752
好评
0
信誉
100
发表于 2024-12-31 10:44:55 | 显示全部楼层  来自 上海
支持一下
回复

使用道具 举报

1

主题

6029

回帖

1万

积分

博士生

Rank: 7Rank: 7Rank: 7

金币
8129
好评
0
信誉
100
发表于 2024-12-31 10:59:20 来自手机  | 显示全部楼层  来自 江苏
感谢大佬分享
回复

使用道具 举报

2

主题

3639

回帖

9649

积分

硕士生

Rank: 6Rank: 6

金币
8236
好评
0
信誉
100

考神MT论坛新人MT论坛帅哥

发表于 2024-12-31 10:59:30 来自手机  | 显示全部楼层  来自 陕西
看看隐藏
回复

使用道具 举报

0

主题

7274

回帖

2万

积分

博士后

Rank: 8Rank: 8

金币
2247
好评
8
信誉
124

考神

发表于 2024-12-31 11:05:46 来自手机  | 显示全部楼层  来自 广东
看看大佬
回复

使用道具 举报

61

主题

3088

回帖

1万

积分

博士生

Rank: 7Rank: 7Rank: 7

金币
4938
好评
70
信誉
120

MT论坛帅哥MT论坛新人

发表于 2024-12-31 11:09:16 来自手机  | 显示全部楼层  来自 浙江
学习学习
回复

使用道具 举报

0

主题

1267

回帖

2764

积分

禁止发言

金币
2369
好评
0
信誉
100
发表于 2024-12-31 11:10:37 来自手机  | 显示全部楼层  来自 广西
看看
回复

使用道具 举报

66

主题

6472

回帖

1万

积分

博士生

Rank: 7Rank: 7Rank: 7

金币
1748
好评
2
信誉
109

考神

发表于 2024-12-31 11:23:36 来自手机  | 显示全部楼层  来自 江西
路过看看
回复

使用道具 举报

发表回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表