APP逆向 day24unidbg上

一.前言

今天开始讲app逆向最后一个也是最重要的unidbg,这已经是从初级进阶到中级的了,我会讲unidbg,讲三节课,分为上中下来和大家讲(由简单到难逐步),这节课主要是和大家讲unidbg的介绍并且会结合之前讲的简单案例来让大家理解,如果过程中不太记得之前的位置定位,可以去看之前的课程,在学习工程中遗忘是难免的,这也是我做教学的初心,希望大家点赞关注加收藏。

二.unidbg的介绍和使用

2.1 unidbg 是什么

unidbg是一个Java开源项目,可以帮助我们去模拟一个安卓或IOS设备,用于去执行so文件中的算法,从而不需要再去逆向他内部的算法
它是一个基于 unicorn 的逆向工具,可以直接调用Android和iOS中的 so 文件

Allows you to emulate an Android native library, and an experimental iOS emulation
允许您模拟 Android native library 和 实验性的 iOS 模拟

 而在什么时候使用unidbg呢?

当加密位置是在so文件的时候,而so文件破解难度大,我们就会使用unidbg,我们之前也教过大家其他两种硬核破解so文件的,分别是frida-rpc和自己编写app来调用,但是问题就是我们不方便交付,特别的麻烦,所以我们可以使用unidbg,再把unidbg的java代码编写成jar包,通过python来调用jar包就好(当然今天我们讲不到这里),后面会讲的,这就有点类似于js逆向时python调用js文件一样!

2.2 下载和使用

这里给出下载地址

Releases · zhkl0228/unidbg · GitHubicon-default.png?t=N7T8https://github.com/zhkl0228/unidbg/releases打开这个网址选择最新版下载就好,下载好解压完,使用idea打开

注意打开时解压后里面的这一层目录

然后我们运行一下

正常出值了就说明没问题,比如我最开始运行就发现报错,排除半天才发现jdk版本错误,当时用的版本是jdk1.7,后来换成1.8就ok了,这个代码是安居客sign的测试代码,运行成功就说明环境没问题了

2.3 关于unidbg的补环境

1 unidbg 模拟了手机设备--》so文件进行加密---》so文件加密时,有两种方式
    - 加密算法,都在so层,全是用c实现的     大姨妈--》不需要补环境
    - 加密算法,在so层--》so又调用了java层--》返回so层继续逻辑--》唯品会--》需要补环境
    
    
2 所谓的补环境--》就是补c层调用java时候的一些类
    unidbg使用java写的---》c调用java的时候---》unidbg是没有对应app的java的代码---》c中调用java时,缺java的这些类---》我们需要把缺的java类补上

所以说,unidbg补环境只在so层调用java的时候才需要补上,也就是补上那些java中的类

三.车智赢案例

刚才我们介绍了一下unidbg,现在我就带大家讲一下之前的unidbg,忘了的话可以去看一下之前的案例

3.1 回顾当时so加密

APP逆向 day13 逆向某智赢登录-CSDN博客文章浏览阅读1k次,点赞23次,收藏17次。pwd 就是对密码进行md5加密udid就是将几个值拼接起来进行des加密,最后再第61个位置加上空格(可忽略)_sign 对载荷进行拼接后 前面加上一串字符,后面加上一串字符进行md5。https://blog.csdn.net/weixin_74178589/article/details/140250795?spm=1001.2014.3001.5501当时我们逆向udid的时候发现执行力des加密,而我们当时get3deskey是直接hook得来的

我们今天用unidbg带大家跑出来这个key是什么

3.2 unidbg的使用步骤

(1)在java/com下创建一个包和类,名字随便取

 (2)设置初始化

这里先给大家截图,讲完思路之后会给大家代码的,这些基本都是固定的

可以发现我们还要单独创建一个目录来导入apk和so文件

这样就创建好了

 这些初始化写好之后就运行一下,代码基本都是固定的,后续只要自己修改包名那些就好了

 运行不报错了

package com.che_des3key;
import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.Module;
import com.github.unidbg.linux.android.AndroidEmulatorBuilder;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.AbstractJni;
import com.github.unidbg.linux.android.dvm.DalvikModule;
import com.github.unidbg.linux.android.dvm.VM;
import com.github.unidbg.memory.Memory;

import java.io.File;

//必须继承AbstractJni
public class CheZhiYing extends AbstractJni {
    public static AndroidEmulator emulator;  // 静态属性,以后对象和类都可以直接使用
    public static Memory memory;
    public static VM vm;
    public static Module module;
    // 1 构造方法--》用来初始化
    public CheZhiYing(){
        // 1.创建设备(32位或64位模拟器), 具体看so文件在哪个目录。 在armeabi-v7a就选择32位
        // 传进设备时,如果是32位,后面so文件就要用32位,同理需要用64位的
        // 这个名字可以随便写,一般写成app的包名    以后可能会动
        emulator = AndroidEmulatorBuilder.for32Bit().setProcessName("com.che168.autotradercloud").build();

        // 2.获取内存对象(可以操作内存)
        memory = emulator.getMemory();

        //3.设置安卓sdk版本(只支持19、23)
        memory.setLibraryResolver(new AndroidResolver(23));

        // 4.创建虚拟机(运行安卓代码需要虚拟机,就想运行py代码需要python解释器一样)    以后会动
        vm = emulator.createDalvikVM(new File("apks/che/che3.32.1.apk"));
        vm.setJni(this); // 后期补环境会用,把要补的环境,写在当前这个类中,执行这个代码即可,但是必须继承AbstractJni
        //vm.setVerbose(true); //是否展示调用过程的细节

        // 5.加载so文件
        DalvikModule dm = vm.loadLibrary(new File("apks/che/libnative-lib.so"), false);   // 以后会动
        dm.callJNI_OnLoad(emulator); // jni开发动态注册,会执行JNI_OnLoad,如果是动态注册,需要执行一下这个,如果静态注册,这个不需要执行,车智赢案例是静态注册

        // 6.dm代表so文件,dm.getModule()得到module对象,基于module对象可以访问so中的成员。
        module = dm.getModule(); // 把so文件加载到内存后,后期可以获取基地址,偏移量等,该变量代指so文件
    }

    //2 sign 成员方法--》主要用来解密
    public void sign(){

    }

    // 3 main方法---》右键直接运行
    public static void main(String[] args) {
        CheZhiYing che=new CheZhiYing();
        che.sign();
    }
}

(3)执行签名

 

jni签名

 因为content是android中的方法,所以这个比较特殊,所以写成了android/content/Context,正常都是根据这个表对应来写就好

代码给出如下

public void sign(){
        // 1 找到java类中jni的类  native方法,找的时候是固定写法
        // com.autohome.ahkit.jni.CheckSignUtil-->.写成 / 形式
        DvmClass CheckSignUtil = vm.resolveClass("com/autohome/ahkit/jni/CheckSignUtil");

        // 2 找到类中的方法--》使用签名的方式找【参数签名和返回值签名】--》固定写法
        // Landroid/content/Context; 就是参数,这个只有一个content类型 要用jni中对应的类型来写
        // Ljava/lang/String 就是返回值,也要用jni中对应的类型来写
        // 之前在jni开发中给过一张对应图了
        String method = "get3desKey(Landroid/content/Context;)Ljava/lang/String;";

        // 3 执行方法,传入参数
        // 第一个参数是:设备对象
        // 第二个参数是:方法
        // 再往后的参数,就是这个方法的参数
        StringObject obj = CheckSignUtil.callStaticJniMethodObject(
                emulator,
                method,
                // 相当于 new 了个contex传入了,但是这个context是空的
                // 具体类型一会讲
                vm.resolveClass("android/content/Context").newObject(null)
        );

        // 4 打印结果
        String result=obj.getValue();
        System.out.println(result);
        
    }

现在再右键

 

可以发现出值了,而这个值就是key,和我们之前的一结果一致

3.3 调用方法--传参和返回值

相信大家在刚才的传参和返回值那里应该都挺蒙蔽的,那我们现在就来具体讲一下,讲完这个就接着和大家讲案例让大家深入理解

使用unidbg调用 jni 中Navite方法时,传入的参数和返回值,不是java的类型,需要是unidgb提供的类型,我们反编译回来的代码是这样:

public static native String get3desKey(Context context);

而我们写unidbg的代码是这样:

StringObject obj = CheckSignUtil.callStaticJniMethodObject(
                        emulator,
                        method,
                        vm.resolveClass("android/content/Context").newObject(null)
                );

因为在使用unidbg时要有包裹概念,要把参数进行包裹再传给unidbg使用,这里是传参包裹的规则

java类型                        包裹                                
字符串:'justin'                 StringObject("justin")                
字节数组:{11,12}            ByteArray({11,22})                 
----------------------------布尔-数字-空-----------------------
布尔:True/False           True/False                      
数字:19                        19                                    
空:null                          null                                   
----------------------------自定义类型----------------------------------------
自定义类型:Info         cls = vm.resolveClass("com/nb/utils/Info");
                                     cls.newObject(对象)

                  可以直接写成vm.resolveClass("com/nb/utils/Info").newObject(new出来的对象)

而我们刚才这么写:

vm.resolveClass("android/content/Context").newObject(null)

是因为content是安卓中的方法,java中没有,而我们这个方法恰巧没有使用content里面的值,如果有的案例需要这个值,那我们就要补环境了

返回值就比较简单

返回值--》被unidbg包裹的对象--》通过getValue得到真正的字符串对象
如果返回字符串 需要用 StringObject 类型接受---》拿到真正的字符串 需要 obj.getValue() 

四.大姨妈案例 

这里给出当时案例的地址,不记得的话可以去看看(前几天的案例要是看过了但是忘了就该打!)

APP逆向 day21大姨妈逆向-CSDN博客文章浏览阅读813次,点赞26次,收藏29次。今天知识点有点多,主要是给大家说了一下绕过root检测,frida-rpc和安卓编写调用so,这个其实后期用的不多,主要是做个了解,后期遇到难读的so我们会用unidbg,还差两个知识点就能讲到了,讲完那个我们的基础课程也算是结束了,大家就到了app逆向入门了,好了,到时候再说吧,晚安!https://blog.csdn.net/weixin_74178589/article/details/140716482?spm=1001.2014.3001.5501

当时我们传入三个参数,第一个参数是0,第二个参数是sb,第三个参数是sb的长度 

这里我们随便拿之前hook到的模拟一下

j2=0
str=64e6176e45397c5989504e76f98ecf2e63b2679euser/login18953675221WA89qByLlDeaGjmVNzXm/w==
j3=85

那我们就来c一下代码嘛,改个包名和文件名就好了

c好的代码修改了如上面,我们运行一下

 

发现运行报错

 还记得这里嘛,说明我们c的是64位的so文件,那我们改一下就好了

改好之后运行不报错了,我这里真的是想办法帮你们把所有坑都排掉,别太感动!!点赞关注加收藏就好 

我们现在来编写sign中的内容,sign中的内容也可以复制然后修改就好,最后我会给出代码的

这个就是之前我们写的类似,注意的是包名中间的.都换成/,参数之间不用分割,中间那个;是因为jni中string对应的后面有分号 

   public void sign(){

        // 1 找到java类中jni的类  native方法,找的时候是固定写法
        // 找到包,找到类
        DvmClass CheckSignUtil = vm.resolveClass("com/yoloho/libcore/util/Crypt");

        // 2 找到类中的方法--》使用签名的方式找【参数签名和返回值签名】--》固定写法
        // 第一个参数: J  long类型对应
        // 第二个参数: Ljava/lang/String; string类型对应
        // 第三个参数: J long类型对应
        // 返回值: Ljava/lang/String;
        // 注意:参数和参数之间不用; 或者,分割 直接写就行了
        String method = "encrypt_data(JLjava/lang/String;J)Ljava/lang/String;";
        // 3 执行方法,传入参数
        // 第一个参数是:设备对象
        // 第二个参数是:方法
        // 再往后的参数,就是这个方法的参数
        StringObject obj = CheckSignUtil.callStaticJniMethodObject(
                emulator,
                method,
                0,
                new StringObject(vm,"64e6176e45397c5989504e76f98ecf2e63b2679euser/login18953675221WA89qByLlDeaGjmVNzXm/w=="),
                85

        );


        // 4 打印结果
        String result=obj.getValue();
        System.out.println(result);

    }

运行结果

 

五.得物案例 

这里给出之前案例的地址

APP逆向 day15 某物逆向_得物app逆向-CSDN博客文章浏览阅读1.8k次,点赞44次,收藏12次。这次讲的很长,主要是学习技术和概念。_得物app逆向https://blog.csdn.net/weixin_74178589/article/details/140303850?spm=1001.2014.3001.5501 

 

我们这里大致回忆一下,当时我们,当时他执行了getByteValues,然后再进行下面的操作,最后把生成的字符串传入 再执行encodeByte,这两个都是jni方法,当时我们只看了encodeByte的参数和返回值,并没有怎么读上面的逻辑,因为读so太麻烦了,而这次我们用jni完整的把这两个方法都搞出来,我们还是先c一下并修改初始化的代码

我们运行一下

 

这个不是报错,只是内部打印的日志

 这个就比前两个要复杂,他要调用两次jni方法,但是殊途同归,可以发现,这样子的好处就是,遇到java中的逻辑代码,我们能够直接复制,稍微修改一点点了,记得当时我们硬核破解so的时候,就在想这个取反之后的字符串为什么没有用到,为啥会没有用,还会在想会不会用错了,但是当我们使用jni的时候完全不会觉得用错了,能够十分自信,而且更加的方便马,这就是用unidbg的好处,简单好破解,这里给出sign中的代码

public void sign(){
        // 内部调用了两次jni方法
        // 1 找到类
        DvmClass AESEncrypt = vm.resolveClass("com/duapp/aesjni/AESEncrypt");
        //2 找到方法
        // 没有参数
        String method = "getByteValues()Ljava/lang/String;";
        // 3 调用
        StringObject byteValues = AESEncrypt.callStaticJniMethodObject(
                emulator,
                method
        );
        // 4 拿到真正的字符串
        String byteValuesString = byteValues.getValue();

        // 5 按照反编译的逻辑执行java代码
        // 直接复制就行了
        StringBuilder sb = new StringBuilder();
        for (int i2 = 0; i2 < byteValuesString.length(); i2++) {
            if (byteValuesString.charAt(i2) == '0') {
                sb.append('1');
            } else {
                sb.append('0');
            }
        }
        String sbString = sb.toString();
        System.out.println(sbString);

        // 6 找到第二个方法
        // 第一个参数: [B 对应字节数组
        // 后面我就不多说了
        String methodEncodeBytes = "encodeByte([BLjava/lang/String;)Ljava/lang/String;";


        // 7 执行方法
        String body="abRecReason0abRectagFengge0abTypesocial_brand_strategy_v454abValue1abVideoCover2deliveryProjectId0lastIdlimit20loginTokenplatformandroidtimestamp1715346585009uuidee13885e68d76ed4v4.74.5";
        StringObject data = AESEncrypt.callStaticJniMethodObject(
                emulator,
                methodEncodeBytes,
                // 按照前面说的包裹好
                new ByteArray(vm, body.getBytes()),
                new StringObject(vm, sbString)
        );

        //8 打印结果
        System.out.println(data.getValue());


    }

运行结果

六.海南航空案例

讲了几个之前的案例,我们这就来讲一个新的案例,担心大家记不清之前的案例了还不愿意回去看,这就完整的和大家讲一个

版本选择 v9.0.0

6.1 抓包分析

我们今天就不完全给他全部破出来,而是只用unidbg破解这一个参数:hnairSign

6.2 找到加密位置 

我们搜索hnairSign

找到一个位置,我们点进去

 

发现在这里,我们再点进去

 

i.p().get(0)-->i.p执行结果是列表ArrayList,取了列表的第0个位置

HNASignature.getHNASignature()--》执行结果是字符串

然后对其进行分割取第0个位置,我们点进去

6.3 hook得到加密参数

 发现在这里是个jni方法,那我们接下来就是hook参数并且找到其对应的so文件 

这里给出hook代码

Java.perform(function () {
    var HNASignature = Java.use("com.rytong.hnair.HNASignature");
    HNASignature.getHNASignature.implementation = function (str,str2,str3,str4,str5) {
        console.log("---------------------")
        console.log("参数1",str);
        console.log("参数2",str2);
        console.log("参数3",str3);
        console.log("参数4",str4);
        console.log("参数5",str5);
        var res = this.getHNASignature(str,str2,str3,str4,str5);
        console.log("返回值=",res);
        return res;
    }
});


//frida -U -f com.rytong.hnair -l hook.js

我们清除数据执行一下,通过抓包的数据搜索

发现参数和返回值

参数1 {}
参数2 {}
参数3 {"abuild":"64249","akey":"184C5F04D8BE43DCBD2EE3ABC928F616","aname":"com.rytong.hnair","atarget":"standard","aver":"9.0.0","caller":"AD_H5","did":"d3e4ffe477e86d99","dname":"Google_Pixel 3","gtcid":"","hver":"9.0.0.35417.7ac
793f2e.standard","mchannel":"huawei","schannel":"AD","slang":"zh-CN","sname":"google\/blueline\/blueline:11\/RQ3A.211001.001\/7641976:user\/release-keys","stime":"1722284925093","sver":"11","system":"AD","szone":"+0800","riskToken":"66a7fb7adXzZGwi8Bf8b3o9WpWYvTtyQMM7ewnx3"}
参数4 21047C596EAD45209346AE29F0350491
参数5 F6B15ABD66F91951036C955CB25B069F
返回值= E3B7A590F71E7C8292165B26BE54814C7F56653E>>64249184C5F04D8BE43DCBD2EE3ABC928F616com.rytong.hnairstandard9.0.0AD_H5d3e4ffe477e86d99Google_Pixel 39.0.0.35417.7ac793f2e.standardhuawei66a7fb7adXzZGwi8Bf8b3o9WpWYvTtyQMM7ewnx3ADzh-CNgoogle/blueline/blueline:11/RQ3A.211001.001/7641976:user/release-keys172228492509311AD+0800>>F6B15ABD66F91951036C955CB25B069F

6.4 找到加密位置 

这个发现找不到我们想要的so文件的位置,之前我们在b站案例中给我一个找到动态注册的so文件以及偏移量直接找到加密方法,这里再次给出

function hook_RegisterNatives() {
    //1 加载安卓手机底层包,系统自带的库,我们hook的RegisterNatives在这个包中
    var symbols = Module.enumerateSymbolsSync("libart.so");
    //2 定义一个变量,用来接收一会找到的addrRegisterNatives的地址
    var addrRegisterNatives = null;
    // 3 循环找到RegisterNatives的地址,赋值给变量
    //注意:此处可能找出多个RegisterNatives的地址,由于咱们是for循环,会把之前的覆盖掉,所有如果hook没反应,尝试加break,使用第一个找到的
    for (var i = 0; i < symbols.length; i++) {
        var symbol = symbols[i];
        if (symbol.name.indexOf("art") >= 0 &&
            symbol.name.indexOf("JNI") >= 0 &&
            symbol.name.indexOf("RegisterNatives") >= 0 &&
            symbol.name.indexOf("CheckJNI") < 0) {
            addrRegisterNatives = symbol.address;
            console.log("RegisterNatives is at ", symbol.address, symbol.name);
            break
        }

    }
    // 4 找到后开始hook
    if (addrRegisterNatives != null) {
        Interceptor.attach(addrRegisterNatives, {
            // 4.1 当进入RegisterNatives时执行
            // RegisterNatives(env, 类型, Java和C的对应关系,个数)
            onEnter: function (args) {
                // 4.2 第0个参数是env
                var env = args[0];
                // 4.3 第1个参数是类型
                var java_class = args[1];
                 // 4.4 通过类型得到具体的类名
                var class_name = Java.vm.tryGetEnv().getClassName(java_class);
                //console.log(class_name);
                // 只有类名为com.bilibili.nativelibrary.LibBili,才打印输出
                var taget_class = "com.rytong.hnair.HNASignature";
                if (class_name === taget_class) {
                    //4.5  只有类名为com.bilibili.nativelibrary.LibBili,再取出第四个参数
                    console.log("\n[RegisterNatives] method_count:", args[3]);
                    // 4.6 第2个参数是:Java和C的对应关系,我们转成指针
                    /*
                    static JNINativeMethod gMethods[] = {
                            {"add", "(III)I", (void *) plus},
                            {"add", "(II)I", (void *) plus},
                            {"add", "(II)I", (void *) plus},
                    };
                     */
                    var methods_ptr = ptr(args[2]);
                    // 4.7 java和c函数对应关系的个数
                    var method_count = parseInt(args[3]);
                    // 4.8 我们循环这个个数,依次移动指针methods_ptr,通过readPointer,往后读取 {"add", "(III)I", (void *) plus},依次读出Java中函数名字,签名和C中的函数指针
                    for (var i = 0; i < method_count; i++) {
                        // 4.8.1 读取Java中函数名字的
                        var name_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3));
                        // 4.8.2 读取签名, 参数和返回值类型
                        var sig_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize));
                        // 4.8.3 读取 C中的函数指针
                        var fnPtr_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize * 2));

                        // 4.8.4 读取java中函数名 字符串名
                        var name = Memory.readCString(name_ptr);
                        // 4.8.5 参数和返回值类型 字符串名
                        var sig = Memory.readCString(sig_ptr);
                        // 4.5.6 根据C中函数指针获取模块
                        var find_module = Process.findModuleByAddress(fnPtr_ptr); // 根据C中函数指针获取模块


                        // 4.8.7 得到该函数的偏移量:ptr(fnPtr_ptr)函数在内存中的地址   减去   该so文件的基地址(find_module.base)====得到偏移量
                        // 地址:函数在内存中的地址
                        // 偏移量:后期单独打开so文件后,可以根据偏移量 定位到函数位置
                        // 基地址:当前so文件从那个位置开始算地址
                        var offset = ptr(fnPtr_ptr).sub(find_module.base)
                        // console.log("[RegisterNatives] java_class:", class_name);
                        // 4.8.8 输出 函数名      参数和返回值类型    模块    偏移量
                        console.log("name:", name, "sig:", sig, "module_name:", find_module.name, "offset:", offset);

                    }
                }
            }
        });
    }
}

setImmediate(hook_RegisterNatives);

// frida -U -f 包名 -l 16.通用脚本_获取动态注册对应关系.js




发现运行啥也没有,说明是静态注册,这里给出找到静态注册so文件的代码

Java.perform(function () {
    var dlsymadd = Module.findExportByName("libdl.so", 'dlsym');
    Interceptor.attach(dlsymadd, {
        onEnter: function (args) {
            this.info = args[1];

        }, onLeave: function (retval) {
            //那个so文件 module.name
            var module = Process.findModuleByAddress(retval);
            if (module == null) {
                return retval;
            }
            // native方法
            var funcName = this.info.readCString();
            // 后期只需要改这里,对应的java方法名
            if (funcName.indexOf("getHNASignature") !== -1) {
                console.log(module.name);
                console.log('\t', funcName);
            }
            return retval;
        }
    })
});


// frida -U -f  包名  -l 24.通用脚本_获取静态注册的so文件.js
// frida -U -f  com.rytong.hnair  -l 24.通用脚本_获取静态注册的so文件.js

 发现是libsignature.so,那我们现在就不用去so中读逻辑了,直接把apk改成zip,解压后把这个so文件和apk一起放入unidbg中就好

6.5 unidbg跑 

 

然后就是c一下那段代码了

 我们把该c好的c好,运行发现不报错,现在就开始写sign

直接写入参数就好了,这里给出代码

 public void sign(){

        // 1 找到类
        DvmClass HNASignature = vm.resolveClass("com/rytong/hnair/HNASignature");
        // 2 找到方法
        // 这里五个参数都是字符串,看起来有带你奇怪
        String method = "getHNASignature(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;";
        //3 执行方法
        StringObject obj = HNASignature.callStaticJniMethodObject(
                emulator,
                method,
                new StringObject(vm,"{}"),
                new StringObject(vm,"{}"),
                new StringObject(vm,"{\"abuild\":\"64249\",\"akey\":\"184C5F04D8BE43DCBD2EE3ABC928F616\",\"aname\":\"com.rytong.hnair\",\"atarget\":\"standard\",\"aver\":\"9.0.0\",\"caller\":\"AD_H5\",\"did\":\"d3e4ffe477e86d99\",\"dname\":\"Google_Pixel 3\",\"gtcid\":\"\",\"hver\":\"9.0.0.35417.7ac793f2e.standard\",\"mchannel\":\"huawei\",\"schannel\":\"AD\",\"slang\":\"zh-CN\",\"sname\":\"google\\/blueline\\/blueline:11\\/RQ3A.211001.001\\/7641976:user\\/release-keys\",\"stime\":\"1722284925093\",\"sver\":\"11\",\"system\":\"AD\",\"szone\":\"+0800\",\"riskToken\":\"66a7fb7adXzZGwi8Bf8b3o9WpWYvTtyQMM7ewnx3\"}"),
                new StringObject(vm,"21047C596EAD45209346AE29F0350491"),
                new StringObject(vm,"F6B15ABD66F91951036C955CB25B069F")
        );

        //4 打印结果
        System.out.println(obj.getValue());

    }

运行结果

 和刚才抓包结果一致,至此破解成功

七.总结

今天讲的干活和内容很多,大家要仔细品味,发现unidbg也没有这么难,下一期会和大家讲中部分,稍微比这个案例难一点,但是也是之前讲过的,大家可以看看之前的案例,对比一下使用unidbg,多多体会

 补充

有需要源码的看我主页签名名字私信我,有求必应

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

往日情怀酿做酒 V1763929638

往日情怀酿作酒 感谢你的支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值