乐于分享
好东西不私藏

JS逆向学习 | 01 js 混淆 源码乱码

JS逆向学习 | 01 js 混淆 源码乱码

字数 947,阅读大约需 5 分钟

前言

最近很多用Codex + mcp逆向JS的文章。

我个人而言,JS端逆向没有安卓端熟练,正好利用大模型把这一块补上。本文是我的解题思路。

我个人用的模型还是以免费居多。以后也尽量争取用免费模型来写文章做题。

链接:https://match.yuanrenxue.cn/match/1

我用TRAE CN + GLM 4.7调用mcp逆向,因为遇到混淆,给大模型卡住了,最后因为上下文太多停止继续运行了。

只能人工充当AI的润滑剂了。

bypass 反调试

5a928b0986445ea2acd4d98d3a2cd6ae.png

右键,Never pause here

9a32839a43f6b4fbaf34994ba4c987e3.png
b5bafe74dd3f21049690955226105d1b.png

hook console.log

(function() {
  // 保存原始方法
  const originalLog = console.log;
  console.log = function(...args) {
    // 可选:不执行原日志,注释下面这行
    // return originalLog.apply(this, args);
  };
})();

解决打印永不言弃

e1566fbea66c836bae0e4d2c015153f1.png

定位到代码后,把代码复制给大模型,我直接给豆包的,让她帮我过。

// 1. 保护原生 toString,让检测永远通过
const nativeToString = Function.prototype.toString;
Object.defineProperty(Function.prototype, 'toString', {
    value: function() {
        // 被检测时返回原生代码字符串
        if (this === eval || this === setInterval) {
            return `function ${this.name}() { [native code] }`;
        }
        return nativeToString.call(this);
    },
    configurable: true,
    writable: true
});

// 2. Hook console.error → 直接屏蔽所有报错
const originalError = console.error;
console.error = function(...args) {
    // 过滤所有报错输出
    return;
};

// 3. Hook debugger 关键字(防无限 debugger)
(() => {
    const _constructor = window.constructor;
    window.constructor = function() {
        return function(){};
    };
    window.constructor.constructor = _constructor;
})();

// 4. Hook setInterval 防止自身被检测
window.setInterval = (() => {
    const original = window.setInterval;
    return function(callback, time) {
        // 替换掉恶意回调,让它空跑
        const safeCallback = function() {};
        return original(safeCallback, time);
    };
})();

然后

f9650d2c4c6410b9e063ef263de332df.png

分析

链接

54462aa11ea0bdbe8862a559aa0f08ae.png

主要参数值就是m
下XHR断点

9b65c0c60796cb485cdcb6a4a42accab.png

分析堆栈

9ad734aff9fb5f46be5f0ffa9c9a4625.png

m: window.match1

a1d81f9726bc716eeb45b2ed29a0a868.png

搜索 match1

c89ae187760b6356847858a3be7d301b.png

此处下断点

369d840609da2bdb55e7cce266acf858.png

进入了VM当中

3573aa55a070c5a84a820b0af0b686d3.png

其中的十六进制转义,console打印

7e78006a7df4d8f46c6255fffe824be8.png

甩给豆包

6e4100fd25b1e5f1f05f787b9980655d.png

可以知道m的组成

93b04d263163bc84631c9e60af60feaa.png
var encryptStr = oo0O0(calcTime.toString()) + window.f;

调试中,可知前者返回是空,主要是后面的window[‘f’],它是怎么来的

f0ce6127892e5c220f11d6a1fb573d2e.png

结果

aceef2e7cec2ee547202a17bd2eb03ec.png

JS格式化:https://www.toolhelper.cn/Format/JavaScript

58af0787848780a7dc1f65aa57726c74.png

在其中发现window[‘f’]

5bf10bf6103bd30d965fbafff7e86a06.png

传入的参数

var calcTime = now + (16798545 - 72936737 + 156138192);

在代码前面补上

var window = window || {};

最后打印

console.log(window.f)

结果

5b98cb36660dfb063eebb370f8769dac.png

生成的和m的请求中的完全一样

75f0a66f793d8dbb28960ec61df857fb.png

验证

c47932ed0693629e480f402f31c1873e.png

成功获取结果

51682f9a8d754c799519ed52ba308477.png
编写一个符合Python最佳编程实践的脚本,该脚本需包含一个功能函数,用于调用位于项目根目录下的test1.js文件。函数应通过合适的Python与JavaScript交互方式(如使用subprocess模块)执行test1.js,并捕获其执行过程中通过console.log输出的所有内容。实现时需确保:
1. 函数设计遵循Python PEP 8编码规范,包含清晰的文档字符串说明功能、参数和返回值
2. 实现错误处理机制,能够捕获并妥善处理JavaScript执行失败、文件不存在等异常情况
3. 确保准确捕获test1.js中所有console.log输出内容,排除其他无关输出
4. 将捕获的console.log内容作为函数的返回值返回,返回类型应为字符串

然后修改Python脚本

修改当前脚本,请求
https://match.yuanrenxue.cn/api/question/1?page=1&pageSize=10&kw=&m=8aa8e425e37049f2eb6a07419353fb82%E4%B8%A81774892661

其中page为1-5
在请求page=5的时候,修改user-agent为yuanrenxue
参数中的m是generate_match1()的返回值
添加Cookie:登录后自己获取

数据包返回的结果为
{"data": [534164, 836185, 194947, 211557, 592499, 563679, 802679, 115123, 819763, 853234]}
将所有返回的结果相加
563348c47dd5ae1a729ac8a2d3721f77.png

参考资料