最近想爬虎扑的全量用户,初步打算从 App 端入手,不出意外,在请求中依旧碰到了加密参数。
请求参数
ios 端和 android 端的请求参数大同小异,这里以 android 端的请求参数为例,
clientId
、_ssid
、_imei
、client
、android_id
这几个是设备和客户端连接相关信息
crt
、stamp
时间戳,不过位数不同
其他几个参数很好理解,只有一个sign
是加密字段,每个请求都会重新计算生成
获取源码
反编译流程可以参考之前的文章链家App反编译破解加密字段,然后使用 JD-GUI 查看源码。
sign 生成逻辑
1
2
|
# 这里将请求参数传给了函数b
paramOkRequestParams.put("sign", q.b(paramOkRequestParams));
|
1
2
3
4
5
|
# 函数b,getSortURL顾名思义,对url排序
public static String b(OkRequestParams paramOkRequestParams)
{
return paramOkRequestParams.getSortURL();
}
|
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
|
# 参数排序后加盐传给函数a
public String getSortURL()
{
Object localObject = new ArrayList(this.stringParams.entrySet());
Collections.sort((List)localObject, new Comparator()
{
public int a(Map.Entry<String, String> paramAnonymousEntry1, Map.Entry<String, String> paramAnonymousEntry2)
{
return ((String)paramAnonymousEntry1.getKey()).toString().compareTo(((String)paramAnonymousEntry2.getKey()).toString());
}
});
new JSONObject(this.stringParams);
if (((Integer)c.a("basic_signature", Integer.valueOf(0), Integer.class)).intValue() == 0) {}
StringBuilder localStringBuilder = new StringBuilder();
localObject = ((List)localObject).iterator();
while (((Iterator)localObject).hasNext())
{
Map.Entry localEntry = (Map.Entry)((Iterator)localObject).next();
if (localStringBuilder.length() > 0) {
localStringBuilder.append("&");
}
localStringBuilder.append((String)localEntry.getKey());
localStringBuilder.append("=");
localStringBuilder.append((String)localEntry.getValue());
}
return w.a(localStringBuilder.toString() + "HUPU_SALT_AKJfoiwer394Jeiow4u309");
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
# 函数a,猜测这里是使用了加密算法,未知点在于b、c
public static String a(String paramString)
{
int i = 0;
b.reset();
b.update(paramString.getBytes());
paramString = b.digest();
c.setLength(0);
while (i < paramString.length)
{
int j = paramString[i] & 0xFF;
if (j < 16) {
c.append('0');
}
c.append(Integer.toHexString(j));
i += 1;
}
return c.toString();
}
|
1
2
3
4
5
6
|
# b对应的是md5加密
private static MessageDigest b;
private static StringBuilder c;
···
b = MessageDigest.getInstance("MD5");
c = new StringBuilder();
|
综上,sign的生成逻辑:
- url中的params转字典
- 根据key排序
- 排序后拼接,k1=v1&k2=v2 这样的格式
- 拼接后字符串加盐
HUPU_SALT_AKJfoiwer394Jeiow4u309
- md5加密
python版本:
1
2
3
4
5
6
|
def get_sign(params_dict):
sorted_dict = {key: params_dict[key] for key in sorted(params_dict)}
params_str = '&'.join([key + '=' + str(sorted_dict[key]) for key in sorted_dict.keys()])
params_str = params_str + 'HUPU_SALT_AKJfoiwer394Jeiow4u309'
sign = hashlib.md5(params_str.encode()).hexdigest()
return sign
|