APP每一个业务网络请求的请求头中都有mtgsig参数,该参数是请求体与其它参数计算的签名值。
java层代码如下:
public static String makeHeader(byte[] arg13, MODE arg14) {
最终会走到Native层进行签名计算
// 是否root、ADB调试状态、USB调试模式等
压缩信息
E53E7D80 78 9C 9D 91 C1 0E C2 20 10 44 FF 65 CF 0D 61 76 x........D.e..av
组合密钥
1631754963 9b69f861-e054-4bc4-9daf-d36ae205ed3e //当前时间加APPkey
RC4加密压缩后数据
.text:C881966C 11 99 LDR R1, [SP,#0x44]
加密后
E53E7D80 62 16 1F 8D D5 8D AF 42 8B D2 2C 32 77 29 5A 5F b...Ս .B...2w)Z_
Base64加密
An2sai6nXEuFYeKbDUk/qEo/7am8Jtn3O2Has5efofCux7iubGRCS8TKpjUgotJ6MGdQrBsvwh/peZwuikT+5rCr4RzN8SXXCeDOtZQ6sbo/snVdESSJweNqd6i/WbIwDOgv5eaWRQoISjdgNfW3hk7tf0QhsZFbOELcPxz5pRzo6d6EsBLFu5Mq8DbVNgsYF+6aqZ7302/G+Rr7MlUT2M9y3EjgjH01L39q/eRJ
判断本地是否有存储,如果有优先读取本地,如果无反谢java层从服务器端获取,这部分详细分析见后面设备指纹部分。
.text:C8A93C78 F0 B5 PUSH {R4-R7,LR}
获取到的dfpid如下:
DAD796C46B5A6525F4B89DF661A97C7A218A219FC24B93F689DEBD92
判断本地是否有存储,如果有优先读取本地,如果无反谢java层从服务器端获取,APP第一次运行进就用UUID与时间加密生成一个,这部分详细分析见后面设备指纹部分。
.text:C8AEE3A4 F0 B5 PUSH {R4-R7,LR}
获取到的xid如下:
Rs8NOy0BFS5JQxfdOoIxpMnKV3iqYWcblAjp0vpnWZyNzyF9rfsi3ekpm4ScaIZgeImizX/5AbS3e838Or4el4+PPPI2kD8XW+8vbvjDBSM=
组合json
{
每一个字段的解释:
a0:版本,a1:appkey, a3:版本,a4:时间,a5:加密的设备环境,a6:固定数字,a7:xid,a8:dfpid,a9:初始化时加密的设备环境信息(前8字符中CRC:f4ec12ef,因为我换手机了所以计算的值会不一样)
获取请求体数据
.text:C8A8FA4C 29 68 LDR R1, [R5]
获取的数据(部分)
CB092000 50 4F 53 54 20 2F 76 35 2F 73 69 67 6E 20 7B 22 POST /v5/sign {"
解密PIC数据获取key (a7),解密流程与初始化时一样。解密后的值
{"a1":0,"a10":400,"a2":"com.sankuai.meituan","a11":"c1ee9178c95d9ec75f0f076a374df94a032d54c8576298d4f75e653de3705449","a3":"0a16ecd60eb56a6a3349f66cdcf7f7bf5190e5a42d6280d8dc0ee3be228398ec","a4":1100030200,"k0":{"k1":"meituan1sankuai0","k2":"meituan0sankuai1","k3":"$MXMYBS@HelloPay","k4":"Maoyan010iauknaS","k5":"34281a9dw2i701d4","k6":"X%rj@KiuU+|xY}?f"},"a5":"11.3.200","a0":"pw/LhTdeoTTyaxPHcHMy+/ssGNS1ihNkrJ+uBI74FIfd90KlTil1m0i7FF/n0bhY","a6":"/HntC9XIfdUyII/UiVfx020EQPpHz2XZY3qzM2aiNmM0i0pB1yeSO689TY9SBB3s","a7":"QsHnU6kFjTYR8Z6tHEvkGMO2Hrt+NRnVQhmxg6EtVBzuzQcBpma3AdhTWNMpesFT","c0":{"c1":true,"c2":false},"a9":"SDEzWXi5LHL/cuMCZ1zYyv+0hIViqWWf+ShbUYILWf4=","a8":1603800117167}
解析json获取a7
QsHnU6kFjTYR8Z6tHEvkGMO2Hrt+NRnVQhmxg6EtVBzuzQcBpma3AdhTWNMpesFT
appkey与pic中的a7异或
.text:C8A90424 20 00 MOVS R0, R4
异或后的值
BC79D120 5E 54 73 4D 30 7A 4C 44 57 34 53 77 44 40 55 51 ^TsM0zLDW4SwD@UQ
再次异或
.text:C8A91C00 loc_C8A91C00 ; CODE XREF: hmac_sha256_sub_BB754BAC+6C↓j
异或后的值
CB0D3000 68 62 45 7B 06 4C 7A 72 61 02 65 41 72 76 63 67 hbE{.Lzra.eArvcg
将异或后的值与请求体组合
CB0D3000 68 62 45 7B 06 4C 7A 72 61 02 65 41 72 76 63 67 hbE{.Lzra.eArvcg
计算组合值的MD5
.text:C8A91C60 2A 00 MOVS R2, R5
计算后得到的值
F0 EF 16 F8 BD C6 7B CC 8C B4 8F AC 4C EC 7A DB A8 A8 D1 05
解密PIC数据获取KEY(a9),解析json获取
a3:0a16ecd60eb56a6a3349f66cdcf7f7bf5190e5a42d6280d8dc0ee3be228398ec
a3为AES KEY解密a9解密后数据,该值作为加密body md5值的key
3ey2scPxek170m6K
AES加密Body计算得到的MD5值
IV 0102030405060708
加密后数据
C7B9C460 06 34 4B B7 17 3B 29 9D FE B9 85 8D 24 6C 52 AEC7B9C470 BB AF 22 3F 8E 43 FB C5 66 2B 54 E2 C6 6A 54 EA
转换成字符串
06344bb7173b299dfeb9858d246c52aebbaf223f8e43fbc5662b54e2c66a54ea
组合json,生成签名
{ "a0": "2.0", "a1": "9b69f861-e054-4bc4-9daf-d36ae205ed3e", "a3": 2, "a4": 1631754963, "a5": "An2sai6nXEuFYeKbDUk/qEo/7am8Jtn3O2Has5efofCux7iubGRCS8TKpjUgotJ6MGdQrBsvwh/peZwuikT+5rCr4RzN8SXXCeDOtZQ6sbo/snVdESSJweNqd6i/WbIwDOgv5eaWRQoISjdgNfW3hk7tf0QhsZFbOELcPxz5pRzo6d6EsBLFu5Mq8DbVNgsYF+6aqZ7302/G+Rr7MlUT2M9y3EjgjH01L39q/eRJ", "a6": 1025, "a7": "Rs8NOy0BFS5JQxfdOoIxpMnKV3iqYWcblAjp0vpnWZyNzyF9rfsi3ekpm4ScaIZgeImizX/5AbS3e838Or4el4+PPPI2kD8XW+8vbvjDBSM=", "a8": "DAD796C46B5A6525F4B89DF661A97C7A218A219FC24B93F689DEBD92", "a9": "f4ec12efNkQBqdtVlV78x1/Mln2Us/xw171NuJjdEXrGWsFDdMV5Te45wqjL0nPO8OFFKjvKthvva+lS9xqhMhSt1WZRjDYpsWc/eh3z4F2JTv3MOh8NEDmk7Frthx5/bczdDIKvRP0QneTfNKSm116fUjdLhOEYlNbym/xI+5jZAEJGfGjltFLEOmtOwgxasgHQh2woMl/vAyr7ePuoVC6wEcbv2+w6n/+Pl1U1KO2YcTw4peiZDqC7iHpTVQH4fWri9R5+Ev1zx/xObVqoxqe3TEW/t2EIRqQ4QoRZRix0xC6C280faz8U5vOqafUnm+qev7tjs7SOV4SNxBv+LEJTxr5IJU302FJEk/CqhKoz5eWRYtT5Z52kEanlfu4AGHcJLC343kpI3GxYw7uPeewA/Ye0qDgZUyfj0MPpaYMPj0UmtvnbXEU4+FaRaCb/LsQtWdOtEiEKveUQU9bTW4NfHch2+6gcHP2/E+UQSlREX67PPa9XN8tgL4H6qzghiE1NL3gYw0rrjzEXiO6jsjvIdzwDjeab9woJyr8W3xSACz3sezUS+AJAKohnJvlQkFM9cdG3lPYS7gByAK++K2/vI714kxJHqCZQQMbVNsoWj5w64YL+sE1A4byzOPgK71oPb9w6Cb+KwVlDtqH8F5vlVkO23Iq8E28BI2vQuq5TLRzMunjo45Ks2Py9ZZuHkGb+QIVpUz6ViB+JlUONKinIJF1p6g==", "a10": "{}", "x0": 1, "a2": "06344bb7173b299dfeb9858d246c52aebbaf223f8e43fbc5662b54e2c66a54ea"}
a2:就是请求体签名值,其它字段上面已经解释过,然后将签名值返回到java层,整个签名流程就完成了。
作者简介:
我是小三,目前从事软件安全相关工作,虽己工作多年,但内心依然有着执着的追求,信奉终身成长,不定义自己,热爱技术但不拘泥于技术,爱好分享,喜欢读书和乐于结交朋友,欢迎加我微信与我交朋友(公众号输入框回复“wx”即可)