# 免责声明:本篇文章仅用来学习交流,请勿用于商业用途,如因违反规定产生任何法律纠纷,本人概不负责。假如本文影响到官方任何利益,请联系我告知,我会在第一时间将文章删除,感谢~

  1. # 前言

    最近处于摆烂状态😢,好久没水文章了,今天水一篇头条的 sign 算法。早就想刚一下,拖了几个月了,要不是兔佬前段时间给喂嘴里,我还得再拖下去。。。

    关于 sign 算法的文章,网上有很多,我感觉吃透两篇就够了,十一姐的 suanshu 算法分析逆向简史的某量算法分析,我这篇文章属于水文,当个故事看看就行了。

  2. # 接口分析

    • # 开发者工具找到接口,今天要分析的参数 _signature 长这样

    • # 直接追调用栈找到入口位置

    • # 跟进函数,进入主要算法逻辑的 acrawler.js 文件,代码充满了 三元表达式if 条件判断

  3. # 插桩怼日志

    • # 在下图循环开始的两个位置插入 log 断点
      "O:", O, "j:", j, JSON.stringify(S, function(key,value){if(value == window){return undefined}return value})

    • # 然后放开断点,跑就完事,等再次断到 r.call(n,o) 的位置,将控制台打印的 log 拷到本地分析;我这里没有清掉缓存,所以有大概 3w 多行的日志,清掉缓存应该有 1.5w 左右

    • # 在分析之前,先补充一下可能用到的知识点
      // 将指定的 utf-16 数字转为字符串
      String.fromCharCode(65)  //  返回 A
      // 也可以传多个参数
      String.fromCharCode(65, 66, 67, 68) // 返回 ABCD
      // 返回指定索引字符对应的 utf-16 的数字,索引默认为 0
      "ABCD".charCodeAt(1)  // 返回 66
      // 将字符串 10 转为整数 10,然后再把整数 10 转为 16 进制
      parseInt("10").toString(16) // 返回 a
      // 第二个参数视为第一个参数的进制数,转为 10 进制
      parseInt("10", 16)	// 16
      名称 / 优先级↓运算符
      乘法,除法,求余*/%
      加法,减法+-
      左移,右移,无符号右移<<>>>>>
      大于,大于等于,小于,小于等于>>=<<=
      相等,不等,全等,不全等==!====!==
      &
      异或^
      |
      逻辑与&&
      逻辑或||
      三元表达式... ? ... : ...
  4. # 部分算法刨析

    • # 如果你看了推荐的文章,你应该知道 signature 由 9 部分构成,每部分都是由一些神奇的算法一个一个字符生成的

    • # 第一部分由服务器返回的数据生成,可以写死,直接从第二部分开始分析直接复制 5 个字符搜一下

    • # 然后采取逆向思维对每个字符算法过程进行分析,下面是我分析的部分笔记

    • # 第 2-7 部分逻辑差不多,跟 2-3 个算法过程,就能大概找到规律了,主要是正确还原对应的 hash 算法,找到每一步的计算过程,比如上面笔记 q 对应的下图日志

    • # 每步计算过程进行盲猜确实费时间,所以可以写个脚本辅助还原,还有些 stringnumber 转换的,就需要你自己测试了。
      function calcType(num1, num2, ret){
          let symbols = [">>", ">>>", "<<", "*", "/", "|", "&", "^", "%", "+", "-"]
          for(var i in symbols){
              let lineCode = String(num1) + symbols[i] + String(num2);
              try{
                  var calcRet = eval(lineCode)
              }catch{
                  console.log("异常:", lineCode)
                  continue;
              }
              if(ret){
                  if (calcRet == ret){
                      console.log("表达式:", lineCode, "结果:", ret)
                  }
              }else{
                  console.log(">>>", lineCode, eval(lineCode))
              }
          }
      }

      可以传 2 个参,打印所有结果,也可以传 3 个参只打印符合条件的结果

    • #8 部分是由 cookie scid 计算生成的,我感觉这部分逻辑比其他部分都要复杂,需要耐心,大体步骤是先生成长的乱码字串,再生成索引取值。

    • #9 部分比较简单,由前面生成 8 部分通过 hash 生成 2 位,生成字串的逻辑按之前的办法随便跟一下就得到了,为什么我说随便,因为相比第 8 部分,这太简单了

  5. # 总结

    • # 重点还是在于坐的住,然后细心一点,边记录边还原
    • # 文中提到的 hash 算法,都是逆向简史那篇文章提到的 SDBMhash 算法,但都有魔改,且有 3 个不同版本
    • # 运算符一定要还原正确,有时候 >>>>>+|^ 结果一样,但可能在其他地方用就不一样,我踩了个大坑
    • # 流氓兔 说第 8 部分是 AES算法 ,我也不是 Q佬 ,可以肉眼解密,有时间在研究。(小白佬纠正了,算法不是 AES ,是 TEA 算法)
    • # 文章水完了,熬不住了, js逆向 太费屁股了
更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

渣渣文 微信支付

微信支付

渣渣文 支付宝

支付宝