乐于分享
好东西不私藏

猿人学修仙之旅——js混淆,源码乱码

猿人学修仙之旅——js混淆,源码乱码

js混淆——源码乱码之m参数

前言

本题使用了一定的AI辅助,在AI当道的世俗下,快来和我一起在猿人学修仙吧!

网站链接

https://match.yuanrenxue.cn/

抓包

进来之后会遇到第一个敌人,setInterval!

直接never pause here

也是直接看到了接口

找参数,反混淆

如图并且如题所示,本题的加密就是m

那么好办了,大脑飞速运转,如果我全局搜索m,那叫m的也太多了,并且不一定能找到。聪明的你想到这题是乱码题。好啊好啊,让我看看乱在哪里。如图,咱们看到了花指令,十六进制等等。诶!这个eval里的怎么这么长?机智的你很快想到,密文不会就藏在这里吧。

可是这个也太恶心了,这不就是被多重转义的巨型字符串吗!但是这可难不倒咱们的大佬,机智的你很快就又想到了,诶?!!!AST!!!

const parse = require("@babel/parser").parse;const generate = require("@babel/generator").default;const traverse = require("@babel/traverse").default;const types = require("@babel/types");const fs = require('fs');var code = 'window[\'\\x75\\x72\\x6c\'] = \'\\x2f\\x61\\x70\\x69\\x2f\' + \'\\x6d\\x61\\x74\\x63\\x68\' + \'\\x2f\\x31\', request = function () {\n    var _0x2268f9 = Date[\'\\x70\\x61\\x72\\x73\\x65\'](new Date()) + (16798545 + -72936737 + 156138192), 'let js_code = codelet ast = parse(js_code);//通用的十六进制转十进制插件const transform_literal = {    NumericLiteral({node}) {        // 检查 node.extra 是否存在        // 并且使用正则 /^0[obx]/i 检查原始文本 (raw) 是否以 0x, 0b 或 0o 开头        if (node.extra && /^0[obx]/i.test(node.extra.raw)) {            // 当你把 extra 删掉,Babel 生成器由于找不到“原始样子”,就会被迫按照 node.value 输出最干净的十进制。            node.extra = undefined;            // console.log(node.value)        }    },    StringLiteral({node}) {        // 检查 node.extra 是否存在        // 并使用正则 /\\[ux]/gi 检查原始文本中是否有反斜杠加 u (Unicode) 或 x (Hex)        if (node.extra && /\\[ux]/gi.test(node.extra.raw)) {            node.extra = undefined;            // console.log(node.value)        }    },}traverse(ast, transform_literal)//十六进制转十进制,本插件为蔡老板公众号提供//https://mp.weixin.qq.com/s/PGn2Wqz4S5fjHPW6fLX0Wgconst visitor = {  // 识别形如 "a" + "b" 的表达式  BinaryExpression(path) {    const { left, operator, right } = path.node;    // 1. 只处理加法运算符    if (operator != '+') return;    // 2. 判断左右两边是否都是字符串字面量    // 注意:如果是 'a' + 'b' + 'c',AST 结构是 (('a'+'b') + 'c')    // 所以这个插件会通过递归或多次遍历把它们全合并    if (types.isStringLiteral(left) && types.isStringLiteral(right)) {      const newValue = left.value + right.value;      // 3. 用新的字符串节点替换掉原来的加法节点      path.replaceWith(types.stringLiteral(newValue));      // 4. 【关键】由于合并后可能产生新的合并机会(比如嵌套加法),      // 我们跳回父节点重新检查      path.parentPath.requeue();    }  }};traverse(ast, visitor);console.log("正在生成最终代码...");const {code: output} = generate(ast, {    jsescOption: {minimal: true}, // 保证中文不乱码    retainLines: false,            // 允许重新格式化});fs.writeFileSync('output.js', output);console.log("反混淆完成!请查看 output.js");

那么具体AST的写法我就不做赘述了,大家可以自行查找或者蔡老板公众号。本处常量折叠是AI写的,还是那句话,拥抱AI,提高速度。

反混淆效果图展示

分析逻辑

机智的你很快就找到了m参数的生成逻辑,首先看_0x2268f9,是个修改后的时间戳Date.parse(new Date()) + 100000000,然后咱们再去看那个_0x57feae,它是由加密函数oo0O0和f参数构成的。那么开始扣代码吧。

逻辑说明

oo0O0内包含了个类似于ob混淆的函数

oo0O0函数最后返回了个”(空),难道这个函数什么都没干吗,其实不是,看第三点

最后在返回前进行了eval(),其实是将window[‘b’]给base64解码了,至于window[‘b’]怎么来的,自然是window.a转换过来的。不过不用担心,这是个定值,断点打到位,copy(atob(window[‘b’]))拿到加密算法。此处还需要注意,最后将mwqqppz换成了mw

可以看到f的由来了,那么m参数就算是大功告成了,接下来完善请求逻辑,咱们进行模拟请求

模拟请求

搞定

记得改UA

总结

猿人学的题目越来越好玩,越来越刁钻了,真是让人意想不到欲罢不能。

感谢蔡老板公众号强而有力的ast插件。

由于爬虫逆向反混淆技术博大精深,本人水平有限,文中若有疏漏或理解偏差之处,恳请各位前辈大佬不吝赐教,我们评论区见。

最后,愿我们在高处相见,亦或在深处重逢

本站文章均为手工撰写未经允许谢绝转载:夜雨聆风 » 猿人学修仙之旅——js混淆,源码乱码

猜你喜欢

  • 暂无文章