APP逆向 day24unidbg上

news2024/9/9 6:28:26

一.前言

今天开始讲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,多多体会

 补充

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

 

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1962461.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

详解工厂模式与抽象工厂模式有什么区别?【图解+代码】

目录 工厂模式&#xff0c;抽象工厂模式是什么&#xff1f; 两种设计模式的流程&#xff1a; 1、工厂模式 2、抽象工厂模式 两种模式的对比 共同点&#xff1a; 不同点&#xff1a; 总结 工厂模式&#xff0c;抽象工厂模式是什么&#xff1f; 我已经具体的写了这两种模…

我的「Java全栈高级架构师高薪就业课」适合什么样的人群学习?

我的《Java全栈高级架构师高薪就业课》上线了~ 这是一套Java全栈微服务架构、以实战项目驱动的课程&#xff01;包含34个模块&#xff0c;1514课时。对标阿里P7级别技术栈而研发&#xff0c;有着循序渐进的学习体系&#xff0c;助你开启Java进阶之旅。 我的这套《Java全栈高级…

海域感知与岸线监控实施方案:总体技术架构

文章目录 引言I 总体架构1.1 物理结构图1.2 功能逻辑结构图1.3 系统架构1.4 雷达光电船只检测系统拓扑图1.5 雷达光电船只联动跟踪效果图II 技术架构存储Geoserver视频see also引言 利用渔船现有的定位导航通讯设备等资源,实现岸线和近岸海域内违法船舶和可疑船舶预警、抓拍、…

系统学习渗透测试:从零到精通的全面指南

渗透测试&#xff0c;作为网络安全领域的一项重要技术&#xff0c;旨在通过模拟黑客攻击来评估计算机系统的安全性。对于想要系统学习渗透测试的人来说&#xff0c;这既是一条充满挑战的道路&#xff0c;也是一次深入了解网络安全的宝贵机会。本文将从基础知识、技能提升、实战…

怎麼使用ixbrowser指紋流覽器?

ixBrowser是一款指紋流覽器流覽器&#xff0c;利用指紋隔離技術確保在與Pixelscan等第三方檢測網站進行測試時具有出色的通過率&#xff0c;能夠輕鬆管理多個獨立帳戶。此外&#xff0c;ixBrowser能夠創建無限的獨立個人資料並邀請團隊成員。簡化了運營&#xff0c;降低了運營成…

转行要趁早!网络安全岗人才稀缺,前景广阔,收藏这一篇就够了

1 网络安全从业人员能力基本要求&#xff0c;您达标了吗&#xff1f; 引导 根据国家市场监督管理总局、国家标准化管理委员会发布中华人民共和国国家标准公告&#xff08;2023年第1号&#xff09;&#xff0c;由全国信息安全标准化技术委员会归口的《信息安全技术 网络安全从业…

设计模式15-门面模式

设计模式15-门面模式 "接口隔离"模式典型模式1. 适配器模式&#xff08;Adapter Pattern&#xff09;2. 装饰模式&#xff08;Decorator Pattern&#xff09;3. 桥接模式&#xff08;Bridge Pattern&#xff09;4. 代理模式&#xff08;Proxy Pattern&#xff09;5. …

分布式日志分析系统--ELK

文章目录 ELK概述ELK主要特点ELK应用架构 Elasticsearch原理JSON格式倒排索引 ES与关系型数据库ES相关概念ES安装说明1.环境初始化2.优化系统资源限制配置3.编辑ES服务文件elasticsearch. yml 优化ELK集群安装脚本scp的使用集群安装成功 Shell命令API使用创建索引创建Type创建分…

yocto系列讲解[实战篇]95 - 使用外部第三方交叉编译器toolchain

By: fulinux E-mail: fulinux@sina.com Blog: https://blog.csdn.net/fulinus 喜欢的盆友欢迎点赞和订阅! 你的喜欢就是我写作的动力! 目录 概述下载toolchain包部署toolchain下载yocto下载toolchain layer添加toolchain layer配置toolchain变量编译和测试验证返回总目录:Yo…

中控屏UI设计全解析:布局与交互技巧

在现代科技的浪潮中&#xff0c;中控屏已成为智能系统不可或缺的交互界面。无论是智能家居、车载系统还是工业控制&#xff0c;一个直观、易用且美观的中控屏 UI 设计对于提升用户体验至关重要。本教程将带领你深入探索中控屏UI设计的精髓&#xff0c;指导你如何打造出既专业又…

一些Kafka面试题

Kafka是如何保证消息不丢失&#xff1f; 1.生产者发送消息到Broker丢失&#xff1a; 设置异步发送&#xff1a;发送失败则使用回调进行记录或者重发 消息重试&#xff1a;参数配置&#xff0c;可以设置重试次数 2.消息在broker中存储丢失 发送确认机制acks acks0&#xf…

创新突破 | OpenCSG发布StarShip CodeReview v1.0.0 Beta版

1. 代码审查很关键但耗时耗力 在软件开发过程中&#xff0c;代码审查是确保代码质量的关键环节。代码审查有助于维护代码标准和发现潜在错误&#xff0c;但也常常耗费大量时间和精力。审查者不仅需要深入理解代码逻辑&#xff0c;还要在繁复的逻辑中识别Bug&#xff0c;这个过…

如何使用 Odoo 16 主生产调度程序规划生产

为了优化运营并提高生产力&#xff0c;企业需要生产管理软件。在当今竞争激烈的经济环境中&#xff0c;有效的资源管理对企业至关重要。为制造业务设计的软件经常用于控制收入增长和盈利能力。ERP&#xff08;企业资源规划&#xff09;系统是专门为制造业创建的&#xff0c;可以…

Java刷题: 丑数判断

题目 丑数 就是只包含质因数 2、3 和 5 的正整数。 给你一个整数 n &#xff0c;请你判断 n 是否为 丑数 。如果是&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 解题思路 我觉得刷题是为了扩宽思考的广度。看到这题的时候&#xff0c;我的大脑是发懵的…

技术成神之路:设计模式(十)备忘录模式

介绍 备忘录模式&#xff08;Memento Pattern&#xff09;是一种行为设计模式&#xff0c;它允许在不破坏封装性的前提下捕获和恢复对象的内部状态。通过备忘录模式&#xff0c;可以在程序运行过程中保存和恢复对象的某个状态&#xff0c;从而实现“撤销”等功能。 1.定义 备忘…

11 优化器

目录 1. 随机梯度下降系优化器&#xff1a;SGD 1.1 算法种类 1.2 优缺点 2 SGDM 即为SGD with momentum 动量 2.1 公式 2.2 动量的优缺点 优点 缺点 2.3 使用场景 3 AdaGrad 3.1 公式 3.2 AdaGrad的优缺点 优点 缺点 3.3 使用场景 3.4 Adam 3.4.1 Adam优化器的…

倒计时:60秒后再输入验证码

思路1&#xff1a;每隔 1 秒种减 1 &#xff0c;直到减到 0 为止。可以写成公用方法。亲测有效。 countDown(){ const TIME_COUNT 60; if (!this.timer) { this.count TIME_COUNT; this.codeShow false; this.timer setInterval(() > { if (this.count > 0 &&…

苹果密码解锁工具已注册专业版_不限制电脑

Aiseesoft iPhone Unlocker&#xff1a;轻松解锁iPhone。功能强大&#xff1a;一键移除4位、6位密码、Touch ID和Face ID。隐私保护&#xff1a;创建密码&#xff0c;安全无忧。数据提醒&#xff1a;解锁时&#xff0c;注意数据和设置将被清除。Apple ID 解锁&#xff1a;快速删…

【Spring Boot教程:从入门到精通】掌握Spring Boot开发技巧与窍门(三)-配置git环境和项目创建

主要介绍了如何创建一个Springboot项目以及运行Springboot项目访问内部的html页面&#xff01;&#xff01;&#xff01; 文章目录 前言 配置git环境 创建项目 ​编辑 在SpringBoot中解决跨域问题 配置Vue 安装Nodejs 安装vue/cli 启动vue自带的图形化项目管理界面 总结 前言 …

Qt基础 | TCP通信 | TCP服务端与客户端程序设计 | QTcpServer | QTcpSocket

文章目录 一、TCP 通信1.TCP 通信概述2.TCP 服务器端程序设计2.1 主窗口定义与构造函数2.2 网络监听与 socket 连接的建立2.3 与 TCP 客户端进行数据通信 3.TCP 客户端程序设计3.1 主窗口定义与构造函数3.2 与服务器端建立 socket 连接3.3 与 TCPServer 的数据收发 4.小结 Qt 网…