Excel VBAでファイル解析(事前準備編)

2024-01-05

■ファイル解析に使用するツール

ファイルを解析する際に必須のツールと言えば、まずはバイナリ・エディタということになりますが、実際に解析を進めるにあたっては、テキスト・ファイルに出力できた方が何かと便利です。
ということで、「ダンプ形式でテキストに落せるツール」の中で最も手軽に利用できる、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でファイルをクローズしています。

  1. Dim num1, num2 As Integer
  2. Dim buf As String
  3. Dim pos As Long
  4. Private Sub Sample1()
  5.     num1 = FreeFile
  6.     Open “C:\xxx.txt" For Input As #num1
  7.     num2 = FreeFile
  8.     Open “C:\yyy.txt" For Output As #num2
  9.     Do Until EOF(num1)
  10.         Line Input #num1, buf
  11.         pos = InStr(buf, Chr(&H9))
  12.         If pos > 0 Then
  13.             buf = Right(“0000″ & Left(buf, pos – 1), 8) & " " & Mid(buf, pos + 1)
  14.         End If
  15.         Print #num2, buf
  16.     Loop
  17.     Close #num2
  18.     Close #num1
  19. 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は作業用のワーク・エリアです。

  1. Dim path As String
  2. Dim size As Long
  3. Dim num As Integer
  4. Dim buf() As Byte
  5. Dim bpos As Long
  6. Dim dlng As Long
  7. Dim OUTpath As Variant
  8. Dim OUTnum As Integer
  9. Dim OUTbuf() As Byte
  10. Dim wByte() As Byte
  11. Dim wStr As String
  12. Dim wLen As Long
  13. Dim wRev As String
  14. Dim wRet As String
  15. Dim i As Long

BinaryFileクラスの入出力関連メソッド

InputFileメソッドは、指定したファイルをバイト型配列に一括入力し、CurrentPositionに0をセットします。
TransferDataメソッドは指定したデータ長のデータを出力用配列に転送し、OutputFileメソッドは指定したファイルに出力用配列のデータを出力します。

  1. Public Sub InputFile(InputFilePath As String)
  2.     path = InputFilePath
  3.     size = FileLen(path)
  4.     num = FreeFile
  5.     Open path For Binary As #num
  6.     ReDim buf(0 To size – 1)
  7.     Get #num, , buf
  8.     Close #num
  9.     bpos = 0
  10. End Sub
  11. Public Sub OutputFile(OutputFilePath As String)
  12.     OUTpath = OutputFilePath
  13.     OUTnum = FreeFile
  14.     Open OUTpath For Binary Access Write As #OUTnum
  15.     Put #OUTnum, , OUTbuf
  16.     Close #OUTnum
  17. End Sub
  18. Public Sub TransferData(cnt As Long)
  19.     ReDim OUTbuf(0 To cnt – 1)
  20.     For i = LBound(OUTbuf) To UBound(OUTbuf)
  21.         OUTbuf(i) = buf(bpos)
  22.         bpos = bpos + 1
  23.     Next i
  24. End Sub

BinaryFileクラスのデータ転送系メソッド

GetData系のメソッドは、指定したデータ長のデータを返し、CurrentPositionを更新します。
但し、SkipDataメソッドはデータを返さず、CurrentPositionの更新のみを行います。

(※)GetDataUTF8メソッドの中で使用しているGetStringA関数については、Excel VBAの覚え書(文字コード編)を参照して下さい。

  1. Public Function GetData(cnt As Long) As Variant
  2.     GetData = 0
  3.     For i = 1 To cnt
  4.         GetData = GetData * 256 + buf(bpos)
  5.         bpos = bpos + 1
  6.     Next i
  7. End Function
  8. Public Function GetDataChar(cnt As Long) As Variant
  9.     GetDataChar = “"
  10.     For i = 1 To cnt
  11.         GetDataChar = GetDataChar & Chr(buf(bpos))
  12.         bpos = bpos + 1
  13.     Next i
  14. End Function
  15. Public Function GetDataHex(cnt As Long) As Variant
  16.     GetDataHex = “"
  17.     For i = 1 To cnt
  18.         GetDataHex = GetDataHex & Right(“0" & Hex(buf(bpos)), 2)
  19.         bpos = bpos + 1
  20.     Next i
  21. End Function
  22. Public Function GetDataNull(cnt As Long) As Variant
  23.     dlng = bpos
  24.     GetDataNull = “"
  25.     Do While buf(bpos) <> &H0
  26.         GetDataNull = GetDataNull & Chr(buf(bpos))
  27.         bpos = bpos + 1
  28.     Loop
  29.     bpos = bpos + 1
  30.     dlng = bpos – dlng
  31.     cnt = dlng
  32. End Function
  33. Public Function GetDataUTF16(cnt As Long) As Variant
  34.     ReDim wByte(1 To cnt)
  35.     For i = 1 To cnt
  36.         wByte(i) = buf(bpos)
  37.         bpos = bpos + 1
  38.     Next i
  39.     wStr = wByte
  40.     GetDataUTF16 = wStr
  41. End Function
  42. Public Function GetDataUTF8(cnt As Long) As Variant
  43.     ReDim wByte(0 To cnt – 1)
  44.     For i = 0 To UBound(wByte)
  45.         wByte(i) = buf(bpos)
  46.         bpos = bpos + 1
  47.     Next i
  48.     wStr = GetStringA(wByte)
  49.     GetDataUTF8 = wStr
  50. End Function
  51. Public Sub SkipData(cnt As Long)
  52.     bpos = bpos + cnt
  53. End Sub

BinaryFileクラスのデータ編集系メソッド

GetPositionHexメソッドはCurrentPositionを16進文字列で返し、ConvertEndianメソッドとHexToCharメソッドは指定した文字列を変換して返します。

  1. Public Function GetPositionHex() As Variant
  2.     GetPositionHex = Right(“0000000" & Hex(bpos), 8)
  3. End Function
  4. Public Function ConvertEndian(wStr As Variant) As Variant
  5.     wLen = Len(wStr)
  6.     wRev = StrReverse(wStr)
  7.     wRet = “"
  8.     For i = 1 To wLen Step 2
  9.         wRet = wRet & Mid(wRev, i + 1, 1)
  10.         wRet = wRet & Mid(wRev, i, 1)
  11.     Next i
  12.     ConvertEndian = wRet
  13. End Function
  14. Public Function HexToChar(wStr As Variant) As Variant
  15.     wLen = Len(wStr)
  16.     HexToChar = “"
  17.     For i = 1 To wLen Step 2
  18.         HexToChar = HexToChar & Chr(CLng(“&H" & Mid(wStr, i, 1)) * 16 + CLng(“&H" & Mid(wStr, i + 1, 1)))
  19.     Next i
  20. End Function

BinaryFileクラスのプロパティ

FilePathプロパティはファイルのパスを取得、FileSizeプロパティはファイル・サイズを取得、CurrentPositionプロパティは読み込みエリア内の位置(先頭からのオフセット)を設定/取得します。

  1. Public Property Get FilePath() As String
  2.     FilePath = path
  3. End Property
  4. Public Property Get FileSize() As Long
  5.     FileSize = size
  6. End Property
  7. Public Property Get CurrentPosition() As Long
  8.     CurrentPosition = bpos
  9. End Property
  10. Public Property Let CurrentPosition(loc As Long)
  11.     bpos = loc
  12. End Property

簡易ダンプをExcelシートに表示する処理

Excelシートの1行に16バイトずつ簡易ダンプを表示するプログラムで、A列にオフセット、B列に16進文字列、C列に文字列を表示しています。

行番号7でBinaryFileオブジェクトをインスタンス化し、行番号8でOpenFileメソッドを実行しています。
行番号12~16で行数を算出し、行番号17~26で1行に16バイト分のデータを表示しています。
行番号18でオフセット、行番号24で16進文字列、行番号26で文字列をセットしています。

  1. Dim sht, bf As Object
  2. Dim INsize As Long
  3. Dim wStr As String
  4. Dim i, lcnt As Long
  5. Private Sub Sample2()
  6.     Set bf = New BinaryFile
  7.     bf.OpenFile (“C:\work\test.txt")
  8.     Set sht = ActiveSheet
  9.     sht.Cells.NumberFormatLocal = “@"
  10.     INsize = bf.FileSize
  11.     lcnt = INsize / 16
  12.     If INsize Mod 16 <> 0 Then
  13.         lcnt = lcnt + 1
  14.     End If
  15.     For i = 1 To lcnt
  16.         sht.Cells(i, 1) = bf.GetPositionHex()
  17.         If (INsize – bf.CurrentPosition) >= 16 Then
  18.             INlen = 16
  19.         Else
  20.             INlen = INsize – bf.CurrentPosition
  21.         End If
  22.         sht.Cells(i, 2) = bf.GetDataHex(INlen)
  23.         sht.Cells(i, 3) = bf.HexToChar(sht.Cells(i, 2))
  24.     Next i
  25.     Set bf = Nothing
  26. End Sub

 

国本温子(著),緑川吉行(著),できるシリーズ編集部(著)
出版社:インプレス
発売日:2022/3/23
単行本(ソフトカバー):A5判/912ページ

大村あつし(著),古川順平(著)
出版社:技術評論社
発売日:2021/1/9
単行本(ソフトカバー):A5判/800ページ

高橋宣成(著)
出版社:技術評論社
発売日:2019/11/25
単行本(ソフトカバー):B5変形判/576ページ

ファイル解析

Posted by hides