本讲是JS逆向系列的进阶内容,核心聚焦 “JS反调试机制的识别与绕过” 和 “代码混淆的识别与还原”——这两类都是前端安全防护的常见手段,目的是阻止他人调试、窃取敏感JS逻辑(如加密算法)。笔记以“反调试(定义→检测→绕过)”和“混淆加密(定义→类型→还原)”为两大主线,结合实操案例拆解,突出“可落地的绕过/还原策略”。

一、JS反调试:识别与绕过

1. 什么是JS反调试?

网站通过特定JS代码限制/禁止开发者工具调试,核心目的是保护前端敏感逻辑(如加密算法、接口地址),常见手段分两类:

  • 主动干扰调试:通过 debugger​ 语句制造死循环,让调试器反复暂停,无法正常分析;
  • 禁用调试工具:拦截F12、右键菜单等操作,直接禁止打开开发者工具。

2. 如何检测反调试?

检测方法简单直接,核心是“尝试调试”,具体场景:

  • 按F12无反应、右键菜单被禁用(提示“禁止调试”);

  • 打开开发者工具后,页面立即暂停(反复出现debugger​)、崩溃或无网络数据包;

  • 其他隐蔽检测手段(前端代码层面):

    • 监听键盘事件(拦截F12按键);
    • 检测浏览器窗口高度差(开发者工具打开会改变窗口尺寸);
    • 检测window.debugger​等调试相关变量;
    • 利用console.log​调用次数、代码执行时间差判断是否被调试。

3. 核心绕过方法(原理+实操+优缺点)

针对“debugger​死循环”类反调试,以下是5种高频绕过策略,按“实用性优先级”排序:

(1)本地覆盖法(推荐,通用性最强)
  • 原理:将远程包含反调试代码的JS文件下载到本地,删除/注释debugger​或反调试函数,再让浏览器加载本地修改后的文件(覆盖远程文件)。

  • 实操步骤(以Chrome为例):

    1. F12打开“源代码”面板,找到触发反调试的JS文件(可全局搜索debugger​);
    2. 右键文件 → 选择“替换内容”/“保存内容以备替换”,将文件保存到本地文件夹;
    3. 在本地文件中删除debugger​语句或注释反调试函数(如enableDebugProtect()​);
    4. 在“源代码”面板的“替换”标签页中启用本地文件覆盖,刷新页面即可正常调试。
  • 优点:彻底移除反调试代码,不影响自身断点调试;

  • 缺点:配置稍复杂,若网站有多个反调试文件(如动态注入的JS),需逐一覆盖。

(2)条件断点法(高效,适合明确debugger​位置)
  • 原理:给debugger​语句设置“永远不成立”的条件(如false​),让调试器跳过该语句。

  • 实操步骤:

    1. 打开开发者工具,当页面暂停在debugger​处时,右键debugger​所在行;
    2. 选择“添加条件断点”,输入false​,点击确定;
    3. 刷新页面,debugger​因条件不成立不再执行,可正常设置自己的断点。
  • 优点:操作简单,不影响自身调试;

  • 缺点:需明确debugger​所在行,若有多个debugger​需逐一设置。

(3)永不暂停法(快速临时绕过)
  • 原理:利用Chrome开发者工具的“一律不在此处暂停”功能,手动标记debugger​行,让调试器直接跳过。

  • 实操步骤:

    1. 页面暂停在debugger​处时,右键debugger​所在行;
    2. 选择“一律不在此处暂停”,该行会被标记为“跳过”;
    3. 刷新页面,调试器不再在该位置暂停。
  • 优点:操作极简单,适合临时绕过少量debugger​;

  • 缺点:对动态注入的debugger​(如eval("debugger")​)失效(行号会变化),多debugger​场景需逐一标记。

(4)禁用断点法(应急方案)
  • 原理:直接禁用开发者工具的所有断点功能,让debugger​语句无法触发暂停。

  • 实操步骤:

    1. 打开开发者工具的“源代码”面板;
    2. 点击顶部的“禁用断点”按钮(图标为“暂停+斜杠”);
    3. 刷新页面,debugger​不再触发暂停,可正常抓包、查看源码。
  • 优点:操作简单,快速绕过所有debugger​;

  • 缺点:“伤敌一千自损八百”——禁用后自己也无法设置断点调试。

(5)函数置空法(进阶,适合全局反调试函数)
  • 原理:若反调试是通过全局函数(如setInterval​循环调用debugger​、console.clear()​清空控制台)实现,可在控制台将这些函数置空,使其失效。

  • 实操步骤:

    1. 找到触发反调试的全局函数(如function enableDebug() { debugger; }​);
    2. 在控制台执行enableDebug = function() {}​(将函数置空);
    3. 刷新页面,反调试函数被改写,不再生效。
  • 优点:精准绕过,不影响其他功能;

  • 缺点:需先定位反调试函数;若网站检测原生函数是否被改写(如校验Function.toString​长度),则失效。

4. 特殊场景:禁用F12的绕过

针对“直接禁止打开F12”的反调试,无需复杂操作,两种简单绕过:

  • 方法1:先打开新标签页,开启开发者工具后,再在该标签页访问目标网站;
  • 方法2:打开目标网站后,连续按两次F12(第一次触发禁用提示,第二次强制打开);
  • 方法3:通过浏览器菜单打开开发者工具(如Chrome:更多工具→开发者工具)。

二、JS混淆加密:识别与还原

1. 什么是JS混淆加密?

通过特定算法将可读的JS代码转换为“面目全非但仍可执行”的代码,核心目的是保护敏感逻辑(如加密算法、接口密钥),避免被轻易窃取。
根据加密强度和成本,分为三类:

  • 开源免费:小公司常用,如JJEncode、AAEncode、JSFuck;
  • 商业收费:中型公司常用,如jsjiami、sojson;
  • 自研加密:大公司专用,安全性最高,还原难度极大。

2. 开源混淆加密(识别+还原)

(1)核心特点
  • 加密后代码特征明显(全是特殊字符、表情、数字等);
  • 还原成本低,网上有大量免费在线解密工具。
(2)案例演示(以JJEncode、AAEncode、JSFuck为例)
① 原始代码
function printLing() {
  console.log('ling');
}
printLing(); // 输出:ling
② 加密效果
  • JJEncode:加密后全是符号和字母组合,如:

    $=~[];$={___:++$,$$$$:(![]+"")[$],__$:++$,$_$_:(![]+"")[$],_$_:++$,$_$$:({}+"")[$],$$_$:($[$]+"")[$],_$$:++$,$$$_:(!""+"")[$],$__:++$,$_$:++$,$$__:({}+"")[$],$$_:++$,$$$:++$,$___:++$,$__$:++$};$.$_=($.$_=$+"")[$.$_$]+($._$=$.$_[$.__$])+($.$$=($.$+"")[$.__$])+((!$)+"")[$._$$]+($.__=$.$_[$.$$_])+($.$=(!""+"")[$.__$])+($._=(!""+"")[$._$_])+$.$_[$.$_$]+$.__+$._$+$.$;$.$$=$.$+(!""+"")[$._$$]+$.__+$._+$.$+$.$$_;$.$=($.___)[$.$_][$.$_];$.$($.$($.$$+"\""+"console.log('ling')"+"\"")())();
    
  • AAEncode:加密后全是表情符号,如:

    ヽ(´▽`)ノfunctionヽ(´▽`)ノprintLingヽ(´▽`)ノ(){ヽ(´▽`)ノconsole.logヽ(´▽`)ノ(´ling´)ヽ(´▽`)ノ}printLingヽ(´▽`)ノ()ヽ(´▽`)ノ
    
  • JSFuck:加密后仅用[]()!+​五种字符,如:

    [][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+([]+[])[([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]])([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+([]+[])[([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]])([]+(![]+[])[+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+([][[]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+([][[]]+[])[+!+[]]+([]+![])[!+[]+!+[]+!+[]]+(![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]])()
    
③ 还原方法
  • 方法1:在线解密工具(推荐):

    • 常用工具:JS解密网(https://www.jsjiami.com/jiemi.html)、站长工具JS解密;
    • 操作:复制加密代码→粘贴到工具→点击解密→获取原始代码。
  • 方法2:手动简化(应急):

    • 开源混淆代码的核心是“最后通过括号执行”,可删除加密代码末尾的执行括号(如()​),在控制台运行,强制报错泄露原始代码;
    • 示例:删除JJEncode加密代码末尾的();​,运行后会报错,错误信息中可能包含原始函数名/逻辑。

3. 商业混淆加密(识别+还原)

(1)核心特点
  • 加密后代码保留基本JS格式,但变量名、函数名被随机混淆(如a123​、x7f9​),包含大量冗余代码、控制流平坦化;
  • 常见标识:代码开头/结尾可能有// jsjiami.com​、// sojson.com​等水印。
(2)案例演示(以jsjiami为例)
① 识别加密方式

访问目标网站(如https://www.eisk.cn/Tides),F12查看JS文件,发现代码变量名随机、有// jsjiami.com​水印,确定为jsjiami商业混淆。

② 还原方法
  • 方法1:免费在线解密工具(优先尝试):

    • 常用工具:JSDec(https://www.liulihaocai.com/jsdec.html)、查错网AES解密(https://www.chacuo.net/jsencryptaes);
    • 操作:复制混淆代码→粘贴到工具→点击解密→获取可读性更高的代码(可能无法完全还原,但可提取核心逻辑)。
  • 方法2:付费破解:

    • 若免费工具失效,可在第三方平台(如猪八戒)找专业人员破解,费用根据加密强度而定;
  • 方法3:动态调试还原(进阶):

    • 若无法直接解密,可通过断点调试,追踪混淆代码的执行流程,提取核心逻辑(如加密函数、密钥);
    • 关键:找到入口函数(如点击按钮触发的函数),逐步调试,忽略冗余代码。
③ 注意事项
  • 部分商业混淆会加入“反还原”机制(如调试时崩溃、代码自毁),需先通过前面的反调试绕过方法处理;
  • 还原后若涉及AES/DES等加密,需从代码中提取密钥(key)、向量(IV),再用对应工具解密数据。

三、核心总结

  1. 反调试绕过优先级:本地覆盖法(最优,彻底移除反调试)→ 条件断点法(精准)→ 永不暂停法(临时)→ 禁用断点法(应急)→ 函数置空法(进阶);

  2. 混淆还原核心思路:

    • 开源混淆:直接用在线工具解密,应急可手动删执行括号报错泄露;
    • 商业混淆:先找免费工具,失效则付费破解或动态调试提取核心逻辑;
    • 自研混淆:还原难度极大,若无法突破可考虑放弃;
  3. 实战关键:

    • 反调试与混淆常同时存在,需先绕过反调试,再进行混淆还原;
    • 调试时多利用“全局搜索”(如debugger​、encrypt​、混淆水印)快速定位核心代码;
    • 优先使用浏览器原生功能(本地覆盖、条件断点),避免依赖第三方工具,提高兼容性。

学习本讲的核心是“灵活应对”——不同网站的反调试/混淆策略不同,需结合实际场景选择合适的方法,多复现案例才能熟练掌握。如果遇到复杂的自研混淆或多层反调试,可优先聚焦“核心功能触发的函数”,忽略无关的防护代码,提高效率。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐