添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

抓包后看到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打印一下整个加密过程