mcpField
D
dsl-vm-reverse

dsl-vm-reverse

github.com/zhaoxuya520セキュリティ43.7k76 回インストール5 週間前に更新
リポジトリ

dsl-vm-reverse について

JavaScript 製のカスタム DSL 仮想マシンやリスク制御エンジンを解析するリバースエンジニアリング向けスキルです。標準 WASM や通常のバンドルと区別しながら、ファイル判定、opcode と定数テーブルの分析、エクスポート関数の追跡、必要に応じたランタイム注入を進めます。

主な機能

  1. 01カスタム DSL VM の特徴判定
  2. 02変数マッピングと opcode の抽出
  3. 03定数テーブル参照の分析
  4. 04エクスポート関数と呼び出し経路の追跡
  5. 05静的解析を補うランタイム注入
  6. 06標準 WASM と通常の JavaScript の区別

活用シーン

  1. 01不審な圧縮 JavaScript ファイルの分類
  2. 02カスタムインタープリターの命令構造の分析
  3. 03リスク制御エンジンのエクスポート関数の特定
  4. 04静的解析で不足する場合のランタイムデータ取得

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/zhaoxuya520/reverse-skill --skill dsl-vm-reverse

インストール後、Claude Code で/dsl-vm-reverseを入力して読み込まれたか確認します。

詳細

🔄 DSL カスタム仮想マシンリバースエンジニアリング(DSL VM Reverse Engineering)

ACTION REQUIRED(読了後すぐに実行)

  1. NOW: 現在のタスクがカスタム JS opcode VM / リスクコントロールエンジンであり、標準 WASM や通常の webpack ではないことを確認する
  2. NOW: scope.md が整うまで case-init;オフラインサンプルは offline / lab を使用
  3. ACT: 「3. 汎用リバースエンジニアリングワークフロー」の Phase 1 からファイル分類を実施し、ディレクトリで止まらない

JavaScript ベースで実装されたカスタム WASM 仮想マシン / リスクコントロールエンジンをリバースエンジニアリングするために使用します


目次


1. 適用範囲

対象ファイルが以下の いずれかの特徴 に該当する場合に本 skill を使用します:

#特徴説明
1IIFE 冒頭 + 大量の1文字変数名!function(){var U=void 0,y=parseInt,E0=Function,...}
2DG() または類似の関数に switch-case ループが含まれるインタプリタのメインループ、d[7]&31 で opcode をデコード
3大きなファイル(500KB+)だがゼロバイト占有率 < 1%非標準 WASM、純粋な JS
4C[number] 定数テーブル参照を含むC[9][xxx] 関数テーブル/文字列テーブル
5単一行に圧縮されたコード583KB の単一行、難読化された変数名
除外ルール
条件本 skill の対象外移動先
ファイルが \x00asm で始まる標準 WASM バイナリreverse-engineering/languages.md
ファイルが Uint8Array([0,97,115,109]) を含み WASM マジックワードがあるWASM 埋め込み.wasm を抽出後、IDA/Ghidra へ
標準 Webpack バンドル(function(e,t,n){...})通常の JSjs-reverse/
ゼロバイト占有率 > 20%WASM バイナリreverse-engineering/languages.md

2. DSL VM の識別特徴

コードの特徴
// 特征 1: IIFE 入口,单字母变量映射数字常量
!function(){
    var U=void 0, y=parseInt, E0=Function, AN=Uint8Array;
    var E=15, l=10, m=12, x=16, S=13, $=11;
    // 数字常量映射为变量名,替代原始数字
    ...
}

// 特征 2: 解释器主循环 DG()
function DG(C, d, ...) {
    var d = [];  // 数组模拟 WASM stack/locals
    for (d[7] = x; d[7] !== U;) {
        var aE = d[7] & 31;         // 低 5 位 = opcode
        var O = d[7] >> 5 & 31;      // 高 5 位 = sub-operation
        switch (aE) {
            case 0: /* ... */ d[7] = 612; break;
            case 1: /* ... */
            // ... N 个 case
        }
    }
}

// 特征 3: 常量表 C[9] 存储函数索引和字符串
// C[9][0] = ["pc"]      → 函数参数描述
// C[9][667] = "string"  → 字符串常量
// C[9][x] = number      → 函数索引

// 特征 4: W(C[index], null, ...) 调用模式
// W = Function.prototype.call.bind(call)
// 所有内置函数通过 C[index] 索引调用

// 特征 5: 指令编码格式
// d[7] = opcode(bit 0-4) | subop(bit 5-9) | operand(bit 10+)
Opcode のエンコード形式

各命令は 32 ビット整数としてエンコードされます:

bit 0-4:   opcode (0-N)
bit 5-9:   sub-operation (0-31)
bit 10-31: operand/立即数

解码:
  aE = d[7] & 31        → opcode
  O  = d[7] >> 5 & 31   → sub-operation
  d[other] = d[7] >> 10  → operand

3. 汎用リバースエンジニアリングワークフロー

Phase 1: ファイル分類(5 分)
# 检查是否为 DSL VM
python3 << 'EOF'
with open('target.js', 'rb') as f:
    head = f.read(100)

# 1. 检查 WASM 魔术字
if head[:4] == b'\x00asm':
    print("标准 WASM 二进制")
    exit()

# 2. 检查零字节占比
data = open('target.js', 'rb').read()
zero_pct = data.count(b'\x00') / len(data) * 100
print(f"零字节占比: {zero_pct:.1f}%")

if zero_pct > 20:
    print("WASM 二进制")
elif head[:2] == b'!f':
    # 检查单字母变量模式
    if b'var U=void 0' in head or b'U=void 0,y=parseInt' in head:
        print("→ DSL VM!")
    else:
        print("普通 JS IIFE")
EOF
Phase 2: 変数マッピングテーブルの抽出(10 分)
import re

with open('target.js', 'r', errors='replace') as f:
    s = f.read()

# 提取开头 2000 字符的 var X=数字 映射
mappings = re.findall(r'var\s+(\w+)\s*=\s*(\d+)', s[:2000])
print('常量映射:')
for name, val in mappings:
    print(f"  {name:4s} = {val:3d} (0x{int(val):02x})")
Phase 3: Opcode の抽出と分類(15 分)
# 1. 提取所有 case
all_cases = re.findall(r'case\s+(\d+):', s)
unique = sorted(set(int(c) for c in all_cases))

print(f"总 case: {len(all_cases)} 个")
print(f"唯一 opcode: {len(unique)} 个: {unique}")

# 2. 分类每个 opcode
for op in unique:
    idx = s.find(f'case {op}:')
    snippet = s[idx:idx+200]
    if 'd[7]=' in snippet:
        op_type = 'BRANCH'
    elif 'return' in snippet:
        op_type = 'RETURN'
    elif 'W(C[' in snippet:
        op_type = 'CALL'
    elif 'new' in snippet:
        op_type = 'ALLOC'
    elif 'try' in snippet or 'catch' in snippet:
        op_type = 'EXCEPTION'
    else:
        op_type = 'ARITH/STORE'
    print(f"  opcode {op:2d}: {op_type}")
Phase 4: 定数テーブルの分析(30 分)
const_refs = re.findall(r'C\[9\]\[(\d+)\]', s)
unique_refs = sorted(set(int(x) for x in const_refs))

print(f"C[9] 引用: {len(unique_refs)} 个索引")
print(f"范围: {min(unique_refs)} - {max(unique_refs)}")

# 对每个引用分析上下文
for ref in unique_refs[:20]:
    idx = s.find(f'C[9][{ref}]')
    ctx = s[max(0,idx-50):idx+80]
    clean = ''.join(c if c.isprintable() else ' ' for c in ctx)
    print(f"  C[9][{ref}] → {clean}")
Phase 5: エクスポート関数の追跡(1〜2 時間)

エクスポート関数(例: getToken)は以下のパスで特定します:

1. 找 AWSCInner.register() 或类似注册调用
2. 确定注册的模块和工厂函数
3. 找工厂函数返回的对象 → 导出函数定义位置
4. 若函数名不在 JS 中 → 在 C[9] 常量表中作字节码存储
5. 追踪调用链:
   AWSCInner._modules['fy'].getToken()
   → W(C[函数索引], null, ...)
   → DG() 解释器执行编码后的指令序列
Phase 6: ランタイムインジェクション(純粋な静的解析では不十分な場合)
// 注入最小 AWSC 兼容环境
const fakeEnv = {
    AWSCInner: {
        _modules: {},
        register(name, moduleName, factory) {
            this._modules[moduleName] = factory();
        }
    }
};

// 执行 DSL VM 代码
dslVmCode();

// 获取导出
const token = fakeEnv.AWSCInner._modules['fy'].getToken({});

4. Opcode の抽出と分類

参考 opcode 対照表(既存事例に基づく)
Opcode操作タイプ特徴
0BRANCHd[7]=xxx 無条件ジャンプ
1CALLW(C[Y],null,function(){...}) 埋め込み関数呼び出し
2ARITHd[4]=0, d[7]=72 変数代入
3ARITHd[0]=d[1][C[x]], d[5]=d[0]<d[3] 比較演算
4STOREd[8]=d[5]in d[4] プロパティアクセス/存在チェック
5ARITHd[8]=d[4]-d[8] 算術演算
6RETURNreturn gV, throw 戻り値/例外スロー
7ALLOCd[6]=[], d[6][C[8]](...) push 操作
8BRANCHd[7]=d[k]?512:425 条件ジャンプ
9STRINGd[6][C[t]]=d[m], new fh(...) 正規表現
10ALLOC関数引数の準備、コールスタックの作成
11STRINGnew fh("\\s",d[5]) 正規表現マッチング
12STOREP[d[9]]=d[4][C[H]](d[3]) データ転送
13CALLC[9][113]=d[9] モジュール初期化
14STRINGd[8]=d[9]+d[m] 文字列連結
15RETURNreturn EL; 関数リターン
16ALLOCvar r,P,Z,B... ローカル変数宣言
17ALLOC(Z=[])[C[8]](69,T,445) 静的配列の初期化
18TABLE関数テーブル/型テーブルの初期化
19EXCEPTIONtry{for(var RK=x;... try-catch ループ
20DOMIs[d[o]] DOM 操作
21STOREグローバル/オブジェクトプロパティの安全な取得
22STRINGnew fh(r,v) 文字列/正規表現処理
23BRANCHtry...catch 安全な取得 + 条件ジャンプ
24CALLW(C[2],null,8,z,FL) 多引数関数呼び出し
25EXCEPTIONtry{...}catch(C){...} 例外キャプチャ + ジャンプ

5. ランタイムキャプチャ方案

方案 A: Selenium + CDP ネイティブイベント(推奨、成功率が最も高い)
from selenium import webdriver

driver = webdriver.Chrome()

# 注入反检测
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
    "source": r"""
        Object.defineProperty(navigator, 'webdriver', {get: () => false});
        Object.defineProperty(navigator, 'plugins', {get: () => [1,2,3,4,5]});
        Object.defineProperty(navigator, 'languages', {get: () => ['zh-CN','zh','en']});
    """
})

# 发送 CDP 原生鼠标事件
driver.execute_cdp_cmd("Input.dispatchMouseEvent", {
    "type": "mousePressed",
    "x": 549.5, "y": 441.2,
    "button": "left", "buttons": 1,
    "clickCount": 1, "pointerType": "mouse"
})
方案 B: Playwright ヘッドレスブラウザ
const { chromium } = require('playwright');

async function run() {
    const browser = await chromium.launch();
    const page = await browser.newPage();

    // 拦截网络请求
    await page.route('**/api/**', async route => {
        await route.continue_();
    });

    await page.goto('https://target-page.com');

    // 等待 DSL VM 初始化
    await page.waitForFunction(() => {
        return window.AWSCInner &&
               window.AWSCInner._modules &&
               window.AWSCInner._modules['fy'];
    });

    // 执行操作
    await page.mouse.move(500, 400);
    await page.mouse.down();
    // ... 操作序列
    await page.mouse.up();
}
方案 C: 純粋なプロトコル検証(成功率が極めて低い)

DSL VM が生成する token は通常、ブラウザコンテキストと強く結びついています(TLS JA3 フィンガープリント、IP、Cookie、リクエストヘッダーなど)。ブラウザから切り離すと、サーバー側でコンテキストの不一致を検出できます。純粋なプロトコル方案は推奨しません。


6. よくあるステータスコード

Code意味対応
0検証通過 ✅sessionId + sig を取り出す
300リスクコントロールによるブロックブロックされ、通過不可
8778検証失敗、リトライが必要操作をリトライ
8776操作が速すぎる、リトライが必要遅延を追加してリトライ
69634汎用失敗パラメータが正しいか確認

7. Skill セルフチェックリスト

  • DSL VM の識別(IIFE + 1文字変数 + DG() インタプリタ)を完了したか?
  • 変数マッピングテーブル(var X=数字)を抽出したか?
  • opcode リストを抽出して分類したか?
  • 定数テーブル C[9] の参照範囲を分析したか?
  • エクスポート関数の登録ポイントを特定したか?
  • 純粋な静的解析では不十分な場合、ランタイムインジェクション方案を試したか?
  • タスク完了後に field-journal へ書き戻したか?
  • 新しいツール/新しいシナリオを発見 → routing.md を更新したか?

ルーティング登録

タイプルート
対象タイプ: WASM / DSL VM / カスタム命令セットreverse-engineering/dsl-vm-reverse/SKILL.md
ユーザー意図: "DSL VM / リスクコントロールエンジンのリバースエンジニアリング"本 skill
ツールチェーン: Playwright / Selenium CDPブラウザインジェクション方案
パスの交差
DSL VM 逆向路径:
  reverse-engineering/dsl-vm-reverse/ → Phase 1-6 工作流
  ↓ 若需要捕获运行时数据
  browser-automation/ → Playwright/Selenium CDP
  ↓ 若需要分析 API 协议层
  js-reverse/ → Observe→Capture→Rebuild

コメント