【VBA】画像ファイルを(意図的に)壊して不慮の事故を防ぐ あるいは暗号化してみる(1)
俺の嫁フォルダががが…
あ!ちょっ…そのフォルダは開けちゃだめ!!なんてことがあったりなかったりするかもしれませんが、そういう場合に慌てないようにあまり見られたくない画像ファイルなんかは暗号化とかしておくとそういった不慮の事故が防げるかもしれませんね。まぁ、すでにひらきなおってる人はそんな必要はありませんが(私)。
今回は VBA で画像ファイルを意図的に壊しちゃいましょうというお話です。ある意味、暗号化といっていいかもしれません。
バイナリ
コンピュータは 0 と 1 ですべて処理をしているという話はどこかで聞いたことがあるかもしれません。ファイルだってそうなんです。
たとえばこの(かわいい)PNG画像ですが、バイナリエディタというちょっと特殊なエディタで開くとこんな感じになっています。
0 と 1 ではありませんね。それは 16進数で表示されているからです。これを 2進数で表示してみましょう。
上の画像では先頭が「89」になっていますが、下の画像では「1000 1001」になっています。
16進数の「8」は 2進数では「1000」、16進数の「9」は 2進数では「1001」なので、ちゃんと対応していますね。
このように、ファイルの実体は膨大な 0 と 1 の羅列になっています。
ちなみに、8bit で 1byte となるので、2進数の「1000 1001」が 1byte に相当します(1, 0 それぞれが 1bit です)。
16進数では「89」が 1byte ですね。
ファイルを壊してみる
ではちょっといたずらをして 2進数の先頭の 1 を 0 に書き換えてみましょう。
【いたずら前】
(かわいい)サムネイル画像がちゃんと表示されてますね。
【いたずら後】
(かわいい)サムネイル画像が表示されなくなってしまいました。
さらに…
たった1か所、わずか 1bit を書き換えただけでファイルが壊れてしまいました。mjk…
まぁ、今回は書き換えた場所がわかっているので、元に戻せばちゃんとファイルも直ります。
かわいいですね。
このようにちょっとでもデータを書き換えるとファイルが壊れてしまいます。
さて、どうすればファイルが壊れるかがわかったのでこれを VBA で実装できればよさそうです。
バイナリモードで開く
先ほどはバイナリエディタで開きましたが、これと同じように VBA で読み込みができればいいですね。VBA ではバイナリモードで開くことで実現できます。
【標準モジュール】
Public Sub ReadBinary() Dim filePath As String Dim fileNo As Long Dim i As Long Dim buffer() As Byte 'バイナリデータ格納用の配列 filePath = "C:\Users\xxxx\Desktop\ファイル暗号化\新しいフォルダー\image01.png" fileNo = FreeFile 'ファイルをバイナリモードで開いてbuffer配列に格納する Open filePath For Binary As #fileNo ReDim buffer(LOF(fileNo)) Get #fileNo, , buffer Close #fileNo '先頭8バイトだけ表示する For i = 0 To 7 Cells(1, i + 1).Value = i + 1 Cells(2, i + 1).Value = buffer(i) Next End Sub
ファイルのデータを格納する配列変数「buffer」を宣言します。変数の型が Byte型 になっていることに注意してください。
通常テキストファイルを開く場合は、[ Open filePath For Input As #fileNo ] のような書き方をすると思います。今回は画像ファイルをバイナリモードで開きたいので、[ Input ] の部分が [ Binary ] となっています。
ファイルを開いたら、データを格納する配列変数「buffer」のサイズを「ReDim」で設定し、「Get」で読み込んだデータを「buffer」に格納しています。「#fileNo」と「buffer」の間のカンマが 2つになっていることに注意してください(引数が一つ省略されています)。
読み込んだデータの先頭 8byte だけをシートに表示させています。
バイナリエディタで開いたものと比較してみましょう。
なんかちょっと違いますね。
エクセルの方は「137 80 78 71 …」となってますが、バイナリエディタでは「89 50 4E 47 …」となっています。
これはエクセルの方が 10進数で表示されているためなので、16進数に変換してみましょう。
ワークシート関数の「=DEC2HEX()」を使うと、10進数を16進数に変換できます。
バイナリエディタで開いたものと同じになりました(1桁のところは頭の0が省略されていると考えてください)。
バイナリデータを書き換える
バイナリモードで読み込むことができたので、これをちょっと書き換えて保存しなおしてみます。
Public Sub ReadWriteBinary() Dim filePath As String Dim fileNo As Long Dim i As Long Dim buffer() As Byte filePath = "C:\Users\celae\Desktop\ファイル暗号化\新しいフォルダー\image01.png" fileNo = FreeFile 'ファイルをバイナリモードで開いてbuffer配列に格納する Open filePath For Binary As #fileNo ReDim buffer(LOF(fileNo)) Get #fileNo, , buffer Close #fileNo '先頭8バイトだけ表示する For i = 0 To 7 Cells(1, i + 1).Value = i + 1 Cells(2, i + 1).Value = buffer(i) Next '----追加---- '先頭の1byteを16進数で90に書き換える buffer(0) = &H90 fileNo = FreeFile 'buffer配列をファイルとして書き出す Open filePath For Binary As #fileNo Put #fileNo, , buffer Close #fileNo '------------ End Sub
先頭の 1byte のみを書き換えてみました。16進数として扱いたいので「&H」を付けています。
書き換えた内容をファイルとして書き出します。読み込み時は「Get」を使いましたが、今回は「Put」を使います。こちらも「#fileNo」と「buffer」の間のカンマが 2つになっていることに注意してください(引数が一つ省略されています)。
では、書き換えたファイルをバイナリエディタで開いた内容を見てみましょう。
先頭が「90」に書き換わり、画像が表示されなくなっていますね。
先頭を「89」に書き換えればまた正しく表示されるようになります。
かわいいですね。
今回は 1ファイルだけを扱いましたが、次回はフォルダ内の画像ファイルをまとめて変換する処理を書いていく予定です。
※バイナリエディタは「TSXBIN」を使わせていただきました。
※今回使用した(かわいい)画像は「V☆カツ」で作成しました。