最近相次いで見つかっているPSPのセーブデータexploitですが、Wagic, Magic the Gathering, and PSP homebrewsでwololo氏が次のステップとなるバイナリーローダーの作り方の記事を掲載していました。【情報源:Wagic, Magic the Gathering, and PSP homebrews】
この記事はPSPのexploitでBinary Loaderを作ろう 第1部の続きになります。
バイナリーローダーをコンパイルする
このステップを実行する前にMatiaz氏とFreeplay氏のsparta_sdkをダウンロードすることをお勧めします。Gripshiftのexploitを利用したsparta_sdkはバイナリーローダーの参考例として非常に有用です。
バイナリーローダーはアセンブラで書いてしまうとそれ自体は非常にシンプルなものになります。SDKを利用してCをベースに書くこともできますが、sparta_sdkのバイナリーローダーはMIPSアセンブラで書かれているようです。アセンブラはC/C++よりもハードルが高いのですが、今回はMatiazs氏の作ったものを今回発見したexploitのケースに当てはめてみたいと思います。ですから何ヶ所かを置き換えるだけ、ということになります。
sparta_sdkのloader.Sのファイルを開いてみてください。基本的な作業内容はsparta binLoaderで使われているファンクションアドレスを置き換えることとなります。Matiaz氏はGripshiftで使えるようなアドレスを入れていますので自分が見つけたゲームexploitとはそこが異なります。記述してある4つのファンクション(sceIoOpen、sceIORead、sceIOClose、sceKernelDcacheInvalidateRange)を、先ほど作成したリストに沿ってGripshiftでの値を自分のゲームでの値に置き換えてください。先ほど私が作ったリストで言うと、sceIoCloseとなっている0x08A69854を0x08C88590に置き換える、などという感じです。
更に、ファイルネームがストアされているアドレスも変えてやる必要があります。ファイルネームとは自分で作ろうとしているバイナリのファイル名のことで、よく使われるのがms0:/h.binです。これをセーブデータのジャンプ箇所のあたりに文字列として記述しておかなければなりません。もちろんそのアドレスをasmコードとして出しておいてください。下記の例で言うと、ms0:/h.binというファイルネームをジャンプポイントより0xF0バイト後ろに置いたことになるので、spartaの0xC0をF0に書き換えます。注意しておきたいのはコンパイルしたバイナリーローダーの長さはF0より小さくしなければならないことです。そうしないとファイルネームのところがバイナリーローダーのコードで上書きされてしまいますよ。変えなければならないのはそのくらいです。ではこのファイルをコンパイルしてSDDATA.BIN(暗号化されていないセーブデータ)の中に書き込んであげましょう。
アセンブラのコンパイルはPSPSDKで提供されている各種ツールのなかでも特に難しいということはありません。ではsparta_sdkをヒントに、ここでコンパイルのためのコマンドを紹介します。psp-as loader.s
psp-objcopy -O binary a.out a.bin最初がコードをコンパイルするコマンドで、次がそれをバイナリー版にするコマンドです。
バイナリーローダーをセーブデータに書き込む
バイナリーローダーのコンパイルができればあとは簡単で、セーブデータに書き込むだけです。手でコピペしてもいいですし、お好きなスクリプト言語を使っても良いでしょう。注意してほしいのは先ほどこの記事でも書きましたが、$raにいれたアドレスから始まるよう正確に書き込むということです。書き込みをするにあたり、SDDATA.BINファイルにexploitの読み込み+バイナリーローダーをコンパイルして書き込みを直接やってしまえるように私の場合はRubyでスクリプトを組みました。コードは自分で見つけたexploit用に大幅に書き換えなければならないので画像としてお見せしておきます。コードを書き込むための方法は自分がやり易いと思うやり方で実行していただいて構いません。
この時点でバイナリーローダーの代わりにhello worldをアセンブラで作って入れておけば良いことにお気づきでしょう。ただ、バイナリーローダーなどではなくもっと簡単なコード(例えばsceKernelExitGameを呼び出すなど)を試してみるようなことはする必要ありません。自分の書いたコードを確実に動作させることに専念してください。
SDKの作成
一見難しそうに思えますが、実はそうでもありません。ファンクションをセーブデータにインポートできていればお茶の子さいさいです。必要なのはprxtoolを使って入手したインポートするファンクションのリストだけで、sparta_sdkのサンプルフォルダにあるsdk.hをアップデートするだけです。迷うようなことは全くありません。今回の例でいうと、0x08C88590を0x08A69854に置き換える、などです。先ほどの”.S”ファイルと同じです。実は、sparta_sdkのsdk.hファイルはベストな例とは言えません。それよりもMOHH exploitのsdk.Sを一度見てみた方が良いでしょう。これもアセンブラですが超シンプルで、ファンクションがどうとかを探す必要すらありません。
ここで、sdk.Sのファンクションの中での”functions imports”ファイルを分析するための簡単なRubyのスクリプトを作りました。ただ、prxtoolにもこの操作をする上で役立つオプションはあるようです。
MOHH exploitにあるsdk.hを探してみてください。”.S”と”.h”というファイルがそうです。Hello worldの作成
SDKの作成ができれば、Hello Worldは本当に簡単です。実際sparta SDKにあるサンプルを書き換えや流用できたわけですからね。最初はできるだけ小さなファイルを作るところから始めて下さい。 簡単に実証するためのCのコードは“sceKernelExitGame()”をコールすることです。作成したSDKとバイナリーローダー(先ほど作成したもの)がきちんと動作することを確認する分にはそれで十分です。sparta_sdkのイベントをすべて自作sdk用に置き換えるだけだと考えてください。代わりにMOHH sdk.Sを使った場合はmakefileに若干変更を加えなければなりません(その場合はspartaのMakefileではなくMOHHのMakefileを見て考えてみてください)。
コンパイル後に出力するファイル名はh.binにします。バイナリーローダーがms0:/h.binを読み込むようにしてあるので、そのh.binをメモリースティックのルートに配置します。バイナリーローダーが入っているSDDATA.binはSAVEPLAINというフォルダ名のサブフォルダ内に配置します。以上の準備が完了したらゲームを起動してください(もちろんSaveGameDeemerとPSPLinkのプラグインは有効にしておきましょう)。exploitが発動して自作Hello Worldが表示されるはずです。トラブルシューティング
exploitの動作がうまく行かない場合、いくつかの原因が考えられます。コンピューターのプログラムは書かれた流れ通りに実行されるだけなので、動作環境が不十分であってもバカ正直に間違った動作をしてしまいます。そんな時はPSPLinkの利用が成功の鍵となります。クラッシュしてしまったらRAMの状態を調べてみてください。正しいアドレスにきちんとジャンプしていますか?バイナリーローダーはそこにちゃんとありますか? すべて正しい場所にあって、おかしな理由で途切れたりしていませんか?実際に動作しているかを確認するためにバイナリーローダーにブレイクポイントを追加してみてください。バイナリーローダーの動作が確認できたら次はRAMに読み込まれるはずのHello Worldが設定したアドレスに読み込まれているかを確認してください。それができていれば今度はまた同様にHello Worldでブレイクポイントを設けてみてください。あとはいかに簡素化するかです。
操作をある程度自動化しないで一つ一つのステップを手動で行っているとかなり苦痛に感じるかもしれません。私は作業を自動化するようなスクリプトを作ることにまず時間を割いた方が良いと思います(バイナリーローダーのコンパイルやそれをセーブデータに書き込む作業など)。これなら自信があると言う言語でスクリプトを作りましょうセーブデータを暗号化し直す
最後のステップは公式ファームウェアでexploitを動作させるようにすることです。SEDというツールでセーブデータexploitを暗号化できます。SEDでの暗号化にはgamekeyが必要です。gamekeyはSaveGameDeemerで作られるSAVEPLAINデータの中にあります。XXXX.bin(XXXXはゲーム自体のコードです)というデータの一番最後の部分がgamekeyです。ファイルの一番最後の20バイトは必ずゼロとなっています。その前の16バイトがそのゲームのgamekeyです
SEDの使い方についてはググってください。ちょっといい加減な説明ですね。使い方さえ分かればSEDについては問題ないでしょう
SECRET: 0
PASS:
ローダーの.Sファイルで書き換える際
sceKernelDcacheInvalidateRange
は存在しないゲームの場合実行しなくても動きます
もちろんsceIo系は必須です