吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 8481|回复: 24
收起左侧

[Android 原创] frida获得阿里系APP签名函数地址及调用

  [复制链接]
tzwsoho 发表于 2021-8-10 02:33
本帖最后由 tzwsoho 于 2021-8-10 12:01 编辑

最近研究了一下几羊的APP,写了个基于frIDA的自动抽奖脚本,这里我单独对其中的签名函数地址的获取做一下解读。
首先,包括几羊APP在内,所有阿里系APP在向服务器发出HTTPS请求时,都会带上一个签名sign,根据大佬的文章(蚂蚁森林自动收能量:https://blog.csdn.net/dieTicket/article/details/102678054)可以知道,这个签名是动态加载libsgmain.so文件,然后调用里面的
[Plain Text] 纯文本查看 复制代码
1
com.alibaba.wireless.security.open.securesignature.a.signRequest(Lcom/alibaba/wireless/security/open/SecurityGuardParamContext;Ljava/lang/String;)Ljava/lang/String;

得出的,其中SecurityGuardParamContext参数我们可以简单地通过jadx反编译得出是这么一个结构体:
[Java] 纯文本查看 复制代码
1
2
3
4
5
6
7
public class SecurityGuardParamContext {
    public String appKey;
    public Map<String, String> paramMap = new HashMap();
    public int requestType;
    public String reserved1;
    public String reserved2;
}

知道了这点,我们先来对这个函数下钩子,看看signRequest的参数分别是什么。

先准备一台root掉的手机,或者雷电模拟器,启动frida-server,这个网上很多教程,这里不再赘述。


然后将以下代码保存为hook.js:
[Asm] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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] 纯文本查看 复制代码
1
2
3
4
5
6
7
# frida-ps -Uia
PID  Name    Identifier
----  ------  ---------------------------
2075  几羊      com.snail.android.lucky
1563  设置      com.android.settings
1911  雷电游戏中心  com.android.flysilkworm
...


将脚本注入几羊APP
[Plain Text] 纯文本查看 复制代码
1
# frida -U --no-pause -l hook.js -p 2075


然后任意点击几羊APP的界面,使几羊产生HTTPS请求,这时可以看到控制台会输入类似以下的字符串:
[Plain Text] 纯文本查看 复制代码
1
2
3
4
5
6
7
8
hooked
p0 = "<instance: com.alibaba.wireless.security.open.SecurityGuardParamContext>" p1 = "" sign = 89aa0266ec4a5e631b82209171d49548
p0 = "<instance: com.alibaba.wireless.security.open.SecurityGuardParamContext>" p1 = "" sign = 3a5774c3aa6ec736334f0c7f11bb5e53
p0 = "<instance: com.alibaba.wireless.security.open.SecurityGuardParamContext>" p1 = "" sign = 0dfca532961a1998237e2903676211f9
p0 = "<instance: com.alibaba.wireless.security.open.SecurityGuardParamContext>" p1 = "" sign = bac3f23414b3345b84c0b7654610d00f
p0 = "<instance: com.alibaba.wireless.security.open.SecurityGuardParamContext>" p1 = "" sign = c6f37ba76d12b97db25946b04039f6ed
p0 = "<instance: com.alibaba.wireless.security.open.SecurityGuardParamContext>" p1 = "" sign = 437fb3b5e9f3026d88347e6b1ff2eb34
p0 = "<instance: com.alibaba.wireless.security.open.SecurityGuardParamContext>" p1 = "" sign = 97793a1b0cdd3108fc4b01d7f2a35361


为了进一步看清p0参数的内容,我们将hook.js脚本改一下:
[JavaScript] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
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] 纯文本查看 复制代码
1
2
3
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是一串由Operation-TypeRequest-DataTs三个参数组成的请求字符串,其中:
Operation-Type是操作类型名,表示要求服务器做的操作,
Request-Data其实是一串Base64字符串,我们随意解码一段:
[JavaScript] 纯文本查看 复制代码
1
[{"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] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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,谢谢!

免费评分

参与人数 5威望 +1 吾爱币 +30 热心值 +5 收起 理由
qtfreet00 + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
笙若 + 1 + 1 谢谢@Thanks!
piopiopio123 + 1 + 1 我很赞同!
timeni + 1 + 1 我很赞同!
涛之雨 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

ColoThor 发表于 2021-8-10 11:41
大佬,能给个文中帖子 蚂蚁森林自动收能量 的地址吗
 楼主| tzwsoho 发表于 2021-8-11 11:03
bhwxha 发表于 2021-8-11 10:31
原始帖子发布时间是2021-8-10 02:33,然后帖子被吞了,现在放出来了,显示于2021-8-10 12:01编辑;
帖子修 ...

没吞,只是我发错版区了,原贴的csdn超链接没有显示出来,我加上了而已
QingRemix 发表于 2021-8-10 10:37
mosou 发表于 2021-8-10 10:49
有没有淘系xsign的
头像被屏蔽
asdswd 发表于 2021-8-10 11:15
提示: 作者被禁止或删除 内容自动屏蔽
 楼主| tzwsoho 发表于 2021-8-10 12:03
ColoThor 发表于 2021-8-10 11:41
大佬,能给个文中帖子 蚂蚁森林自动收能量 的地址吗

已经改过了,这论坛不知道为什么把超链接给吃了
 楼主| tzwsoho 发表于 2021-8-10 12:04
mosou 发表于 2021-8-10 10:49
有没有淘系xsign的

应该所有阿里出的APP都是用同一种签名算法的,淘宝、淘特之类的还没研究过
yangningnb 发表于 2021-8-10 17:03
阿里web系列的有吗?
ColoThor 发表于 2021-8-10 18:14
tzwsoho 发表于 2021-8-10 12:03
已经改过了,这论坛不知道为什么把超链接给吃了

好的,谢谢
咔c君 发表于 2021-8-10 21:10
学习了不错
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2025-4-13 21:32

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表