先抓包获得提交订单的请求如下

可以看到签名的参数在header里面,名字叫做x-sign,jadx搜索一下


然后在接着搜索X_SIGN
然后根据名字猜测到在这个位置

函数如下

public String getSign(HashMap<String, String> params, String appKey) {
        String str;
        UnsupportedEncodingException e;
        SecException e2;
        String str2 = "";
        String str3 = (String) mo28972a((Map<String, String>) params, appKey).get("INPUT");
        try {
            if (this.f13463e == null || StringUtils.isBlank(str3)) {
                TBSdkLog.m3641e("mtopsdk.InnerSignImpl", mo44553c() + " [getSign]middleTier null or data data ", "appKeyIndex=" + this.f23497a.appKeyIndex + ",authCode=" + this.f23497a.authCode);
                return "";
            }
            HashMap hashMap = new HashMap();
            hashMap.put("data", str3.getBytes("UTF-8"));
            hashMap.put("env", Integer.valueOf(m13472d()));
            hashMap.put("appkey", appKey);
            HashMap sign = this.f13463e.getSign(hashMap);
            if (sign == null || sign.isEmpty()) {
                TBSdkLog.m3641e("mtopsdk.InnerSignImpl", mo44553c() + " [getSign]get sign failed with no output ", "appKeyIndex=" + this.f23497a.appKeyIndex + ",authCode=" + this.f23497a.authCode);
                return "";
            }
            str = (String) sign.remove(HttpHeaderConstant.X_SIGN);
            try {
                if (!StringUtils.isNotBlank(str)) {
                    return str;
                }
                params.putAll(sign);
                return str;
            } catch (UnsupportedEncodingException e3) {
                e = e3;
                TBSdkLog.m3642e("mtopsdk.InnerSignImpl", mo44553c() + " [getSign]your input data transfer to byte utf-8 failed ", "appKeyIndex=" + this.f23497a.appKeyIndex + ",authCode=" + this.f23497a.authCode, e);
                return str;
            } catch (SecException e4) {
                e2 = e4;
                TBSdkLog.m3643e("mtopsdk.InnerSignImpl", mo44553c() + " [getSign]get sign failed and SecException errorCode " + e2.getErrorCode() + ",appKeyIndex=" + this.f23497a.appKeyIndex + ",authCode=" + this.f23497a.authCode, (Throwable) e2);
                return str;
            }
        } catch (UnsupportedEncodingException e5) {
            UnsupportedEncodingException unsupportedEncodingException = e5;
            str = str2;
            e = unsupportedEncodingException;
            TBSdkLog.m3642e("mtopsdk.InnerSignImpl", mo44553c() + " [getSign]your input data transfer to byte utf-8 failed ", "appKeyIndex=" + this.f23497a.appKeyIndex + ",authCode=" + this.f23497a.authCode, e);
            return str;
        } catch (SecException e6) {
            SecException secException = e6;
            str = str2;
            e2 = secException;
            TBSdkLog.m3643e("mtopsdk.InnerSignImpl", mo44553c() + " [getSign]get sign failed and SecException errorCode " + e2.getErrorCode() + ",appKeyIndex=" + this.f23497a.appKeyIndex + ",authCode=" + this.f23497a.authCode, (Throwable) e2);
            return str;
        }
    }

不用去关心他到底怎么计算签名,直接写一段hook看一下是否用的这个函数进行签名

    setTimeout(function() {
    Java.perform(function() {


        var HttpRequestEntity = Java.use('mtopsdk.security.b'); //要hook的类名完整路径
        // var func = new HttpRequestEntity();
        // func.signature('1', '13123', false);
        HttpRequestEntity.getSign.implementation = function(arg1, arg2) { // 重写要hook的方法getSign,当有多个重名函数时需要重载,function括号为函数的参数个数

            var Sign = this.getSign(arg1, arg2); //调用原始的函数实现并且获得返回值,如果不写的话我们下面的代码会全部替换原函数

            send("arg1:" + arg1); //打印参数值
            send("arg2:" + arg2);


            send("result:" + Sign); //打印返回值

            return Sign; //函数有返回值时需要返回
        };

    })

});
➜  x frida-ps -U |grep damai
16738  cn.damai
17005  cn.damai:channel
➜  x frida -l damai.js -U -f cn.damai --no-pause
     ____
    / _  |   Frida 12.7.22 - A world-class dynamic instrumentation toolkit
   | (_| |
    > _  |   Commands:
   /_/ |_|       help      -> Displays the help system
   . . . .       object?   -> Display information about 'object'
   . . . .       exit/quit -> Exit
   . . . .
   . . . .   More info at https://www.frida.re/docs/home/
Spawned `cn.damai`. Resuming main thread!
message: {'type': 'send', 'payload': 'arg1:{data={"itemId":"613369982548","scenario":"itemsku","channel_from":"damai_market","bizCode":"ali.china.damai","appType":"1","osType":"2","exParams":"{}","source":"10101","version":"6000076"}, lng=118.818906, utdid=XCquBhVOGfwDAMHCRzpMcJHX, [email protected]_android_7.7.2, deviceId=Auw_p33fvcb-qYhQnFUd4IAw1zJfUPYAfdVSWlF8OCH7, sid=149c5f8c17bf88a759f4ec5ebc6ae27a, uid=2206462755405, x-features=27, t=1584889999, v=2.0, appKey=23781390, api=mtop.alibaba.detail.subpage.getdetail, lat=32.107127}'} data: None
message: {'type': 'send', 'payload': 'arg2:23781390'} data: None
message: {'type': 'send', 'payload': 'result:ab25b000902a1cb73174adb1f6ffd602c2b885dd8e6efbc4ec'} data: None

看参数基本就是这个函数了,我们再把之前抓包抓到的参数拿去签名然后对比一下结果是否一样校验一下
在看一下sign的这个类,其实还有一个init初始化函数

   public void init(@NonNull MtopConfig mtopConfig) {
        super.init(mtopConfig);
        String c = mo44553c();
        try {
            SignStatistics.m23759a(mtopConfig.uploadStats);
            long currentTimeMillis = System.currentTimeMillis();
            this.f13461c = SecurityGuardManager.getInstance(this.f23497a.context);
            m13470a(StringUtils.isEmpty(mtopConfig.appKey) ? m13468a(mtopConfig.appKeyIndex, mo44552b()) : mtopConfig.appKey, mo44552b());
            MtopSDKThreadPoolExecutorFactory.submit(new InnerSignImpl$1(this, this.f23497a.context, c));
            m13471a(mtopConfig);
            if (TBSdkLog.isLogEnable(LogEnable.InfoEnable)) {
                TBSdkLog.m3644i("mtopsdk.InnerSignImpl", c + " [init]ISign init SecurityGuard succeed.init time=" + (System.currentTimeMillis() - currentTimeMillis));
            }
        } catch (SecException e) {
            int errorCode = e.getErrorCode();
            SignStatistics.m23758a(SignStatsType.TYPE_SG_MANAGER, String.valueOf(errorCode), "");
            TBSdkLog.m3643e("mtopsdk.InnerSignImpl", c + " [init]ISign init SecurityGuard error.errorCode=" + errorCode, (Throwable) e);
        } catch (Exception e2) {
            TBSdkLog.m3643e("mtopsdk.InnerSignImpl", c + " [init]ISign init SecurityGuard error.", (Throwable) e2);
        }
    }

我们在写一个hook看一下传进来的参数是什么

setTimeout(function() {
    Java.perform(function() {


        var HttpRequestEntity = Java.use('mtopsdk.security.b'); //要hook的类名完整路径
        // var func = new HttpRequestEntity();
        // func.signature('1', '13123', false);
        HttpRequestEntity.init.implementation = function(arg1) { // 重写要hook的方法getSign,当有多个重名函数时需要重载,function括号为函数的参数个数

            var Sign = this.init(arg1); //调用原始的函数实现并且获得返回值,如果不写的话我们下面的代码会全部替换原函数

            send("arg1:" + arg1); //打印参数值
            //mtopsdk.mtop.global.MtopConfig


            send("result:" + Sign); //打印返回值

            return Sign; //函数有返回值时需要返回
        };

    })

});

执行结果如下

➜  x frida -l init.js -U -f cn.damai --no-pause
     ____
    / _  |   Frida 12.7.22 - A world-class dynamic instrumentation toolkit
   | (_| |
    > _  |   Commands:
   /_/ |_|       help      -> Displays the help system
   . . . .       object?   -> Display information about 'object'
   . . . .       exit/quit -> Exit
   . . . .
   . . . .   More info at https://www.frida.re/docs/home/
Spawned `cn.damai`. Resuming main thread!
[Samsung SM-G9550::cn.damai]-> message: {'type': 'send', 'payload': 'arg1:[email protected]'} data: None

可以看到传进来的是mtopsdk.mtop.global.MtopConfig这么一个类,那么我们来看一下这个类
这个类初始化的时候也有一个参数

  public MtopConfig(String instanceId2) {
        this.instanceId = instanceId2;
    }

再写一个hook看一下

setTimeout(function() {
    Java.perform(function() {


        var HttpRequestEntity = Java.use('mtopsdk.mtop.global.MtopConfig'); //要hook的类名完整路径
        // var func = new HttpRequestEntity();
        // func.signature('1', '13123', false);
        HttpRequestEntity.$init.implementation = function(arg1) { // 重写要hook的方法getSign,当有多个重名函数时需要重载,function括号为函数的参数个数

            var Sign = this.$init(arg1); //调用原始的函数实现并且获得返回值,如果不写的话我们下面的代码会全部替换原函数

            send("arg1:" + arg1); //打印参数值
            //mtopsdk.mtop.global.MtopConfig


            send("result:" + Sign); //打印返回值

            return Sign; //函数有返回值时需要返回
        };

    })

});

结果如下

➜  x frida -l config.js -U -f cn.damai --no-pause
     ____
    / _  |   Frida 12.7.22 - A world-class dynamic instrumentation toolkit
   | (_| |
    > _  |   Commands:
   /_/ |_|       help      -> Displays the help system
   . . . .       object?   -> Display information about 'object'
   . . . .       exit/quit -> Exit
   . . . .
   . . . .   More info at https://www.frida.re/docs/home/
Spawned `cn.damai`. Resuming main thread!
[Samsung SM-G9550::cn.damai]-> message: {'type': 'send', 'payload': 'arg1:INNER'} data: None
message: {'type': 'send', 'payload': 'result:undefined'} data: None
message: {'type': 'send', 'payload': 'arg1:OPEN'} data: None
message: {'type': 'send', 'payload': 'result:undefined'} data: None
message: {'type': 'send', 'payload': 'arg1:INNER'} data: None
message: {'type': 'send', 'payload': 'result:undefined'} data: None
message: {'type': 'send', 'payload': 'arg1:OPEN'} data: None

可以看到要么是OPEN,要么是INNER,那么就非常明了了,我们写一个脚本把参数带进去签名一下对比一下结果
这是原始参数

message: {'type': 'send', 'payload': 'arg1:{data={"itemId":"613369982548","scenario":"itemsku","channel_from":"damai_market","bizCode":"ali.china.damai","appType":"1","osType":"2","exParams":"{}","source":"10101","version":"6000076"}, lng=118.818906, utdid=XCquBhVOGfwDAMHCRzpMcJHX, [email protected]_android_7.7.2, deviceId=Auw_p33fvcb-qYhQnFUd4IAw1zJfUPYAfdVSWlF8OCH7, sid=149c5f8c17bf88a759f4ec5ebc6ae27a, uid=2206462755405, x-features=27, t=1584889999, v=2.0, appKey=23781390, api=mtop.alibaba.detail.subpage.getdetail, lat=32.107127}'} data: None
message: {'type': 'send', 'payload': 'arg2:23781390'} data: None
message: {'type': 'send', 'payload': 'result:ab25b000902a1cb73174adb1f6ffd602c2b885dd8e6efbc4ec'} data: None

脚本如下

import frida, sys
from urllib import parse
from time import sleep

def on_message(message, data):
    global result
    result=message
    print('----------------------------------------------------------------')
    print(message,data)
        
jscode = """
function sign(args) {
    Java.perform(function () {
        var HashMap = Java.use('java.util.HashMap');
        var hm = HashMap.$new();
        var hm1=HashMap.$new();

        var config = Java.use('mtopsdk.mtop.global.MtopConfig');
        var mconfig=config.$new("INNER");
        console.log(args)
        hm1.put("buyNow","true");
        hm1.put("exParams",args);
        hm1.put("buyParam","613369982548_1_4314464576860")

        hm.put("data",args);
        hm.put("lng","118.818906");
        hm.put("utdid","XCquBhVOGfwDAMHCRzpMcJHX");
        hm.put("ttid","[email protected]_android_7.7.2")
        hm.put("deviceId","Auw_p33fvcb-qYhQnFUd4IAw1zJfUPYAfdVSWlF8OCH7")
        hm.put("sid","149c5f8c17bf88a759f4ec5ebc6ae27a")
        hm.put("uid","2206462755405")
        hm.put("x-features","27")
        hm.put("t","1584889999")
        hm.put("v","2.0")
        hm.put("appKey","23781390")
        hm.put("api","mtop.alibaba.detail.subpage.getdetail")
        hm.put("lat","32.107127")
        console.log(hm)
        var HttpRequestEntity = Java.use('mtopsdk.security.b');
        var func = HttpRequestEntity.$new()
        func.init(mconfig);
        var result = func.getSign(hm,"23781390")
        send("sign:" + result);
        return result;
    })
}
function onMessage(pokeMessage) {
    sign(pokeMessage['line']);
    recv('sign', onMessage);
}
recv('sign', onMessage);
"""
process = frida.get_usb_device().attach('cn.damai')
result=[]
script = process.create_script(jscode)
script.on('message', on_message)
script.load()
# params='''{"buyNow":"true","exParams":"{\"umpChannel\":\"10001\",\"coupon\":\"true\",\"websiteLanguage\":\"zh_CN_#Hans\",\"channel\":\"damai_app\",\"atomSplit\":\"1\",\"seatInfo\":\"\",\"coVersion\":\"2.0\"}","buyParam":"613369982548_1_4314464576860"}'''
params='''{"buyNow":"true","exParams":"{\\"umpChannel\\":\\"10001\\",\\"coupon\\":\\"true\\",\\"websiteLanguage\\":\\"zh_CN_#Hans\\",\\"channel\\":\\"damai_app\\",\\"atomSplit\\":\\"1\\",\\"seatInfo\\":\\"\\",\\"coVersion\":\\"2.0\\"}","buyParam":"613369982548_1_4314464576860"}'''
# params='''"{\\"umpChannel\\":\\"10001\\",\\"coupon\\":\\"true\\",\\"websiteLanguage\\":\\"zh_CN_#Hans\\",\\"channel\\":\\"damai_app\\",\\"atomSplit\\":\\"1\\",\\"seatInfo\\":\\"\\",\\"coVersion\":\\"2.0\\"}"'''
# print(params)
params ='''{"itemId":"613369982548","scenario":"itemsku","channel_from":"damai_market","bizCode":"ali.china.damai","appType":"1","osType":"2","exParams":"{}","source":"10101","version":"6000076"}'''
script.post({"type": "sign",'line':params})

'''
lng = 118.818534, utdid = XCquBhVOGfwDAMHCRzpMcJHX, 
ttid = 10005890 @damai_android_7 .7 .2, 
deviceId = Auw_p33fvcb - qYhQnFUd4IAw1zJfUPYAfdVSWlF8OCH7, 
sid = 149 c5f8c17bf88a759f4ec5ebc6ae27a, 
uid = 2206462755405, x - features = 27, t = 1584888568, v = 4.0, appKey = 23781390, 
api = mtop.trade.order.build, lat = 32.106986
'''
while True:
    if result!=[]:
        print(result)
        print('over')
        break
    sleep(1)

'''
message: {'type': 'send', 'payload': 'arg1:{data={"itemId":"613369982548","scenario":"itemsku","channel_from":"damai_market","bizCode":"ali.china.damai","appType":"1","osType":"2","exParams":"{}","source":"10101","version":"6000076"}
, lng=118.818906,
 utdid=XCquBhVOGfwDAMHCRzpMcJHX, [email protected]_android_7.7.2, deviceId=Auw_p33fvcb-qYhQnFUd4IAw1zJfUPYAfdVSWlF8OCH7, 
 sid=149c5f8c17bf88a759f4ec5ebc6ae27a, uid=2206462755405, x-features=27, t=1584889999, v=2.0, appKey=23781390, api=mtop.alibaba.detail.subpage.getdetail, lat=32.107127}'} data: None
message: {'type': 'send', 'payload': 'arg2:23781390'} data: None
message: {'type': 'send', 'payload': 'result:ab25b000902a1cb73174adb1f6ffd602c2b885dd8e6efbc4ec'} data: None
'''

最新结果如下

➜  x python3 test.py
{"itemId":"613369982548","scenario":"itemsku","channel_from":"damai_market","bizCode":"ali.china.damai","appType":"1","osType":"2","exParams":"{}","source":"10101","version":"6000076"}
{data={"itemId":"613369982548","scenario":"itemsku","channel_from":"damai_market","bizCode":"ali.china.damai","appType":"1","osType":"2","exParams":"{}","source":"10101","version":"6000076"}, lng=118.818906, utdid=XCquBhVOGfwDAMHCRzpMcJHX, [email protected]_android_7.7.2, deviceId=Auw_p33fvcb-qYhQnFUd4IAw1zJfUPYAfdVSWlF8OCH7, sid=149c5f8c17bf88a759f4ec5ebc6ae27a, uid=2206462755405, x-features=27, t=1584889999, v=2.0, appKey=23781390, api=mtop.alibaba.detail.subpage.getdetail, lat=32.107127}
----------------------------------------------------------------
{'type': 'send', 'payload': 'sign:ab25b000902a1cb73174adb1f6ffd602c2b885dd8e6efbc4ec'} None
{'type': 'send', 'payload': 'sign:ab25b000902a1cb73174adb1f6ffd602c2b885dd8e6efbc4ec'}
over
➜  x

对比一下之前的签名,一模一样,证明找对地方了

下面还需要解决x-mini-wua与wua
其实和sign都在同一个类里面,按照上面的方法在进行hook即可,

public String getWua(HashMap<String, String> params, String appKey) {
        String str;
        UnsupportedEncodingException e;
        SecException e2;
        String str2 = "";
        String str3 = (String) params.get("sign");
        try {
            if (this.f13463e == null || StringUtils.isBlank(str3)) {
                TBSdkLog.m3641e("mtopsdk.InnerSignImpl", mo44553c() + " [getWua]middleTier null or data data ", "appKeyIndex=" + this.f23497a.appKeyIndex + ",authCode=" + this.f23497a.authCode);
                return "";
            }
            HashMap hashMap = new HashMap();
            hashMap.put("data", str3.getBytes("UTF-8"));
            hashMap.put("env", Integer.valueOf(m13472d()));
            HashMap wua = this.f13463e.getWua(hashMap);
            if (wua == null || wua.isEmpty()) {
                TBSdkLog.m3641e("mtopsdk.InnerSignImpl", mo44553c() + " [getWua]get wua failed with no output ", "appKeyIndex=" + this.f23497a.appKeyIndex + ",authCode=" + this.f23497a.authCode);
                return "";
            }
            str = (String) wua.remove(ApiConstants.WUA);
            try {
                if (!StringUtils.isNotBlank(str)) {
                    return str;
                }
                params.putAll(wua);
                return str;
            } catch (UnsupportedEncodingException e3) {
                e = e3;
                TBSdkLog.m3642e("mtopsdk.InnerSignImpl", mo44553c() + " [getWua]your input data transfer to byte utf-8 failed ", "appKeyIndex=" + this.f23497a.appKeyIndex + ",authCode=" + this.f23497a.authCode, e);
                return str;
            } catch (SecException e4) {
                e2 = e4;
                TBSdkLog.m3643e("mtopsdk.InnerSignImpl", mo44553c() + " [getWua]get wua failed and SecException errorCode " + e2.getErrorCode() + ",appKeyIndex=" + this.f23497a.appKeyIndex + ",authCode=" + this.f23497a.authCode, (Throwable) e2);
                return str;
            }
        } catch (UnsupportedEncodingException e5) {
            UnsupportedEncodingException unsupportedEncodingException = e5;
            str = str2;
            e = unsupportedEncodingException;
            TBSdkLog.m3642e("mtopsdk.InnerSignImpl", mo44553c() + " [getWua]your input data transfer to byte utf-8 failed ", "appKeyIndex=" + this.f23497a.appKeyIndex + ",authCode=" + this.f23497a.authCode, e);
            return str;
        } catch (SecException e6) {
            SecException secException = e6;
            str = str2;
            e2 = secException;
            TBSdkLog.m3643e("mtopsdk.InnerSignImpl", mo44553c() + " [getWua]get wua failed and SecException errorCode " + e2.getErrorCode() + ",appKeyIndex=" + this.f23497a.appKeyIndex + ",authCode=" + this.f23497a.authCode, (Throwable) e2);
            return str;
        }
    }

    public String getMiniWua(HashMap<String, String> params, HashMap<String, String> ext) {
        String str;
        SecException e;
        String str2 = "";
        try {
            if (this.f13463e == null) {
                TBSdkLog.m3641e("mtopsdk.InnerSignImpl", mo44553c() + " [getMiniWua]middleTier ", "appKeyIndex=" + this.f23497a.appKeyIndex + ",authCode=" + this.f23497a.authCode);
                return "";
            }
            HashMap hashMap = new HashMap();
            hashMap.put("env", Integer.valueOf(m13472d()));
            if (ext == null) {
                ext = new HashMap<>();
            }
            ext.put(C3934e.f8409i, params.get("api"));
            hashMap.put("extend_paras", ext);
            HashMap miniWua = this.f13463e.getMiniWua(hashMap);
            if (miniWua == null || miniWua.isEmpty()) {
                TBSdkLog.m3641e("mtopsdk.InnerSignImpl", mo44553c() + " [getMiniWua]get miniwua failed with no output ", "appKeyIndex=" + this.f23497a.appKeyIndex + ",authCode=" + this.f23497a.authCode);
                return "";
            }
            str = (String) miniWua.remove("x-miniwua");
            try {
                if (!StringUtils.isNotBlank(str)) {
                    return str;
                }
                params.putAll(miniWua);
                return str;
            } catch (SecException e2) {
                e = e2;
                TBSdkLog.m3643e("mtopsdk.InnerSignImpl", mo44553c() + " [getMiniWua]get miniwua failed and SecException errorCode " + e.getErrorCode() + ",appKeyIndex=" + this.f23497a.appKeyIndex + ",authCode=" + this.f23497a.authCode, (Throwable) e);
                return str;
            }
        } catch (SecException e3) {
            SecException secException = e3;
            str = str2;
            e = secException;
            TBSdkLog.m3643e("mtopsdk.InnerSignImpl", mo44553c() + " [getMiniWua]get miniwua failed and SecException errorCode " + e.getErrorCode() + ",appKeyIndex=" + this.f23497a.appKeyIndex + ",authCode=" + this.f23497a.authCode, (Throwable) e);
            return str;
        }
    }

标签: 安全WIKI