你追踪一个目标网站,千辛万苦抓到接口,看着请求参数里一长串加密字段,深吸一口气,切到 Sources 面板。

然后你看到了这个:

var _0x4b8c = ['\x66\x69\x72\x73\x74''\x73\x65\x63\x6f\x6e\x64''\x74\x68\x69\x72\x64'];
function _0x5a3f(_0x12e4, _0x3f2a) {
 return _0x4b8c[_0x12e4 - 0x1];
}

你心想:这特么是什么鬼。

别急。搞逆向的,谁没被混淆恶心过。关键是,你得先知道自己面对的是哪种。


一、压缩混淆 — 这不算混淆

给新手一句话:不是所有的"乱"都是混淆。

很多网站根本没用混淆,只是用 UglifyJS 或 Terser 压缩了一下:

  • 变量名变成 a、b、c、d
  • 空格换行全部删掉
  • 文件挤成一行

怎么认:点一下格式化({}按钮),逻辑清清楚楚,变量名虽然短但控制流完整。

怎么打:格式化,5秒完事。

这玩意儿叫压缩,不叫混淆。但很多新手就倒在这一步——"啊代码好难看不懂"。废话,你把所有换行删了当然看不懂。


二、字符串加密 — 真正的混淆开始了

所有字符串被抽出来塞进一个数组,用下标访问。

原版:

var url = "https://api.example.com/login";

混淆后:

var _0xabc = ["https://api.example.com/login""POST""application/json"];
var url = _0xabc[0];

看着很憨对吧?但当这个数组有几百个元素,元素之间还互相引用,每个字符串被拆成字符再拼接——哦豁。

怎么认:代码开头一大串数组声明,里面全是十六进制字符串。这是 Obfuscator.io 的招牌动作。

怎么打:

  • 方案 A:AST 还原,找出定义数组的地方,把下标引用替换成实际值
  • 方案 B:在 Console 里执行一下,让解密函数自己跑,你直接看结果

三、控制流平坦化 — 能让脑子短路

正常的 if/else,一秒看懂逻辑。

平坦化之后,它变成了一只 switch 怪兽:

var state = 1;
while (true) {
 switch (state) {
 case 1if (a > 10) state = 2else state = 3break;
 case 2doA(); state = 4break;
 case 3doB(); state = 4break;
 case 4break loop;
 }
}

每一行代码都像一粒珠子,被拆散了扔进一个罐子里,然后用一根叫 state 的线一颗颗串回去。

你摇摇罐子,珠子哗啦啦响——但你看不出原来是什么图案。

怎么认:一个几百行甚至几千行的 while(true) + switch,里面全是 state 赋值和 break。

怎么打:

  • 方案 A:硬看,把每个 state 的映射关系画出来(适合几百行的规模)
  • 方案 B:写个 AST 脚本批量还原(@babel/core + @babel/types 就能做)
  • 方案 C:偷懒——不还原,直接在关键位置打断点跟值

控制流平坦化解起来最费脑。但好消息是——大部分网站只对核心加密函数用这招,不是全文件都套。


四、反调试 — 纯搞心态的

不复杂,但就是烦。

最常见的:无限 debugger。

function endless() {
 debugger;
 requestAnimationFrame(endless);
}

打开 DevTools,它就像贴着脸皮的蚊子,不停在你面前飞。按一下 Resume,马上又停住。按一下,又停住。

我一个朋友当年第一次遇到,以为电脑坏了,重启了三次。

还有更阴的:

  • 检测 DevTools 是否浮动(浮动窗口改变视口大小)
  • 检测 console 是否被打开
  • 用 toString 检测原生函数有没有被你劫持

怎么打:Deactivate breakpoints(那个暂停符带斜杠的按钮),一秒清静。

如果它检测 DevTools 本身,那就用 Remote Debugging 绕过。

反调试不是真正的混淆,它是混淆的保镖。帮你把烦它的人挡在外面。


五、虚拟机保护 — 代码穿上防弹衣

这是最高级别的 JS 混淆,没有之一。

原理很简单粗暴:把你的 JS 代码编译成自定义字节码,然后写一个解释器去跑这个字节码。

原始代码里的所有逻辑,在"混淆后"的文件里根本看不见。你看到的只有:

  • 一个巨大的数字数组(字节码)
  • 一个几千行的解释器函数(CPU)
  • 解释器逐条读取数组并执行

这就像你自己发明了一台手机 CPU 的指令集,然后用软件模拟出这颗 CPU,再让程序跑在上面。

代码的"意思"被锁在了这颗虚拟 CPU 里面。你拿到的是——一颗芯片的数据手册和一个看不懂的二进制文件。

怎么认:混淆后的代码结构特殊——"一堆看起来像数据的数组 + 一个很长的执行函数"。

典型代表:JScrambler 的 VM 级别保护。

怎么打:

  • 不要正面硬还原,人力成本打不住
  • 方案一:Hook 解释器,在它读取和执行每条指令时截获中间结果
  • 方案二:找解释器主循环,在指令读取处下断,观察行为
  • 方案三:放弃还原,走运行时——直接跑完拿结果

六、混合攻防 — 现实中的网站什么样

以上六种技术,在同一个网站里通常是多选,不是单选

瑞数的 JS 保护: 字符串加密 + 动态代码生成 + 定期自更新。你拆好的逻辑,过几天刷新一下,又变了。它的混淆是动态的,每次加载可能生成不同结构的脏代码。

极验的验证码 JS: 控制流平坦化 + 反调试 + 设备指纹采集串在一起。你解了加密参数没用的,它的风控在校验你的浏览器环境。

淘宝/京东的反爬: 没那么花哨的混淆,但串联了请求校验、时序校验、行为检测。JS 只是其中一环。

而且越往后你会发现,混淆已经不是"让代码变难看"了——它是安全体系的第一道门。它背后站着风控、校验、指纹、限流。你就算把这个门砸开了,里面还有其它的门。


遇到混淆别慌。先翻两眼,判断对面是第几级的选手。

木棍就别掏枪,激光炮就别拿拳头怼。

搞逆向这么多年,最大的教训不是技术不够硬,而是方向选错了,越努力越白干