首页 > 其他分享 >APP逆向 day26unidbg下-pdd(anti)案例

APP逆向 day26unidbg下-pdd(anti)案例

时间:2024-08-05 19:23:49浏览次数:17  
标签:lang return String APP vm equals anti day26unidbg signature

一.前言

今天我们讲unidbg的下篇,也就是unidbg基础的最后一个部分,我们上节课也有补环境,比如补java环境,补安卓环境,这节课我们讲的肯定比这些都要难,我会给出一个之前讲过的案例,然后会讲一个全新的案例,pdd,这个里面的环境就更加难了,让我们接着往下看吧

二.B站sign参数

2.1 回顾sign

不记得的可以去往期回顾一下,这里给出地址

APP逆向 day18某站逆向 part3-CSDN博客文章浏览阅读1.2k次,点赞23次,收藏19次。因为之前被封,所以很久才更新,今天这个主要是后面的两个hook脚本很重要,app逆向是真的难,真的难找,很大一部分比的就是大家的hook代码。https://blog.csdn.net/weixin_74178589/article/details/140632798?spm=1001.2014.3001.5502我这里给出几张重要的截图

 我们找到这个this.b就是sign值

 

this.b是signedQuery初始化传入的第二个参数

在这里传媒如一个map对象最后tostring 

 

最后执行s在c中进行加密

加密的so文件时libbili.so

2.2 分析

1 so文件和方法
    libbili.so
    static native SignedQuery s(SortedMap<String, String> sortedMap);
2 入参和返回值
    入参:sortedMap---》hook得到数据--》包裹--》传给unidbg
    返回值:SignedQuery类型---》app自己定义的类型
        
        
3 hook 参数和返回值
入参:
map= {actual_played_time=0, aid=884507902, appkey=1d8b6e7d45233436, auto_play=0, build=6240300, c_locale=zh-Hans_CN, channel=xxl_gdt_wm_253, cid=233035308, epid=0, epid_status=, from=2, from_spmid=main.ugc-video-detail.0.0, last_play_progress_time=0, list_play_time=0, max_play_progress_time=0, mid=0, miniplayer_play_time=0, mobi_app=android, network_type=1, paused_time=0, platform=android, play_status=0, play_type=1, played_time=0, quality=32, s_locale=zh-Hans_CN, session=907a218ff7237664b2910757062ce5a40d1f08fc, sid=0, spmid=main.ugc-video-detail.0.0, start_ts=0, statistics={"appId":1,"platform":3,"version":"6.24.0","abtest":""}, sub_type=0, total_time=0, type=3, user_status=0, video_duration=674}
返回值= actual_played_time=0&aid=884507902&appkey=1d8b6e7d45233436&auto_play=0&build=6240300&c_locale=zh-Hans_CN&channel=xxl_gdt_wm_253&cid=233035308&epid=0&epid_status=&from=2&from_spmid=main.ugc-video-detail.0.0&last_play_progress_time=0&list_play_time=0&max_play_progress_time=0&mid=0&miniplayer_play_time=0&mobi_app=android&network_type=1&paused_time=0&platform=android&play_status=0&play_type=1&played_time=0&quality=32&s_locale=zh-Hans_CN&session=907a218ff7237664b2910757062ce5a40d1f08fc&sid=0&spmid=main.ugc-video-detail.0.0&start_ts=0&statistics=%7B%22appId%22%3A1%2C%22platform%22%3A3%2C%22version%22%3A%226.24.0%22%2C%22abtest%22%3A%22%22%7D&sub_type=0&total_time=0&ts=1716387614&type=3&user_status=0&video_duration=674&sign=ed5a33857d99b8442a3fe182aa214eed


4 拼凑出SortedMap--》包裹后---》传给unidbg
    包裹方式一:ProxyDvmObject.createObject(vm,map)
    包裹方式一:vm.resolveClass("类").newObject(map)
    
5 返回值:SignedQuery类型
    app自定义类型---》可以DvmObject<?>类型泛指---》unidbg中所有类型,父类都是DvmObject---》StringObject也是DvmObject---》拿到具体的值DvmObject对象.getValue()
    

6 是否需要不环境?libbili.so中的s方法
    -so内部一定执行了  c调用java
        -c中是没有SignedQuery类的--》返回值是SignedQuery的对象
        -于是:c内部一定调用了java

7 所以在c内部调用java,完成SignQuery的初始化--》必须传入两个参数
而第二个参数,就是sign的值
          public SignedQuery(String str, String str2) {
                this.a = str;
                this.b = str2;
            }

8 分析:so内部--》传入sortedMap,通过某种加密方式加密---》通过c调用java,实例化得到了SignedQuery对象,第一个参数是:sortedMap转成了字符串,第二个参数就是  sign 的加密结果

9 使用unidbg运行时,一定需要补环境--》SignedQuery--》两种方案破解sign
    -1 在需要补SignedQuery环境时,打印出第二个参数,其实就是sign
    -2 完整补SignedQuery,自己把返回的SignedQuery对象,调用toString,返回整个字符串
 

这里我会讲第二种,讲第二种的时候也能讲到第一种,那我们先编写大致逻辑框架,除sign函数以外的直接c就好了

2.3 unidbg运行

 我们直接把unidbg初始化写好,然后运行发现不报错,那么我们现在就要开始编写sign部分的代码了

编写sign中的内容

这里主要是 SignedQuery是apk内部定义的,我们这里没有,所以用一个 DvmObject<?>来接受,这个是所有返回值的父类,然后最后返回 String res=singedQuery.getValue().toString();调用他内部的tostring方法,这样就能跑出最后结果

这里给出编写sign的代码

    public void sign(){
        // 0 构造SortedMap
        SortedMap<String, String> map=new TreeMap<String, String>();
        // 这不全--》我们目标是把sign跑出来,所以暂时传这一点点
        map.put("actual_played_time", "0");
        map.put("aid", "884507902");
        map.put("appkey", "1d8b6e7d45233436");
        map.put("auto_play", "0");
        map.put("ts", "1647952932");

        // 1 找到java类中jni的类  native方法,找的时候是固定写法
        DvmClass LibBili = vm.resolveClass("com/bilibili/nativelibrary/LibBili");

        // 这个返回值是apk内部的,包名类名前面加个L
        String method = "s(Ljava/util/SortedMap;)Lcom/bilibili/nativelibrary/SignedQuery;";

        //3 执行方法
        // 之前我们写的返回值都是StringObject 或者ByteArray
        // 但是这个前面分析他的返回值类型是signedQuery 而这个是apk内部定义的类,我们此时就可以使用DvmObject<?> ,这个是unidbg中所有返回值的父类
        DvmObject<?> singedQuery = LibBili.callStaticJniMethodObject(
                emulator,
                method,
                ProxyDvmObject.createObject(vm, map)
        );

        // 4 打印结果
        // singedQuery.getValue()--->SignedQuery 的对象-->有个toString方法--->返回字符串--》带sign的字符串,这样结果就是字符串类型了
        String res=singedQuery.getValue().toString();
        System.out.println(res);

    }

2.4 补环境

运行肯定会报错,这里我们就需要补环境

 这个就是传入一个字典,判断是否为空

我们有两种操作,一种直接返回True(因为我们知道传入的字典不为空),另一种就是主动调用

那我们又来补这个,这个不就是字典根据键来取值嘛,应该是字符串类型的,只是他用了object来泛指

 这里我们知道是string类型,所以可以用方式二来写,如果不知道的话,可以直接用第一种方便的来

我们运行看看

这个不就是调用了java中自己定义的方法吗

这个我就带着大家一步步来写

我们按照他的逻辑来,是不是补成这样,但是少了 SignedQuery类,还有里面的r方法,那我们去源代码里面扣一个来

把这个r方法扣进来,发现报错的有 TextUtils.isEmpty, b, ContainerUtils.FIELD_DELIMITER

很明显b是里面定义的方法,那TextUtils.isEmpty是什么呢,他是安卓中的判断是否为空,可以去chatgpt问一下,这里是不是可以直接调用string中的内置方法isEmpty()来替换呢ContainerUtils.FIELD_DELIMITER我们双击点进去发现是"&",也可以直接替换

b方法直接c就行了

我们把那些修改,再把b给扣进去,发现又需要c,我们再扣,这后面我就不说了,流程都一样,接着扣,修改就行了,补完之后,我们再运行

那我们就接着补,我们补之前先来分析一下这个代码,这个不就是SignedQuery类实例化的时候传入两个参数嘛,而这个第二个参数不就是我们要的sign值嘛,当时我们说了可以完整补完,也可以部分补,那我们来演示一下

 这样不就是了吗,这里异常报错是因为我们没有补完,因为我们最后返回的对象是个空嘛,然后上面最开始的又打印了最后的字符串,所以报错了

那我们现在完整的补

发现我们打印的结果是这个鬼样子,这个是为啥呢,这个不就是打印java中类的地址吗,只有调用的,这个不就是没有调用toString嘛,还记得我们当是不是通过toString来定位加密位置的,所以我们抠代码要把toString带上,那个相当于重写

这样就出结果啦

这里给出完整补环境代码

//放到sign内部
    @Override
    public boolean callBooleanMethod(BaseVM vm, DvmObject<?> dvmObject, String signature, VarArg varArg) {
        if(signature.equals("java/util/Map->isEmpty()Z")){
            //这个就是判断是不是这个字典是不是空嘛
            //方式一,直接返回True,因为我们已经知道这个字典不是空
            //return true;

            //方式二 主动调用,取出传入的对象
            Map m=(Map)dvmObject.getValue();
            // 打印这个map看一下,就是我们拼凑出来,传入的
            return m.isEmpty();
        }

        return super.callBooleanMethod(vm, dvmObject, signature, varArg);
    }

    @Override
    public DvmObject<?> callObjectMethod(BaseVM vm, DvmObject<?> dvmObject, String signature, VarArg varArg) {
        if(signature.equals("java/util/Map->get(Ljava/lang/Object;)Ljava/lang/Object;")){
            // 报错是:map根据key去取值--》c调用java--》map.get('actual_played_time')
            // 方式一:使用Object泛指:
            // Map m =(Map) dvmObject.getValue();
            // //取出参数:取第0个参数--》我们这个只有一个参数
            //Object key=varArg.getObjectArg(0).getValue();
            // Object value=m.get(key);
            // return ProxyDvmObject.createObject(vm,value);

            //方式二,知道了具体是string类型
            Map m =(Map) dvmObject.getValue();
            //取出参数:取第0个参数--》我们这个只有一个参数
            String key=(String)varArg.getObjectArg(0).getValue();
            String value=(String)m.get(key);
            return new StringObject(vm,value);
        }


        return super.callObjectMethod(vm, dvmObject, signature, varArg);
    }

    @Override
    public DvmObject<?> callStaticObjectMethod(BaseVM vm, DvmClass dvmClass, String signature, VarArg varArg) {
        if(signature.equals("com/bilibili/nativelibrary/SignedQuery->r(Ljava/util/Map;)Ljava/lang/String;")){
            // SignedQuery对象--》调用r方法,传入map,返回字符串
            // 首先拿到参数 varArg.getObjectArg
            Map m =(Map) varArg.getObjectArg(0).getValue();

            // 然后我们取对象就不能用dvmObject,因为这个里面没有SignedQuery,apk定义的,得我们主动创建
            String res=SignedQuery.r(m);
            return new StringObject(vm,res);
        }


        return super.callStaticObjectMethod(vm, dvmClass, signature, varArg);
    }

    @Override
    public DvmObject<?> newObject(BaseVM vm, DvmClass dvmClass, String signature, VarArg varArg) {
        if(signature.equals("com/bilibili/nativelibrary/SignedQuery-><init>(Ljava/lang/String;Ljava/lang/String;)V")){
            // 方式一:打印sign 第二个参数就是
            //  String sign=(String) varArg.getObjectArg(1).getValue();
            // System.out.println(sign);
            // return vm.resolveClass("com/bilibili/nativelibrary/SignedQuery").newObject(null);

            // 方式二:补齐,实例化得到对象
            String v1=(String) varArg.getObjectArg(0).getValue();
            String sign=(String) varArg.getObjectArg(1).getValue();
            SignedQuery sq=new SignedQuery(v1,sign);
            return vm.resolveClass("com/bilibili/nativelibrary/SignedQuery").newObject(sq);


        }

        return super.newObject(vm, dvmClass, signature, varArg);
    }


//定义类,单独放
class SignedQuery{
    public final String a;
    public final String b;
    private static final char[] f15567c = "0123456789ABCDEF".toCharArray();


    public SignedQuery(String str, String str2) {
        this.a = str;
        this.b = str2;
    }




    static String r(Map<String, String> map) {
        if (!(map instanceof SortedMap)) {
            map = new TreeMap(map);
        }
        StringBuilder sb = new StringBuilder(256);
        for (Map.Entry<String, String> entry : map.entrySet()) {
            String key = entry.getKey();
            if (!key.isEmpty()) {
                sb.append(b(key));
                sb.append("=");
                String value = entry.getValue();
                sb.append(value == null ? "" : b(value));
                sb.append("&");
            }
        }
        int length = sb.length();
        if (length > 0) {
            sb.deleteCharAt(length - 1);
        }
        if (length == 0) {
            return null;
        }
        return sb.toString();
    }

    static String b(String str) {
        return c(str, null);
    }

    static String c(String str, String str2) {
        StringBuilder sb = null;
        if (str == null) {
            return null;
        }
        int length = str.length();
        int i = 0;
        while (i < length) {
            int i2 = i;
            while (i2 < length && a(str.charAt(i2), str2)) {
                i2++;
            }
            if (i2 == length) {
                if (i == 0) {
                    return str;
                }
                sb.append((CharSequence) str, i, length);
                return sb.toString();
            }
            if (sb == null) {
                sb = new StringBuilder();
            }
            if (i2 > i) {
                sb.append((CharSequence) str, i, i2);
            }
            i = i2 + 1;
            while (i < length && !a(str.charAt(i), str2)) {
                i++;
            }
            try {
                byte[] bytes = str.substring(i2, i).getBytes("UTF-8");
                int length2 = bytes.length;
                for (int i3 = 0; i3 < length2; i3++) {
                    sb.append('%');
                    sb.append(f15567c[(bytes[i3] & 240) >> 4]);
                    sb.append(f15567c[bytes[i3] & 15]);
                }
            } catch (UnsupportedEncodingException e) {
                throw new AssertionError(e);
            }
        }
        return sb == null ? str : sb.toString();
    }

    private static boolean a(char c3, String str) {
        return (c3 >= 'A' && c3 <= 'Z') || (c3 >= 'a' && c3 <= 'z') || !((c3 < '0' || c3 > '9') && "-_.~".indexOf(c3) == -1 && (str == null || str.indexOf(c3) == -1));
    }

    public String toString() {
        String str = this.a;
        if (str == null) {
            return "";
        }
        if (this.b == null) {
            return str;
        }
        return this.a + "&sign=" + this.b;
    }

}

三.PDD anti-token破解

3.1 目标

1.目标
    破解搜索功能请求头中的  anti-token
    
2.版本选择:v6.32.0
1 通过hook查找方法在那个so文件中--》之前学过
    -动态注册脚本,静态注册脚本
    
3.补环境:app内部的参数值,系统参数值---》通过frida-hook得到--》搜索得到写死

4.使用SocksDroid转发再进行抓包

3.2 抓包和反编译搜索

 我们发现有时候配置了 SocksDroid也抓不到,那我们在无网络的时候进入,然后有网络了立马抓,这样就能抓到了

我们要破的就是这个吗,那我们现在来发编译搜索

我们直接搜索anti-token

 

发现很多地方,我这里直接告诉大家是第四个,我们点进去

发现f就是那个,那我们点进去看看

 

发现f是是一个接口,那我们是不是要找到这个接口的具体实现类,那我们查找这个接口的用例

这里我告诉大家是最后一个,我们点进去

我们找到这个f的实现类在这里,我们再点进去

 

我们再点进去

 

发现在这里,这不就是jni的方法吗,但是这里没有给出哪个so文件,我们之前给大家说过hook静态注册和动态注册,不知道大家记不记得,但是在hook之前我们先hook确定传入的参数,第一个参数是context,我们先不管,看看另一个参数是啥

 发现参数就是时间戳

那我们接下来就hook一下是静态注册和动态注册来判断so文件了,我直接告诉大家是动态注册,大家也可以去试试

hook完长这样 说明是在libpdd_secure.so里面,那我们把这两个都c到unidbg里面去

3.3 unidbg跑

我们编写好主要的初始化函数和sign方法

 

我们运行一下

 发现报错,那我们开始补环境

3.4 补环境

3.4.1 补腾讯日志库

我们在刚才报错截图里可以看到tencent,那我们百度搜索一下,这个是腾讯日志库,那我们就补

 他这个是日志,而且是void,我们直接return; 就好了

3.4.2 补手机权限

我们搜索发现 这个是获取手机权限的

1 报错是: android/content/Context->checkSelfPermission(Ljava/lang/String;)I
2 安卓开发者--》在Manifest文件中添加权限
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ANSWER_PHONE_CALLS" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    
3 用户使用app,会弹窗提醒

4  ContextCompat.checkSelfPermission()方法检测授权状态,返回的结果为PackageManager中的两个常量:PERMISSION_GRANTED(已授权)和PERMISSION_DENIED(未授权)
    public static final int PERMISSION_DENIED = -1; # 未授权
    public static final int PERMISSION_GRANTED = 0; # 授权
    
    
5 获取这个返回值的方式:
    获取方式一:我们可以通过hook拿到
    获取方式二:我们直接搜索写死-1或0
    获取方式三:我们自己写安卓应该,看自己手机的状态

那我们直接返回0,其实要返回-1的,后面出问题了再解释

 

3.4.3 getSystemService

再次运行

1  android/content/Context->getSystemService(Ljava/lang/String;)Ljava/lang/Object;
    -获得SystemService,后期为了拿到:sim卡状态,网络状态,运行商,电池。。。
    
2 安卓中对应
/*
* SIM的状态信息:
*  SIM_STATE_UNKNOWN             未知状态 0
*  SIM_STATE_ABSENT                 没插卡 1
*  SIM_STATE_PIN_REQUIRED     锁定状态,需要用户的PIN码解锁 2
*  SIM_STATE_PUK_REQUIRED    锁定状态,需要用户的PUK码解锁 3
*  SIM_STATE_NETWORK_LOCKED   锁定状态,需要网络的PIN码解锁 4
*  SIM_STATE_READY            就绪状态 5
*/ 

 我们再运行

发现这个错和补环境没关系,那是因为安卓11之后不允许获取手机权限, 所以得返回-1

改完之后再运行

 

 这里我就不和前面一样说为什么了,大家百度搜一下就知道啦,然后补系统方法,我就一次补好,我和大家说一下补app自己的方法

3.4.4 补app自己的方法

我们发现报这个错误,一是可以去app中找逻辑,二是可以直接hook,发现是个固定值,这里就不给出hook脚本了

 

3.4.5 补系统方法isDebuggerConnected

isDebuggerConnected是否有调试器挂载到程序上

运行

 

3.4.6 补异常

后面的报错我就先过,自己搜搜就知道了

3.4.7 补replace

补到发现报这个错,这个就是replace,要动脑子,我教大家补

 

3.4.8 补文件操作

发现报这个错,这个是文件的,我一次给大家补好

 

 

这些都补好之后,正常出值了

 

3.4.9 补环境代码

代码如下


    @Override
    public void callStaticVoidMethodV(BaseVM vm, DvmClass dvmClass, String signature, VaList vaList) {
        if(signature.equals("com/tencent/mars/xlog/PLog->i(Ljava/lang/String;Ljava/lang/String;)V")){
            return;
        }

        super.callStaticVoidMethodV(vm, dvmClass, signature, vaList);
    }

    @Override
    public int callIntMethod(BaseVM vm, DvmObject<?> dvmObject, String signature, VarArg varArg) {
        if(signature.equals("android/content/Context->checkSelfPermission(Ljava/lang/String;)I")){
            String s=(String) varArg.getObjectArg(0).getValue();
            // System.out.println(s); // android.permission.READ_PHONE_STATE
            return -1;
        }
        if(signature.equals("android/telephony/TelephonyManager->getSimState()I")){
            return 5; // 表示没插卡
        }

        if (signature.equals("android/telephony/TelephonyManager->getNetworkType()I")) {
            // 网络类型:https://codeleading.com/article/33471321733/
            return 13;
        }
        if (signature.equals("android/telephony/TelephonyManager->getDataState()I")) {
            return 0;
        }
        if (signature.equals("android/telephony/TelephonyManager->getDataActivity()I")) {
            return 4;
        }
        return super.callIntMethod(vm, dvmObject, signature, varArg);
    }

// 补:callObjectMethod

    @Override
    public DvmObject<?> callObjectMethod(BaseVM vm, DvmObject<?> dvmObject, String signature, VarArg varArg) {
        if(signature.equals("android/content/Context->getSystemService(Ljava/lang/String;)Ljava/lang/Object;")){
            // 补个null---》后续,在c中调用 SystemService 获取手机状态信息--》再缺什么就继续补:sim卡信息,运行上信息。。。
            return vm.resolveClass("android/telephony/TelephonyManager").newObject(null);
            //不能用 ProxyDvmObject.createObject(vm,null) 补

        }
        if(signature.equals("android/telephony/TelephonyManager->getSimOperatorName()Ljava/lang/String;")){
            // 拿运营商:getSimOperatorName
            return new StringObject(vm, "中国电信");
        }
        if(signature.equals("android/telephony/TelephonyManager->getSimCountryIso()Ljava/lang/String;")){
            // 拿地区
            return new StringObject(vm, "cn");
        }
        if (signature.equals("android/telephony/TelephonyManager->getNetworkOperator()Ljava/lang/String;")) {
            //https://blog.csdn.net/ztp800201/article/details/44198031/
            return new StringObject(vm, "46003");
        }
        if (signature.equals("android/telephony/TelephonyManager->getNetworkOperatorName()Ljava/lang/String;")) {
            //https://blog.csdn.net/Myfittinglife/article/details/118685804
            return new StringObject(vm, "中国电信");
        }
        if (signature.equals("android/telephony/TelephonyManager->getNetworkCountryIso()Ljava/lang/String;")) {
            // 获取国家代码
            return new StringObject(vm, "cn");
        }
        if (signature.equals("java/lang/Throwable->getStackTrace()[Ljava/lang/StackTraceElement;")) {
            return new ArrayObject(vm.resolveClass("java/lang/StackTraceElement").newObject(null));
        }
        if (signature.equals("java/lang/StackTraceElement->getClassName()Ljava/lang/String;")) {
            return new StringObject(vm, "");
        }

        if (signature.equals("java/io/ByteArrayOutputStream->toByteArray()[B")) {
            ByteArrayOutputStream obj = (ByteArrayOutputStream) dvmObject.getValue();
            return new ByteArray(vm, obj.toByteArray());
        }
        return super.callObjectMethod(vm, dvmObject, signature, varArg);
    }

    @Override
    public DvmObject<?> callStaticObjectMethodV(BaseVM vm, DvmClass dvmClass, String signature, VaList vaList) {
        if (signature.equals("com/xunmeng/pinduoduo/secure/EU->gad()Ljava/lang/String;")) {
            return new StringObject(vm, "7202111111112f2");
        }
        return super.callStaticObjectMethodV(vm, dvmClass, signature, vaList);
    }

    @Override
    public boolean callStaticBooleanMethod(BaseVM vm, DvmClass dvmClass, String signature, VarArg varArg) {
        if (signature.equals("android/os/Debug->isDebuggerConnected()Z")) {
            return false;
        }
        return super.callStaticBooleanMethod(vm, dvmClass, signature, varArg);
    }

    @Override
    public DvmObject<?> newObject(BaseVM vm, DvmClass dvmClass, String signature, VarArg varArg) {
        if (signature.equals("java/lang/Throwable-><init>()V")) {
            Throwable t=new Throwable(); // 可以new出来,可以传null
            return vm.resolveClass("java/lang/Throwable").newObject(t);
        }
        //补文件
        if (signature.equals("java/io/ByteArrayOutputStream-><init>()V")) {
            ByteArrayOutputStream obj = new ByteArrayOutputStream();
            return vm.resolveClass("java/io/ByteArrayOutputStream").newObject(obj);
        }
        if (signature.equals("java/util/zip/GZIPOutputStream-><init>(Ljava/io/OutputStream;)V")) {
            try {
                OutputStream chunk = (OutputStream) varArg.getObjectArg(0).getValue();
                GZIPOutputStream obj = new GZIPOutputStream(chunk);
                return vm.resolveClass("java/util/zip/GZIPOutputStream").newObject(obj);
            } catch (Exception e) {
                System.out.println("写入错误1" + e);
            }
        }


        return super.newObject(vm, dvmClass, signature, varArg);
    }
    public DvmObject<?> callObjectMethodV(BaseVM vm, DvmObject<?> dvmObject, String signature, VaList vaList) {
        if (signature.equals("java/lang/String->replaceAll(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;")) {
            String origin = (String) dvmObject.getValue();
            String a0 = (String) vaList.getObjectArg(0).getValue();
            String a1 = (String) vaList.getObjectArg(1).getValue();
            String result = origin.replaceAll(a0, a1);
            return new StringObject(vm, result);
        }
        return super.callObjectMethodV(vm, dvmObject, signature, vaList);
    }

    public void callVoidMethod(BaseVM vm, DvmObject<?> dvmObject, String signature, VarArg varArg) {
        if (signature.equals("java/util/zip/GZIPOutputStream->write([B)V")) {
            GZIPOutputStream obj = (GZIPOutputStream) dvmObject.getValue();
            byte[] chunk = (byte[]) varArg.getObjectArg(0).getValue();
            try {
                obj.write(chunk);
            } catch (Exception e) {
            }
            return;
        }
        if (signature.equals("java/util/zip/GZIPOutputStream->finish()V")) {
            GZIPOutputStream obj = (GZIPOutputStream) dvmObject.getValue();
            try {
                obj.finish();
            } catch (Exception e) {
            }
            return;
        }
        if (signature.equals("java/util/zip/GZIPOutputStream->close()V")) {
            GZIPOutputStream obj = (GZIPOutputStream) dvmObject.getValue();
            try {
                obj.close();
            } catch (Exception e) {
            }
            return;
        }
        super.callVoidMethod(vm, dvmObject, signature, varArg);
    }

四.总结 

今天的内容很多,主要pdd的环境是真的难,难所以值钱呀,我至少写了10个小时,感谢点赞关注加收藏,发现补环境是不是很恼火,没办法,纯算更难,加油补吧!

补充

有需要源码的看我主页签名名字私

 

 

 

 

标签:lang,return,String,APP,vm,equals,anti,day26unidbg,signature
From: https://blog.csdn.net/weixin_74178589/article/details/140875955

相关文章

  • 《Advanced RAG》-05-探索语义分块(Semantic Chunking)
    摘要文章首先介绍了语义分块在RAG中的位置和作用,并介绍了常见的基于规则的分块方法。然后,阐述了语义分块的目的是确保每个分块包含尽可能多的独立语义信息。接着,文章分别介绍了三种语义分块方法的原理和实现方法,并对每种方法进行了总结和评估。文章观点语义分块是R......
  • Android Camera close异常导致app的input ANR案例分析
    1.背景在日常的项目开发过程中,经常会收到用户或者测试同仁报过来的ANR(ApplicationNotResponse)的问题,本文结合作者的日常工作中遇到的典型案例,分享ANR的分析过程。ANR(‌ApplicationNotResponding)‌主要分为以下几种类型:‌Inputdispatchingtimedout:‌当输入事件(......
  • 出现 No mapping for DELETE/GET等
    出现NomappingforDELETE/GET等错误一:请求url不对修改前如下图可知后端请求url为http://localhost:8080/user/addressBook运行后控制台出现发现后端请求url比前端请求url少了/改正:在@DeleteMapping后面加上/ @DeleteMapping("/")@ApiOperation("根据id......
  • Apple开发_正则表达式相关
    NSString+Regex.h#import<Foundation/Foundation.h>//正则表达式相关@interfaceNSString(Regex)//邮箱验证-(BOOL)is_Email;//手机号码验证-(BOOL)is_Phone_Num;//车牌号验证-(BOOL)is_Car_No;//网址验证-(BOOL)is_Url;//邮政编码-(BOOL)is_......
  • iOS开发基础147-ABM集中管理Apple设备
    AppleBusinessManager(ABM)是一种集中管理Apple设备、应用程序和内容的解决方案。它可以帮助企业简化部署和管理Apple设备。接入ABM可以让公司在设备设置、应用分发和内容管理方面更加高效和灵活。与传统的企业开发者账号(即AppleDeveloperEnterpriseProgram)和MDM(MobileDev......
  • SpringBoot-书店信息管理系统+93494(免费领源码+开发文档)可做计算机毕业设计JAVA、PHP
    基于springboot书店信息管理系统摘 要书店信息管理系统采用B/S结构、java开发语言、以及Mysql数据库等技术。系统主要分为管理员和用户两部分,管理员管理主要功能包括:首页、轮播图、公告栏、资源管理(图书资讯、资讯分类)交流管理(留言板、留言板分类)系统用户(管理员、顾客用户......
  • spring bean生命周期中BeanNameAware、BeanFactoryAware或ApplicationContextAwar
    BeanNameAware、BeanFactoryAware和ApplicationContextAware是Spring框架中提供的三个Aware接口,它们允许Bean在生命周期的特定阶段获取关于自身或容器的信息。以下是关于这三个Aware接口的详细解释:1.BeanNameAware定义与功能:BeanNameAware接口允许Bean获取自己在Spring......
  • uniapp底部栏设置未读红点或角标
    uniapp底部栏设置未读红点或角标pages.json{...//省略"tabBar":{"color":"#333333","selectedColor":"#3296fa","backgroundColor":"#ffffff","bor......
  • uniapp页面跳转传参
    uniapp页面跳转传参1.uni.navigateTo传:<view@click="showDetail({id:1})"></view>showDetail(data){uni.navigateTo({url:"/pages/sys/workbench/productCenterFirm/productCenterFirmDetail?id="+......
  • uniapp中u-input点击事件失效
    uniapp中u-input点击事件失效当给u-input设置了disabled/readonly属性后,pc浏览器中点击事件失效,但是app/移动端h5中却仍有效解决办法给外边包上一个盒子设置点击事件,给input加上css属性:pointer-events:nonepointer-eventsCSS属性指定在什么情况下(如果有)某个特定的图......