針對微軟 screnc.exe (Scripting.Encoder) 編碼的 .vbe/.jse/.asp/.hta 等檔案,提供純 VBScript 解碼器實現。支援單檔多腳本區塊解碼、命令列/介面雙模式、標準輸出/訊息框雙輸出。
' === decovbe.vbs ===
Option Explicit
Dim oArgs, srcFile
Set oArgs = WScript.Arguments
srcFile = ""
Select Case oArgs.Count
Case 0 ' GUI 模式:選擇檔案對話框
srcFile = BrowseForFolder("Choose an encoded file", &H4031, &H0011)
Case 1
If InStr(oArgs(0), "?") = 0 Then srcFile = oArgs(0)
Case Else
WScript.Echo "Too many parameters"
End Select
Set oArgs = Nothing
If srcFile <> "" Then
Dim fso, file, content
Set fso = CreateObject("Scripting.FileSystemObject")
If fso.FileExists(srcFile) Then
Set file = fso.OpenTextFile(srcFile, 1)
content = file.ReadAll
file.Close
Set file = Nothing
Const TAG_START = "#@~^"
Const TAG_END = "==^#~@"
Dim posStart, posEnd
Do
posEnd = 0
posStart = InStr(content, TAG_START)
If posStart > 0 Then
' 驗證長度標記:TAG_START 後 10 字元為 "=="
If (InStr(posStart, content, "==") - posStart) = 10 Then
posEnd = InStr(posStart, content, TAG_END)
If posEnd > 0 Then
' 提取編碼區塊:跳過 4+8=12 字元頭部,結束前 6 字元尾部
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
Else
WScript.Echo srcFile & " not found"
End If
Set fso = Nothing
Else
WScript.Echo "Please give a filename"
WScript.Echo "Usage: " & WScript.FullName & " " & WScript.ScriptFullName & " "
End If
' === 解碼核心 (同 decode.vbs) ===
Function DecodeBlock(encoded)
Dim se, i, c, j, index, temp
Dim decodeMap(127)
Const COMB = "1231232332321323132311233213233211323231311231321323112331123132"
Set se = CreateObject("Scripting.Encoder")
For i = 9 To 127: decodeMap(i) = "JLA": Next
For i = 9 To 127
temp = Mid(se.EncodeScriptFile(".vbs", String(3, Chr(i)), 0, ""), 13, 3)
For j = 1 To 3
c = Asc(Mid(temp, j, 1))
decodeMap(c) = Left(decodeMap(c), j-1) & Chr(i) & Mid(decodeMap(c), j+1)
Next
Next
decodeMap(42) = Left(decodeMap(42), 1) & ")" & Right(decodeMap(42), 1)
Set se = Nothing
encoded = Replace(Replace(encoded, "@&", Chr(10)), "@#", Chr(13))
encoded = Replace(Replace(encoded, "@*", ">"), "@!", "<")
encoded = Replace(encoded, "@$", "@")
index = -1
For i = 1 To Len(encoded)
c = Asc(Mid(encoded, i, 1))
If c < 128 Then index = index + 1
If (c = 9) Or ((c > 31) And (c < 128)) Then
If (c <> 60) And (c <> 62) And (c <> 64) Then
encoded = Left(encoded, i-1) & Mid(decodeMap(c), Mid(COMB, (index Mod 64) + 1, 1), 1) & Mid(encoded, i+1)
End If
End If
Next
DecodeBlock = encoded
End Function
' === 檔案選擇對話框 ===
Function BrowseForFolder(prompt, browseType, location)
Dim shell, folder, path
Set shell = CreateObject("Shell.Application")
On Error Resume Next
Set folder = shell.BrowseForFolder(0, prompt, browseType, location)
path = folder.ParentFolder.ParseName(folder.Title).Path
If Err.Number <> 0 Then path = ""
Set folder = Nothing: Set shell = Nothing
BrowseForFolder = path
End Function
' 命令列模式 (CScript 輸出至 stdout,可重導向)
cscript //nologo decovbe.vbs encoded.vbe > decoded.vbs
' GUI 模式 (WScript 彈出選擇對話框,結果以訊息框顯示)
wscript decovbe.vbs
' 批次解碼資料夾所有 .vbe
for %f in (*.vbe) do cscript //nologo decovbe.vbs "%f" > "%~nf.vbs"
' 編碼區塊結構:
' #@~^ : 固定起始標記 (4 bytes)
' [Base64-like Length] : 8 字元,編碼內容長度/校驗
' [Encoded Script] : 實際編碼腳本內容
' ==^#~@ : 固定結束標記 (6 bytes)
' 多腳本檔案範例 (HTML 中內嵌 VBScript + JScript):
'
'
' 解碼器迴圈可依序處理所有區塊
| 階段 | 技術細節 | 關鍵洞察 |
|---|---|---|
| 映射表建構 | 窮舉 ASCII 9-127,編碼 3 字元,觀察輸出建構反向表 | 利用 Encoder 確定性,無需逆向工程 XOR 密鑰 |
| COMB 序列 | 長度 64 週期字串 "123123233232..." | 決定每字元使用映射表第 1/2/3 位,增加靜態分析熵 |
| 特殊轉義 | @& → LF, @# → CR, @* → >, @! → <, @$ → @ | 保護標記字元不出現於編碼資料中 |
| Bug 修正 | decodeMap(42) 強制 ')' 防止誤解為 '>' | Encoder 某版本對 ')' 編碼有缺陷 |
| 副檔名 | 原始類型 | 編碼後標記 | 解碼支援 |
|---|---|---|---|
| .vbe | VBScript | #@~^ | ✓ 完整 |
| .jse | JScript | #@~^ | ✓ 完整 |
| .asp | ASP (VBS/JS) | #@~^ | ✓ 區塊級 |
| .hta | HTA | #@~^ | ✓ 區塊級 |
| .htm/.html | HTML + 腳本 | #@~^ | ✓ 區塊級 |
| .wsf | Windows Script File | #@~^ | ✓ 區塊級 |
screnc.exe 原版算法 (XOR + Base64-like),不支援第三方加殼器。#!/usr/bin/env python3
import sys, re, base64
COMB = "1231232332321323132311233213233211323231311231321323112331123132"
def build_decode_map():
# 需要 Windows 環境執行 Encoder COM 物件,或預計算映射表
# 此處略過,實際可移植上述 VBScript 邏輯
pass
def decode_vbe(content):
pattern = re.compile(r'#@~\^(.+?)==\^#~@', re.DOTALL)
def replace(match):
encoded = match.group(1)[8:-6] # 移除長度標記
return decode_block(encoded)
return pattern.sub(replace, content)
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: python decode.py encoded.vbe")
sys.exit(1)
with open(sys.argv[1], 'r', encoding='utf-8', errors='ignore') as f:
content = f.read()
print(decode_vbe(content))
合法使用場景:
- 自有腳本遺失原始碼、需恢復維護
- 授權代碼審計、安全評估
- 惡意腳本分析 (沙箱環境)
- 教學研究、編碼格式逆向工程學習
違法風險:
- 破解商業軟體授權檢查腳本
- 繞過 DRM/加殼保護
- 違反 DMCA 1201 / 當地反繞過法條
- 侵犯軟體著作權、許可協議
原則:技術中立,用途定性。僅對合法授權、自有、公開研究樣本使用本工具。
歷史註記:Jean-Luc Antoine (2001) 首發此解碼器,展示了腳本編碼而非加密的本質。微軟隨後在 Windows Script 5.6+ 加強編碼,但基本架構未變。現代開發已棄用 VBScript/JScript,轉向 PowerShell/JavaScript/TypeScript,編碼混淆需求由javascript-obfuscator、PyArmor、Dotfuscator等現代工具滿足。