セーブデータ内に"aaaa"を入れることでバッファーオーバーフローにより$raに0x61616161が現れるのはexploitです。
例えば
- コード: 全て選択
Exception - Bus error (instr)
Thread ID - 0x0485F51F
Th Name - main
Module ID - 0x0487572B
Mod Name - USODAYON
EPC - 0x61616160
Cause - 0x10000018
BadVAddr - 0xFED9D88C
Status - 0x60088613
zr:0x00000000 at:0xDEADBEEF v0:0x00000000 v1:0x00000220
a0:0x00000088 a1:0x089F5E1C a2:0x089F0000 a3:0x089F0000
t0:0xDEADBEEF t1:0x00000000 t2:0x00000000 t3:0x00000003
t4:0x088E87E8 t5:0xDEADBEEF t6:0xDEADBEEF t7:0xDEADBEEF
s0:0x089F5E1C s1:0x09FFE3A4 s2:0x09FFE7D0 s3:0x00000021
s4:0x00000001 s5:0x08800000 s6:0xDEADBEEF s7:0xDEADBEEF
t8:0xDEADBEEF t9:0xDEADBEEF k0:0x09FFE800 k1:0x00000000
gp:0x0892F320 sp:0x09FFE380 fp:0x09FFE790 ra:0x61616161
"aaaa"を16進数で表した61616161(HEXコードだと0x61616161 ちなみに"AAAA"だと0x41414141になります。必ずしも"aaaa"である必要はありません)が$raに表示されていたらそれはexploitです。
では、以下の場合はどうでしょう。実はこれもexploitです。
- コード: 全て選択
Exception - Address load/inst fetch
Thread ID - 0x0463FD5F
Th Name - user_main
Module ID - 0x04644711
Mod Name - USODAYON
EPC - 0x088BE860
Cause - 0x10000010
BadVAddr - 0xC5587624
Status - 0x60088613
zr:0x00000000 at:0xDEADBEEF v0:0x000004A0 v1:0x089CD520
a0:0x00000000 a1:0x089D0000 a2:0xFFFFFFFF a3:0x61616161
t0:0xBCBCBCAC t1:0x089C0000 t2:0x089D0000 t3:0x00000240
t4:0x00000008 t5:0x089BD0C0 t6:0x08C1A070 t7:0x00000000
s0:0x00000000 s1:0x089CA598 s2:0x61616161 s3:0x089D0000
s4:0x089BB974 s5:0x089CAE0C s6:0x0000002C s7:0x00000000
t8:0xDEADBEEF t9:0xDEADBEEF k0:0x09FFFB00 k1:0x00000000
gp:0x089C6110 sp:0x09FFEDD0 fp:0x09FFEDD0 ra:0x088B8B60
0x088BE860: 0x8CE20004 '....' - lw $v0, 4($a3)
host0:/>disasm 0x088BE860 5
0x088BE860: 0x8CE20004 '....' - lw $v0, 4($a3)
0x088BE864: 0x10400011 '..@.' - beqz $v0, 0x088BE8AC
0x088BE868: 0x8EB10008 '....' - lw $s1, 8($s5)
0x088BE86C: 0x02202821 '!( .' - move $a1, $s1
0x088BE870: 0x0040F809 '..@.' - jalr $v0
PSPLinkの結果を見て次に何をどうすれば良いのか分からないと時間だけかかってしまいます。
PSPLinkの結果が少し変わっただけで何をしたら良いのか分からず、個別パターンごとに誰かに指示を仰ぐととてつもなく時間がかかるので、最低限の逆アセンブラの基本だけ書きます。
セーブデータをHEXエディタで開くとこのような数字の羅列が出てきます。
- コード: 全て選択
00004A20: 8A 11 20 0E 18 00 22 AE 4B 13 20 0E 21 20 40 00
00004A30: 1C 00 23 8E 21 20 00 02 21 10 62 00 8A 11 20 0E
00004A40: 1C 00 22 AE 49 13 20 0E 21 20 40 00 20 00 23 8E
00004A50: 21 20 00 02 21 10 62 00 8A 11 20 0E 20 00 22 AE
00004A60: 47 13 20 0E 21 20 40 00 24 00 23 8E 21 20 00 02
数字の羅列では人間が理解できないので、それを分かるようにするための言語がアセンブラです。アセンブラでプログラムを作るのが正規のやり方だとすると、逆に数字の羅列を分かりやすくアセンブラで表示することを逆アセンブルするといいます。
EPC (Exception Program Counter)は、そこに示されたアドレスでクラッシュしていることを表しています。
そのアドレスの前後で何が起こっているのかを解析するために逆アセンブル(Disassemble)をして表示させます。
そのためのコマンド(命令)が
disasm
です。
原則としてexploitの解析をする場合には逆アセンブラでの解析が必要ですが、以下の場合には不要です。
1:$raに0x61616161が出た場合
$raに0x61616161が出た場合には逆アセンブラする必要がありません。$raは「戻りアドレス」が入っているので必ずそのアドレスへ戻る仕組みになっているからです。
2:どのレジスタにも0x61616161が無い場合
どのレジスタにも0x61616161が無いということは、レジスタコントロールができないことを意味します。つまりコントロールできるものが一切無い場合には"調べても無駄"ということです。
コマンド(命令)で
disasm 0x088BE860 5
というのは、0x088BE860から5行分逆アセンブルした結果を表示させなさいという意味です。(注意:5行だけで結果が出るのはかなり稀な超ラッキーなケースです。普通は20行〜30行の逆アセンブルをするようにしてください。)
0x088BE860 というアドレスはどこから来ているのかと言うと、
EPC 0x088BE860
となっているEPCで表示されたアドレスにあたります。
逆アセンブルして気が付くと思いますが、一番左に表示されているアドレスは4バイトずつ増えています。これは4バイトづつで1つの命令になっているからです。
逆アセンブルすると1つの命令が4バイトで構成されて1行に表示されているわけですから
disasm 0x088BE860 5
というのは0x088BE860から20バイト分の逆アセンブル結果が表示されていることになります。
場合によっては
disasm 0x088BE850 20
というコマンドで、0x088BE860より0x10バイト前からの逆アセンブルが必要になる事もあります。
先ほどの例の場合
s2:0x61616161
a3:0x61616161
の2つのレジスタがコントロールできていますが、逆アセンブラの結果で出てくるのは$a3だけで、なぜ$s2に0x61616161が入ったのかは全く分かりません。
もしかするとs2:0x61616161へ先に入った値が$a3へコピーされているかもしれません。
それを調べるにはEPCで表示されたアドレスより前の逆アセンブルが必要になります。
つまり、EPCで表示されたアドレスの前後で何が起こっているのかを表示させて状況を確認するためにdisasmコマンドを利用するのです。
クラッシュしたEPCのアドレスより前の逆アセンブル結果には、何が起こってレジスタに例えば「aaaa」と入れたものが「61616161」と入っているのかが出てきます。
後ろ部分には、その結果何が起こるのかが出てきます。
何が出てくるとexploitなのかと言うと、今回の例の場合
lw $v0, 4($a3) <- $a3で$v0がコントロールできる
・
・
・
jalr $v0 <- コントロールできる$v0のアドレスへジャンプ命令で飛ばす事が出来る
となり、任意のアドレスへのジャンプ(分岐)命令がポイントになります。
つまりjalr(ジャンプコマンドの一つ)の後に出てくるレジスタをユーザーがコントロールできれば任意の場所にジャンプさせることが出来るので、ユーザーが自分で書き換えが出来るセーブデータ部分にコードを仕込んでおき、そのコードが書かれているアドレスにジャンプさせることが自由に出来れば自作コードを実行することが出来る
ということです。
exploitになる可能性が存在するかどうかの判断としては、EPCのアドレス以降の逆アセンブラ結果にジャンプ命令や、分岐命令が存在するかどうかを基準にしてください。
ジャンプ命令や、分岐命令が無い場合にはexploitにはなりません。
以下にジャンプ/分岐命令の例を挙げておきます。意味は英文から読み取ってください。命令は英文の頭文字を合わせたものになっているので非常に分かりやすいでしょう。分岐は条件を満たさないといけないので使える可能性はほとんどありません。基本的にはジャンプ命令が無い場合にはexploitにならないと考えてください。
ジャンプ命令
j :Jump
jal :Jump And Link
jr :Jump Register
jalr :Jump And Link Register
分岐命令
beq :Branch on Equal
bne :Branch on Not Equal
blez :Branch on Less than or Equal to Zero
bgtz :Branch on Greater Than Zero
bltz :Branch on Less Than Zero
bgez :Branch on Greater than or Equal to Zero
bltzal :Branch on Less Than Zero And Link
bgezal :Branch on Greater than or Equal to Zero And Link
「aaaa」の数を増やす減らすは、挙動を変えてみるために行っています。1バイト変えるだけでもEPCの値が変わる可能性がありますし、クラッシュアドレスが変われば全く別ものになります。
が、いくら増やしてもEPCの値が全く変わらない場合にはそのゲームはさっさと諦めるか、全く異なるアドレスへの文字入力を狙ってみた方が良いでしょう。