某电商app的sign分析

发布时间 2024-01-04 12:40:19作者: 怎么可以吃突突

定位sign关键位置

抓包后看到sign的值为16个字节,猜测应该是一个md5

可以通过hookNewStringUTF利用字符串长度筛选定位到关键位置,也可以通过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

  1. 先调用gettimeofday添加时间戳st=
  2. 调用lrand48() % 3生成encryptIdoffset,并与1拼接得到参数sv=
  3. 添加了st=sv=的url和encryptIdoffset作为参数调用自定义的加密函数
  4. 返回的加密数据进行base64编码
  5. base64编码后的结果进行md5并转化为字符串得到sign

分析3中的自定义加密函数,其首先会利用之前随机生成的offsetencryptId选择对应的生成算法和key。

最后得到offsetencryptIdsv和生成算法的对应关系如下表

分析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打印一下整个加密过程