☰
JS 混淆与反调试绕过实战
2026/9/30 8:39:30 网站建设 项目流程

JS 混淆与反调试绕过实战

前言

在上一篇《JS 逆向入门:读懂前端加密参数,突破接口签名校验》中,我们学习了定位 sign 签名函数、提取加密算法。但在真实逆向场景,很多网站不会把明文 JS 直接给到你。他们会使用 JS 混淆压缩、反调试代码,只要按下 F12 打开开发者工具,页面立刻触发无限 debugger,代码全是乱码,变量名全是_0xabc123,普通断点调试根本无法开展。

JS 混淆用来降低代码可读性,反调试用来阻止调试器动态跟踪代码执行。两者结合,是前端最常用的防护手段。本文结合实战,讲解各类混淆类型、反调试原理,以及对应的绕过方案,适合做接口安全测试、JS 逆向学习。

免责声明:本文内容仅用于授权环境安全测试、网络安全学习。严禁对未授权网站、H5、小程序进行逆向、反调试、批量接口请求,违规操作触犯法律法规,请遵守网络安全相关规定。

0x01 JS 混淆的常见类型与特征

JS 混淆本质:不改变代码原有业务逻辑,对变量、字符串、执行流程进行变形,增加阅读难度。常见分为 5 类,很多网站会叠加多种混淆一起使用。

1.1 变量 / 标识符混淆(最简单)

将有业务含义的变量、函数名,替换为无意义十六进制名称。
原始代码:

function getSign(params){ return md5(params); }

混淆后:

function _0x34af(_0x98bc){ return _0x56de(_0x98bc); }

特点:只是改名,代码执行流程不变。
反混淆:浏览器 Source 面板点击{}格式化代码,手动重命名变量,适合新手练习。

1.2 字符串数组混淆(高频)

把所有字符串统一存入数组,代码中通过数组下标读取字符串,字符串本身还会做 Base64、Unicode、十六进制编码,全局搜索关键词(sign、md5)直接失效。
示例:

const _0x44=['md5','timestamp','sign']; console[_0x44[0]];

处理思路:在 Console 把数组打印出来,或者断点在数组初始化完成之后,直接打印数组内容,还原原始字符串。

1.3 控制流平坦化(最头疼的混淆)

把原本线性顺序的代码,拆成while + switch循环跳转,打乱正常执行顺序,插入大量无用 case 分支。阅读代码时完全看不出原本逻辑,是 JS 混淆器(如 obfuscator)的标志性功能。

特点:代码看起来循环嵌套很多,大量 case,阅读极其困难,但代码运行逻辑不变。
处理思路:不硬啃全部代码,优先 XHR 断点定位加密入口,动态调试看实际走哪个 case 分支,不需要静态通读全部代码。

1.4 垃圾代码注入

插入大量永远不会执行的假分支、无效函数,干扰阅读。

if(1===2){ // 永远不会执行的垃圾代码 }else{ // 真正业务逻辑 }

调试的时候,单步调试会自动跳过无效分支,动态调试可以无视垃圾代码。

1.5 动态执行混淆 eval /new Function

核心逻辑字符串放在eval()、new Function()里面,页面运行的时候才动态解析并执行代码。静态查看源码看不到真实业务逻辑,代码是运行时生成。

eval('var a=1; debugger;'); new Function("debugger")();

这也是无限 debugger 常用写法,静态检索找不到 debugger 关键字。

0x02 常见 JS 反调试手段原理

反调试,就是 JS 代码检测当前是否开启了 Chrome DevTools 调试器,如果检测到,就触发 debugger、关闭页面、抛出异常,打断逆向人员的调试。

2.1 无限 debugger(最常见)

两种实现方式:

  1. 直接写死debugger;
  2. 定时器循环动态生成 debugger,典型代码:
setInterval(function(){ new Function("debugger")(); },500)

打开 F12 之后,每隔几百毫秒触发一次断点,F8 放行之后立刻再次断住,无法正常调试。

2.2 窗口尺寸检测(检测开发者工具是否打开)

原理:DevTools 打开,浏览器窗口可视区域高度 / 宽度会发生变化。JS 监听 resize 事件,判断窗口尺寸差值,一旦检测到 DevTools 打开,触发反调试逻辑。

2.3 时间差检测(高精度计时检测)

代码连续执行一段循环,记录前后时间差。如果开启调试器,断点会造成代码执行时间变长,时间差异常,判定当前正在被调试。使用performance.now()获取高精度时间。

2.4 控制台 Console 检测

检测 console 对象、console.log 是否被调用,部分站点检测 console.toString 特征。
有些站点会检测控制台面板是否打开,一旦打开直接关闭页面。

2.5 键盘快捷键监听

监听F12、Ctrl+Shift+I、Ctrl+U快捷键,拦截按键,禁止打开开发者工具、禁止查看源码。

局限:只能拦截快捷键,用户通过右键检查打开开发者工具,该方法失效。

0x03 实战:反调试绕过方案(从简单到进阶)

3.1 方式一:右键添加【一律不在此处暂停】(静态 debugger 首选)

找到 debugger 代码行,行号右键,选择一律不在此处暂停。Chrome 会直接忽略这一行断点。
适用:写死debugger;的静态代码。
缺点:对 eval/new Function 动态生成的 debugger 无效。

3.2 方式二:条件断点设置 false

右键 debugger 行,添加条件断点,填入false。
无论代码执行到这一行,条件永远为 false,不会触发 debugger 暂停。

3.3 方式三:Console 直接重写 debugger 函数(万能简单脚本)

打开 Console,在页面触发 debugger之前执行这段代码,把 debugger 置空。

debugger = function(){};

注意:如果已经断住,先 F8 放行,快速粘贴脚本,再刷新页面。

3.4 方式四:Hook Function,绕过 new Function (“debugger”)

很多无限 debugger 是通过new Function动态创建,重写 Function 构造函数,拦截包含 debugger 字符串的调用:

const originalFunc = Function; Function = function(){ const str = arguments[0]; if(str && str.includes('debugger')){ return function(){}; } return originalFunc.apply(this,arguments); }

3.5 方式五:Hook setInterval,干掉定时器无限 debugger

针对 setInterval 循环触发 debugger 的场景,Hook 定时器,拦截定时执行 debugger 的任务。

const originalSetInterval = setInterval; setInterval = function(fn,time){ if(fn.toString().indexOf('debugger') !== -1){ return null; } return originalSetInterval(fn,time); }

3.6 方式六:Overrides 本地文件替换(静态 JS 文件终极方案)

Chrome Source -> Overrides,选择本地文件夹,启用覆盖。

  1. 找到目标混淆 JS 文件,右键 Save for overrides;
  2. 本地打开文件,删除所有 debugger、反调试检测代码;
  3. Ctrl+S 保存,刷新页面,浏览器加载本地修改后的 JS 文件,绕过全部静态反调试。

适合:JS 文件一次性加载,不是动态 eval 生成代码的场景。
缺点:eval 动态执行的代码,Overrides 无法修改内部字符串。

3.7 方式七:Tampermonkey 篡改猴脚本预注入 Hook

如果页面一加载就触发反调试,来不及手动在 Console 粘贴代码,可以使用篡改猴脚本,页面加载前自动注入 Hook 代码。
简易 Tampermonkey 模板:

// ==UserScript== // @name Bypass AntiDebug // @match https://xxx.com/* // @grant none // ==/UserScript== (function(){ debugger = function(){}; const _Func = Function; Function = function(){ if(arguments[0] && arguments[0].includes("debugger")){ return ()=>{} } return _Func.apply(this,arguments) } })()

0x04 混淆代码反混淆实战技巧

绕过反调试之后,我们就可以安心调试混淆代码,下面是反混淆实操方法。

4.1 格式化代码

Source 面板打开 JS,点击{}大括号按钮,一键美化压缩的单行代码。混淆代码美化之后,虽然变量名是乱码,但代码分行,能看清结构。

4.2 字符串数组还原

字符串数组混淆,找到数组定义的位置,断点在数组初始化完成之后,Console 直接打印数组变量,查看全部明文。

console.log(_0x44)

可以复制数组内容,做字典替换,批量替换代码中的_0x44[0]为真实字符串。

4.3 控制流平坦化不用硬读静态代码

控制流平坦化的代码,静态阅读非常痛苦。逆向的核心不是静态读代码,而是动态调试。
使用 XHR 断点断住接口请求,顺着调用栈,跟着 F11 单步进入加密函数,观察变量实时值,只关注加密逻辑的执行分支,忽略不会走到的 case。

4.4 提取关键加密函数,剥离浏览器环境

找到加密逻辑之后,复制函数,剥离 window、document 等浏览器环境依赖,放到 NodeJS 中运行,验证加密结果。
如果存在环境缺失(如缺少 CryptoJS),把对应的 JS 库一起导出。

0x05 高级对抗:反 Hook 检测

现在很多高强度混淆站点增加反 Hook 检测,用来检测开发者是否重写了原生函数。
常见检测手段:

  1. 判断Function.toString()内容是否被篡改;
  2. 校验原生 API 的哈希值;
  3. 检测 window 对象属性是否被 Proxy 代理。

遇到反 Hook 检测,简单的置空 Hook 脚本直接失效。解决思路:

  1. 使用 Proxy 做无痕代理,保留原生 toString 特征;
  2. 使用 CDP 协议远程调试,不在页面 JS 层面 Hook;
  3. 更换浏览器(Firefox 部分反调试检测失效)。

0x06 实战完整逆向流程(推荐)

  1. 打开 Burp 抓包,确定目标接口,确认存在 sign 等加密参数;
  2. 打开 Chrome 开发者工具,页面触发无限 debugger;
  3. 优先使用 Hook 脚本,在页面加载前注入,绕过反调试;
  4. 开启 XHR 断点,触发接口请求,断住代码;
  5. 格式化混淆 JS,通过调用栈回溯定位加密入口函数;
  6. 动态调试,还原字符串数组,理清加密逻辑;
  7. 提取加密算法,本地 NodeJS 复现,验证输出结果;
  8. 复现成功,回到 Burp Repeater,自动生成签名,开展接口漏洞测试。

0x07 高频踩坑总结

❌坑 1:找到 debugger 直接 F8 放行,反复无限断点

没有提前 Hook 或者禁用 debugger,放行之后定时器再次触发 debugger,需要提前执行 Hook 脚本。

❌坑 2:静态通读控制流平坦化混淆代码

控制流平坦化静态阅读效率极低,逆向优先动态调试,跟着执行流走。

❌坑 3:混淆绕过成功,但提取函数在 Node 报错

代码依赖浏览器全局对象(window、navigator、crypto),需要补全浏览器环境,或者只提取纯算法部分。

❌坑 4:Hook 脚本写太晚,页面 JS 已经执行完毕

页面一加载就执行反调试,必须 Tampermonkey 预注入脚本,不能等页面加载完再粘贴。

❌坑 5:混淆 = 加密,无法逆向

JS 混淆只是增加阅读成本,JS 代码最终必须交给浏览器解释执行,只要浏览器能跑,就一定能动态调试还原,不存在绝对无法逆向的前端 JS。

0x08 企业前端防护思路(甲方视角)

  1. JS 混淆、反调试只能提高逆向成本,不能彻底阻止逆向,不能作为接口安全的唯一防护;
  2. 敏感业务、资金交易逻辑不要全部放在前端 JS,核心校验放在后端;
  3. 混淆推荐使用成熟的 JS-Obfuscator,叠加控制流平坦化、字符串加密,增加逆向成本;
  4. 增加反 Hook 检测、环境校验,检测到被调试时返回虚假参数;
  5. 高敏感接口增加 IP 风控、行为风控、验证码,不要单纯依靠前端签名 + 混淆。

总结

JS 混淆用来静态阅读防护,反调试用来动态调试防护。两者组合是前端保护 JS 逻辑的常用手段。
逆向对抗的核心思路:绕过反调试,动态调试优先,不硬啃静态混淆代码。
普通站点使用简单 Hook 脚本、Overrides 文件替换就可以绕过;高强度站点会加入反 Hook、时间差检测,需要更复杂的无痕 Hook 或者 CDP 远程调试。

再次强调,学习这类技术的目的是授权环境的接口安全测试。前端混淆与反调试,只能阻挡普通爬虫,无法阻挡具备逆向能力的测试人员,后端业务校验才是安全的最后防线。

一句话记住:混淆是增加阅读难度,反调试是打断动态跟踪;浏览器能执行的 JS,就一定可以被逆向分析。


最后

关于网络安全技术储备

学好网络安全不论是就业还是做副业赚钱都不错,但要学会网络安全还是要有一个学习规划。最后大家分享一份全套的网络安全学习资料,给那些想学习网络安全的小伙伴们一点帮助!

对于0基础小白入门:

如果你是零基础小白,想快速入门网络安全是可以考虑的。

一方面是学习时间相对较短,学习内容更全面更集中。

二方面是可以找到适合自己的学习方案

包括:网安成长学习路线图、SRC&黑客文档、护网行动、黑客必读书单、面试题、学习视频等教程。带你从零基础系统性的学好网络安全!

需要的可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】

👉1.成长路线图&学习规划👈
要学习一门新的技术,作为新手一定要先学习成长路线图,方向不对,努力白费。

对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图&学习规划。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。

👉2.网安入门到进阶视频教程👈
很多朋友都不喜欢晦涩的文字,我也为大家准备了视频教程,其中一共有21个章节,每个章节都是当前板块的精华浓缩。(全套教程文末领取哈)

👉3.SRC&黑客文档👈
大家最喜欢也是最关心的SRC技术文籍&黑客技术也有收录

SRC技术文籍:

黑客资料由于是敏感资源,这里不能直接展示哦!(全套教程文末领取哈)

👉4.护网行动资料👈
其中关于HW护网行动,也准备了对应的资料,这些内容可相当于比赛的金手指!

👉5.黑客必读书单👈

随着互联网技术的飞速发展,网络安全已经成为了当今科技领域的一大热点。这些SQL注入、CCNA、Web渗透、Linux服务器等,以其强大的语言理解和防御能力,正在守护着我们网络世界。 那以下这些PDF籍就是非常不错的学习资源。

👉6.网络安全岗面试题合集👈
当你自学到这里,你就要开始思考找工作的事情了,而工作绕不开的就是真题和面试题。

这份完整版的网络安全学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询