Linux 環境でゲーム機エミュレーターが可能な読者は、 この節を読むのを飛ばして結構だ(そんなに長いものでもないが)。
サイズの巨大な逆アセンブルしたテキストファイルをいくつも抱え込むと、 どうしても高度なテキスト処理能力が欲しくなる。 そして、それは愛用のテキストエディターが処理する以上の能力がなければ意味がない。 そこで、知名度も実績も十二分にあるテキスト処理用の GNU ツールを利用することを考えた。 Windows 環境で解析作業をするので、Cygwin をインストールしておく。
各種ツールを利用するのは Cygwin コンソール上からだけとは限らない。 現代的な各種 IDE や高水準なテキストエディターが提供する「外部プログラム呼び出し」機能、 すなわち利用者がコマンドラインを指示し、 メニュー項目選択時もしくは即時にそれらを起動するという作りになっている。 そこから awk, sed のような軽いテキスト処理コマンドを呼び出してもよし、 逆アセンブリーコード処理専用のシェルスクリプトを書いて、それを呼び出すもよし、だ。
高水準アプリがマクロ言語によるテキスト処理機能を提供する場合もある。 しかし、本書ではそういうものを利用するという考えはしない。
以降、本書で Cygwin コンソールを利用する状況を説明する場合、シェルは Bash とする。
プロンプト (PS1) は $
で表記する。
C/C++ の関数相当の機能を有する printf コマンドを利用することができる。 電卓でまかなえる陳腐な例だが、十進数を十六進数に変換するには以下のようにする。
$
printf "%X\n" 1000000
F4240
しばしば連番をテキストファイルにコメントしておきたい状況になる。 そういう場合にはエクセルを起動でも構わぬが、好みで seq を用いる。
$
seq 4
1 2 3 4$
seq 10 3 20
10 13 16 19$
seq 0x3925 0x3C 0x3BFF | xargs printf "7E%04X\n"
7E3925 7E3961 7E399D 7E39D9 … 省略 7E3BF5
seq に単一の整数 N を与えると、1 から N まで 1 ずつ増加する連番が得られる。 |
|
seq に3 つパラメーターを渡す場合、それぞれの意味は FIRST, INCREMENT, LAST として処理される。 |
|
SFC 版ドラクエ 3 の通称 3925 構造体のアドレスを書きたくなって seq を利用したとする。
バンクは皆 $7E なので入力には含めず、出力書式に込めることにした。
勇者のアドレスが $7E3925 で、ルイーダの酒場にいる順番に 出力結果を十六進数で表示したいのだが、seq の書式指定オプションはそれをサポートしない。 よって、前項で説明した printf にパイプラインを作る。 仲間の人数がわかっていれば、head にさらなるパイプラインを作ってもよい。
|
ドラクエのスーファミ ROM イメージから、特定の構造体データ配列をすべてテキストダンプしたいことがある。
例えば、SFC 版ドラクエ 3 のモンスター構造体配列(5.5.1 構造体 $C20000
: モンスター)を見たくなったとしよう。
まずは頭を使わずにコンソールから直接コマンドラインを入力してみよう。
$
od --address-radix=x1 \ --skip-bytes=$(( 0x20000 )) \ --format=uC \ --read-bytes=$(( 0x25 * 0xA0 )) \ --output-duplicates \ --width=$(( 0x25 )) \ dq3.smc | sed -e '$d'
od が出力するアドレスを十六進数で表示させるのオプション。 |
|
モンスター配列の先頭のアドレスを |
|
ダンプを 1 バイト単位で行い、符合なし整数として解釈させる。 |
|
読み込むことになる総バイト数。シェルに計算させた結果を渡す。
ここで |
|
これを指定しないと、同じデータが連続して表れた場合に省略されてしまう。 |
|
モンスター構造体のサイズ。C/C++ で言うところの sizeof の値。 |
|
ロムイメージファイル名を渡してダンプする。 最後の sed は、出力の最後の行がゴミなので、それを消しているだけだ。 |
構造体データ配列のダンプのたびに上記のような長いコマンドラインを入力するのは面倒なので、 通常はこれを不変部分と可変部分を分離してスクリプトにしておく。 具体的には、ロムイメージファイル、オフセット、sizeof 構造体、そして配列長が可変である。 これらはスクリプトの引数として指定できるようにしておけばよい。
DisPel の -d
オプションによるダンプの方が指定は楽なのだが、
od の --size
オプションに相当する値の上限がどうやら 255 らしいので、
キャラクターのレベルアップ構造体データ等の巨大なデータのダンプができない。
特定の ROM イメージに対して DisPel をコンソールから起動する作業を続けていると、
やがて位置オプションの指定が面倒なことに気付く。例えば SFC 版ドラクエ 3 の場合は
-h
, -s
は必ず指定するし、
古いバージョンの DisPel を利用しているのならば、
ROM イメージは普通はヘッダを削っておくものだから -n
も指定する。
指定するたびに違う値になるのは、逆アセンブル範囲を示す部分だけだ。
そこで、以下のようにスクリプトを書いておき、dispel を直接利用するのではなく、
これを利用することにすると多少は楽だ。
#!/bin/bash # # script: disdq3 # example: # disdq3 -b C2 # disdq3 -r C20000-C28000 DISPEL=~/bin/dispel.exe ROM=~/data/dq3.smc # このスクリプトに渡されたすべてのコマンドライン引数を # DisPel にそのまま引き渡す # # DisPel のバージョンが v1 未満の場合は -n は不要となるので注意 $DISPEL -n -h -s -p $* "$(cygpath -d $ROM)"