飞不高 发表于 2025-3-10 04:09:45

a_bogus、msToken、fp、verifyFp | bdms_1.0.1.19 签名算法分析记录

【作者主页】:小鱼神1024
【擅长范畴】:JS逆向、小步伐逆向、AST还原、验证码突防、Python开辟、欣赏器插件开辟、React前端开辟、NestJS后端开辟等等
    本文章中所有内容仅供学习交换利用,不消于其他任何目的,不提供完整代码,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切结果均与作者无关!若有侵权,请联系作者立刻删除!
前言

最近听小伙伴说,a_bogus 签名算法又变了,出于学习目的,于是乎,我决定重新分析记录一下,渴望能帮助到有需要的小伙伴。
前置分析

我们在请求header中发现,有很多请求都带有a_bogus、msToken、fp、verifyFp这四个参数的值是动态变革的,所以我们猜测这四个参数应该是加密参数。
https://i-blog.csdnimg.cn/img_convert/5056624a03fce125e7d17b2952fd5161.png
逆向分析

fp、verifyFp

从上图可以发现,fp、verifyFp这两个参数的值是一样的。
全局搜索 verifyFp,打上断点,重新请求,发现断住了。如下图:
https://i-blog.csdnimg.cn/img_convert/4fb3b36b605aa27fd1cfbf2f5dc17aa1.png
此中,fp、verifyFp的值来自 r, 往上翻可以看到,var r = n.getFp(),打上断点,重新请求。进入getFp 函数,如下图:
https://i-blog.csdnimg.cn/img_convert/3ad813af717b1cc9ee89509922b71968.png
提取函数为:
function get_fp() {
    var e = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".split("")
      , t = e.length
      , n = Date.now().toString(36)
      , r = [];
    r = r = r = r = "_",
    r = "4";
    for (var o = 0, i = void 0; o < 36; o++)
      r || (i = 0 | Math.random() * t,
      r = e);
    return "verify_" + n + "_" + r.join("")
}
msToken

经过测试发现,它不是前端js天生的,是服务端天生之后,生存到cookie中的,如下图:
https://i-blog.csdnimg.cn/img_convert/becb3da74144bfb5e713e4d688b8ed4e.png
经过多次对比发现,它的天生方式和 base64 算法天生相似,所以我们可以尝试模拟天生,代码如下:
function get_ms_token(length = 182) {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
let result = '';
for (let i = 0; i < length; i++) {
      result += chars.charAt(Math.floor(Math.random() * chars.length));
}
return encodeURIComponent(result);
}
a_bogus

重头戏来喽。打起精力来,这部分插桩分析可能有点枯燥,耐心看完,信任你会有收获的。
我也把自己当成小白,从头开始分析,一步步来。
由于平台大部分接口临时没有对a_bogus 参数做强校验,但二级品评接口是个例外,如果不加a_bogus 参数,会返回错误。为了验证a_bogus 参数天生的是否正确,我们决定先从二级品评接口入手。
通过跟栈分析,发现a_bogus 参数是在 bdms.js 文件中天生的,点击进去,发现是 vmp 代码,如下图:
https://i-blog.csdnimg.cn/img_convert/29b734656fc79bc9af54f99508fb656a.png
有些小伙伴第一时间可能想补环节,但是,尝试过之后的结果会让你失望的,因为你都很难找到天生入口。。
所以,我们换个思路,直接插桩纯算。
说到插桩,你可以尝试一下我之前写的插桩日记框架,可能会让你事半功倍。传送门:终极逆向插桩日记框架,让欣赏器瓦解成为历史!
利用日记框架在bdms.js 文件中插桩,如下图:
https://i-blog.csdnimg.cn/img_convert/3a8f6f04c1a4dbd5e804975a87a585ca.png
https://i-blog.csdnimg.cn/img_convert/ab46efbdd499609e08a98974a65e9a25.png
由于运算符比较多,我就不一一截图展示了。自己把常见的运算符都插桩下即可。
打开日记文件,开始分析。
https://i-blog.csdnimg.cn/img_convert/ff6ca05fc23f1051951805a3f117e7c9.png
https://i-blog.csdnimg.cn/img_convert/14bcf477bc35237a1475c2c2ff1e8b31.png
首先,我们发现请求参数通过加盐 dhzx, 得到新的值:device_platform=webapp&aid=6383&channel=channel_pc_web&item_id=7429636428608425267&comment_id=7431107242646258473&cut_version=1&cursor=0&count=3&item_type=0&update_version_code=170400&pc_client_type=1&pc_libra_divert=Mac&version_code=170400&version_name=17.4.0&cookie_enabled=true&screen_width=1280&screen_height=800&browser_language=zh-CN&browser_platform=MacIntel&browser_name=Chrome&browser_version=131.0.0.0&browser_online=true&engine_name=Blink&engine_version=131.0.0.0&os_name=Mac+OS&os_version=10.15.7&cpu_core_num=8&device_memory=8&platform=PC&downlink=10&effective_type=4g&round_trip_time=0&webid=7427765608665040399&uifid=63dd93172fb5fdaa8078f33ae0ba1106c8e3f1f870eecbc4b54b497d452c3517e3b7a5ab3d4ec186d7be006b7a6d53846c6734c86b69acdaa2eb531c0fa92958a8cb940dd76c55017b279b6778ad806977b04a00d235639ba1505bb8c942fc1f1ffdb6b5bed6e26fc7db5b9400d1d9d20450dca0257efb46047e349b49ef1ed79c5ceaff02e8b12e4efffc9114f06bb77651d820b35a2638844fee7a6ac6db85&msToken=ahDrxe9ibTXPfbP25qOkt6QDX0xXfaehFEV-e5XofFV3eQQBqtpPVa_SYmy-Gdi2wSRdz4JN_U1I_fghOF2VNxh_B0A1MlFqT0vsgUqOvv5WRg-W_yIuqJrYt_e-76afo7T6nlzQIiSNZF04A82HjbCnogmaut96WjCkWSJivKn1TdYy04jsXw%3D%3D , + , dhzx , ====> , device_platform=webapp&aid=6383&channel=channel_pc_web&item_id=7429636428608425267&comment_id=7431107242646258473&cut_version=1&cursor=0&count=3&item_type=0&update_version_code=170400&pc_client_type=1&pc_libra_divert=Mac&version_code=170400&version_name=17.4.0&cookie_enabled=true&screen_width=1280&screen_height=800&browser_language=zh-CN&browser_platform=MacIntel&browser_name=Chrome&browser_version=131.0.0.0&browser_online=true&engine_name=Blink&engine_version=131.0.0.0&os_name=Mac+OS&os_version=10.15.7&cpu_core_num=8&device_memory=8&platform=PC&downlink=10&effective_type=4g&round_trip_time=0&webid=7427765608665040399&uifid=63dd93172fb5fdaa8078f33ae0ba1106c8e3f1f870eecbc4b54b497d452c3517e3b7a5ab3d4ec186d7be006b7a6d53846c6734c86b69acdaa2eb531c0fa92958a8cb940dd76c55017b279b6778ad806977b04a00d235639ba1505bb8c942fc1f1ffdb6b5bed6e26fc7db5b9400d1d9d20450dca0257efb46047e349b49ef1ed79c5ceaff02e8b12e4efffc9114f06bb77651d820b35a2638844fee7a6ac6db85&msToken=ahDrxe9ibTXPfbP25qOkt6QDX0xXfaehFEV-e5XofFV3eQQBqtpPVa_SYmy-Gdi2wSRdz4JN_U1I_fghOF2VNxh_B0A1MlFqT0vsgUqOvv5WRg-W_yIuqJrYt_e-76afo7T6nlzQIiSNZF04A82HjbCnogmaut96WjCkWSJivKn1TdYy04jsXw%3D%3Ddhzx,后续就进入进行两次某种算法加密。
经过测试发现,这个是标准的 sm3 算法,即:sm3(sm3(搜索参数+dhzx))。当然了,你可以扣 sum 函数,也可以盘算出值。
日记继续往下翻,发现盐值 dhzx 也进行两次 sm3 算法加密,即:sm3(sm3(dhzx))。
日记继续发下翻,发现 user-agent 进入我们的视野,同时发现一个长度为3的数组,即:,经过测试,Windows 系统下,这个数组为 ,都是固定的。
https://i-blog.csdnimg.cn/img_convert/9574bbeeb198c6f224db60615fdcb28f.png
后续就进入了一个循环盘算,一开始我也不清晰它是什么算法,但是它有一个特点,就是先初始化一个从 255 - 0 的数组,然后又是一个 0 - 255 的循环,而且每次还进行雷同的运算,如下:
https://i-blog.csdnimg.cn/img_convert/de55ee910835e42d18c1abde56568820.png
看它的运算规则,很像 rc4 算法,如下:
function rc4(key, str) {
    var s = [], i = 0, j = 0, x, res = '';
    for (var k = 0; k < 256; k++) {
      s = k;
    }
    for (k = 0; k < 256; k++) {
      j = (j + s + key.charCodeAt(k % key.length)) % 256;
      x = s;
      s = s;
      s = x;
    }
    for (var k = 0; k < str.length; k++) {
      i = (i + 1) % 256;
      j = (j + s) % 256;
      x = s;
      s = s;
      s = x;
      res += String.fromCharCode(str.charCodeAt(k) ^ s[(s + s) % 256]);
    }
    return res;
}
所以,我们可以大胆猜测,它就是 rc4 算法,只不外它的 key 是一个数组,如下:
var key = ;
经过代码验证,它不是标准的 rc4 算法,而是 rc4 算法的变种,即魔改的 rc4 算法。
遇到类似的运算加密,只管不要根据日记去还原代码,很贫苦的,亲身经历过的。。。,而是只管能找到类似结构的标准算法上去改造,如许对于插桩纯算,很节省大量时间。
所以根据日记,很容易就得到魔改后的 rc4 算法,如下:
function rc4_magic_encrypt(plaintext, key) {
var s = [];
for (var i = 0; i < 256; i++) {
    s = 255 - i;
}
var j = 0;
for (var i = 0; i < 256; i++) {
    j = (j * s + j + key.charCodeAt(i % key.length)) % 256;
    var temp = s;
    s = s;
    s = temp;
}

var i = 0;
var j = 0;
var cipher = [];
for (var k = 0; k < plaintext.length; k++) {
    i = (i + 1) % 256;
    j = (j + s) % 256;
    var plaintext_charCodeAt = plaintext.charCodeAt(k);
    var temp = s;
    var t = (temp + s) % 256;
    s = s;
    s = temp;
    cipher.push(String.fromCharCode(plaintext_charCodeAt ^ s));
}
return cipher.join("");
}
https://i-blog.csdnimg.cn/img_convert/43f23daa7011736f1833bddb7f565626.png
继续往下翻,可以看到,上述魔改后的 rc4 算法加密后,再进行三个字符一组进行循环,而且还看到:a << 16 、a << 8 等关键运算。此时,我暗自窃喜,因为这种运算,很容易想到 base64 算法。标准如下:
function standardBase64Encode(inputString) {
    // 标准Base64字符集
    var base64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

    // 处理一个3字节组的函数,将其转换为4个Base64字符
    function processGroup(a, b, c) {
      // 组合三个字节为一个24位整数
      var combined = (a << 16) | (b << 8) | c;

      // 从24位整数中提取4个6位部分
      var part1 = (combined >> 18) & 63; // 提取最高的6位
      var part2 = (combined >> 12) & 63; // 提取次高的6位
      var part3 = (combined >> 6) & 63;// 提取次低的6位
      var part4 = combined & 63;         // 提取最低的6位

      // 将每部分映射到标准Base64字符集
      return [
            base64Chars.charAt(part1),
            base64Chars.charAt(part2),
            base64Chars.charAt(part3),
            base64Chars.charAt(part4)
      ];
    }

    // 将输入字符串转为字节数组
    var inputArray = [];
    for (var i = 0; i < inputString.length; i++) {
      inputArray.push(inputString.charCodeAt(i));
    }

    var encodedStr = ""; // 存储最终编码结果
    for (var i = 0; i < inputArray.length; i += 3) {
      // 每次处理三个字节
      var group = inputArray.slice(i, i + 3); // 获取3字节组
      var paddedGroup = group.slice(0); // 复制数组
      while (paddedGroup.length < 3) {
            // 不足3字节时用0填充
            paddedGroup.push(0);
      }
      // 处理组并将结果拼接到最终字符串
      var encodedGroup = processGroup(paddedGroup, paddedGroup, paddedGroup);
      encodedStr += encodedGroup.join(""); // 将编码的字符数组拼接为字符串
    }

    // 处理末尾填充(如果有的话)
    var paddingLength = (3 - inputArray.length % 3) % 3;
    if (paddingLength > 0) {
      encodedStr = encodedStr.slice(0, -paddingLength) + Array(paddingLength + 1).join("=");
    }

    return encodedStr; // 返回编码后的字符串
}

// 使用示例:
var encoded = standardBase64Encode("Hello, World!");
console.log(encoded); // 输出:SGVsbG8sIFdvcmxkIQ==
经过验证,它又不是标准的 base64 算法,而是魔改后的 base64 算法。此时,我内心是瓦解的。。
没办法,只能再继续分析日记,在原有的 base64 算法基础上,再进行魔改。经过一番努力,终于找到了规律,并还原。
上述有了 rc4 魔改算法的履历,这个我就不贴出来了,毕竟我们学习插桩本领的。不难的,多尝试,努力提拔自己。
继续往下翻日记,发现魔改 base64 加密后的结果,又进行了 sm3 加密。日记如下:
https://i-blog.csdnimg.cn/img_convert/28fe828209bc3372de4bdd5bbf5c7175.png
继续往下翻日记,很难找到规律了。此时,我内心又是瓦解的。
当时,我想着既然正向找不到规律,那我就逆向分析,看看能不能找到规律。于是,我就找到天生 a_bogus 的地方,进行逆向分析。
全局搜索日记中的 a_bogus,找到天生 a_bogus 的地方,如下:
https://i-blog.csdnimg.cn/img_convert/648b27fc84c101cec48f890f866b9495.png
从下往上翻日记,发现 a_bogus 是从长度为 134 位数组得到的,如下:
https://i-blog.csdnimg.cn/img_convert/d130e6f2ee423567209b6c9f965d0ea8.png
https://i-blog.csdnimg.cn/img_convert/6a6532be85a57f2a3a821c1a5609570c.png
当然了,差别欣赏器,环境也不一样,加密参数也不一样,所以,你的欣赏器未必是 134 位数组。这是为啥有的人得到结果是:184、188、192 长度 a_bogus 的缘故起因。
经过日记分析得到,a_bogus 是从长度为 134 位数组通过魔改的 rc4 算法得到的。
那问题又来了。这个长度为 134 位数组又是从哪里来的呢?
134位数组分析,和相干js文件,会分享到知识星球当中,需要的小伙伴自取,仅供学习交换。
至此,a_bogus 的天生逻辑就分析完了。
参数验证

写个小例子,验证下天生的参数是否正确,如下:
https://i-blog.csdnimg.cn/img_convert/1c63bfc3135eab334a4558a420aa9c60.png
搞定!!
如果另有什么疑问,欢迎留言讨论!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: a_bogus、msToken、fp、verifyFp | bdms_1.0.1.19 签名算法分析记录