JavaScript混淆防护与调试技术探析
字数 1472 2025-08-06 00:52:37
JavaScript混淆防护与调试技术探析
JavaScript的渊源
JavaScript最初由Brendan Eich于1995年为Netscape浏览器开发,目的是让网页具有交互性。它实现了网页动态效果,如:
- 鼠标悬停显示提示信息
- 表单数据验证
- 动态加载内容
在浏览器中的执行(BS架构)
JavaScript在浏览器中的解析步骤:
<script>标签处理- 无async/defer:立即执行,可能阻断HTML解析
- async属性:异步加载,加载完成后立即执行
- defer属性:异步加载,HTML解析完成后执行
在App中的应用(CS架构)
在移动应用中,JavaScript可用于:
- 注入JS修改请求和响应(MITM攻击)
- 去除APP开屏广告
- 绕过功能限制
- 修改应用行为
JavaScript混淆技术
混淆的起源:JS压缩
早期JS压缩技术:
- 删除空格、换行和注释
- 替换局部变量名为更短名称
- 合并多个JS文件
- 移除死代码
- 使用短语法:
- 逻辑运算符简化条件表达式
- 模板字符串代替字符串连接
- 箭头函数简化函数表达式
- 默认参数值
- 解构赋值
- 预编译模板
- 使用CDN引入公共库
现代混淆技术
使代码不可读
-
变量名和函数名替换:
- 将有意义名称替换为无意义字符序列
-
字符串加密:
- 运行时解密字符串,增加逆向难度
-
改变代码结构:
- 使用IIFE(立即调用函数表达式)封装代码
- 减少全局变量使用
-
插入死代码:
- 添加不会执行的无用代码片段
-
控制流混淆:
- 将简单逻辑改为复杂控制结构
- 使用switch和循环结构伪装简单判断
-
高级算法和技术:
- 代理混淆(函数调用转为代理调用)
- AST(抽象语法树)变形
使代码不可调试
-
无限debugger:
var c = new RegExp("1"); c.toString = function () { setInterval(function() { debugger }, 1000); } console.log(c); -
内存耗尽攻击:
var startTime = new Date(); debugger; var endTime = new Date(); var isDev = endTime - startTime > 100; var stack = []; if (isDev) { while (true) { stack.push(this); console.log(stack.length, this); } } -
反直觉技术:
- 将JS代码隐藏在PNG图片元数据中
- 通过Canvas API提取并执行隐藏代码
JavaScript反混淆技术
在线工具
使用大模型(GPT)
大语言模型能有效还原混淆代码,还原度可达98%
Chrome开发者工具技巧
-
忽略无限debugger:
- 在Sources面板选中debugger语句
- 右键选择"Add script to ignore list"
-
动态调试:
- 设置断点
- 单步执行
- 观察变量变化
实战案例
百度翻译接口逆向(2024.2.24)
-
分析请求参数:
- sign和ts参数随query变化
- transtype在realtime和enter间切换
-
定位关键函数:
- 全局搜索"sign:"或"sign="
- 在index.36217dc5.js中找到sign生成函数
-
提取sign生成算法:
- 硬编码关键变量(window[d]值)
- 重构n函数和a函数
-
最终生成脚本:
function n(t, e) { // 算法实现... } a = function(t) { // 算法实现... } const query = "abandon"; console.log(`from=en&to=zh&query=${query}&simple_means_flag=3&sign=${a(query)}&token=27e9578934647317beb78881e9e2300e&domain=common&ts=1708512893507`)
有道翻译接口逆向(2024.2.24)
-
分析请求:
- sign和mysticTime参数变化
- sign可能是MD5哈希
- mysticTime是时间戳
-
定位关键函数:
- 全局搜索"md5"或"createHash"
- 找到sign生成函数
-
重构sign生成:
const crypto = require('crypto') function c(e) { return crypto.createHash("md5").update(e.toString()).digest("hex") } function sign(e, t) { return c(`client=${u}&mysticTime=${e}&product=${d}&key=${t}`) } const e = "ydsecret://query/iv/C@lZe2YzHtZ2CYgaXKSVfsb7Y4QWHjITPPZ0nQp87fBeJ!Iv6v^6fvi2WN@bYpJ4"; const t = (new Date()).getTime(); console.log(sign(e, t)); -
解密翻译结果:
- 定位密文位置
- 使用获取的key进行AES解密
关键点总结
- JavaScript混淆的核心目标是使代码不可读和不可调试
- 现代混淆技术结合了多种方法增加逆向难度
- 反混淆需要结合工具、大模型和动态调试技术
- 实战中定位关键函数是逆向的核心步骤
- Chrome开发者工具的高级功能能有效应对反调试