【オンメモリ動的コード組み立て】ファイル作成を行わないセキュリティに配慮した動的スクリプト実行技術
レガシーシステムの保全、あるいはエンドポイントのセキュリティ管理において、VBScript(Visual Basic Scripting Edition)は今なお死なない実用技術の一つである。しかし、EDR(Endpoint Detection and Response)や次世代アンチウイルス(NGAV)が高度化した現代において、スクリプトファイルを一時的にでもローカルディスク(特に `%TEMP%` など)へ書き出すアプローチは、セキュリティポリシー上、極めてハイリスクな悪手とみなされる。
「ディスクに書き込まず、メモリ上でコードを組み立て、そのまま評価・実行する」
この要件を満たす鍵が、VBScriptのコアに潜む `Execute` および `ExecuteGlobal` メソッド、そしてWSHの実行コンテキストの完全な掌握である。本稿では、ファイルレス実行の極限と、それを支えるメモリ管理・動的評価の深淵を解説する。
—
1. なぜ「ファイルレス動的実行」が必要なのか
エンタープライズ環境において、VBScriptを用いた自動化スクリプトの動的生成(例えば、動的に変化するAPIエンドポイントや接続文字列をコードに埋め込んで実行するケースなど)は珍しくない。しかし、従来の「文字列を `.vbs` ファイルとして一時保存し、`WScript.Shell` の `Run` や `cscript.exe` でキックする」手法には、致命的な欠陥がある。
- I/Oボトルネック: ディスクへの書き込みと読み込みが発生し、パフォーマンスを著しく阻害する。
- アンチウイルスの誤検知(False Positive): ディスク上に生成された未知のスクリプトは、ファイルスキャンのトリガーとなり、隔離されるリスクが高い。
- フォレンジック上の脆弱性: 処理が中断・終了したあとも、ディスクの空き領域(Slack Space)にスクリプトの平文が残存し、情報漏洩の温床となる。
メモリ上でコードを生成し、VBScriptのランタイムコンテキストへ直接流し込むオンメモリ動的コード組み立ては、これらすべての課題を根底から解決する唯一のアーキテクチャである。
—
2. `Execute` と `ExecuteGlobal` のメカニズムと限界
VBScriptには、実行時に文字列をコードとして評価する機能がネイティブで備わっている。
- `Execute メソッド`: 呼び出されたプロシージャのスコープ内でコードを評価する。変数や関数はローカルスコープに閉じる。
- `ExecuteGlobal メソッド`: グローバルスコープに変数や関数をインジェクトする。動的に関数を定義して後続から呼び出す場合はこちらが必須となる。
しかし、これらのメソッドは万能ではない。最大のリスクは「シンタックスエラーが実行時まで検知されないこと」、そして「型安全性やIntelliSenseの恩恵を一切受けられないこと」である。したがって、組み立てる文字列は厳密なロジックに基づき、動的構築中のエスケープ漏れや構文崩壊を防ぐ設計が求められる。
—
3. 【実装】ファイル作成を一切行わないオンメモリ動的実行エンジン
以下のコードは、ディスクへの書き込みを一切行わず、実行時に動的な設定を反映したコードブロックをメモリ上で組み立て、`ExecuteGlobal` を用いて安全に評価・実行する実用サンプルである。
‘ ==============================================================================
‘ 致命的なまでの安全性を誇るファイルレス・オンメモリコード実行エンジン
‘ Architecture: VBScript Memory-Eval Pattern
‘ ==============================================================================
Option Explicit
Sub Main()
Dim dynamicCode
Dim apiEndpoint, timeoutSec
‘ 1. 動的に変化するパラメータ(外部APIやDBから取得したと仮定)
apiEndpoint = “https://api.internal.enterprise.local/v1/sync”
timeoutSec = 45
‘ 2. メモリ上で実行するVBScriptコードを文字列として完全に構築する
‘ ※ディスクへの書き込みは1バイトたりとも発生しない
Set dynamicCode = CreateObject(“Scripting.Dictionary”)
dynamicCode.Add 1, “Dim g_ExecutionResult”
dynamicCode.Add 2, “Function InvokeDynamicProcess()”
dynamicCode.Add 3, ” Dim objHttp”
dynamicCode.Add 4, ” Set objHttp = CreateObject(“”MSXML2.ServerXMLHTTP.6.0″”)”
dynamicCode.Add 5, ” ”
dynamicCode.Add 6, ” ‘ 動的に埋め込まれたパラメータの利用”
dynamicCode.Add 7, ” objHttp.Open “”POST””, “”” & apiEndpoint & “””, False”
dynamicCode.Add 8, ” objHttp.setTimeouts 5000, 10000, ” & (timeoutSec 1000) & “, ” & (timeoutSec 1000)
dynamicCode.Add 9, ” objHttp.setRequestHeader “”Content-Type””, “”application/json”””
dynamicCode.Add 10, ” ”
dynamicCode.Add 11, ” On Error Resume Next”
dynamicCode.Add 12, ” objHttp.Send “”{“”action””: “”execute””}”””
dynamicCode.Add 13, ” If Err.Number <> 0 Then”
dynamicCode.Add 14, ” InvokeDynamicProcess = “”ERROR: “” & Err.Description”
dynamicCode.Add 15, ” Err.Clear”
dynamicCode.Add 16, “Else”
dynamicCode.Add 17, ” InvokeDynamicProcess = “”SUCCESS: Status “” & objHttp.status”
dynamicCode.Add 18, “End If”
dynamicCode.Add 19, ” On Error GoTo 0″
dynamicCode.Add 20, ” Set objHttp = Nothing”
dynamicCode.Add 21, “End Function”
‘ 3. Dictionaryから結合して一撃のスクリプト文字列を生成
Dim compiledScriptString
compiledScriptString = Join(dynamicCode.Items(), vbCrLf)
‘ 4. メモリ空間へのインジェクションと実行
On Error Resume Next
‘ グローバルスコープへ関数を展開
ExecuteGlobal compiledScriptString
If Err.Number <> 0 Then
WScript.Echo “[FATAL] オンメモリコンパイルエラー: ” & Err.Description
Exit Sub
End If
On Error GoTo 0
‘ 5. 動的生成された関数を通常通り呼び出し
Dim result
result = InvokeDynamicProcess()
WScript.Echo “[INFO] 実行結果: ” & result
‘ 6. オブジェクトの明示的解放(メモリリークの根絶)
Set dynamicCode = Nothing
End Sub
‘ エントリポイントのキック
Main()
—
4. チーフアーキテクトが教える:メモリ最適化とライフサイクルの極意
VBScriptはCOM(Component Object Model)ベースのランタイムであり、ガベージコレクション(GC)の挙動は .NET Framework のような世代別GCに比べてプリミティブである。特に動的コード評価を行う環境下では、以下の設計指針を厳守しなければならない。
① 参照の循環とメモリリークの防止
`ExecuteGlobal` 内で生成されたオブジェクト(上記コードにおける `MSXML2.ServerXMLHTTP.6.0` など)は、スコープの消滅時に解放されるが、グローバル空間に関数が常駐する場合、関数内で静的に参照されたCOMオブジェクトはプロセス終了まで解放されない危険性がある。
必ずプロシージャ内でローカル変数としてインスタンス化し、処理の終端で `Set obj = Nothing` を明示すること。
② 文字列連結のコスト管理
膨大なスクリプトを動的組み立てる際、`&` 演算子による単純な文字列結合をループ内で行うと、メモリの再割り当て(Reallocation)が頻発し、ヒープフラグメンテーションを引き起こす。
上記サンプルコードのように `Scripting.Dictionary` や配列に一度パーツを格納し、最後に `Join` 関数 一発でメモリブロックを構築する手法が、パフォーマンスとメモリ効率の観点から最も優れている。
③ エラーハンドリングの境界線
`Execute` / `ExecuteGlobal` の内部で発生した構文エラーや実行時エラーは、その評価を行っているコンテキストで `On Error Resume Next` が有効であっても、親ルーチンへ適切に伝播しないケースがある。動的コードの組み立てと実行の間には、必ず厳格な `Err` オブジェクトの監視コードを挟むべきである。
—
5. 総括
ファイルレスでの動的コード実行は、単なる「テクニック」にとどまらず、セキュリティ要件の厳しい近代インフラストラクチャにおいてVBScriptを生かし続けるための生命線である。
ディスクを汚さず、メモリの深淵でコードを錬成し、用が済めば跡形もなく消え去る――。
この領域までVBScriptの挙動をコントロールできて初めて、真のレガシー/自動化エンジニアと名乗ることができる。枯れた技術の底にある無限の可能性を、自身のコードベースで体感してほしい。
