抓包后看到sign的值为16个字节,猜测应该是一个md5
可以通过hook
NewStringUTF
利用字符串长度筛选定位到关键位置,也可以通过url中的关键字段去定位组包位置。这里利用后者,搜索
x-api-eid-token
字段,注意这里最好使用此url特有的字段,这样好筛选。jadx中看到此字段被
CHANGEABLE_PARAM_LIST
引用
继续往上回溯引用
CHANGEABLE_PARAM_LIST
的地方
getChangeableParamStr
向上回溯
getChangeableParamStr
的引用有多个,经过打印筛选得到实际的引用为
getQueryParamsStr
。此函数调用
getStaticParamStr
函数得到
UNCHANGEABLE_PARAM_LIST
中包含的固定的参数值,调用
getChangeableParamStr
得到
CHANGEABLE_PARAM_LIST
中包含的不固定会变化的参数值。最后将固定的参数和不固定的参数拼接后返回。
继续往上回溯
getQueryParamsStr
引用,最后得到
addStatQueryParam--->getStatisticReportString--->getQueryParamsStr
。查看
addStatQueryParam
函数其会将
getStatisticReportString
返回的固定和不固定参数拼接后的结果作为参数调用
addStateQueryParamInternal
查看
addStateQueryParamInternal
,其先会调用
getUrl
获取当前url,然后与传入的参数进行拼接,最后调用
setUrl
重新设置url
此时还没有涉及到
sign
,继续回溯
addStatQueryParam
的引用得到
setupParams
。其会调用
addStatQueryParam
添加查询参数,调用
addCustomQueryParam
添加自定义业务参数
对
setUrl
和上述分析过程中的关键函数进行hook观察url的变化情况,可以发现在调用了
addCustomQueryParam
添加了自定义参数后(并且在调用doSignUsingJdGuard函数之前)紧接着又添加了
sign
参数。
所以最后找到是
signature
函数,其会调用
com.jingdong.common.network.JDNetworkDependencyFactory$3.signature
计算得到
sign
等参数,最后调用
seturl
冲新设置url。
com.jingdong.common.network.JDNetworkDependencyFactory$3.signature
函数会调用jni函数
getSignFromJni
分析sign算法
getSignFromJni
对应的native函数在
libjdbitmapkit.so
中
先调用
gettimeofday
添加时间戳
st=
调用
lrand48() % 3
生成
encryptId
和
offset
,并与1拼接得到参数
sv=
添加了
st=
和
sv=
的url和
encryptId
,
offset
作为参数调用自定义的加密函数
返回的加密数据进行
base64
编码
base64
编码后的结果进行
md5
并转化为字符串得到
sign
值
分析3中的自定义加密函数,其首先会利用之前随机生成的
offset
和
encryptId
选择对应的生成算法和key。
最后得到
offset
,
encryptId
,
sv
和生成算法的对应关系如下表
分析
TenSeattos
生成算法,其会轮询加密每一个字符
用c将加密算法还原如下
void TenSeattosEncrypt(char* input, int input_len)
int v4, v5;
char v6;
const char* TenSeattos_key = "80306f4370b39fd5630ad0529f77adb6";
unsigned char table[0x10] = { 0x37, 0x92, 0x44, 0x68, 0xA5, 0x3D, 0xCC, 0x7F, 0xBB, 0xF, 0xD9, 0x88, 0xEE, 0x9A, 0xE9, 0x5A };
for (int i = 0; i != input_len; ++i) {
v4 = i & 7;
v5 = table[i & 0xF];
v6 = (v5 + (*(unsigned char*)(input + i) ^ *(unsigned char*)(TenSeattos_key + v4) ^ table[i & 0xF])) ^ table[i & 0xF];
*(unsigned char*)(input + i) = v6;
*(unsigned char*)(input + i) = *(unsigned char*)(TenSeattos_key + v4) ^ v6;
知道其中一种算法就可以固定sv参数去请求接口了,frida hook打印一下整个加密过程