Excel VBAでファイル解析(事前準備編)
■ファイル解析に使用するツール
ファイルを解析する際に必須のツールと言えば、まずはバイナリ・エディタということになりますが、実際に解析を進めるにあたっては、テキスト・ファイルに出力できた方が何かと便利です。
ということで、「ダンプ形式でテキストに落せるツール」の中で最も手軽に利用できる、certutil.exeについて詳細を説明します。
certutil.exeの使用法
certutil.exeはWindows標準コマンドなので、コマンド・プロンプトから「certutil」と打つだけで実行できます。
certutil.exeには多くのスイッチがありますが、「-encodehex」を指定すると、16進ダンプをテキスト・ファイルに出力してくれます。
コマンド・プロンプトから「certutil -encodehex -?」と入力すれば、使用法が表示されます(下図参照)。
- 使用法:
- CertUtil [オプション] -encodehex InFile OutFile [type]
- ファイルを 16 進数でエンコードします
- オプション:
- -f — 強制的に上書きします
- -Unicode — リダイレクトされた出力を Unicode として書き込む
- -UnicodeText — 出力ファイルを Unicode で書き込む
- -gmt — 時刻を GMT で表示します
- -seconds — 時間を秒とミリ秒で表示します
- -v — メッセージを詳細に表示します
- -privatekey — パスワードと秘密キーのデータを表示します
- -pin PIN — スマート カードの PIN
- -sid WELL_KNOWN_SID_TYPE — 数値 SID
- 22 — ローカル システム
- 23 — ローカル サービス
- 24 — ネットワーク サービス
出力ファイルの中身は、以下のようなイメージです。
- 0000 8e 67 97 70 96 40 3a 0d 0a 20 20 43 65 72 74 55 .g.p.@:.. CertU
- 0010 74 69 6c 20 5b 83 49 83 76 83 56 83 87 83 93 5d til [.I.v.V….]
- 0020 20 2d 65 6e 63 6f 64 65 68 65 78 20 49 6e 46 69 -encodehex InFi
- 0030 6c 65 20 4f 75 74 46 69 6c 65 20 5b 74 79 70 65 le OutFile [type
- 0040 5d 0d 0a 20 20 83 74 83 40 83 43 83 8b 82 f0 20 ].. .t.@.C….
■certutilの出力ファイルを整形するExcelツール
certutilの出力ファイルは、左端のオフセットの表示桁数が可変になっており、最初は4桁で表示されますが、値が大きくなると桁数が増えて行きます。
筆者はこれが気になって仕方がないため、以下のExcelツールで8桁に統一しています。
処理の概要
処理の流れは以下の通りです。
①入力ファイルと出力ファイルをオープン
②1行ずつレコードを入力し、オフセットの部分を編集した後、レコードを出力
③使用済のファイルをクローズ
サンプル・プログラム
行番号6~7で入力ファイルをオープンし、行番号8~9で出力ファイルをオープンしています。
行番号11~18がレコード単位の繰返し処理になっており、行番号12でレコードを入力し、行番号13~16でTAB(Chr(&H9))を空白に置換え、行番号17でレコードを出力しています。
行番号20~21でファイルをクローズしています。
- Dim num1, num2 As Integer
- Dim buf As String
- Dim pos As Long
- Private Sub Sample1()
- num1 = FreeFile
- Open “C:\xxx.txt" For Input As #num1
- num2 = FreeFile
- Open “C:\yyy.txt" For Output As #num2
- Do Until EOF(num1)
- Line Input #num1, buf
- pos = InStr(buf, Chr(&H9))
- If pos > 0 Then
- buf = Right(“0000″ & Left(buf, pos – 1), 8) & " " & Mid(buf, pos + 1)
- End If
- Print #num2, buf
- Loop
- Close #num2
- Close #num1
- End Sub
■BinaryFileクラスの詳細
筆者がExcel VBAでファイル解析を行う時に使用している、ファイル解析用の自作クラス・モジュールをご紹介します。
仮に「BinaryFileクラス」と名付けているものですが、本シリーズで紹介するサンプル・プログラムは、全てこのクラス・モジュールを使用しますので、少し詳しく説明を行います。
”勢いで作ったまま、真面目に見直しを行っていない”ため、稚拙なプログラムになっていますが、基本的な機能は充足していると思います。
BinaryFileクラスの入出力関連メソッド
BinaryFileクラスの入出力関連メソッドは、下表の通りです。
InputFileメソッド | |||||||||||
Sub InputFile(入力ファイルのパス As String) | |||||||||||
指定したファイルを配列に読み込み、CurrentPositionを0にセット | |||||||||||
OutputFileメソッド | |||||||||||
Sub OutputFile(出力ファイルのパス As String) | |||||||||||
指定したファイルを作成し、出力用配列のデータを書き出す | |||||||||||
TransferDataメソッド | |||||||||||
Sub TransferData(データ長 As Long) | |||||||||||
指定したデータ長のデータを出力用配列に転送する |
BinaryFileクラスのデータ転送系メソッド
BinaryFileクラスのデータ転送系メソッドは、下表の通りです。
GetDataメソッド | |||||||||||
Function GetData(データ長 As Long) As Long | |||||||||||
指定したデータ長のデータを整数型で返す | |||||||||||
GetDataCharメソッド | |||||||||||
Function GetDataChar(データ長 As Long) As String | |||||||||||
指定したデータ長のデータを文字列(String型)で返す | |||||||||||
GetDataHexメソッド | |||||||||||
Function GetDataHex(データ長 As Long) As String | |||||||||||
指定したデータ長のデータを16進文字列(String型)で返す | |||||||||||
GetDataNullメソッド | |||||||||||
Function GetDataNull(データ長 As Long) As String | |||||||||||
Nullが現れるまでのデータを文字列(String型)で返す(文字数をデータ長で返す) | |||||||||||
GetDataUTF16メソッド | |||||||||||
Function GetDataUTF16(データ長 As Long) As String | |||||||||||
指定したデータ長のUTF-16データを文字列(String型)で返す | |||||||||||
GetDataUTF8メソッド | |||||||||||
Function GetDataUTF8(データ長 As Long) As String | |||||||||||
指定したデータ長のUTF-8データを文字列(String型)で返す | |||||||||||
SkipDataメソッド | |||||||||||
Sub SkipData(データ長 As Long) | |||||||||||
指定したデータ長のデータをスキップする |
BinaryFileクラスのデータ編集系メソッド
BinaryFileクラスのデータ編集系メソッドは、下表の通りです。
ConvertEndianメソッド | |||||||||||
Function ConvertEndian(16進文字列 As String) As String | |||||||||||
指定した文字列をBig Endian⇔Little Endian変換して返す | |||||||||||
GetPositionHexメソッド | |||||||||||
Function GetPositionHex() As String | |||||||||||
CurrentPositionを16進文字列(String型)で返す | |||||||||||
HexToCharメソッド | |||||||||||
Function HexToChar(16進文字列 As String) As String | |||||||||||
指定した16進文字列を文字列(String型)に変換して返す |
BinaryFileクラスのプロパティ
BinaryFileクラスのプロパティは、下表の通りです。
CurrentPositionプロパティ | |||||||||||
Property CurrentPosition As Long | |||||||||||
CurrentPositionを設定/取得する | |||||||||||
FilePathプロパティ(読み取り専用) | |||||||||||
Property FilePath As String | |||||||||||
FilePathを取得する | |||||||||||
FileSizeプロパティ(読み取り専用) | |||||||||||
Property FileSize As Long | |||||||||||
FileSizeを取得する |
■BinaryFileクラスの内容と使用例
BinaryFileクラスの処理概要
InputFileメソッドを実行すると、指定したファイルをバイナリ・モードでByte型の配列に一括入力し、CurrentPositionに0をセットします。
GetData系のメソッドを実行すると、指定したデータ長のデータを返し、CurrentPositionを更新します。
SkipDataメソッドはデータを返さず、CurrentPositionの更新のみを行います。
(CurrentPosionプロパティに値を設定することも可能です)
他にもファイル解析に必要なメソッドやプロパティをいくつか実装しています。
BinaryFileクラスのデータ宣言部
行番号1~6で入力ファイル関連の変数を定義しており、行番号1「path」はファイルのパス、行番号2「size」はファイル・サイズ、行番号3「num」はファイル番号、行番号4「buf」は入力エリア(配列)、行番号5「bpos」は入力エリア内の位置(先頭からのオフセット)、行番号6「dlng」はGetDataNullメソッドのデータ長です。
行番号7~9は出力ファイル関連の変数、行番号10~15は作業用のワーク・エリアです。
- Dim path As String
- Dim size As Long
- Dim num As Integer
- Dim buf() As Byte
- Dim bpos As Long
- Dim dlng As Long
- Dim OUTpath As Variant
- Dim OUTnum As Integer
- Dim OUTbuf() As Byte
- Dim wByte() As Byte
- Dim wStr As String
- Dim wLen As Long
- Dim wRev As String
- Dim wRet As String
- Dim i As Long
BinaryFileクラスの入出力関連メソッド
InputFileメソッドは、指定したファイルをバイト型配列に一括入力し、CurrentPositionに0をセットします。
TransferDataメソッドは指定したデータ長のデータを出力用配列に転送し、OutputFileメソッドは指定したファイルに出力用配列のデータを出力します。
- Public Sub InputFile(InputFilePath As String)
- path = InputFilePath
- size = FileLen(path)
- num = FreeFile
- Open path For Binary As #num
- ReDim buf(0 To size – 1)
- Get #num, , buf
- Close #num
- bpos = 0
- End Sub
- Public Sub OutputFile(OutputFilePath As String)
- OUTpath = OutputFilePath
- OUTnum = FreeFile
- Open OUTpath For Binary Access Write As #OUTnum
- Put #OUTnum, , OUTbuf
- Close #OUTnum
- End Sub
- Public Sub TransferData(cnt As Long)
- ReDim OUTbuf(0 To cnt – 1)
- For i = LBound(OUTbuf) To UBound(OUTbuf)
- OUTbuf(i) = buf(bpos)
- bpos = bpos + 1
- Next i
- End Sub
BinaryFileクラスのデータ転送系メソッド
GetData系のメソッドは、指定したデータ長のデータを返し、CurrentPositionを更新します。
但し、SkipDataメソッドはデータを返さず、CurrentPositionの更新のみを行います。
(※)GetDataUTF8メソッドの中で使用しているGetStringA関数については、Excel VBAの覚え書(文字コード編)を参照して下さい。
- Public Function GetData(cnt As Long) As Variant
- GetData = 0
- For i = 1 To cnt
- GetData = GetData * 256 + buf(bpos)
- bpos = bpos + 1
- Next i
- End Function
- Public Function GetDataChar(cnt As Long) As Variant
- GetDataChar = “"
- For i = 1 To cnt
- GetDataChar = GetDataChar & Chr(buf(bpos))
- bpos = bpos + 1
- Next i
- End Function
- Public Function GetDataHex(cnt As Long) As Variant
- GetDataHex = “"
- For i = 1 To cnt
- GetDataHex = GetDataHex & Right(“0" & Hex(buf(bpos)), 2)
- bpos = bpos + 1
- Next i
- End Function
- Public Function GetDataNull(cnt As Long) As Variant
- dlng = bpos
- GetDataNull = “"
- Do While buf(bpos) <> &H0
- GetDataNull = GetDataNull & Chr(buf(bpos))
- bpos = bpos + 1
- Loop
- bpos = bpos + 1
- dlng = bpos – dlng
- cnt = dlng
- End Function
- Public Function GetDataUTF16(cnt As Long) As Variant
- ReDim wByte(1 To cnt)
- For i = 1 To cnt
- wByte(i) = buf(bpos)
- bpos = bpos + 1
- Next i
- wStr = wByte
- GetDataUTF16 = wStr
- End Function
- Public Function GetDataUTF8(cnt As Long) As Variant
- ReDim wByte(0 To cnt – 1)
- For i = 0 To UBound(wByte)
- wByte(i) = buf(bpos)
- bpos = bpos + 1
- Next i
- wStr = GetStringA(wByte)
- GetDataUTF8 = wStr
- End Function
- Public Sub SkipData(cnt As Long)
- bpos = bpos + cnt
- End Sub
BinaryFileクラスのデータ編集系メソッド
GetPositionHexメソッドはCurrentPositionを16進文字列で返し、ConvertEndianメソッドとHexToCharメソッドは指定した文字列を変換して返します。
- Public Function GetPositionHex() As Variant
- GetPositionHex = Right(“0000000" & Hex(bpos), 8)
- End Function
- Public Function ConvertEndian(wStr As Variant) As Variant
- wLen = Len(wStr)
- wRev = StrReverse(wStr)
- wRet = “"
- For i = 1 To wLen Step 2
- wRet = wRet & Mid(wRev, i + 1, 1)
- wRet = wRet & Mid(wRev, i, 1)
- Next i
- ConvertEndian = wRet
- End Function
- Public Function HexToChar(wStr As Variant) As Variant
- wLen = Len(wStr)
- HexToChar = “"
- For i = 1 To wLen Step 2
- HexToChar = HexToChar & Chr(CLng(“&H" & Mid(wStr, i, 1)) * 16 + CLng(“&H" & Mid(wStr, i + 1, 1)))
- Next i
- End Function
BinaryFileクラスのプロパティ
FilePathプロパティはファイルのパスを取得、FileSizeプロパティはファイル・サイズを取得、CurrentPositionプロパティは読み込みエリア内の位置(先頭からのオフセット)を設定/取得します。
- Public Property Get FilePath() As String
- FilePath = path
- End Property
- Public Property Get FileSize() As Long
- FileSize = size
- End Property
- Public Property Get CurrentPosition() As Long
- CurrentPosition = bpos
- End Property
- Public Property Let CurrentPosition(loc As Long)
- bpos = loc
- End Property
簡易ダンプをExcelシートに表示する処理
Excelシートの1行に16バイトずつ簡易ダンプを表示するプログラムで、A列にオフセット、B列に16進文字列、C列に文字列を表示しています。
行番号7でBinaryFileオブジェクトをインスタンス化し、行番号8でOpenFileメソッドを実行しています。
行番号12~16で行数を算出し、行番号17~26で1行に16バイト分のデータを表示しています。
行番号18でオフセット、行番号24で16進文字列、行番号26で文字列をセットしています。
- Dim sht, bf As Object
- Dim INsize As Long
- Dim wStr As String
- Dim i, lcnt As Long
- Private Sub Sample2()
- Set bf = New BinaryFile
- bf.OpenFile (“C:\work\test.txt")
- Set sht = ActiveSheet
- sht.Cells.NumberFormatLocal = “@"
- INsize = bf.FileSize
- lcnt = INsize / 16
- If INsize Mod 16 <> 0 Then
- lcnt = lcnt + 1
- End If
- For i = 1 To lcnt
- sht.Cells(i, 1) = bf.GetPositionHex()
- If (INsize – bf.CurrentPosition) >= 16 Then
- INlen = 16
- Else
- INlen = INsize – bf.CurrentPosition
- End If
- sht.Cells(i, 2) = bf.GetDataHex(INlen)
- sht.Cells(i, 3) = bf.HexToChar(sht.Cells(i, 2))
- Next i
- Set bf = Nothing
- End Sub
出版社:インプレス
発売日:2022/3/23
単行本(ソフトカバー):A5判/912ページ
出版社:技術評論社
発売日:2021/1/9
単行本(ソフトカバー):A5判/800ページ
出版社:技術評論社
発売日:2019/11/25
単行本(ソフトカバー):B5変形判/576ページ
ディスカッション
コメント一覧
まだ、コメントがありません