白乐天

道阻且长,行则将至。

淘小说app参数sign值逆向及vip逻辑分析

App信息

包名:com.martian.ttbook

抓包分析数据

发送登录请求,找到登录相关数据包,分析sign参数

Jadx反编译apk

搜索sign

intercept

双击跳转到sign出现的位置

通过分析上下文可以确定这就是我们要的参数,接下来分析这个参数是怎么生成的

d.d

它从d.d(treeMap, ConfigSingleton.D().l().f26381b);这个地方过来,我们进入到d方法里看看

利用frida hook d方法查看它的参数和返回值

hook d

1
2
3
4
5
6
7
8
9
10
11
function hook_d(){
Java.perform(function(){
let d = Java.use("ba.d");
d["d"].implementation = function (treeMap, str) {
console.log(`d.d is called: treeMap=${treeMap}, str=${str}`);
let result = this["d"](treeMap, str);
console.log(`d.d result=${result}`);
return result;
};
})
}

hook结果

1
2
3
4
d.d is called: 
treeMap={appid=mibook, brand=google, channel=Vivo, code=1111, device_id=b5ffdb56a1f546bc978c7237a06e55e4, model=Pixel 3, optype=0, ostype=0, osversion=9, package_name=com.martian.ttbook, phone=17550373741, t=1737260784077, token=dd1c0464-7a19-460f-b149-8ca0231380e2, uid=83742270, version_code=488, version_name=10.3.6},
str=mibook_123456
d.d result=24DFDE384CECB241FF0C667046DCD1CF

e

d方法的返回值调用了e方法,进入e方法查看一下

这里使用了md5算法,然后对结果又进行了变换,最终转换为字符串返回。

hook e

1
2
3
4
5
6
7
8
9
10
11
function hook_e(){
Java.perform(function(){
let d = Java.use("ba.d");
d["e"].implementation = function (bArr) {
console.log(`d.e is called: bArr=${Java.use("java.lang.String").$new(bArr)}`);
let result = this["e"](bArr);
console.log(`d.e result=${result}`);
return result;
};
})
}

hook 结果

1
2
d.e is called: bArr=appid=mibook&brand=google&channel=Vivo&code=1111&device_id=b5ffdb56a1f546bc978c7237a06e55e4&model=Pixel 3&optype=0&ostype=0&osversion=9&package_name=com.martian.ttbook&phone=17550373739&t=1737268010279&token=dd1c0464-7a19-460f-b149-8ca0231380e2&uid=83742270&version_code=488&version_name=10.3.6&key=mibook_123456
d.e result=1c6a4ca1d667b3f3878b7d25d59dfce8

Python还原

1
2
3
4
5
6
7
8
9
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import requests
import hashlib
import time

def md5_call(data):
# 创建md5对象
md5 = hashlib.md5()
# 更新要加密的数据,参数要是字节类型
md5.update(data.encode("utf-8"))
# 获取加密后的数据,以字节码表示
md5_byte = md5.digest()
return md5_byte

# 定义URL和请求头
url = "http://tybook.taoyuewenhua.net/phone_login.do"
headers = {
"Accept-Language": "zh-CN-#Hans",
"Connection": "close",
"Accept-Encoding": "gzip",
"User-Agent": "okhttp/4.11.0",
}

# 定义查询参数
params = {
"appid": "mibook",
"brand": "google",
"channel": "Vivo",
"code": "1111",
"device_id": "b5ffdb56a1f546bc978c7237a06e55e4",
"model": "Pixel 3",
"optype": "0",
"ostype": "0",
"osversion": "9",
"package_name": "com.martian.ttbook",
"phone": "17550373739",
"t": "1737268010279", # str(int(time.time())),
"token" : "dd1c0464-7a19-460f-b149-8ca0231380e2",
"uid": "83742270",
"version_code": "488",
"version_name": "10.3.6",
}

# 生成sign
def generate_dign(params):
treemap_str = "&".join([key+"="+value for key,value in params.items()])
treemap_str+="&key=mibook_123456"
# print(treemap_str)
md5_bytes = list(md5_call(treemap_str))
cArr = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']
sign_str = ""
for b in md5_bytes:
sign_str+=cArr[(b>>4)&15]
sign_str+=cArr[b&15]
# print(sign_str)
return sign_str



generate_dign(params)

params["sign"]=generate_dign(params)
print(params)

# 发送GET请求
response = requests.get(url, headers=headers, params=params)

# 检查响应并输出结果
if response.status_code == 200:
print("Response:")
print(response.text) # 打印响应内容
else:
print(f"Failed to fetch data. HTTP Status Code: {response.status_code}")
1
2
Response:
{"errcode":-1,"errmsg":"图形验证码,请填入弹框里"}

vip逻辑分析

jadx里搜索getIsVip

getIsVip

利用frida进行hook

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function hook_vip(){
Java.perform(function(){
Java.choose("com.martian.rpauth.response.MartianRPAccount",{
onMatch:function(obj){
console.log(obj.isVip.value);
obj.isVip.value = Java.use("java.lang.Boolean").$new(true);
console.log("replaced isvip:",obj.isVip.value);
},onComplete:function(){
console.log("onComplete!");
}
})


let MartianRPAccount = Java.use("com.martian.rpauth.response.MartianRPAccount");
MartianRPAccount["getIsVip"].implementation = function () {
console.log(`MartianRPAccount.getIsVip is called`);
let result = this["getIsVip"]();
console.log(`MartianRPAccount.getIsVip result=${result}`);


return 1;
};
})
}

hook 结果