reverse-skills-max: initial public release (restored, redacted, hardened)
This commit is contained in:
154
vendor-new/rev-skills/.claude/skills/re-script-deob/SKILL.md
Normal file
154
vendor-new/rev-skills/.claude/skills/re-script-deob/SKILL.md
Normal file
@@ -0,0 +1,154 @@
|
||||
---
|
||||
name: re-script-deob
|
||||
description: 脚本/宏去混淆:PowerShell、VBA、JavaScript。触发词:PowerShell混淆、VBA宏、JS去混淆、脚本解密、恶意脚本
|
||||
capabilities: [deobfuscation]
|
||||
---
|
||||
|
||||
# 脚本/宏去混淆(PowerShell / VBA / JavaScript)
|
||||
|
||||
## 何时使用 / 何时不用
|
||||
|
||||
- 用:.ps1 / .docm / .xlsm / .js / .jse / .hta 等脚本与宏的混淆还原(编码、字符串拼接、执行链)
|
||||
- 用:钓鱼附件宏、恶意下载器脚本([[re-malware]] → [[re-managed]] 路径)
|
||||
- 不用:编译产物(native 走 [[re-binary-core]]、.NET 走 [[re-dotnet]]、Java 走 [[re-java]])
|
||||
- 不用:脚本完全可读(直接读逻辑,无需本技能)
|
||||
- 注意:**动态执行默认沙箱([[re-analyze/platform-tips]] 最高原则)**——静态解码不执行可免沙箱,任何"运行脚本取下一层"的步骤必须进 [[re-sandbox]]
|
||||
|
||||
## 工具准备
|
||||
|
||||
参考 [[re-analyze/platform-tips]]——本技能静态解码为主,免沙箱;执行链跟踪中需要运行时(跑脚本/开宏)的步骤按最高原则进沙箱。
|
||||
|
||||
### python3(解码主力)
|
||||
|
||||
- Linux: `apt install python3` / `dnf install python3` / `pacman -S python`
|
||||
- macOS: 自带;Windows: 官方安装器或 `choco install python`
|
||||
- 验证: `python3 --version`
|
||||
|
||||
### oletools(VBA 宏提取/解码,可选但强烈建议)
|
||||
|
||||
- `pip install oletools`(依赖 pyparsing 自动装上)
|
||||
- 验证: `olevba --help`
|
||||
|
||||
### xxd / sed(十六进制与文本处理)
|
||||
|
||||
- Debian/Ubuntu: `apt install xxd`(新版本独立包,旧版本在 `vim-common`);Fedora: `dnf install vim-common`(xxd 传统由 vim-common 提供,F38+ 也有独立 `xxd` 子包);Arch: `pacman -S xxd`
|
||||
- macOS: 自带(vim 附送)
|
||||
- Windows: 无自带 xxd——用 WSL 或 PowerShell `Format-Hex`
|
||||
- sed 全平台自带;验证: `xxd -v && sed --version`
|
||||
|
||||
### PowerShell(Windows 内置)/ pwsh(Linux/macOS)
|
||||
|
||||
- Windows: 内置 `powershell.exe`(或 PowerShell 7 `pwsh`)
|
||||
- Linux: `apt install powershell`(Microsoft 源)或 `snap install powershell`;macOS: `brew install --cask powershell`
|
||||
- 验证: `pwsh --version`
|
||||
|
||||
### js-beautify(JS 美化,可选)
|
||||
|
||||
- `pip install jsbeautifier`;验证: `js-beautify --version`
|
||||
|
||||
## 操作步骤
|
||||
|
||||
按顺序执行;每层还原结果存档编号(`layer_01.ps1` → `layer_02.ps1` …),执行链跟踪中"运行脚本拿下一层"的步骤一律在沙箱内。
|
||||
|
||||
1. **识别脚本类型与混淆风格**:
|
||||
```sh
|
||||
file sample.ps1 && head -c 512 sample.ps1
|
||||
grep -oiE 'IEX|Invoke-Expression|-EncodedCommand|FromBase64String|eval\(|unescape|fromCharCode|Chr\(|StrReverse|Document_Open|AutoOpen' sample.ps1
|
||||
```
|
||||
- PowerShell 特征: `-EncodedCommand` / `IEX` / `FromBase64String` / `[Convert]::`
|
||||
- VBA 特征: `Sub AutoOpen` / `Document_Open` / `Chr(` / `StrReverse` / `Evaluate` / `Shell`
|
||||
- JS 特征: `eval(` / `unescape` / `fromCharCode` / `\xHH` 十六进制 / `document.write`
|
||||
- 混淆风格分类:纯编码(base64/hex/char-code)、字符串拼接(`'co'+'mmand'`)、执行链(外层 IEX/eval 嵌套内层载荷)、字符反转/替换
|
||||
|
||||
2. **逐层还原(先解码,再跟执行链)**:
|
||||
- 顺序:从最外层剥——先解纯编码层,再跟踪 IEX/eval 参数直到最内层 payload
|
||||
- 每层解完回到步骤 1 重新识别(新层可能是不同混淆手法)
|
||||
- 最终目标:得到可读的"真实逻辑"(URL、命令、载荷),存档最终层
|
||||
- 执行链中"执行后输出下一层"的步骤 → 沙箱内运行
|
||||
|
||||
3. **PowerShell(-enc 解码、IEX 链)**:
|
||||
- `-enc` 解码(安全,不执行):
|
||||
```sh
|
||||
pwsh -NoProfile -Command '$d=[Convert]::FromBase64String("BASE64"); [Text.Encoding]::Unicode.GetString($d)'
|
||||
```
|
||||
- IEX 链(沙箱内把 IEX 换成输出拿下一层): `sed 's/IEX(/Write-Host (/g' layer_01.ps1 > layer_02.ps1`
|
||||
- 结构化提取字符串字面量(AST,不执行):
|
||||
```powershell
|
||||
$ast = [System.Management.Automation.Language.Parser]::ParseFile('layer_01.ps1', [ref]$null, [ref]$null)
|
||||
$ast.FindAll({ $args[0] -is [System.Management.Automation.Language.StringConstantExpressionAst] }, $true) | % { $_.Value }
|
||||
```
|
||||
- 常见手法:`-join`/`-split` 字符拼接、`$env:XXX` 变量替换、字符串反转
|
||||
|
||||
4. **VBA(olevba 提取宏 + 还原)**:
|
||||
```sh
|
||||
olevba -c sample.docm > macro.txt # 提取宏源码
|
||||
olevba --decode -c sample.docm > macro_decoded.txt # 自动解常见字符串混淆(--decode 自 oletools 0.24/2015 起就有,无版本门槛)
|
||||
```
|
||||
- 手动还原:`Chr(65)` 拼接用 python3 换算 ASCII;`StrReverse(...)` 反转;`Evaluate("...")` 里的执行串
|
||||
- 找自动执行入口:`AutoOpen` / `Document_Open` / `Workbook_Open` / `Auto_Open`
|
||||
- 动态验证(必须沙箱):沙箱内 Office/LibreOffice 打开文档(启用宏),观察行为与下一层输出
|
||||
|
||||
5. **JS(去混淆/解编码)**:
|
||||
- `eval(` → 静态替换为 `console.log(`(或 `print(`)观察载荷
|
||||
- char-code 解码: `python3 -c "print(''.join(chr(int(c)) for c in '72,101,108,108,111'.split(',')))"`
|
||||
- `\xHH` 十六进制: `python3 -c "print(bytes.fromhex('68656c6c6f').decode())"`(先剥 `\x` 前缀)
|
||||
- base64 串: `python3 -c "import base64; print(base64.b64decode('...'))"`
|
||||
- 美化: `js-beautify layer_01.js -o pretty.js`
|
||||
- 动态(沙箱):`node payload.js` 或浏览器沙箱执行拿下一层
|
||||
|
||||
## 具体去混淆链配方
|
||||
|
||||
承接步骤 1 的混淆风格分类,按配方执行(方法为核心,工具可替换):
|
||||
|
||||
**eval / 执行函数替换**:把 `eval` / `IEX` / `Invoke-Expression` / `bash` 替换为输出语句(JS 中 `eval = console.log`;PowerShell 中把 `IEX(...)` 换成打印),运行后打印底层代码;解一层、看一层、再解下一层,每层存档(`layer_01.ps1` → `layer_02.ps1` …)。
|
||||
|
||||
**JS 常见编码函数(看到即解码目标)**:`unescape()`(URL 解码 %XX)、`String.fromCharCode()`(字符码数组)、`atob()`(Base64);十六进制 `\xHH` / Unicode `\uHHHH` 批量转义解码(`python3 -c "import sys; print(sys.argv[1].encode().decode('unicode_escape').decode(errors='replace'))" '<串>'`);`document.write` 换成打印。
|
||||
|
||||
**PowerShell -enc / IEX 链**:`-EncodedCommand` 后的 base64 解码注意 UTF-16LE:
|
||||
```powershell
|
||||
[System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String($encoded))
|
||||
```
|
||||
|
||||
**垃圾代码检测**(识别特征五条):
|
||||
- NOP sled
|
||||
- push/pop 成对出现、互相抵消
|
||||
- 运算结果为 0/恒等(算术垃圾)
|
||||
- 死写入:寄存器写入后、下次写入前从未被读
|
||||
- 无条件跳转到下一条指令
|
||||
|
||||
真实逻辑形如 `junk, junk, junk, CALL target, junk, junk`——提取所有真实调用目标、忽略周围噪音(可用脚本按 `call` 指令 + 垃圾目标过滤实现)。
|
||||
|
||||
**Hex 编码载荷**:hex 转字节后先试常见变换:逐字节减 1、XOR 单字节密钥(0x01 起递增试)。
|
||||
|
||||
**常见解码链模式**:`base64 decode → gzip decode → reverse → base64 decode`;每层输出用 `file` 判断类型并验证可读性;验证失败说明层序或编码判断错,回退一层重试。
|
||||
|
||||
## 高级混淆对抗(商业混淆器)
|
||||
|
||||
JScrambler 类商业混淆器的手法与对抗:
|
||||
|
||||
- **特征识别**:bootstrap 加载器(自执行入口)、字符串表隐藏(数组 + 索引引用)、`_0x` 变量重命名模式、函数体加密(运行时解密)
|
||||
- **控制流平坦化(CFF)对抗**:dispatcher 识别(switch 分发中心)→ 状态变量追踪 → 分支还原为顺序/条件结构(方法衔接 [[re-deobfuscate]])
|
||||
- **字符串加密对抗**:隐藏字符串表定位(解码函数调用点)→ 运行时提取(沙箱内执行解码函数取值,见 [[re-sandbox]])或静态还原(解码循环脚本化)
|
||||
- **死代码注入对抗**:无引用函数过滤(按调用关系,无调用者即候选删除)
|
||||
- 工具链:js-beautify 美化 → 按手法选对抗路径;动态侧沙箱执行取值(默认沙箱原则)
|
||||
|
||||
## 跨域联合
|
||||
|
||||
- [[re-managed]]:网关工作流步骤②(反编译)③(去混淆)固定调用本技能
|
||||
- [[re-malware]]:恶意脚本/钓鱼宏样本路径(docm/ps1/js 附件 → 沙箱行为 + 本技能还原载荷)
|
||||
- [[re-sandbox]]:一切动态执行(跑脚本、开宏)强制前置,见 [[re-analyze/platform-tips]] 默认沙箱原则
|
||||
- 配套:[[re-triage]](初勘)、[[re-ioc]](提取脚本中的 C2 域名/URL 作为 IOC)、[[re-protocol]](脚本下载的回连流量)
|
||||
|
||||
## 常见坑与陷阱
|
||||
|
||||
- **混淆层层嵌套需耐心逐层解**:现象——解了一层又一层、感觉没完;原因——多层混淆叠加(编码+拼接+执行链)是常态;对策——逐层解、每层存档编号、解完重跑识别,别跳层也别想一步到位
|
||||
- **olevba 提取后仍是混淆的**:现象——`olevba -c` 提取的宏还是满屏 `Chr(65) & Chr(66)` 拼接;原因——olevba 只负责提取不负责还原;对策——用 `--decode` 自动解常见手法,剩余手动还原,最后动态验证还原结果正确
|
||||
- **恶意脚本必须沙箱内运行**:现象——本地直接 `pwsh sample.ps1` 后系统被改/发生外联;原因——脚本可能是下载器或持久化植入(`platform-tips` 默认沙箱原则的典型违例场景);对策——一切动态执行进 [[re-sandbox]](网络隔离 + 快照),静态解码可免沙箱
|
||||
- **正则盲改易破坏脚本结构**:现象——sed 全局替换后语法错误、下一层解不出来;原因——混淆串内部包含被替换的模式、字符串字面量被误伤;对策——优先 AST/结构化解析(PowerShell AST、JS 括号匹配),每次替换后先做语法检查(`pwsh -NoProfile -Command "[scriptblock]::Create((Get-Content layer.ps1 -Raw))"` / `node --check layer.js`)再进入下一步
|
||||
- **webpack 打包定位签名函数**:现象——搜 "sign" 结果太多;原因——打包压缩变量名;对策——搜特征串(`sign=`)或用网络面板 initiator 列回溯发起请求的调用栈(比搜源码快)
|
||||
- **本地复现结果不一致**:现象——签名逻辑对但服务端不认;原因——参数排序/时间戳精度不对;对策——核对源码 sort 逻辑(按 key 字母序 + 特殊字符规则);时间戳用 `Math.floor(Date.now() / 1000)`(秒级)
|
||||
- **密钥在另一 chunk**:现象——签名函数里找不到密钥;原因——密钥经 require 从其他 chunk 引入;对策——签名函数断点处 console.log 打印密钥变量
|
||||
(来源:reverse-skill field-journal,MIT)
|
||||
- **转译产物先还原再分析**:现象——JS 里看到 `var state=0; while(true){switch(state){…}}` 状态机循环或 `_asyncToGenerator(function*(){…})` 包装,逻辑像一团乱麻;原因——generator/async 被 Babel/Regenerator 等转译链降级为状态机与包装器,源级语义被机械摊平;对策——识别「真常量条件 while + 单 switch 体」模式后按 case 顺序展平为线性语句,人工状态变量随之消失;async 则先全程序扫描出被包装的 generator 函数,再把函数体内 Yield 还原为 Await 并内联包装器;先看 helper 函数名确认转译链(Babel/Regenerator 等各有特征指纹),针对已知工具链写反变换,比通用还原更省力
|
||||
(来源:hermes-decomp(SymbioticSec),MIT)
|
||||
- **补丁前先算清改动长度**:现象——改完的脚本/bundle 无法运行或结构表解析错乱;原因——同长改动可以原位覆写,变长改动会牵动后续全部偏移与结构段,未联动修正就会写坏文件;对策——同长→原位覆写,不动结构表;变长→重建受影响的结构段(如字符串表)并搬迁后续段、联动修正所有偏移;共享存储/重叠引用的数据一律拒绝补丁;补丁后重新解析一遍结构表做一致性校验,不一致即回滚——不支持的场景显式报错,绝不停工写坏文件(通用规则详见 [[re-hybrid-app]] 对应坑条目,Hermes 具体布局见该技能;来源:hermes-decomp(SymbioticSec),MIT)
|
||||
Reference in New Issue
Block a user