猿人学js逆向比赛第一届第十四题

发布于:2025-06-29 ⋅ 阅读:(15) ⋅ 点赞:(0)

一、预处理代码

利用ast将代码还原,还原后可以看到这里用有一些eval检测点,这里先进行手动删除,

在这里插入图片描述

替换到网页中的代码后发现陷入到了死循环,这里仍然进行手动删除

在这里插入图片描述

二、分析请求

在这里插入图片描述

通过定位堆栈请求,可以看到先调用了sp函数,然后进行在请求的页面,那么下面分析sp函数

在这里插入图片描述

这里可以看到是先设置了一个mz,然后又发了一个请求,并将请求到的内容执行了一下,那么这里先看一下得到的代码是什么。

在这里插入图片描述

这里可以看到是一个混淆过的代码,那么继续利用ast尝试还原看一下,还原后经过分析无效代码,然后手动删除,最终得到了下面的结果,那么实际上这里就是请求一下,然后获取v14v142这两个参数并赋值给了window。

在这里插入图片描述

在这里插入图片描述

继续分析sp函数,这里可以看到经过一系列的计算最终赋值给了设置了cookie中的’m’参数,至此sp函数结束,然后这里看了一下请求中并没有什么别的参数了。

三、获取v14与v142

在上面分析sp函数中得到,需要先设置cookie 中的mz参数,然后再去请求。这里看到应该是取了浏览器环境中的一系列指纹,然后得到了z这个指纹数组,然后base64编码了一下,就设置给了mz。

在这里插入图片描述

手动将z从浏览器里面取出来,然后设置给编码一下设置给cookie,如下所示:

在这里插入图片描述

得到了混淆代码后,发现无法直接用正则将需要的值取出来。在这里插入图片描述

因为刚才还原了这个代码,简单看了一下没有用到什么别的环境,所以这里直接简单补了一下,顺利得到需要的参数。补的环境如下:

window = global;
setInterval=function(){};
function get_config(){
    return {
        'v14':window.v14,
        'v142':window.v142,
    }
}

在这里插入图片描述

四、获取cookie中的m

继续扣取cookie中m参数。将a,b这种赋值的代码直接拿下来。同时这有获取z的toString()顺手直接从浏览器中取下来然后修改代码。

在这里插入图片描述

遇到E函数的调用,这里就讲这个函数扣下来,同时跟进去,可以看到关键字jsencrypt这里就可以合理怀疑RSA加密算法,这里先从浏览器里面取一下,仍然先尝试一下标准算法,如果不对后面回过头来在处理这个。

  function E(K) {
    function d(h, b) {
      var D = b;
      var I = _n("jsencrypt");
      var u = new I();
      var Q = u["encode"](h, D);

      return Q;
    }
    result = d(K, K);
    return result;
  }

=====》》》

window = global;
const JSEncrypt = require('jsencrypt')
rsa_key ="-----BEGIN PUBLIC KEY-----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDq04c6My441Gj0UFKgrqUhAUg+kQZeUeWSPlAU9fr4HBPDldAeqzx1UR92KJHuQh/zs1HOamE2dgX9z/2oXcJaqoRIA/FXysx+z2YlJkSk8XQLcQ8EBOkp//MZrixam7lCYpNOjadQBb2Ot0U/Ky+jF2p+Ie8gSZ7/u+Wnr5grywIDAQAB-----END PUBLIC KEY-----"

function Encrypt(Z, a){
    rsa = new JSEncrypt()
    rsa["setPublicKey"](rsa_key)
     var X = a ? a + "|" + Z : Z;
    return encodeURIComponent(rsa["encrypt"](X));
}
function E(K) {
    result = Encrypt(K, K);
    return result;
}
console.log(E(1751089504000))

下面继续分析,调用m5函数得到的了32位的值,合理怀疑md5,然而经过对比标准算法,发现不一样,应该是魔改了,那么这里将m5函数取拿下来。下面一步步的跟然后是调用了gee函数。在抠这个函数的时候,encrypt1函数没有返回值,这里发现疑似一个对称算法,于是,这里尝试与本地的标准算法做对比。(其实encrypt应该是rsa的算法)

在这里插入图片描述

可以看到这里是一样的。那么这里将这部分代码修改为已知的算法。

在这里插入图片描述

于是这个函数就成了:

cu["encrypt1"] = function (ci, cP, cm) {
  var srcs = CryptoJS.enc.Utf8.parse(ci);
  var key = CryptoJS.enc.Utf8.parse(cP);
  var iv = CryptoJS.enc.Utf8.parse("0000000000000000");
  var cn = CryptoJS.AES.encrypt(srcs, key, {
          iv: iv,
          mode: CryptoJS.mode.CBC,
          padding: CryptoJS.pad.Pkcs7
      });
  var cR = cn["ciphertext"]["words"];
  var cg = cn["ciphertext"]["sigBytes"];
  var cN = [];
  for (var cX = 0; cX < cg; cX++) {
    var cB = cR[cX >>> 2] >>> 24 - cX % 4 * 8 & 255;
    cN["push"](cB);
  }
  return cN;
};

经过比较得到和浏览器一样的结果。

在这里插入图片描述

五、构建请求

经过上面的分析得到:

在这里插入图片描述

这里首先怀疑那个构没有比较的rsa部分。将那部分代码替换回原本的网页中的webpack打包的代码,并补上navigator部分的环境后,再次请求。可以得到请求了

在这里插入图片描述

当时当请求后面页数的时候可以看到是被拦截到的,这里凭借经验判断,应该是有调用次数的限制。于是这里尝试起一个node api接口测试一下。

在这里插入图片描述

当起了一个接口后再起发请求是可以获取剩下的数据的。

在这里插入图片描述

六、结束语

通过node api 的方式确实可以调用这个,但是超过5次,我想再次调用的时候就要重启服务,所以这里补充一种调用方式,这里经过测试后得到实际上这里要的也是E函数的调用次数,也是每次执行就循环到响应的次数即可。
在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到