微軟 Scripting.Encoder 物件提供 VBScript/JScript 原始碼「加密」(實為編碼混淆),生成 .vbe/.jse 檔案。本文提供官方編碼器封裝腳本,並深度解析手工解碼算法還原原始碼的完整 VBScript 實現。
' === encode.vbs:將 .vbs 編碼為 .vbe ===
If LCase(Right(WScript.FullName, 11)) = "wscript.exe" Then WScript.Quit(0)
If WScript.Arguments.Count < 2 Then
WScript.Echo "Usage: cscript //nologo encode.vbs source.vbs target.vbe"
WScript.Quit(1)
End If
srcFile = WScript.Arguments(0)
dstFile = WScript.Arguments(1)
Set fso = CreateObject("Scripting.FileSystemObject")
Set src = fso.OpenTextFile(srcFile, 1) ' ForReading
content = src.ReadAll
src.Close
' 核心:Scripting.Encoder.EncodeScriptFile
encoded = CreateObject("Scripting.Encoder").EncodeScriptFile(".vbs", content, 0, "VBScript")
fso.OpenTextFile(dstFile, 2, True).Write encoded ' ForWriting, Create
WScript.Echo "Encoded: " & dstFile
cscript //nologo encode.vbs myscript.vbs myscript.vbe
解碼器不依賴 Scripting.Encoder,純 VBScript 還原編碼邏輯,適用於無法使用 COM 物件的環境。
' === decode.vbs:將 .vbe 還原為原始碼 ===
Option Explicit
Dim oArgs, srcFile
Set oArgs = WScript.Arguments
If oArgs.Count = 0 Then
WScript.Echo "Usage: cscript //nologo decode.vbs encoded.vbe"
WScript.Quit(1)
End If
srcFile = oArgs(0)
Dim fso, file, content
Set fso = CreateObject("Scripting.FileSystemObject")
If Not fso.FileExists(srcFile) Then
WScript.Echo "File not found: " & srcFile
WScript.Quit(2)
End If
Set file = fso.OpenTextFile(srcFile, 1)
content = file.ReadAll
file.Close
' === 核心解碼邏輯 ===
Const TAG_START = "#@~^"
Const TAG_END = "==^#~@"
Dim posStart, posEnd
Do
posEnd = 0
posStart = InStr(content, TAG_START)
If posStart > 0 Then
' 檢查標記後 10 字元是否為 "=="
If (InStr(posStart, content, "==") - posStart) = 10 Then
posEnd = InStr(posStart, content, TAG_END)
If posEnd > 0 Then
' 提取編碼區塊:跳過 TAG_START(4) + 長度標記(8) = 12 字元
' 結束前 6 字元為 TAG_END
Dim encodedBlock
encodedBlock = Mid(content, posStart + 12, posEnd - posStart - 12 - 6)
' 解碼並替換
content = Left(content, posStart - 1) & DecodeBlock(encodedBlock) & Mid(content, posEnd + 6)
End If
End If
End If
Loop Until posEnd = 0
WScript.Echo content
' === 解碼核心函數 ===
Function DecodeBlock(encoded)
Dim se, i, c, j, index, temp
Dim decodeMap(127)
Const COMB = "1231232332321323132311233213233211323231311231321323112331123132"
' 1. 建構反向映射表:利用 Encoder 編碼已知字元推導對應關係
Set se = CreateObject("Scripting.Encoder")
For i = 9 To 127
decodeMap(i) = "JLA" ' 佔位,長度 3
Next
For i = 9 To 127
' 編碼 3 個相同字元 chr(i),提取編碼後的 3 字元(位置 13-15)
temp = Mid(se.EncodeScriptFile(".vbs", String(3, Chr(i)), 0, ""), 13, 3)
For j = 1 To 3
c = Asc(Mid(temp, j, 1))
' 將第 j 位映射回 chr(i)
decodeMap(c) = Left(decodeMap(c), j-1) & Chr(i) & Mid(decodeMap(c), j+1)
Next
Next
' 修正已知 Bug:')' (42) 可能被誤解碼為 '>' (62)
decodeMap(42) = Left(decodeMap(42), 1) & ")" & Right(decodeMap(42), 1)
Set se = Nothing
' 2. 預處理特殊轉義序列
encoded = Replace(Replace(encoded, "@&", Chr(10)), "@#", Chr(13)) ' LF, CR
encoded = Replace(Replace(encoded, "@*", ">"), "@!", "<") ' >, <
encoded = Replace(encoded, "@$", "@") ' @ 本身
' 3. 逐字元解碼
index = -1
For i = 1 To Len(encoded)
c = Asc(Mid(encoded, i, 1))
If c < 128 Then index = index + 1
' 僅處理可列印字元與 Tab,跳過 < > @ (已轉義)
If (c = 9) Or ((c > 31) And (c < 128)) Then
If (c <> 60) And (c <> 62) And (c <> 64) Then
' COMB 序列決定使用 decodeMap 中第幾個字元 (1/2/3)
Dim combIndex
combIndex = Mid(COMB, (index Mod 64) + 1, 1)
encoded = Left(encoded, i-1) & Mid(decodeMap(c), combIndex, 1) & Mid(encoded, i+1)
End If
End If
Next
DecodeBlock = encoded
End Function
' 編碼後檔案結構範例:
' #@~^AwQAAA==...編碼內容...==^#~@
' 標記結構:
' #@~^ : 固定起始標記 (4 bytes)
' AwQAAA== : 長度/校驗資訊 (8 bytes, Base64-like)
' ...編碼資料... : 實際編碼腳本內容
' ==^#~@ : 固定結束標記 (6 bytes)
| 階段 | 操作 | 關鍵點 |
|---|---|---|
| 編碼 | 逐字元 XOR 混淆 + Base64 類似編碼 + 特殊字元轉義 | 非加密,無金鑰,純混淆 |
| 解碼映射表建構 | 窮舉 ASCII 9-127 編碼 3 字元,觀察輸出建構反向查找表 | 利用 Encoder 確定性特性,無需逆向算法 |
| COMB 序列 | "123123233232..." 決定每字元使用映射表第 1/2/3 位 | 周期 64,增加靜態分析難度 |
| 特殊轉義 | @& → LF, @# → CR, @* → >, @! → <, @$ → @ | 避免編碼區塊中出現標記衝突字元 |
定性:Script Encoder 屬於源碼混淆,非加密。無金鑰、算法公開、可完全逆向。
用途:防止誤修改、隱藏邏輯細節、簡單授權檢查繞過門檻。
不可用於:保護機密演算法、金鑰儲存、知識產權核心邏輯。
ConvertTo-SecureString + ConvertFrom-SecureString (DPAPI 機器/用戶級加密);模組簽名 (Authenticode)。pkg 打包為二進制、bytenode V8 bytecode 編譯、javascript-obfuscator 混淆。Dotfuscator、ConfuserEx 混淆;核心邏輯編譯為 Native (AOT) 或放入 Azure Key Vault / HSM。' === batch_decode.vbs:批次解碼資料夾所有 .vbe ===
Dim fso, folder, file
Set fso = CreateObject("Scripting.FileSystemObject")
Set folder = fso.GetFolder(".")
For Each file In folder.Files
If LCase(fso.GetExtensionName(file.Name)) = "vbe" Then
WScript.Echo "Decoding: " & file.Name
Dim content, decoded
Set file = fso.OpenTextFile(file.Path, 1)
content = file.ReadAll
file.Close
' 呼叫上述 DecodeBlock 邏輯(需複製函數體)
decoded = DecodeFullContent(content)
fso.OpenTextFile(fso.GetBaseName(file.Name) & ".vbs", 2, True).Write decoded
End If
Next
WScript.Echo "Batch decode completed."
法律提醒:逆向工程、解碼他人受保護腳本可能違反軟體授權協議、DMCA 反繞過條款或當地法律。僅對自有代碼、授權代碼、安全研究(經許可)使用本工具。