1、上次自己构造了一个app来调用x音的关键so,结果在一条“LDR  R0, [R4,#0xC] “语句卡住了:通过ida查看得知:R4就是第三个参数,这里被当成了地址使用(java层怪不得用long类型)!第三个参数我是用frida hook得到的,换了个环境地址肯定也变了,所以这里直接”抄袭“拿过来用肯定报错,这种反调试的方法实在是秒啊!动态调试暂时卡壳,我们先来静态分析一下卡住语句的上下游:

.text:000139A4 000 F0 B5                       PUSH            {R4-R7,LR}
.text:000139A6 014 03 AF                       ADD             R7, SP, #0xC
.text:000139A8 014 2D E9 00 0F                 PUSH.W          {R8-R11}
.text:000139AC 024 93 B0                       SUB             SP, SP, #0x4C
.text:000139AE 070 CD E9 03 23                 STRD.W          R2, R3, [SP,#0x68+var_5C]
.text:000139B2 070 05 46                       MOV             R5, R0
.text:000139B4 070 3A 48                       LDR             R0, =(__stack_chk_guard_ptr - 0x139BC)
.text:000139B6 070 0C 46                       MOV             R4, R1
.text:000139B8 070 78 44                       ADD             R0, PC  ; __stack_chk_guard_ptr
.text:000139BA 070 00 68                       LDR             R0, [R0] ; __stack_chk_guard
.text:000139BC 070 01 90                       STR             R0, [SP,#0x68+var_64]
.text:000139BE 070 00 68                       LDR             R0, [R0]
.text:000139C0 070 38 49                       LDR             R1, =(unk_99110 - 0x139CA)
.text:000139C2 070 12 90                       STR             R0, [SP,#0x68+var_20]
.text:000139C4 070 E0 68                       LDR             R0, [R4,#0xC] ; 自己构造的app在R4的值是第3个long参数,地址无效
.text:000139C6 070 79 44                       ADD             R1, PC  ; unk_99110
.text:000139C8 070 10 90                       STR             R0, [SP,#0x68+var_28]
.text:000139CA 070 08 31                       ADDS            R1, #8
.text:000139CC 070 04 30                       ADDS            R0, #4  ; rwlock
.text:000139CE 070 0F 91                       STR             R1, [SP,#0x68+var_2C]
.text:000139D0 070 F3 F7 36 EF                 BLX             pthread_rwlock_rdlock
.text:000139D4 070 11 90                       STR             R0, [SP,#0x68+var_24]

  卡住的语句后面做了注释:从R4+C的地方取4字节数据存入R0,然后把R0存到栈上;接着把R0+4,这里ida已经识别出了是rwlock读写锁,然后就是调用pthread_rwlock_rdlock获取读写锁的读锁!这就很关键了:

读写锁机制下,允许同时有多个读者读访问共享资源,只有写者才需要独占资源。相比互斥机制,读写机制由于允许多个读者同时读访问共享资源,进一步提高了多线程的并发度。这里我个人猜测:加密字段输入了长长的url+http头的很多字段,需要输出4个加密字段,如果让单线程顺序读取并计算,效率很低,影响用户体验,所以使用多线程机制协同:多个线程同时读取输入,分别计算不同的加密字段

从这里开始用读写锁,结合上面的分析大胆猜测:接下来要开始生成加密字段了!换个角度,这个函数附近有好些地方都调用pThread_Create函数,从这里开始计算机密字段嫌疑很大!

  2、既然卡在了第三个地址参数,自然需要分析一下这个参数的来源,直接上frida,先hook h.a方法,看看这个函数在java层的调用路径:

at ms.bd.c.h.a(Native Method)
        at ms.bd.c.b.a()
        at ms.bd.c.u1$a.a(:34013379)

      发现是u1$a.a在调用,在jadx静态分析u1$a.a这个方法,发现是

String[] strArr = (String[]) C85964b.m218696a(50331649, 0, C86039u1.this.f357108d, str, (String[]) arrayList.toArray(new String[0]));  这行代码调用了b.a方法,里面涉及到了long参数(已经标黄),而这个long参数是u1类的成员变量,在u1.a方法被设置了,这个函数的参数只有1个long类型,继续hook这个方法:调用栈如下:

 [Android Emulator 5554::com.ss.android.ugc.aweme]-> 3069366032

java.lang.Throwable
        at ms.bd.c.u1.a(Native Method)
        at ms.bd.c.t1.a()
        at ms.bd.c.b$a.a()
        at ms.bd.c.b.b()
        at ms.bd.c.h.b()
        at ms.bd.c.h.a(Native Method)
        at ms.bd.c.b.a(:33882150)
        at ms.bd.c.m1.a()
        at com.bytedance.mobsec.metasec.ml.c.a()
        at com.ss.android.ugc.aweme.sec.SecApiImpl.initSec(SecApiImpl.kt:117965016)
        at com.ss.android.ugc.aweme.net.t$g.c(NetworkInitTask.kt:17170615)

   神奇地发现:居然还是h.a在调用,形成环形了,唯一的解释:h.a参数不同,生成的结果就不同!之前hook h.a的时候确实也发现了其他参数,但当时目的是追踪这4个加密字段,完全没重视其他参数。哎,悔不当初!

  接着追溯:上面调用栈中有一个方法是com.ss.android.ugc.aweme.sec.SecApiImpl.initSec,该方法部分代码如下(太多了,这里只贴一部分);

public final void initSec(Context context, String str, int i, String str2, String str3, boolean z, SecGetDataCallBack dVar) {
        String str4;
        if (!PatchProxy.proxy(new Object[]{context, str, Integer.valueOf(i), str2, str3, Byte.valueOf(z ? (byte) 1 : 0), dVar}, this, changeQuickRedirect, false, 338895).isSupported) {
            C51302a.m136764a(4, "Sec", "initSec");
            if (!PatchProxy.proxy(new Object[]{context, str, Integer.valueOf(i), str2, str3, Byte.valueOf((byte) z), dVar}, null, DmtSec.f284302a, true, 338875).isSupported) {
                DmtSec.f284308g = new SecInitReceiver(DmtSec.C66800a.f284321b);
                IntentFilter intentFilter = new IntentFilter();
                intentFilter.addAction("com.ms.init");
                DmtSec.m171500a(context, DmtSec.f284308g, intentFilter);
                SecLogger bVar = SecLogger.f284353b;
                bVar.mo193744a(SecLogger.f284354c, "init language = " + str + ", aid = " + i + ", appName = " + str2 + ", channel= " + str3);
                long currentTimeMillis = System.currentTimeMillis();
                long currentTimeMillis2 = System.currentTimeMillis();
                GlobalContext.setContext(context);
                C30329a.C30330a aVar = new C30329a.C30330a(String.valueOf(i), "bo95dJizD1WFcV03zOuLzN5Pn1sFtVa3szqiVQmflMJTNW0p0Kpqfw8D4i0zUlfrou4kuYt/i0521YRygM83dwv/wn3DD+TMJF+QFzW9wb8Qq2/1B4jPMbObrDNdyMMukpAYqy1fLWtbLGVIPxsFsZegwQy5lsRX9h49PH/Qx8MwgYvWvH7ZTFLV28LwTWZiljQyBPaBE+TsyumEu0Y+JRkeidHFEYcVs0yRoa+xC004hugQhdPupIt6dBiWA4phsB3fNJZjFTAKGE1lPB4gzt6Qf+FmlgZBbRvT8zekxTV2HZ5dUvSutB2/0QpbHKAvWL4DRA==");
                aVar.mo248346a(0);
                aVar.mo248347a("tk_key", "douyin");

   代码里面有写死的字符串,比如tk_key、douyin,还有很长的base64编码的bo95dJizD1WFcV03zOuLzN5Pn1sFtVa3sz....,刚好在hook h.a方法的时候,有一组参数是这样的:

enter=============ms.bd.c.h.a=======================================================
arg[0]:67108865
arg[1]:0
arg[2]:0
arg[3]:["1128","","","bo95dJizD1WFcV03zOuLzN5Pn1sFtVa3szqiVQmflMJTNW0p0Kpqfw8D4i0zUlfrou4kuYt\/i0521YRygM83dwv\/wn3DD+TMJF+QFzW9wb8Qq2\/1B4jPMbObrDNdyMMukpAYqy1fLWtbLGVIPxsFsZegwQy5lsRX9h49PH\/Qx8MwgYvWvH7ZTFLV28LwTWZiljQyBPaBE+TsyumEu0Y+JRkeidHFEYcVs0yRoa+xC004hugQhdPupIt6dBiWA4phsB3fNJZjFTAKGE1lPB4gzt6Qf+FmlgZBbRvT8zekxTV2HZ5dUvSutB2\/0QpbHKAvWL4DRA==","","","","","","0","-1",[],["tk_key","douyin"]]
arg[4]:null
java.lang.Throwable
    at ms.bd.c.h.a(Native Method)
    at ms.bd.c.b.a(:33882150)
    at ms.bd.c.m1.a()
    at com.bytedance.mobsec.metasec.ml.c.a()
    at com.ss.android.ugc.aweme.sec.SecApiImpl.initSec(SecApiImpl.kt:117965016)
    at com.ss.android.ugc.aweme.net.t$g.c(NetworkInitTask.kt:17170615)

  猜测args[3]就是在initSec这里拼凑出来的!回到u1.a方法的调用栈,分析这个栈的思路:一层一层网上追溯,看看到底是哪个地方改变了long参数的值,根据一些magic number,找到了

ms.bd.c.ml.a()函数,这个函数刚好有同样的magic number,并且也在调用栈上!从代码看,这个函数调用了b.a,然后b.a调用了h.a,也符合调用栈的回溯,而且调用的b.a的返回值下面也被强制转成了long类型,所以这里实锤了就是ms.bd.c.ml.a()生成了long参数!

         

frida通过rpc调用提供python编程接口 frida rpc_字段

        ms.bd.c.ml.a()调用ms.bd.c.b.a(67108866,str)函数生成了a,a被强制转成了long类型,所以这里重点关注ms.bd.c.b.a(67108866,str)这个函数;由于还有str参数不知道是啥,我们自己调用的时候也不知道怎么传参,所以这里继续hook ms.bd.c.b.a函数,看看传入了什么参数,如下:

enter=============ms.bd.c.b.a==========================
arg[0]:67108866
arg[1]:1128
java.lang.Throwable
        at ms.bd.c.b.a(Native Method)
        at ms.bd.c.m1.a()
        at com.bytedance.mobsec.metasec.ml.c.a()
        at com.ss.android.ugc.aweme.sec.SecApiImpl.initSec(SecApiImpl.kt:117965023)
        at com.ss.android.ugc.aweme.sec.SecApiImpl.initSec(Native Method)
        at com.ss.android.ugc.aweme.net.t$g.c(NetworkInitTask.kt:17170615)
        at com.bytedance.ies.ugc.aweme.network.f.a(Network.kt:34013540)
        at com.bytedance.ies.ugc.aweme.network.f$a.call(Network.kt:262169)
        at bolts.Task$10.run(Task.java:262180)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
        at com.ss.android.ugc.aweme.bp.d$3$1.run(NewInstanceFactory.java:262193)
        at java.lang.Thread.run(Thread.java:761)

ms.bd.c.b.a retval:-1500374080
 leave=============ms.bd.c.b.a==========================

  发现另一个参数是1128,返回是-1500374080=0xFFFFFFFFA6921BC0,看着确实像个地址;数值上和hook u1.a时看着差异较大,但我能确定就是这个函数生成了long参数,原因:

     (1)数值不等可能是js不制obj直接转成long导致的,需要想办法转换类型

     (2)从ms.bd.c.ml.a()函数的代码分析,调用ms.bd.c.b.a的返回的值被转成了long使用!

     (3)从frida打印函数调用的顺序看,打印了ms.bd.c.u1.a后立即打印ms.bd.c.h.a,说明这两个存在调用关系

  既然确认ms.bd.c.b.a返回了long,这里马上用自己的app调用ms.bd.c.b.a(67108866,"1128")试试,结果如下:函数的返回值居然是null!

       

frida通过rpc调用提供python编程接口 frida rpc_java_02

   这里出乎意料,我hook x音app时明明有返回的呀,并不是null!又出啥问题了? 不过这次有明显的改善:自己写的app至少没崩,说明参数设置是没任何问题的,个人猜测是metasec_ml内部可能有些检测机制,发现是第三方调用就返回null!

   为了查明原因,继续用ida调试,诡异的现象发生了:F7单步调试的时候遇到跳转的地址有问题,报错!

  

frida通过rpc调用提供python编程接口 frida rpc_字段_03

F8步过也不报错,就特么F7步入报错),trace的时候遇到了和用unidbg类似的问题,总式因为mutex卡在死循环这里鬼打墙:实在没办法了,把0x72C8E这4个字节NOP掉,不让上锁!

   

frida通过rpc调用提供python编程接口 frida rpc_android_04

   trace又能顺利执行了!从trace的结果看:R0和R1分别从两个地方取值,然后相减得到的结果保存到R0,也就是返回值,这里是0,怪不得67108866=0x4000002和1128这组参数返回的是null;

00003667    libmetasec_ml.so:F31D0514    LDR             R0, [SP,#0xC]       R0=0A423869                                 
00003667    libmetasec_ml.so:F31D0516    LDR             R1, [R5]            R1=0A423869                                 
00003667    libmetasec_ml.so:F31D0518    SUBS            R0, R1, R0          R0=00000000 Z=1 N=0

  由于不知道原app是怎么跑的(感兴趣的小伙伴也可以用frida stalker trace原app),这里我也没法继续分析R0和R1俩个值为啥相等(因为没有原app trace的对比,我也不知道自己代码执行的路径中哪个分支走错了)!回到我们自己构造的app卡住的代码,如下:

frida通过rpc调用提供python编程接口 frida rpc_字段_05

   R4就是h.a传入的第三个long函数,这里是个地址,加上0xC后取出值存放在R0,然后又存放在栈上,最后+4后得到rwlock传入pthread_rwlock_rdlock,那么问题来了:原app中b.a(0x4000002,"1128")得到的是R4的地址,又经过一系列算式得到rwlock,为啥我们不自己构造一个rwlock,然后把地址传给R4了?自己从写写个so,里面生成pthread_rwlock_t对象,然后调用pthread_rwlock_init初始化,把对象的地址保存;由于原app中涉及到R4+0xC和R0+4等“偏移”,所以我在c代码里用了结构体;为了便于查找,给rwlock周围的变量复制了0x11111111、0x22222222等数值,结果如下:

      

frida通过rpc调用提供python编程接口 frida rpc_android_06

   从ida调试的结果看,原来卡住的“LDR R0, [R4,#0xC]”的这样代码现在能正常执行了!R0确实指向了rwlock(从内存的值看,调用pthread_rwlock_init初始化后还是0,那初始化还有啥用了?)

         

frida通过rpc调用提供python编程接口 frida rpc_java_07

R1明显是我自己构造magic number,这里被当成地址来用了,说明我当初构造的rwlock结构体前面的数值应该是个地址!这里的偏移0xF357465A-0xF3569000=0xb65a;

       

frida通过rpc调用提供python编程接口 frida rpc_java_08

   往上追溯,这里的R1来自R4+4,这里也刚过上一个卡点;

        

frida通过rpc调用提供python编程接口 frida rpc_字段_09

    既然找到原因了,继续补呗!在自己的结构体把原来的0x22222222换成地址(注意:根据单步调试自己写的app分析,这里一共有4层指针引用,每层都要自己写指针嵌套引用);补上后继续调试,特么又遇到同样的问题(如下):还是地址为0,只不过换了个地方,说明构造的地址已经通过了上次代码的执行;

    

frida通过rpc调用提供python编程接口 frida rpc_字段_10

   往上追溯调试:偏移为0xB8C0的地方,此时R1就是我自己构造的p4指针,但是这里很鸡贼地取了p4+8作为地址,而我并没有构造p4+8,所以内存是0(p4我构造的是0x77777777);这里的p1到p4是我自定义的指针,层层递进引用(建议下载末尾的源码查看具体的定义和调用)!

        

frida通过rpc调用提供python编程接口 frida rpc_java_11

   继续漫漫追溯,发现这里的push把寄存器的值压栈上了,这里的偏移:0x6D970

        

frida通过rpc调用提供python编程接口 frida rpc_android_12

   发现R1和R2还是从栈上取得!这里得偏移:0x13A14

      

frida通过rpc调用提供python编程接口 frida rpc_java_13

      发现是之前R1和R2存栈上得!偏移:0xB8C0,又回到了p4+8的地方!

       

frida通过rpc调用提供python编程接口 frida rpc_android_14

   继续用结构体去补:貌似补上了!

       

frida通过rpc调用提供python编程接口 frida rpc_java_15

       又发现一个地方:0xBE4C;还好自己填的值辨识度高,这里一眼就看出了是那个字段的赋值有问题!继续补上!

   

frida通过rpc调用提供python编程接口 frida rpc_java_16

     继续往下:发现我们自己填的0x22222222被当成跳转的代码地址了,呵呵......    偏移:13A42

     

frida通过rpc调用提供python编程接口 frida rpc_java_17

   由于是跳转到新地址,此时我也不知道应该补什么地址,只能继续查看原app的跳转地址。这里可以用frida hook,看看context;也可以直接用ida调试原app;我直接用ida,简单方便,查到了这里跳转的地址:偏移是0x14581

        

frida通过rpc调用提供python编程接口 frida rpc_字段_18

   来到0x14581这里,发现还有大量的计算逻辑:原本是想把上面的BLX R6直接NOP掉,但是看到还有这么多代码,担心逻辑出错,想想还是算了;只能想办法得到metasec的基址,再加上0x14581的偏移来替代我之前设置的0x22222222,来保证原有的逻辑正常!

  

frida通过rpc调用提供python编程接口 frida rpc_java_19

x音原来的app是可以正常运行的,hook的结果也是对的,但自己补全了参数得到的结果是0,直接传参调用的结果还是0,说明:(1) h.a还有其他的反调试或检测逻辑:一旦发现so被第三方调用了,直接返回0!(2)我自己补的参数可能有问题导致代码运行的逻辑出错!文章末尾是我自己构建的app,哪位能提示甚至帮忙把第三个参数构造好,站内私信我加微信发红包!

    直接来硬的不行那就继续绕呗!有两种思路:

  •  x音原app调用ms.bd.c.b.a(67108866,“1128”)生成了第三个long参数,为啥我不能调用了?
  •    x音原app调用ms.bd.c.b.a生成那4个加密字段,为啥我不能调用了?唯一不确定的就是第三个long参数,直接hook原app得到后再“为我所用”呗!

先hook ms.bd.c.b.a得到第三个long参数,保存后再通过rpc主动执行ms.bd.c.b.a生成加密字段!rpc代码如下:

      call.js文件:

function printStringArry(strArr){
    var FastJson = Java.use('com.alibaba.fastjson.JSON'); 
    return FastJson.toJSONString(strArr);
}

function convert2ArrayList(str){
    var ArrayList = Java.use('java.util.ArrayList').$new();
    var strObj = Java.use('java.lang.String').$new();
    var strArray = new Array();
    strArray = str.split(",");
    for(var i=0;i<strArray.length;i++){
        ArrayList.add(strArray[i]);
    }
    return ArrayList;
}

var longParam;
function getLongParam(){
    Java.perform(function(){
        var h_class = Java.use("ms.bd.c.h");
        h_class.a.overload('int', 'int', 'long', 'java.lang.String', 'java.lang.Object').implementation = function(){
            if(arguments[2]!=0){
                longParam = arguments[2];
                console.log('\n longParam = arguments[2]:' + longParam);
            }
            return this.a(arguments[0],arguments[1],arguments[2],arguments[3],arguments[4]);
        }
    });
}

function ms_bd_c_h_a(args0,args1,args2,args3,args4){
    var encrypt_result;
    Java.perform(function() {
        args2 = longParam;
        args4 = convert2ArrayList(args4.toString());
        try{
            var targetClass = Java.use("ms.bd.c.h");
            encrypt_result = targetClass.a(args0,args1,args2,args3,args4);
        }catch(e){
            console.log(e.stack);
        }
        console.log("encrypt_result is :"+printStringArry(encrypt_result));
    });
    return encrypt_result;
}

setImmediate(getLongParam);

rpc.exports =  {
    encrypt: ms_bd_c_h_a
};

  python文件:注意,args4是post数据包的head,需要改成和url匹配的head,否则app会崩掉!

# -*- coding, utf-8 -*-
import codecs
import frida
import time

session = frida.get_usb_device().attach('抖音')

#读取JS脚本
with codecs.open('./call.js', 'r', 'utf-8') as f:
    source = f.read()

script = session.create_script(source)
script.load()

rpc = script.exports

time.sleep(5)#给hook预留时间,让x音触发ms.bd.c.h.a函数;期间也可以手动点赞、滑动屏幕等方式触发ms.bd.c.h.a函数

args0 = 50331649
args1 = 0
args2 = 0
args3 = "https,//aweme.snssdk.com/aweme/v1/commit/item/digg/?aweme_id=7016928444202175783&type=0&channel_id=0&city=510100&activity=0&os_api=25&device_type=SM-G9750&ssmix=a&manifest_version_code=150501&dpi=280&app_name=aweme&version_name=15.5.0&ts=1633766716&cpu_support64=false&app_type=normal&ac=wifi&appTheme=light&host_abi=armeabi-v7a&channel=lephone_xh_sd_1128_0415&update_version_code=15509900&_rticket=1633766717162&device_platform=android&iid=2401771765105502&version_code=150500&cdid=5b43e48d-b149-4c8a-8863-b2d84e650be4&openudid=b83ec6a675adba6a&device_id=4380918606995591&resolution=1080*1920&device_brand=samsung&language=zh&os_version=7.1.2&aid=1128&minor_status=0&mcc_mnc=46000"
args4 = ["accept-encoding","gzip","cookie","n_mh=B6WRe0yd-1qIuffF6ZWNO-CSGlW1Q-VhC0E79NrqYTg;uid_tt=b21518a30e097fbd558cdddf9bcfd3a5;uid_tt_ss=b21518a30e097fbd558cdddf9bcfd3a5;sid_tt=5a51412bfb955ee582edae8d48765690;sessionid=5a51412bfb955ee582edae8d48765690;sessionid_ss=5a51412bfb955ee582edae8d48765690;d_ticket=6b7d0d3678f21faa482196c460483d4eed15d;install_id=2542488099492919;ttreq=1$a01a1173c36665a50314924786f4704df6cdeb45;sid_guard=5a51412bfb955ee582edae8d48765690%7C1633073022%7C5184000%7CTue%2C+30-Nov-2021+07%3A23%3A42+GMT;odin_tt=0ea847f78343f7e969e78ba7b9239200535f7a60e9667c1a9bd3eff221ae71e00ec61567785d8a107011c961fae3961c835c25f4bfd09dec3446bd650115e45263f7c216cd7d33846418d3b45f505996","passport-sdk-version","18","sdk-version","2","x-ss-req-ticket","1633766717163","x-tt-dt","AAA3VJFIKPXTQ3DZW622UN5YMCIJ3AQ5BZMAI2TMBJQASG3PQIMUKVBQYQG2YCXGALRNNZBQUJ7XDNZ4FXIGI2TL5LI5XLUXSPCTZ4NJGDU4JCIL2UF6OEV25GKGINMX7ARAHHRP5IU6VITY2YJ4BCI","x-tt-token","005a51412bfb955ee582edae8d48765690009b144562dfd76dacbe19854da5bd41e9bc9c249278cf5cfd759602ab0bab22f34d19554661df3791190f9068394dd1e6f7edd268b7fa3c5a0b745f1aee15931aa0b0f43260e7297fb7d16d872614ca256-1.0.1"]
result = rpc.encrypt(args0,args1,args2,args3,args4)
print("five gods,",result)

session.detach()

  在写rpc调用时遇到的几个坑在这里分享一下,希望对大家有所帮助:

  • 用int(data)转换,在js统一识别成number类型;我想过用Java.cast、Java.use('java.lang.Long').parseLong.overload('java.lang.String').call(Java.use('java.lang.Long'), args2)等方式强转成long,但都没卵用!
  • 如果x音是故意这么干的,说明反调试做的牛逼;如果不是,说明鲁棒性没考虑周全,没有对错误的参数做处理);如果直接传入["accept-encoding":"gzip","cookie":"n_mh=B6WRe0yd-".....] 这种list类型会爆下面的错误,说明python的list根本不匹配java.lang.Object
Error: a(): argument types do not match any of:
   .overload('int', 'int', 'long', 'java.lang.String', 'java.lang.Object')

ms.bd.c.u1$a.a方法代码:String[] strArr = (String[]) C85964b.m218696a(50331649, 0, C86039u1.this.f357108d, str, (String[]) arrayList.toArray(new String[0])); 这里明显直接调用了ms.bd.c.b.a方法,连第三个long参数都直接用了,不需要自己幸苦生成;用户只需要传入url和post包的head参数即可,更加省事,感兴趣的小伙伴建议自行尝试rpc调用这个函数试试!

public final Map<String, String> mo70417a(String str, Map<String, List<String>> map) {
            String str2;
            PatchProxyResult proxy = PatchProxy.proxy(new Object[]{str, map}, this, f357109a, false, 431597);
            if (proxy.isSupported) {
                return (Map) proxy.result;
            }
            HashMap hashMap = new HashMap();
            if (!(str == null || map == null)) {
                if (str.toLowerCase().contains((String) C85985h.m218727a(16777217, 0, 0, "2412bc", new byte[]{43, 34, 86, 86})) || str.toLowerCase().contains((String) C85985h.m218727a(16777217, 0, 0, "fd1c18", new byte[]{Byte.MAX_VALUE, 114, 86, 7, 29}))) {
                    C86055z1.m218845a().mo248383b();
                    ArrayList arrayList = new ArrayList();
                    for (Map.Entry<String, List<String>> entry : map.entrySet()) {
                        String key = entry.getKey();
                        if (entry.getValue() == null || entry.getValue().size() <= 0) {
                            str2 = null;
                        } else {
                            str2 = entry.getValue().get(0);
                        }
                        if (!(key == null || str2 == null)) {
                            arrayList.add(key);
                            arrayList.add(str2);
                        }
                    }
                    String[] strArr = (String[]) C85964b.m218696a(50331649, 0, C86039u1.this.f357108d, str, (String[]) arrayList.toArray(new String[0]));
                    if (strArr != null) {
                        HashMap hashMap2 = new HashMap();
                        for (int i = 0; i < strArr.length; i += 2) {
                            hashMap2.put(strArr[i], strArr[i + 1]);
                        }
                        return hashMap2;
                    }
                } else {
                    throw new RuntimeException((String) C85985h.m218727a(16777217, 0, 0, "3ff0e1", new byte[]{43, 112, 85, 73, 79, 53, 36, 7, 53, 101, 98, 108, 1, 80, 74, 105, 56, 83, 35, 112, 49}));
                }
            }
            return hashMap;
        }

   同时,在metasec_ml偏移0x13220处发现了重要的函数:第一个参数是url

      

frida通过rpc调用提供python编程接口 frida rpc_android_20

so层0x13220的这个函数和java层的ms.bd.c.u1$a.a方法在参数上出奇一致,很有可能0x13220也参与了加密字段的生成,至少是提供了加密算法的原始数据!

     

frida通过rpc调用提供python编程接口 frida rpc_java_21

 

  自己构造app: 链接:https://pan.baidu.com/s/1JavGwlMKtcpnQkaVB2zmNw    提取码:3fd6    调用ms.bd.c.b.a时返回值是0,暂时还没生成加密字段,问题还在排查中;能帮忙解决问题的私信我加微信,我发红包!