frida获得阿里系APP签名函数地址及调用

查看 95|回复 9
作者:tzwsoho   
最近研究了一下几羊的APP,写了个基于frida的自动抽奖脚本,这里我单独对其中的签名函数地址的获取做一下解读。
首先,包括几羊APP在内,所有阿里系APP在向服务器发出HTTPS请求时,都会带上一个签名sign,根据大佬的文章(蚂蚁森林自动收能量:https://blog.csdn.net/dieTicket/article/details/102678054)可以知道,这个签名是动态加载libsgmain.so文件,然后调用里面的
[Plain Text] 纯文本查看 复制代码com.alibaba.wireless.security.open.securesignature.a.signRequest(Lcom/alibaba/wireless/security/open/SecurityGuardParamContext;Ljava/lang/String;)Ljava/lang/String;
得出的,其中SecurityGuardParamContext参数我们可以简单地通过jadx反编译得出是这么一个结构体:
[Java] 纯文本查看 复制代码public class SecurityGuardParamContext {
    public String appKey;
    public Map paramMap = new HashMap();
    public int requestType;
    public String reserved1;
    public String reserved2;
}
知道了这点,我们先来对这个函数下钩子,看看signRequest的参数分别是什么。
先准备一台root掉的手机,或者雷电模拟器,启动frida-server,这个网上很多教程,这里不再赘述。
然后将以下代码保存为hook.js:
[Asm] 纯文本查看 复制代码
function hook() {
        if (!Java.available) {
                console.error('Java API not available');
                return;
        }
        Java.perform(function () {
                console.log('hooked');
                ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                Java.enumerateClassLoaders({
                        onMatch: function (loader) {
                                try {
                                        if (loader.findClass('com.alibaba.wireless.security.open.securesignature.a')) {
                                                // console.log(loader);
                                                Java.classFactory.loader = loader;
                                                Java.use('com.alibaba.wireless.security.open.securesignature.a').signRequest.implementation = function (p0, p1) {
                                                        const ret = this.signRequest(p0, p1);
                                                        console.log('p0 =', JSON.stringify(p0), 'p1 =', JSON.stringify(p1), 'sign =', ret);
                                                        return ret;
                                                };
                                        }
                                } catch (e) {
                                        // console.error('enumerateClassLoaders err', e.stack);
                                }
                        },
                        // DO NOT REMOVE 'onComplete' FUNCTION
                        onComplete: function () {
                        }
                });
        });
}
hook();
获得几羊APP的PID
[Plain Text] 纯文本查看 复制代码# frida-ps -Uia
PID  Name    Identifier
----  ------  ---------------------------
2075  几羊      com.snail.android.lucky
1563  设置      com.android.settings
1911  雷电游戏中心  com.android.flysilkworm
...
将脚本注入几羊APP
[Plain Text] 纯文本查看 复制代码# frida -U --no-pause -l hook.js -p 2075
然后任意点击几羊APP的界面,使几羊产生HTTPS请求,这时可以看到控制台会输入类似以下的字符串:
[Plain Text] 纯文本查看 复制代码hooked
p0 = "" p1 = "" sign = 89aa0266ec4a5e631b82209171d49548
p0 = "" p1 = "" sign = 3a5774c3aa6ec736334f0c7f11bb5e53
p0 = "" p1 = "" sign = 0dfca532961a1998237e2903676211f9
p0 = "" p1 = "" sign = bac3f23414b3345b84c0b7654610d00f
p0 = "" p1 = "" sign = c6f37ba76d12b97db25946b04039f6ed
p0 = "" p1 = "" sign = 437fb3b5e9f3026d88347e6b1ff2eb34
p0 = "" p1 = "" sign = 97793a1b0cdd3108fc4b01d7f2a35361
为了进一步看清p0参数的内容,我们将hook.js脚本改一下:
[JavaScript] 纯文本查看 复制代码
function stringifyMap(m) {
        var HashMapEntry = Java.use('java.util.HashMap$HashMapEntry');
        var entrySet = m.entrySet();
        var it = entrySet.iterator();
        var obj = {};
        while (it.hasNext()) {
                var node = Java.cast(it.next(), HashMapEntry);
                var key = node.getKey().toString();
                var value = node.getValue().toString();
                obj[key] = value;
        }
        return JSON.stringify(obj);
}
function hook() {
        if (!Java.available) {
                console.error('Java API not available');
                return;
        }
        Java.perform(function () {
                console.log('hooked');
                ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                Java.enumerateClassLoaders({
                        onMatch: function (loader) {
                                try {
                                        if (loader.findClass('com.alibaba.wireless.security.open.securesignature.a')) {
                                                // console.log(loader);
                                                Java.classFactory.loader = loader;
                                                Java.use('com.alibaba.wireless.security.open.securesignature.a').signRequest.implementation = function (p0, p1) {
                                                        const ret = this.signRequest(p0, p1);
                                                        console.log('appKey =', p0.appKey.value, 'paramMap =', stringifyMap(p0.paramMap.value), 'requestType =', p0.requestType.value);
                                                        return ret;
                                                };
                                        }
                                } catch (e) {
                                        // console.error('enumerateClassLoaders err', e.stack);
                                }
                        },
                        // DO NOT REMOVE 'onComplete' FUNCTION
                        onComplete: function () {
                        }
                });
        });
}
hook();
这里不用重新使用frida加载hook.js,frida会自动检测到文件改变,自动重载脚本文件,这也是frida强大的功能之一。
然后我们继续点击几羊界面,可以看到类似以下的输出:
[Plain Text] 纯文本查看 复制代码hooked
appKey = SNAIL_APP_KEY_ANDROID paramMap = {"INPUT":"Operation-Type=alipay.mobile.aggrbillinfo.user.sign&Request-Data=W3siYXBkaWQiOiJlWU9Ja2tud0tMZndBVFNaQ2VUL3RkdDdpZEQwbERYeEhOM21LWG1Od0ZCcUI2UmlHdnZ4K1B3eSIsImNsaWVudEtleSI6IlVMYmVxMUFQTnciLCJjbGllbnRWZXJzaW9uIjoiMy40LjAuOTciLCJtb2RlbCI6IlBDUlQwMCIsInBsYXRmb3JtIjoiQW5kcm9pZCIsInN5c3RlbVN3aXRjaFN0YXR1cyI6dHJ1ZSwidG9rZW4iOiI3MmQ1YWQ4ZmIwZmIwOWNiMTRjMGI1OWNkNjY2ZTJhNCIsInVzZXJJZCI6IjgwODgwMjcxMDExMDM3MDYiLCJ1dGRpZCI6IllRN2MvYUdnSjlNREFMR1dKMEEzdFhRKyJ9XQ==&Ts=Nii7Fou"} requestType = 4
appKey = SNAIL_APP_KEY_ANDROID paramMap = {"INPUT":"Operation-Type=alipay.mobile.aggrbillinfo.message.new.index&Request-Data=W3siYXBkaWQiOiJlWU9Ja2tud0tMZndBVFNaQ2VUL3RkdDdpZEQwbERYeEhOM21LWG1Od0ZCcUI2UmlHdnZ4K1B3eSIsImNsaWVudEtleSI6IlVMYmVxMUFQTnciLCJjbGllbnRWZXJzaW9uIjoiMy40LjAuOTciLCJtb2RlbCI6IlBDUlQwMCIsInBsYXRmb3JtIjoiQW5kcm9pZCIsInRva2VuIjoiNzJkNWFkOGZiMGZiMDljYjE0YzBiNTljZDY2NmUyYTQiLCJ1c2VySWQiOiI4MDg4MDI3MTAxMTAzNzA2IiwidXRkaWQiOiJZUTdjL2FHZ0o5TURBTEdXSjBBM3RYUSsifV0=&Ts=Nii7Gay"} requestType = 4
我们可以看到appKey的值固定是字符串SNAIL_APP_KEY_ANDROID
paramMap里面固定是INPUT做key,后面的Value是一串由
[color=]Operation-Type
Request-DataTs三个参数组成的请求字符串,其中:
Operation-Type是操作类型名,表示要求服务器做的操作,
Request-Data其实是一串Base64字符串,我们随意解码一段:
[JavaScript] 纯文本查看 复制代码[{"apdid":"eYOIkknwKLfwATSZCeT/tdt7idD0lDXxHN3mKXmNwFBqB6RiGvvx+Pwy","clientKey":"ULbeq1APNw","clientVersion":"3.4.0.97","model":"PCRT00","platform":"Android","systemSwitchStatus":true,"token":"72d5ad8fb0fb09cb14c0b59cd666e2a4","userId":"8088027101103706","utdid":"YQ7c/aGgJ9MDALGWJ0A3tXQ+"}]
可以看到里面包含了这些内容,那我们可以按这些字段去jadx搜索,就可以知道这些值是怎么得来的。
Ts其实就是取当时时间毫秒数,用自定义的64进制转换方法转换成的字符串,在开头提到的文章《蚂蚁森林自动收能量》里面有说明,这里不再赘述。
最后的requestType,这个值我们通过jadx反编译(com.alipay.mobile.common.netsdkextdepend.security.DefaultSecurityManager.signature(SignRequest signRequest))得知,使用MD5算法时是4。
还有reserved1和reserved2是保留用的,都是空字符串,这里不再列出。
知道了上面这些参数的含义,我们可以写个函数来模拟调用signRequest函数并导出,从而自己计算sign签名的值,最终可以模拟各种各样阿里系APP的HTTPS请求!
[JavaScript] 纯文本查看 复制代码
function signRequest(p) {
        // console.log('operationType =', p.operationType);
        // console.log('requestData =', p.requestData);
        // console.log('ts =', p.ts);
        if (!securesignature || !securesignature.signRequest) {
                console.error('securesignature instance not found, please click homepage first!');
                return '';
        }
        const clsSecurityGuardParamContext = Java.use('com.alibaba.wireless.security.open.SecurityGuardParamContext');
        const instSecurityGuardParamContext = clsSecurityGuardParamContext.$new();
        const appKeyField = clsSecurityGuardParamContext.class.getDeclaredField('appKey');
        const requestTypeField = clsSecurityGuardParamContext.class.getDeclaredField('requestType');
        const paramMapField = clsSecurityGuardParamContext.class.getDeclaredField('paramMap');
        // Set fields accessable
        appKeyField.setAccessible(true);
        requestTypeField.setAccessible(true);
        paramMapField.setAccessible(true);
        // Make map
        const HashMap = Java.use("java.util.HashMap");
        const paramHashMap = HashMap.$new();
        const INPUT = `Operation-Type=${p.operationType}&Request-Data=${p.requestData}&Ts=${p.ts}`;
        paramHashMap.put('INPUT', INPUT);
        // Set values
        appKeyField.set(instSecurityGuardParamContext, 'SNAIL_APP_KEY_ANDROID');
        requestTypeField.setInt(instSecurityGuardParamContext, 4);
        paramMapField.set(instSecurityGuardParamContext, paramHashMap);
        // Print values and verify
        // var appKey = appKeyField.get(instSecurityGuardParamContext);
        // var requestType = requestTypeField.get(instSecurityGuardParamContext);
        // var paramMap = paramMapField.get(instSecurityGuardParamContext);
        // console.log(
                // 'appKey =', appKey, '\n',
                // 'requestType =', requestType, '\n',
                // 'paramMap =', stringifyMap(Java.cast(paramMap, HashMap)),
                // '\n', '*'.repeat(100));
        return securesignature.signRequest(instSecurityGuardParamContext, '');
}
rpc.exports = {
        signRequest,
};
完整的代码在这里:https://github.com/tzwsoho/auto_snail_lucky/tree/master/sign_tool
感谢阅读,请对我的自动抽奖脚本多多支持,多多点Star,谢谢!

代码, 文本

ColoThor   

大佬,能给个文中帖子 蚂蚁森林自动收能量 的地址吗
tzwsoho
OP
  


bhwxha 发表于 2021-8-11 10:31
原始帖子发布时间是2021-8-10 02:33,然后帖子被吞了,现在放出来了,显示于2021-8-10 12:01编辑;
帖子修 ...

没吞,只是我发错版区了,原贴的csdn超链接没有显示出来,我加上了而已
QingRemix   

学习了!!!!
mosou   

有没有淘系xsign的
asdswd   


ColoThor 发表于 2021-8-10 11:41
大佬,能给个文中帖子 蚂蚁森林自动收能量 的地址吗

已经改过了,这论坛不知道为什么把超链接给吃了
tzwsoho
OP
  


mosou 发表于 2021-8-10 10:49
有没有淘系xsign的

应该所有阿里出的APP都是用同一种签名算法的,淘宝、淘特之类的还没研究过
tzwsoho
OP
  

阿里web系列的有吗?
yangningnb   


tzwsoho 发表于 2021-8-10 12:03
已经改过了,这论坛不知道为什么把超链接给吃了

好的,谢谢
ColoThor   

学习了不错
您需要登录后才可以回帖 登录 | 立即注册