| name | js-deobfuscate |
| description | AI-driven JavaScript deobfuscation and reverse engineering skill. Use when analyzing obfuscated JS files from javascript-obfuscator, JScrambler, or similar tools. Covers stack-based VM interpreter analysis, instrumentation-based bytecode extraction, string decryption, opcode disassembly, and source recovery. Trigger: obfuscated JS, scrambled JS, VM-protected JS, deobfuscation, javascript-obfuscator, JScrambler. |
JS Deobfuscate
AI 驱动的 JavaScript 反混淆。核心方法论源自 AI Agent 成功破解 javascript-obfuscator 和 JScrambler 的实战经验——插桩优先,让混淆器自己解码自己。
核心原则
- 不要一次性实现反混淆器 — 先运行混淆后的代码建立基线行为
- 插桩优先于重实现 — patch 运行时环境,让混淆器的自有函数暴露内部状态
- 分层剥离 — 逐层识别并移除混淆层,而非一次暴力破解
- 从不猜测 — 从运行时捕获的实证数据出发,每一步可验证
工作流:五步反混淆
第一步:建立基线
node obfuscated.js
目的:确认代码可执行,建立"正确行为"参考。
第二步:分析混淆层结构
读取混淆后 JS,识别存在的混淆层。常见层(从外到内):
- String array rotation — IIFE 包裹的字符串数组洗牌
- String decryption — RC4/base64 解密函数(如
U())
- Environment fingerprint — 检测是否在预期环境中运行
- Custom serialization — zigzag-encoded varints 等二进制格式
- Stack-based VM interpreter — ~1500 行 dispatch loop,~200 opcodes
- Opcode shuffling — Block key XOR + shuffle table 查表
- Jump target encryption — Jump key XOR 修改
- Stack value encryption — seKey XOR 加密整数栈值
- Anti-tampering — 定时检查 (
bU()),暂停会触发 opcode 表重排
第三步:插桩(关键步骤)
不要尝试手动实现反序列化器或解码器。改为插桩(instrumentation):
3.1 字符串解密插桩
找到字符串解密函数(如 U()),用 console.log 包装其输入输出:
const originalU = U;
U = function(...args) {
const result = originalU.apply(this, args);
console.log(`U(${JSON.stringify(args)}) => ${result}`);
return result;
};
3.2 反序列化器插桩
找到自定义二进制反序列化器(如 B()),包装其返回值:
const originalB = B;
B = function(...args) {
const result = originalB.apply(this, args);
console.log('B result:', JSON.stringify(result, null, 2));
return result;
};
3.3 VM Dispatch Loop 插桩
找到 VM 主循环(dispatch loop),在每个 opcode 执行前后记录:
console.log(`OPCODE: ${opcode}, OPERANDS: ${JSON.stringify(operands)}, STACK: ${JSON.stringify(stack)}`);
单次运行即可捕获:
- 参数个数、局部变量数
- 所有常量(数值、字符串名)
- 完整的 bytecode 流和执行轨迹
- blockKey、jumpKey、seKey 等密钥
第四步:Bytecode 反汇编
从插桩输出中提取 bytecode 流,进行反汇编:
- Opcode 还原 — 每个 opcode XOR blockKey,在 shuffle table 中查找对应操作
- 跳转目标还原 — 跳转操作数 XOR jumpKey 得到真实目标
- 栈值解密 — 栈上的加密整数 XOR seKey 解密
- 命名操作 — 将原始 opcode 索引映射为人类可读名称:
PUSH_CONST, STORE_LOCAL, LOAD_ARG, MUL, SUB,
LOAD_LOCAL, GT, JMP_FALSE, DUP, POP, RETURN
第五步:源码重构
根据指令流中的操作序列,逐步还原为等价 JavaScript:
LOAD_ARG 0 -> quantity
LOAD_ARG 1 -> unitPrice
MUL -> quantity * unitPrice
STORE_LOCAL 0 -> let total = ...
LOAD_CONST 0.15 -> const taxRate = 0.15
...
最终输出可读的业务逻辑源码。
关键技术备忘
| 混淆层 | 识别特征 | 应对策略 |
|---|
| String array shuffle | IIFE + 字符串数组 + index 访问 | 插桩捕获数组内容 |
| RC4 string decryption | charCodeAt + charCodeAt 循环 | 插桩 U() 函数 |
| Environment fingerprint | eval + .length 属性检测 | 替换为固定值 |
| Custom serialization | readVarint / zigzag 编码 | 插桩 B() 反序列化器 |
| Stack VM interpreter | switch + opcode dispatch loop | 插桩 dispatch 记录每步 |
| Opcode shuffle | ^ blockKey + table lookup | 从运行时捕获 blockKey |
| Jump encryption | ^ jumpKey 修改跳转目标 | 从运行时捕获 jumpKey |
| Stack encryption | ^ seKey 加密整数值 | 从运行时捕获 seKey |
| Anti-tampering | performance.now() / Date.now() 检测 | 运行时 patch 时间函数 |
参考
脚本说明
scripts/
instrument_strings.js — 字符串解密函数自动插桩模板
instrument_vm.js — VM dispatch loop 插桩模板
disassemble.py — 从插桩日志中提取 bytecode 并反汇编