上に戻る
4.ディスアセンブルしてみる
概要
 逆アセンブルについてやってこうと思います。逆アセンブルというのは、プログラムを『見易く』するための処置と言えばいいでしょうか……
 やっと、プログラム改造っぽくなってきました……遅すぎ。
 あ、そうそうファミコン専用の話です。今回は。
その前に……
 ゲームのプログラムはどのように作られるのでしょうか?
 まぁ、前々回(パドルのスピード変更)のようにバイナリエディタを使ってチマチマと機械語を打ち込んでいってもできなくはないはずですが、そんなことをメインでやる人はかなり奇特な方だと思います^^
 まぁ、普通はプログラミング言語を使うでしょうな。
高級言語
 C言語とか、“普通の”プログラミング言語は、こんな風に呼ばれるらしいです。
 多くの言語で、コンパイルによって、ある一定のCPUの機械語を出力できるようになっていると思います。javaなんかはちょっと違うみたいですが。
 例えば、1〜200までの和を求めるプログラム
 for( tmp=0,i=1 ; i<=200 ; i++ )
 {
  tmp += i ;
 }
 をPentium互換(?)にコンパイルすると、以下のような機械語が出力されました。
 (ちなみに、tmpとiをレジスタ割り当てしているらしい)
33 c9 b8 01 00 00 00 03 c8 40 3d c8 00 00 00 7e f6
低級言語
 高級言語に対し、アセンブリ言語(?)は、低級言語と言われているらしいです。
 アセンブリの定義は知らないのですが、『ソースコードにCPUの命令(に付けられたラベル)』を直に書いていき、1つの記述が1つのCPU命令に対応……概ね1対1で対応するような感じの物でしょうか……
(実際は、様々なラベルやマクロなんかがあるから全然1対1じゃないけど)
 対象のCPUに特化した記述ができるので、そのCPUの性能を最大限に引き出す事が可能ですが、そのCPU互換以外の環境で動かそうと思ったらほとんど0からプログラミングし直さないとならなくなります。
 (ある程度は変換で対応できる?)
 こういった面において、高級言語が遥かに優れています。
 しかし、昔は、ハードウェア制約がとてつもなく厳しく、さらにCPUが、性能を最大限に活かさないとどーにもならんような性能だったりするので、アセンブリが開発に用いられていたようです。
 今はそんなこと無いので、普通は高級言語を使っていて(昔と比べて比較的)容易に機種マルチなソフト展開ができるのではないでしょうか……知らんけど^^
 ちょっと、ファミコンのCPUで、上のように、1〜200までの和を求めるアセンブリを書いてみます。書き方はアセンブラによって違うと思いますが……
 何をやっているかはさっぱりわからんと思いますが^^
Vtmp0 = $00
Vtmp1 = $01

lda #$00
sta <Vtmp0
sta <Vtmp1
ldx #$C8 ;C8h=200d
.sumloop
txa
clc
adc <Vtmp0
sta <Vtmp0
lda <Vtmp1
adc #$00
sta <Vtmp1
dex
bne .sumloop
 アセンブラに通すと、以下のような機械語が出力されました。
A9 00 85 00 85 01 A2 C8 8A 18 65 00 85 00 A5 01 69 00 85 01 CA D0 F1
 16ビット演算に対応していないせいか、レジスタの数が少ないせいか、少し上のより長めです。
ディスアセンブル
 今回のテーマの『ディスアセンブル』(逆アセンブル)は、機械語のプログラムを、なんとかアセンブリレベルまで戻して見易くすることです。
 例えば、少し上の、ファミコンで1〜200までを足し合わせるプログラムを、『ディスアセンブル』してみます。
8000 : A9 00 lda #$00
8002 : 85 00 sta $00
8004 : 85 01 sta $01
8006 : A2 C8 ldx #$C8
8008 : 8A   txa
8009 : 18   clc
800A : 65 00 adc $00
800C : 85 00 sta $00
800E : A5 01 lda $01
8010 : 69 00 adc #$00
8012 : 85 01 sta $01
8014 : CA   dex
8015 : D0 F1 bne $8008
 これの意味はおいておいて、少なくとも、
A9 00 85 00 85 01 A2 C8 8A 18 65 00 85 00 A5 01 69 00 85 01 CA D0 F1
 よりはだいぶ見やすくなったのがわかる思います。
やや、1対1の関係
 上のほうで、アセンブリは、機械語と概ね1対1の関係があると書きました。
 これは、かなり偽りの多い記述です^^

 ちょっとまとめると、もともと、
Vtmp0 = $00
Vtmp1 = $01

lda #$00
sta <Vtmp0
sta <Vtmp1
ldx #$C8 ;C8h=200d
.sumloop
txa
clc
adc <Vtmp0
sta <Vtmp0
lda <Vtmp1
adc #$00
sta <Vtmp1
dex
bne .sumloop
 というソースを、アセンブリして、
A9 00 85 00 85 01 A2 C8 8A 18 65 00 85 00 A5 01 69 00 85 01 CA D0 F1
 となって、この数字の羅列を、ディスアセンブルすると、
8000 : A9 00 lda #$00
8002 : 85 00 sta $00
8004 : 85 01 sta $01
8006 : A2 C8 ldx #$C8
8008 : 8A   txa
8009 : 18   clc
800A : 65 00 adc $00
800C : 85 00 sta $00
800E : A5 01 lda $01
8010 : 69 00 adc #$00
8012 : 85 01 sta $01
8014 : CA   dex
8015 : D0 F1 bne $8008
 となったのでした。
 数学的に(?)1対1の関係があったら、逆変換できるはずです。
 ところが、アセンブル→ディスアセンブルとしたとき、
 上のリストと下のリストを見比べて、Vtmp0とか、.sumloopとかいった、プログラミング上必要な“だけ”の『ラベル』は当然失われてしまっています。
(説明に無理があるけどね……
 このページを見ている人は、上のようなアセンブリを知らないはずなんだけど、
 それに使う『ラベル』が失われた……とかいわれても……ねぇ)
 これは、ディスアセンブルで失われるものの氷山の一角(?)なのですが、まぁ、いろいろ失われるにせよ、数字の羅列より、文字の入った逆アセンブル結果のほうが人間にとって見やすいのは明白ですね。
MD6502
 ディスアセンブルするためには、ディスアセンブラというものを使います。
 MD6502というソフトを自分は使っています……というか、それ以外知らない^^
 MD6502で、検索サイトで検索すれば、すぐに見つかると思います。
 ……と、思ったら、転載してよいとのことなので、置かせていただきます。
 md6502
 製作者のMinachunさんに感謝しながら使わせてもらいましょう……

 MD6502はCUIです……慣れていない人は面食らうかもしれません。
 とりあえず、以下では『使えれば良いや』的な解説になります。
やっと作業へ
 実際にディスアセンブルしてみましょう。
 お好きなソフトを選んで……と、言いたいのですが、そういうわけにはいきません。
 とりあえず、プログラムが32KBのものをオススメします。或いは、16KBか。
 バイナリエディタで開いて、プログラムロムの大きさを表す5バイト目(位置04)の値が、01や02のものを選んでください。
プログラムを切り出す
 前回で述べたように、ファミコンのROMイメージは、3つに分かれています。
 ディスアセンブルしたいのは『プログラムロム』ですので、『ヘッダ』や『キャラクタロム』は要りません。
 そんなわけで、バイナリエディタで『ヘッダ』と『キャラクタロム』を切り落とします。
 ……実は、そんなことしなくてもディスアセンブルできるのですが。
 16KBの『プログラムロム』のものは、4000hまで、
 32KBの『プログラムロム』のものは、8000hまでになればOKです。

 厄介ですが、16KBのものは、このあと、ファイル全体をコピーして、ファイルの末尾にくっつけてください。
 つまり、内容が2回繰り返す……と。これで、サイズ8000hになります。
コマンドプロンプト?
 md6502はコンソール画面から動かさなければなりませんが、ちょっと面倒です。
 ということで、バッチってのを使います。
 md6502のフォルダの中に、今の、『プログラムロム』を切り出したものを、input.binという名前にしてコピーしてください。
 さらに、md6502のフォルダ内に、Windowsメモ帳等で、以下の内容のテキストを作成します。
md6502 input.bin output.txt
 最後に改行を入れたほうがいいかも。ファイルの名前は、『(適当な名前).bat』とします。
(※『(適当な名前).bat.txt』にならないように注意)
 出来たら、今の『(適当な名前).bat』をダブルクリックします。
 すると、一瞬黒い窓が表示され、そして、md6502のフォルダに、output.txtができたはず。
 それが、ディスアセンブル結果です。
例によって……
 μブロック002をディスアセンブルした結果を例としてあげて見ます。
 なにしろ、メーカー製のソフトの逆アセ結果とか、載せるとまずいからねぇ……自分もこのクソゲーを何回も引っ張り出したくないんですが^^
 実はおかしな記述をしているところが結構あったりして、あんまり出してこないほうがいいんですが……

 μブロック002のディスアセンブル結果(の一部)
オチ?
 とりあえず、逆アセンブルできればOKです。
 プログラムが32KBより大きいソフトに関しては……どーしよ(汗)
 次回から、逆アセ結果を見ていこうかなぁなんて考えていたりします……
(14)2007年1月14日 プレさ兵衛
inserted by FC2 system