认识Unidbg

了解Unicorn

Unicorn是一个基于QEMU的轻量级、多平台、多架构的CPU模拟器框架,它允许用户在不同平台上模拟不同架构的CPU操作。

Unidbg

unidbg 是一款基于 unicorn 和 dynarmic(ARM的动态重编译器) 的逆向工具,可以模拟执行so文件。

安装项目

在github上下载项目unidbg,可以直接clone到本地
下载好之后用IDEA打开,等待加载依赖(科学上网)

项目结构

在这里插入图片描述
  在unidbg-android目录包含了特定于 Android 平台的模拟和分析工具,src下有main和test两个目录,main包含主程序的代码,test包含用于测试 Unidbg 功能的测试代码。
  在unidbg-api目录里面包含了unidbg提供的API接口。

分析实例

unidbg\unidbg-android\src\test\java\com\bytedance\frameworks\core\encrypt

在这里插入图片描述

构造函数里的模拟器介绍

    TTEncrypt(boolean logging) {
        this.logging = logging;

        emulator = AndroidEmulatorBuilder
        	.for32Bit()  //指定模拟器目标平台
        	.setProcessName("com.qidian.dldl.official") //设置进程名
            .addBackendFactory(new Unicorn2Factory(true)) //模拟器的底层执行引擎
            .build(); // 创建模拟器实例
            
        // 获取模拟器的内存操作接口
        final Memory memory = emulator.getMemory(); 
        // 设置系统库解析器
        memory.setLibraryResolver(new AndroidResolver(23)); 
        
        // 创建一个 Dalvik 虚拟机实例。
        vm = emulator.createDalvikVM(); 
        // 设置虚拟机的日志输出模式。
        vm.setVerbose(logging); 
        
        // 调用虚拟机的 loadLibrary 方法来加载指定的本地库
        // 第二个参数 false 表示不自动调用库的 JNI_OnLoad 函数。
        DalvikModule dm = vm.loadLibrary(new File("unidbg-android/src/test/resources/example_binaries/libttEncrypt.so"), false); 
        // 手动执行JNI_OnLoad函数
        dm.callJNI_OnLoad(emulator); 
        // 获取加载的库对应的模块对象
        module = dm.getModule(); 
		// 解析类TTEncryptUtils
        TTEncryptUtils = vm.resolveClass("com/bytedance/frameworks/core/encrypt/TTEncryptUtils");
    }

destroy()

    void destroy() {
    	// 调用 IOUtils.close 方法来关闭 emulator 实例。
        IOUtils.close(emulator);
        if (logging) {
        	// 在控制台上打印字符串 "destroy"。
            System.out.println("destroy");
        }
    }

ttEncrypt()

这个函数代码比较多,我把关键的部分留下来

    byte[] ttEncrypt() {
        if (logging) {
            ...
        }
        if (logging) {
            emulator.attach(DebuggerType.ANDROID_SERVER_V7); // 附加IDA android_server,可输入c命令取消附加继续运行
        }
        byte[] data = new byte[16];
        ByteArray array = TTEncryptUtils.callStaticJniMethodObject(emulator, "ttEncrypt([BI)[B", new ByteArray(vm, data), data.length); // 执行Jni方法
        return array.getValue();
    }

main()

    public static void main(String[] args) throws Exception {
    	// 创建TTEncrypt 类实例
        TTEncrypt test = new TTEncrypt(true);
		// 调用 TTEncrypt 实例的 ttEncrypt 方法
        byte[] data = test.ttEncrypt();
        // 用于打印或以其他方式检查 data 数组的内容。"ttEncrypt" 是一个标签,用于标识这些数据是来自 ttEncrypt 方法的结果。
        Inspector.inspect(data, "ttEncrypt");
		// 调用 TTEncrypt 实例的 destroy 方法,清理和释放与 emulator 相关的资源。
        test.destroy();
    }

ttEncrypt函数里的callStaticJniMethodObject

在 Unidbg 框架中,callStaticJniMethodObject 是一个用于调用 Android 应用中静态 JNI 方法的方法。

ByteArray array = TTEncryptUtils.callStaticJniMethodObject(emulator, "ttEncrypt([BI)[B", new ByteArray(vm, data), data.length);

这里面TTEncryptUtils是获取的Java类的DvmClass对象。
callStaticJniMethodObject方法用于调用该类的静态JNI方法。
emulator是AndroidEmulator 实例,它提供了执行环境。
ttEncrypt([BI)[B是 JNI 方法的签名。指定了方法的名称(ttEncrypt),参数类型(一个字节数组 byte[],表示为 [B),I表示整型,和返回类型(一个字节数组 byte[])。
new ByteArray(vm, data) 创建了一个新的 ByteArray 实例,它包装了要加密的数据 data。vm 是虚拟机实例,用于创建和管理 ByteArray 对象。
data.length 是传递给 JNI 方法的第二个参数,它可能是加密方法需要的额外信息,例如数据的长度。

callStaticJniMethodObject

通过符号寻找函数的地址,在动态注册函数中以符号为键寻找函数地址,如果找不到,则按静态注册规则拼接符号,然后寻找函数地址函数名和函数签名

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值