某网赚游戏sign解密

某网赚游戏分析时,提示我root机无法正常登录,打算深入看看。

抓包发现其会提交设备及环境信息上去:

某网赚游戏sign解密_第1张图片

 换个手机,尝试修改root、black_app等参数,发现最终响应数据显示失败,前面可能会有验证

重新抓一次,发现应用第一步登录时,会下发一个token,由token和请求参数 最终会运算得到一个sign,由sign来验证是否改了包

登录时的请求参数

某网赚游戏sign解密_第2张图片

响应数据

{
"code": 200,
"msg": "success",
"time_stamp": "2021-09-30 15:32:53",
"token": "MDQzMTZlMzg5OTEwNDNiM2E2YzYyNTE2ZGI1ZmM1NjNjRDIyODJEOQ=="
}

这个下发的token后面都会用到

通过分析代码发现其sign的运算比较简单:

1 通过一个native函数getSignKey得到key

2 param=所有请求参数中,除了channel 和 app_id字段外,其他字段的拼接(当然sign字段也不算,他此时还没算出来呢)

3 第二步的param再拼接上第一步的key

4 对第三部的结果求md5,最后就得到sign的值

所以关键还是要得到这个native函数getSignKey返回的key,通过对该native函数hook,发现其参数二为app_id,参数三为channel

函数原型:public static native String getSignKey(Context context, String str, String str2);

下面看汇编代码

.text:00002E18 var_7C = -0x7C
.text:00002E18 var_24 = -0x24
.text:00002E18 var_14 = -0x14
.text:00002E18 var_10 = -0x10
.text:00002E18 arg_0 = 8
.text:00002E18
.text:00002E18 ; __unwind {
.text:00002E18 PUSH {R4-R7,LR}
.text:00002E1A ADD R7, SP, #0xC
.text:00002E1C STR.W R8, [SP,#0xC+var_10]!
.text:00002E20 SUB SP, SP, #0x70
.text:00002E22 MOV R8, R0
.text:00002E24 LDR R0, =(__stack_chk_guard_ptr - 0x2E2E)
.text:00002E26 MOV R1, R2               ; context -> R1 将上下文放入R1
.text:00002E28 MOV R5, R3               ; param2 -> R5 将参数2放入 R5
.text:00002E2A ADD R0, PC ; __stack_chk_guard_ptr
.text:00002E2C LDR R0, [R0] ; __stack_chk_guard
.text:00002E2E LDR R0, [R0]
.text:00002E30 STR R0, [SP,#0x80+var_14]
.text:00002E32 MOV R0, R8
.text:00002E34 BLX j_getSign
.text:00002E38 MOV R0, R8
.text:00002E3A MOV R1, R5              ; 对 param2 转换为 cstr
.text:00002E3C BLX j_Jstring2CStr
.text:00002E40 LDR R1, [R7,#arg_0]     ; 由于 JNIEnv 和 this 的站位,参数3在native变成第五个参数,该参数由栈传递
.text:00002E42 MOV R6, R0
.text:00002E44 MOV R0, R8
.text:00002E46 BLX j_Jstring2CStr     ; 对 param3 转换为 cstr
.text:00002E4A MOV R4, R0
.text:00002E4C MOV R0, R6 ; s
.text:00002E4E BLX strlen             ; 求 param2 的长度
.text:00002E52 MOV R5, R0
.text:00002E54 MOV R0, R4 ; s
.text:00002E56 BLX strlen             ; 求 param3 的长度
.text:00002E5A ADD R0, R5             ; 将 param2 与 param3 长度相加
.text:00002E5A                        ; size = len(param2) + len(param3) + 0x10
.text:00002E5C ADDS R0, #0x10 ; size
.text:00002E5E BLX malloc             ; 向内存申请size大小的空间
.text:00002E62 MOV R1, R6 ; src
.text:00002E64 MOV R5, R0
.text:00002E66 BLX strcpy
.text:00002E6A MOV R0, R5 ; dest
.text:00002E6C MOV R1, R4 ; src
.text:00002E6E BLX strcat            ; 将 param2 放入申请的buff 然后拼上 param3
.text:00002E72 MOV R0, R5 ; s
.text:00002E74 BLX strlen
.text:00002E78 LDR R1, =(aZEjgup850fHaba - 0x2E82)
.text:00002E7A ADD R0, R5
.text:00002E7C MOVS R2, #0x11
.text:00002E7E ADD R1, PC ; "Z#EJgUP850F*HaBA"
.text:00002E80 BLX __aeabi_memcpy    ; 再拼上 Z#EJgUP850F*HaBA
.text:00002E80                       ; buff = param2 + param3 + Z#EJgUP850F*HaBA
.text:00002E84 MOV R0, R5 ; s
.text:00002E86 BLX strlen
.text:00002E8A ADD R6, SP, #0x80+var_7C
.text:00002E8C MOV R4, R0
.text:00002E8E MOV R0, R6
.text:00002E90 BLX j_MD5Init       ; 标准 MD5 算法,在局部变量内填入4个 模数
 
 
以下为 MD5Init函数的汇编代码                                
.text:000020E4 MD5Init                               
.text:000020E4                                        
.text:000020E4 ; __unwind {
.text:000020E4                 PUSH            {R7,LR}
.text:000020E6                 MOV             R7, SP
.text:000020E8                 MOVW            R2, #0x2301            
.text:000020EC                 MOVW            R3, #0xAB89
.text:000020F0                 MOVW            R12, #0xDCFE
.text:000020F4                 MOVW            LR, #0x5476
.text:000020F8                 MOVS            R1, #0
.text:000020FA                 MOVT.W          R2, #0x6745             R2 = 0x67452301
.text:000020FE                 MOVT.W          R3, #0xEFCD             R3 = 0xEFCDAB89
.text:00002102                 MOVT.W          R12, #0x98BA            R12 = 0x98BADCFE
.text:00002106                 MOVT.W          LR, #0x1032             LR = 0x10325476
.text:0000210A                 STRD.W          R1, R1, [R0],#8
.text:0000210E                 STMIA.W         R0, {R2,R3,R12,LR}
.text:00002112                 POP             {R7,PC}
 
查阅资料发现 R2 R3 R12 LR 中的4个常数 刚好为标准MD5算法的4个模数
 
 
下面继续分析getSignKey

.text:00002E94 MOV R0, R6
.text:00002E96 MOV R1, R5
.text:00002E98 MOV R2, R4
.text:00002E9A BLX j_MD5Update     ; 参数一: 被填入MD5算法模数数组的局部变量的地址(传引用)
.text:00002E9A                     ; 参数二: buff
.text:00002E9A                     ; 参数三: len(buff)
.text:00002E9E ADD R4, SP, #0x80+var_24
.text:00002EA0 MOV R0, R6
.text:00002EA2 MOV R1, R4
.text:00002EA4 BLX j_MD5Final       ; 完成KD5 运算,并将结果写入参数er中(R1)
.text:00002EA8 MOVS R0, #0x21 ; '!' ; size
.text:00002EAA BLX malloc           ; 申请长度33的空间
.text:00002EAE MOV R5, R0
.text:00002EB0 MOV R0, R4
.text:00002EB2 MOV R1, R5
.text:00002EB4 MOVS R2, #0x10
.text:00002EB6 BLX j_ByteToHexStr    ; 将byte转换为 16进制 字符串
.text:00002EBA MOVS R0, #0
.text:00002EBC MOV R1, R5
.text:00002EBE STRB.W R0, [R5,#0x20]  ; 在该缓冲区第33位写入0
.text:00002EC2 MOV R0, R8
.text:00002EC4 BLX j_charToJstring    ; 将该长度为 32 的16进制字符串转化为jString并 返回
.text:00002EC8 LDR R1, =(__stack_chk_guard_ptr - 0x2ED0)
.text:00002ECA LDR R2, [SP,#0x80+var_14]
.text:00002ECC ADD R1, PC ; __stack_chk_guard_ptr
.text:00002ECE LDR R1, [R1] ; __stack_chk_guard
.text:00002ED0 LDR R1, [R1]
.text:00002ED2 SUBS R1, R1, R2
.text:00002ED4 ITTT EQ
.text:00002ED6 ADDEQ SP, SP, #0x70
.text:00002ED8 LDREQ.W R8, [SP+0x10+var_10],#4
.text:00002EDC POPEQ {R4-R7,PC}
.text:00002EDE BLX __stack_chk_fail

所以综合以上 getSignKey 函数的功能为对 app_id + channel + Z#EJgUP850F*HaBA 求MD5,还挺简单的。

搞定了sign接下来就可以写个脚本生成sing来改包了

你可能感兴趣的:(安卓逆向,java)