Deobfuscates malicious JavaScript from web attacks, phishing pages, and droppers by reversing encoding layers, eval chains, string operations, and control flow obfuscation. For JS malware analysis and script investigations.
npx claudepluginhub killvxk/cybersecurity-skills-zhThis skill uses the workspace's default tool permissions.
- 调查带有混淆 JavaScript 的钓鱼页面,该脚本执行凭据窃取或重定向操作
Deobfuscates malicious JavaScript code from web attacks, phishing pages, and droppers by reversing encoding layers, eval chains, string manipulation, and control flow obfuscation for malware analysis.
Deobfuscates malicious JavaScript from phishing pages, web skimmers, and droppers by reversing encoding, eval chains, string manipulation, and control flow obfuscation.
Deobfuscates multi-layered PowerShell malware using AST analysis, dynamic tracing, PSDecode, PowerDecode, and Python scripts to reveal hidden payloads and C2 infrastructure. For incident response and malware analysis.
Share bugs, ideas, or general feedback.
不适用于仅被压缩的生产代码混淆 JavaScript;对此类代码使用标准美化工具即可。
jsbeautifier 库用于代码格式化在不执行的情况下隔离恶意 JavaScript:
# 从 HTML 文件中提取 JavaScript
python3 << 'PYEOF'
from html.parser import HTMLParser
class ScriptExtractor(HTMLParser):
def __init__(self):
super().__init__()
self.in_script = False
self.scripts = []
self.current = ""
def handle_starttag(self, tag, attrs):
if tag == "script":
self.in_script = True
self.current = ""
def handle_endtag(self, tag):
if tag == "script":
self.in_script = False
if self.current.strip():
self.scripts.append(self.current)
def handle_data(self, data):
if self.in_script:
self.current += data
with open("malicious_page.html") as f:
parser = ScriptExtractor()
parser.feed(f.read())
for i, script in enumerate(parser.scripts):
with open(f"script_{i}.js", "w") as f:
f.write(script)
print(f"已提取 script_{i}.js({len(script)} 字节)")
PYEOF
# 美化提取的 JavaScript
npx js-beautify script_0.js -o script_0_pretty.js
对所使用的混淆方法进行分类:
常见 JavaScript 混淆技术:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
字符串编码:
- 十六进制编码: "\x68\x65\x6c\x6c\x6f" -> "hello"
- Unicode 转义: "\u0068\u0065\u006c\u006c\u006f" -> "hello"
- Base64: atob("aGVsbG8=") -> "hello"
- charCodeAt/fromCharCode:String.fromCharCode(104,101,108,108,111)
- 数组查找: var _0x1234 = ["hello","world"]; _0x1234[0]
Eval 调用链:
- eval(atob("..."))
- eval(unescape("..."))
- new Function("return " + decoded)()
- document.write("<script>" + decoded + "</script>")
- setTimeout(decoded, 0)
控制流:
- 带打乱顺序的 switch-case 分发器
- 不透明谓词(始终为真/假的条件)
- 死代码插入
- 变量名混淆(_0x4a3b, _0xab12)
反分析:
- 调试器陷阱:setInterval(function(){debugger;}, 100)
- Console 检测:覆盖 console.log
- 时序检查:performance.now() 差值
- DevTools 检测:window.outerWidth - window.innerWidth > 100
消除反调试和反分析陷阱:
// 分析前移除调试器陷阱
// 在混淆脚本中替换:
// 之前:
setInterval(function() { debugger; }, 100);
// 之后(已消除):
setInterval(function() { /* debugger 已移除 */ }, 100);
// 消除 DevTools 检测
// 之前:
if (window.outerWidth - window.innerWidth > 160) { window.location = "about:blank"; }
// 之后:
if (false) { window.location = "about:blank"; }
// 消除时序检查
// 覆盖 performance.now 以返回一致的值
const originalNow = performance.now;
performance.now = function() { return 0; };
逐层解码编码字符串:
# 用于解码常见 JS 混淆模式的 Python 脚本
import re
import base64
import urllib.parse
def decode_hex_strings(code):
"""将 \\xNN 序列替换为 ASCII 字符"""
def hex_replace(match):
hex_str = match.group(0)
try:
return bytes.fromhex(hex_str.replace("\\x", "")).decode("ascii")
except:
return hex_str
return re.sub(r'(?:\\x[0-9a-fA-F]{2})+', hex_replace, code)
def decode_unicode_escapes(code):
"""将 \\uNNNN 序列替换为字符"""
def unicode_replace(match):
return chr(int(match.group(1), 16))
return re.sub(r'\\u([0-9a-fA-F]{4})', unicode_replace, code)
def decode_charcode_arrays(code):
"""解析 String.fromCharCode 调用"""
def charcode_replace(match):
codes = [int(c.strip()) for c in match.group(1).split(",")]
return '"' + "".join(chr(c) for c in codes) + '"'
return re.sub(r'String\.fromCharCode\(([0-9,\s]+)\)', charcode_replace, code)
def decode_base64_strings(code):
"""解析带静态字符串的 atob() 调用"""
def atob_replace(match):
try:
decoded = base64.b64decode(match.group(1)).decode("utf-8")
return f'"{decoded}"'
except:
return match.group(0)
return re.sub(r'atob\(["\']([A-Za-z0-9+/=]+)["\']\)', atob_replace, code)
# 应用所有解码器
with open("script_0.js") as f:
code = f.read()
code = decode_hex_strings(code)
code = decode_unicode_escapes(code)
code = decode_charcode_arrays(code)
code = decode_base64_strings(code)
with open("script_0_decoded.js", "w") as f:
f.write(code)
print("已解码字符串写入 script_0_decoded.js")
在不执行的情况下展开 eval/Function 构造器调用链:
// Node.js 脚本,用于安全解析 eval 调用链
// 在隔离环境中运行:node --experimental-vm-modules deobfuscate.js
const vm = require('vm');
// 创建带日志记录的沙箱上下文
const sandbox = {
eval: function(code) {
console.log("=== EVAL 已拦截 ===");
console.log(code.substring(0, 500));
console.log("===================");
return code; // 返回代码而不执行
},
document: {
write: function(html) {
console.log("=== DOCUMENT.WRITE 已拦截 ===");
console.log(html.substring(0, 500));
},
getElementById: function() { return { innerHTML: "" }; }
},
window: { location: { href: "" } },
atob: function(s) { return Buffer.from(s, 'base64').toString(); },
unescape: unescape,
setTimeout: function(fn) { if (typeof fn === 'string') console.log("TIMEOUT CODE:", fn); },
console: console,
String: String,
Array: Array,
parseInt: parseInt,
RegExp: RegExp,
};
const context = vm.createContext(sandbox);
// 在沙箱中加载并执行混淆脚本
const fs = require('fs');
const code = fs.readFileSync('script_0.js', 'utf8');
try {
vm.runInContext(code, context, { timeout: 5000 });
} catch(e) {
console.log("执行错误(预期):", e.message);
}
检查还原出的恶意逻辑:
去混淆后的恶意软件类别与 IoC 提取:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
凭据窃取器:
- 表单 action URL(数据泄露端点)
- XMLHttpRequest/fetch 目标地址
- 目标输入字段名称(username, password, cc_number)
Web 嗅探器(Magecart):
- 支付表单覆盖注入
- 卡数据泄露 URL
- 键盘记录器事件监听器(onkeypress, oninput)
重定向脚本:
- location.href 赋值中的目标 URL
- 基于 user-agent 或 referrer 的条件重定向
- 伪装逻辑(向爬虫展示良性内容)
漏洞利用工具包落地页:
- 浏览器/插件版本检查
- 漏洞利用载荷 URL
- 编码为数组或编码字符串的 shellcode
| 术语 | 定义 |
|---|---|
| Eval 调用链(Eval Chain) | 嵌套的 eval()、Function() 或 document.write() 调用层,每层解码一层混淆后传递给下一层 |
| 字符串数组旋转(String Array Rotation) | 将所有字符串存储在打乱顺序的数组中并通过计算索引访问的混淆技术,用于隐藏字符串字面量 |
| 死代码插入(Dead Code Insertion) | 添加永远不会执行的非功能性代码块,以增加分析复杂性并迷惑模式匹配 |
| 不透明谓词(Opaque Predicate) | 结果预先确定但难以静态判断的条件表达式;用于掩盖控制流 |
| 反调试(Anti-Debugging) | 用于检测并阻止浏览器 DevTools 或调试器使用的 JavaScript 技术,包括 debugger 语句和时序检查 |
| Web 嗅探器(Web Skimmer) | 注入到电商网站以从结账表单中窃取支付卡数据的恶意 JavaScript(Magecart 攻击) |
场景背景:被攻陷的电商网站在其结账页面注入了混淆的 JavaScript。需要对脚本进行去混淆,以识别数据泄露端点并确定哪些客户数据被窃取。
方法:
常见陷阱:
JavaScript 恶意软件去混淆报告
=========================================
来源: checkout.js(注入到 example-shop.com)
混淆方式: obfuscator.io(字符串数组 + 旋转 + 十六进制编码)
已移除层数: 3
已识别的混淆技术
[1] 包含 247 个条目的字符串数组,旋转量 0x1a3
[2] 十六进制编码的字符串引用(\x68\x65\x6c\x6c\x6f)
[3] Base64 包装的 eval 调用链(2 层)
[4] 反调试:setInterval debugger 陷阱
去混淆后的功能
类型: Magecart 支付卡嗅探器
目标表单: input[name*="card"], input[name*="cc_"]
捕获数据: 卡号、有效期、CVV、持卡人姓名
泄露方式: 通过 XMLHttpRequest 进行 POST
泄露 URL: hxxps://analytics-cdn[.]com/collect
泄露格式: JSON { "cn": card_number, "exp": expiry, "cv": cvv }
触发方式: 结账页面的表单提交事件
提取的 IoC
域名: analytics-cdn[.]com
IP: 185.220.101[.]42
URL: hxxps://analytics-cdn[.]com/collect
hxxps://analytics-cdn[.]com/gate.js