バイナリの深淵を制御せよ:ADODB.Streamによる「外科手術的」パッチ技術
レガシーシステムの保守において、テキストベースのコンフィグファイルなどという甘美なものは存在しない。そこにあるのは、仕様書も失われた`.dat`や`.bin`の無機質なバイトの羅列だ。
多くのエンジニアは、バイナリファイルを前にして「専用ツールがない」「解析不能」と匙を投げる。だが、VBScriptを骨の髄まで理解した我々にとって、バイナリは単なるメモリ上のバイト配列に過ぎない。今日は、OS標準の`ADODB.Stream`を駆使し、巨大なバイナリファイルから特定のシグネチャを索敵し、直接書き換える「外科手術」の手法を伝授する。
—
1. なぜ ADODB.Stream なのか
VBScriptでファイルを扱う際、`Scripting.FileSystemObject (FSO)` を使うのは素人だ。`FSO`はテキスト処理には適しているが、バイナリの読み書きにおいて、その内部変換のオーバーヘッドは致命的だ。
一方、`ADODB.Stream` は本来データベースのバイナリデータ(BLOB)を扱うために設計されている。これを用いる最大の利点は、「バイナリデータをメモリ上のバッファとして直接ロードし、バイト単位のオフセットアクセスが可能である」という点に尽きる。
—
2. 実装の核心:バイトパターン検索と置換のロジック
バイナリパッチで最も重要なのは「検索」と「置換」の整合性だ。特に、パッチ後のデータ長が変化しない置換であれば、ファイルサイズを維持したまま、特定のバイトオフセットを上書きできる。
以下に、バイナリファイル内の特定シグネチャを検索し、別パターンのバイト列に置換するエンジンの雛形を示す。
バイナリパッチ実行スクリプト (`patcher.vbs`)
Option Explicit
‘ メモリ保護のため定数を定義
Const adTypeBinary = 1
Const adModeReadWrite = 3
Sub PatchBinaryFile(strFilePath, arrSearch, arrReplace)
Dim objStream
Set objStream = CreateObject(“ADODB.Stream”)
‘ ストリームの初期化とバイナリモード設定
objStream.Type = adTypeBinary
objStream.Open
objStream.LoadFromFile strFilePath
‘ バイナリを配列として抽出
Dim bData
bData = objStream.Read
‘ 検索と置換のロジック
Dim i, j, bMatch
For i = 0 To UBound(bData) – UBound(arrSearch)
bMatch = True
‘ シグネチャのマッチングチェック
For j = 0 To UBound(arrSearch)
If bData(i + j) <> arrSearch(j) Then
bMatch = False
Exit For
End If
Next
‘ 置換実行
If bMatch Then
For j = 0 To UBound(arrReplace)
bData(i + j) = arrReplace(j)
Next
‘ 連続置換を防ぐ場合はここでExit For
End If
Next
‘ ストリームをクリアして書き戻し
objStream.Position = 0
objStream.Write bData
objStream.SetEOS ‘ データの末尾を確定
objStream.SaveToFile strFilePath, 2 ‘ 2 = adSaveCreateOverWrite
‘ オブジェクトの明示的解放(メモリ管理の鉄則)
objStream.Close
Set objStream = Nothing
End Sub
‘ 使用例: 0x41 0x42 を 0x58 0x59 に置換
Dim searchPattern: searchPattern = Array(&H41, &H42)
Dim replacePattern: replacePattern = Array(&H58, &H59)
PatchBinaryFile “C:\data\target.bin”, searchPattern, replacePattern
—
3. シニアエンジニアが意識すべき「極限の知見」
このコードをそのまま現場に投入するにあたり、以下の3点に留意してほしい。
① メモリオーバーヘッドへの警戒
`objStream.Read` はファイル全体をメモリにロードする。数GB単位のファイルを扱う場合、この方法は `OutOfMemory` を招く。巨大なファイルに対しては、`Stream.Read(Size)` を用いてバッファを分割し、ストリーミング処理で再帰的に検索するアーキテクチャへの昇華が必要だ。
② シグネチャの衝突(False Positive)
バイナリの検索において、置換対象のシグネチャが意図しない箇所に存在する可能性を常に考慮せよ。検索対象のバイト列には、必ず前後の文脈(オフセットの特定やヘッダーとの距離)を含めること。
③ システム環境の保守性
VBScriptは現在、レガシーなOS環境で動くことが多い。`ADODB.Stream` は `msado15.dll` に依存している。環境によっては `ActiveX Component Can’t Create Object` が発生する場合がある。その際は `regsvr32 msado15.dll` が正しく登録されているかを確認し、必要であれば `COM` の依存関係を管理するドキュメントをチーム内に残せ。
—
結びに代えて
バイナリを直接叩くということは、システムの心臓部にメスを入れる行為だ。ドキュメントが存在しないブラックボックスに対し、バイナリの構造を読み解き、論理的帰結としてパッチを当てる。これは現代の開発者が忘れ去った「エンジニアの矜持」そのものだ。
スクリプトを走らせる前に、必ずバイナリのバックアップを取ること。そして、置換後の動作確認にはプロトコルアナライザやデバッガを併用せよ。これこそが、VBScriptを支配する者の流儀である。
