2Gほどのバイナリファイルを開こうと思ったらエラーになったり読み込むのに時間が掛かったりして苦労したことがあったので、そうゆう時のために大きめのファイルの扱えるバイナリエディタを調べてみました。ちなみにその時はHexcurse + dd + catで目的は達成できたように記憶しています。
今回使用した環境はLubuntu16.04(64bit)、メモリ4Gです。/dev/urandomを使って作成した8Gくらいのファイルを指定してストレスなく起動するかどうかで判断しています。エディタは標準パッケージからインストールできるもののみを対象としています。
大きめのファイルが扱えたバイナリエディタ
- Bless Hex Editor - A full featured hexadecimal editor(注1)
- DHEX - ncurses based hex editor with diff mode
- Hexcurse - Ncurses-based hex editor with many features
- hexedit - view and edit files in hexadecimal or in ASCII
- lfhex - large file hex editor
- Ncurses Hexedit - Edit files/disks in hex, ASCII and EBCDIC
- shed - simple hex editor with a pico-style interface
- Tweak - Efficient text-mode hex editor(注2)
- wxHexEditor - hexadecimal editor for massive files
(注1)Bless Hex Editorはファイルを開くことはできましたが表示がうまくされずエディタとして使用することができませんでした。
(注2)Tweakはファイルは開けますが保存に時間がかかります。
それぞれの特徴
特徴というほどでもないのですが使ってみて思ったところを書きます。ディスクの読み書きについてはファイル名として/dev/sdb1のように指定することで読み書きができるものもありますが、ここではヘルプ等で明記されているものだけを書いています。
変更すると即保存されてしまうコマンドもありますので、ちょっと試す場合でもバックアップを取ってから行う事をおすすめいたします。
Bless Hex Editor
アプリの種類: GTK2.0
インストールコマンド: sudo apt install bless
起動コマンド: bless [file]...
ファイルは開けましたが0x00-0x19と0xe6-0xffあたりの16進数が表示されないという不思議な現象が起きてエディタとして使うことができませんでした。Ask Ubuntuでも同様の書き込みがありましたので私だけではないようです。参考URL)https://askubuntu.com/questions/818477/problem-when-displaying-hex-bytes-in-bless
DHEX
アプリの種類: コンソール
インストールコマンド: sudo apt install dhex
起動コマンド: dhex [options] file...
終了キー: F10(変更可)
保存キー: F10(変更可、終了時にSaveを選択する事で保存)
ファイル保存といった操作はファンクションキーで行いショートカットキーは使えません。最初の起動時にキーの割当を設定する画面が表示されるのがちょっと面倒ですがLubuntuデフォルトではF10でファイルメニューが開いてしまうため別のキーに割り当てるといったことも可能です。1)オフセット移動(16進数のみ)。2)計算機能。3)ファイルの比較。4)-o*でオプションで起動時のオフセット指定。といった機能があります。
※今回使用したバージョンは0.68でしたが0.7では最初の起動時でもキーの割当をする画面は表示されませんでした。ファンクションキー以外にもShift+*に対応したため')'(JISキーボードの場合Shift+9)で終了できます。
Hexcurse
アプリの種類: コンソール
インストールコマンド: sudo apt install hexcurse
起動コマンド: hexcurse [options] file
終了キー: CTRL+q 又は F8
保存キー: CTRL+s 又は F2
画面をぱっと見た感じはファンクションキー操作オンリーに見えますが、実際にはショートカットキーも使えます。アドレス表示を16進数と10進数に切り替えることができまF1でヘルプ表示できます。
hexedit
アプリの種類: コンソール
インストールコマンド: sudo apt install hexedit
起動コマンド: hexedit [options] file
終了キー: CTRL+c
保存キー: CTRL+w 又は F2
F1でヘルプ表示できます。コピーペーストや選択した範囲を別のファイルへの書き出すといった機能があります。
lfhex
アプリの種類: Qt4
インストールコマンド: sudo apt install lfhex
起動コマンド: lfhex [options] file...
かなりシンプルなバイナリエディタです。HEXとASCIIを同時に表示することができないかわりに画面いっぱいのHEX表示や画面いっぱいのASCII表示といったことができます。Qtを使っている関係上Lubuntuの場合だとインストールサイズが大きめになります。
Ncurses Hexedit
アプリの種類: コンソール
インストールコマンド: sudo apt install ncurses-hexedit
起動コマンド: hexeditor [options] file
終了キー: CTRL+c
保存キー: CTRL+o
CTRL-gでヘルプ表示。1)オフセット移動(16進数のみ)。2)追加・削除(起動オプションで-bを指定しメモリーに読み込む必要があります)。3)ディスク読み書き(起動オプションで-dを指定、書き込みもする場合は-fも指定)。
shed
アプリの種類: コンソール
インストールコマンド: sudo apt install shed
起動コマンド: shed [options] file...
終了キー: X
保存キー: なし(変更すると即保存)
変更すると即保存されてしまうので注意が必要です。またjump toで0x100000000を指定しても0x0にジャンプしてしまうようです、それ以降にジャンプしたい場合は4Gのように単位指定すればジャンプできます。
Tweak
アプリの種類: コンソール
インストールコマンド: sudo apt install tweak
起動コマンド: tweak [options] file
終了キー: CTRL+x CTRL+c(2ストローク)
保存キー: CTRL+x CTRL+s(2ストローク)
追加・削除が行える数少ないエディタですがその代償として保存は遅いです。操作キーはemacsライクらしく、F1でヘルプ表示やファンクションキーによる操作、CTRL+Cでの終了といったことはできません。事前にヘルプを読んでおいた方が良いかなと思います。
wxHexEditor
アプリの種類: GTK3.0
インストールコマンド: sudo apt install wxhexeditor
起動コマンド: wxHexEditor [file]
hexのhとeditorのeが大文字というのがちょっと違和感がありますがコマンド名はwxHexEditorで正しいです。50MBを超えるファイルを読み込むと読み取り専用(Read-Only)となりますが、Option → File ModeからWritebleを選択すれば保存できるようになります。1)オフセット移動。2)ファイルの比較。3)ディスクからの読み取り(WritableやDirect Writeを選択しても私の環境では書き込みができませんでした)。4)追加・削除。等々、今回調べたエディタの中では最も機能が豊富ですが、GTK関係のエラーが出るところが気になるところです。
おまけ
バイナリエディタは内容を表示したりするのは便利なんですが、編集したり計算したりするはコマンドの方が便利というか、慣れているので、そのメモです。
ddでバイナリファイルから指定範囲内を切り出す。
ddコマンドを使えばバイナリファイルから必要な部分を取り出すことができます。
$ dd if=in.img of=out.img bs=1 skip=16 count=256
16進数や計算式で指定することもできます。
$ dd if=in.img of=out.img bs=1 skip=$((0x10)) count=$((0x10*16))
catでバイナリファイルを結合する。
catコマンドはテキストファイルだけでなくバイナリファイルも連結することができます。
$ cat in-1.img in-2.img > out.img
ddでバイナリファイルの一部を書き換える
元のファイルを書き換えるということはあまりしないのですが、一箇所だけ書き換えたい時とか、別のファイルで書き換えたい時とかに使えます。countは省略可能ですがつけた方が安心かなと思います。またconv=notruncを忘れるとファイルが切り詰められてしまうので注意が必要です。
$ printf "\x00\xff" | dd of=out.img seek=16 bs=1 count=2 conv=notrunc
$ dd if=in.img of=out.img seek=16 bs=1 count=256 conv=notrunc
メディアをイメージファイルに変換して編集する
メディアを直接読み書きできるエディタもありますが、可能ならイメージファイルに変換して編集する方が安全に作業できるかなと思います。
$ sudo dd if=/dev/sdb of=usb.img
イメージファイルに変換してしまえばバックアップをとったり、解析したり、編集したりするのがかなり楽になります。イメージファイルはループバックデバイスを使用すればハードディスクのようにマウントすることができますが、今回のようにディスクを丸ごと変換している場合はoffsetオプションを使用してパーティションを指定する必要があります。
$ fdisk -l usb.img
Disk usb.img: 1.9 GiB, 2004877312 bytes, 3915776 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x68f7c20e
Device Boot Start End Sectors Size Id Type
usb.img1 2048 1002047 1000000 488.3M c W95 FAT32 (LBA)
$ sudo mount -o loop,offset=$((2048*512)) usb.img /mnt
またイメージファイルはVDI形式に変換すればVirtualBoxで使用することもできますので、編集作業の全てをVirtualBox上で行うことも可能です。
$ VBoxManage convertfromraw usb.img usb.vdi --format VDI
VDI形式を元のイメージファイル形式に戻す事もできます。実行時にdoes not match the value {dc61fe63-...}みたいなエラーが表示された場合は、VirtualBoxを起動してFile → Virtual Media Managerで該当のvdiファイルを削除するとエラーがでなくなります。
$ VBoxManage clonehd usb.vdi usb-fromvdi.img --format RAW
10進数や16進数の相互変換や計算
エディタによっては計算機能のあるものもありますが、やっぱり慣れているコマンドの方が楽なのでそのメモです。
printfを使って16進数を10進数に変換、10進数を16進数に変換。
$ printf "%#x\n" 100 #10進数→16進数
0x64
$ printf "%#d\n" 0x100 #16進数→10進数
256
$ printf "%#d\n" $((0x100)) #16進数→10進数
256
bashの計算式とprintfを組み合わせることもできます。
$ printf "%#x\n" $((0x100*2+100*4)) #256*2 + 100*4
0x390
$ printf "%#d\n" $((0x100*2+100*4)) #256*2 + 100*4
912
大きな数値(64bit)も扱えます。OSのbit数には依存しないので32bitのLubuntuでも同じ結果になります。
$ printf "%#x\n" -1
0xffffffffffffffff
$ printf "%#d\n" $((0xffffffffffffffff))
-1
$ printf "%#u\n" $((0xffffffffffffffff))
18446744073709551615
$ printf "%#d\n" $((0x7fffffffffffffff))
9223372036854775807
$ printf "%#d\n" $((0x8000000000000000+1))
-9223372036854775807
$ printf "%#u\n" $((0x8000000000000000+1))
9223372036854775809
エディタ画面等から16進数をコピー・ペーストして10進数に変換する際のメモです。値が32bitリトルエンディアンで格納されている場合とかに使えます。
$ echo "11 22 33 44" | xxd -p -r | od -An -td4 --endian=little
1144201745
$ echo $((0x44332211)) #念のため同じなのかを確認
1144201745
$ echo "55 66 77 88" | xxd -p -r | od -An -td4 --endian=little
-2005440939
$ echo "55 66 77 88" | xxd -p -r | od -An -tu4 --endian=little
2289526357
$ echo "55 66 77 88" | xxd -p -r | od -An -tu2 --endian=little
26197 34935
$ echo "55 66 77 88" | xxd -p -r | od -An -td2 --endian=little
26197 -30601
変数に代入できますので計算したりすることもできます。
$ n=$(echo "11 22 33 44" | xxd -p -r | od -An -td4 --endian=little)
$ echo $n
1144201745
$ echo $((n + 1024))
1144202769
$ echo $((n + 0x400))
1144202769
ファイルから取り出して計算する事もできます。
$ od -tx1 -N 16 data.img
0000000 00 00 11 22 33 44 00 00 00 00 00 00 00 00 00 00
$ n=$(dd if=data.img skip=2 bs=1 count=4 2>/dev/null | od -An -td4 --endian=little)
$ echo $n
1144201745
$ echo $((n + 1024))
1144202769
$ echo $((n + 0x400))
1144202769