PSPのexploitでBinary Loaderを作ろう 第2部





最近相次いで見つかっている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のファイルを開いてみてください。

loader

基本的な作業内容はsparta binLoaderで使われているファンクションアドレスを置き換えることとなります。Matiaz氏はGripshiftで使えるようなアドレスを入れていますので自分が見つけたゲームexploitとはそこが異なります。記述してある4つのファンクション(sceIoOpen、sceIORead、sceIOClose、sceKernelDcacheInvalidateRange)を、先ほど作成したリストに沿ってGripshiftでの値を自分のゲームでの値に置き換えてください。先ほど私が作ったリストで言うと、sceIoCloseとなっている0x08A698540x08C88590に置き換える、などという感じです。
更に、ファイルネームがストアされているアドレスも変えてやる必要があります。ファイルネームとは自分で作ろうとしているバイナリのファイル名のことで、よく使われるのがms0:/h.binです。これをセーブデータのジャンプ箇所のあたりに文字列として記述しておかなければなりません。もちろんそのアドレスをasmコードとして出しておいてください。下記の例で言うと、ms0:/h.binというファイルネームをジャンプポイントより0xF0バイト後ろに置いたことになるので、spartaの0xC0をF0に書き換えます。注意しておきたいのはコンパイルしたバイナリーローダーの長さはF0より小さくしなければならないことです。そうしないとファイルネームのところがバイナリーローダーのコードで上書きされてしまいますよ。

saveplain_inject

変えなければならないのはそのくらいです。ではこのファイルをコンパイルしてSDDATA.BIN(暗号化されていないセーブデータ)の中に書き込んであげましょう。
アセンブラのコンパイルはPSPSDKで提供されている各種ツールのなかでも特に難しいということはありません。ではsparta_sdkをヒントに、ここでコンパイルのためのコマンドを紹介します。

psp-as loader.s
psp-objcopy -O binary a.out a.bin

最初がコードをコンパイルするコマンドで、次がそれをバイナリー版にするコマンドです。

バイナリーローダーをセーブデータに書き込む
バイナリーローダーのコンパイルができればあとは簡単で、セーブデータに書き込むだけです。手でコピペしてもいいですし、お好きなスクリプト言語を使っても良いでしょう。注意してほしいのは先ほどこの記事でも書きましたが、$raにいれたアドレスから始まるよう正確に書き込むということです。

書き込みをするにあたり、SDDATA.BINファイルにexploitの読み込み+バイナリーローダーをコンパイルして書き込みを直接やってしまえるように私の場合はRubyでスクリプトを組みました。コードは自分で見つけたexploit用に大幅に書き換えなければならないので画像としてお見せしておきます。コードを書き込むための方法は自分がやり易いと思うやり方で実行していただいて構いません。

ruby

この時点でバイナリーローダーの代わりにhello worldをアセンブラで作って入れておけば良いことにお気づきでしょう。ただ、バイナリーローダーなどではなくもっと簡単なコード(例えばsceKernelExitGameを呼び出すなど)を試してみるようなことはする必要ありません。自分の書いたコードを確実に動作させることに専念してください。

SDKの作成
一見難しそうに思えますが、実はそうでもありません。ファンクションをセーブデータにインポートできていればお茶の子さいさいです。必要なのはprxtoolを使って入手したインポートするファンクションのリストだけで、sparta_sdkのサンプルフォルダにあるsdk.hをアップデートするだけです。迷うようなことは全くありません。今回の例でいうと、0x08C885900x08A69854に置き換える、などです。先ほどの”.S”ファイルと同じです。

sdk

実は、sparta_sdkのsdk.hファイルはベストな例とは言えません。それよりもMOHH exploitのsdk.Sを一度見てみた方が良いでしょう。これもアセンブラですが超シンプルで、ファンクションがどうとかを探す必要すらありません。

sdk_asm

ここで、sdk.Sのファンクションの中での”functions imports”ファイルを分析するための簡単なRubyのスクリプトを作りました。ただ、prxtoolにもこの操作をする上で役立つオプションはあるようです。
MOHH exploitにあるsdk.hを探してみてください。”.S”と”.h”というファイルがそうです。

Hello worldの作成
SDKの作成ができれば、Hello Worldは本当に簡単です。実際sparta SDKにあるサンプルを書き換えや流用できたわけですからね。最初はできるだけ小さなファイルを作るところから始めて下さい。 簡単に実証するためのCのコードは“sceKernelExitGame()”をコールすることです。作成したSDKとバイナリーローダー(先ほど作成したもの)がきちんと動作することを確認する分にはそれで十分です。

hello

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については問題ないでしょう?



  1. J416’s avatar

    SECRET: 0
    PASS:
    ローダーの.Sファイルで書き換える際
    sceKernelDcacheInvalidateRange
    は存在しないゲームの場合実行しなくても動きます
    もちろんsceIo系は必須です

  2. まも助’s avatar

    SECRET: 0
    PASS:
    >J416さん
    >ローダーの.Sファイルで書き換える際
    >sceKernelDcacheInvalidateRange
    >は存在しないゲームの場合実行しなくても動きます
    >もちろんsceIo系は必須です

    貴重な情報ありがとうございます。

    これを見て取り組んでみよう、と思う方が続々出てきてくれることを願っています。
    そうすればフォーラムがもっと盛り上がるかな、なーんて。

  3. neuron’s avatar

    SECRET: 0
    PASS:
    大変参考になりました!

  4. まも助’s avatar

    SECRET: 0
    PASS:
    >neuronさん

    参考にしてくださいね。
    ただ、あくまでも私は翻訳しただけで内容はwololoさんです。彼が一番の立役者です。

  5. pshk’s avatar

    SECRET: 0
    PASS:
    はじめましてまもすけさん。
    自分は昨日セーブデータのexploit(PSP-1000の6.30でもクラッシュは確認)を見つけたようなので、この記事を参考にしてバイナリローダーを作っていたのですが、何度実行してもsceIoOpenのあたりでBus Errorになってしまいます。
    それで、prxtoolでeboot.pbpを開いたとき、sceIoOpenなどの関数の実アドレスが0x08000000番台ではないこと(prxtoolで表示されている関数のアドレスが正しくないこと)が原因かと思いましたがこれは違いますよね?
    他の原因としては何が考えられるでしょうか?

    同じ名前でGameGazフォーラムに登録してこの質問をしようとしたのですが、アクティベートのメールが1日経っても届かなくてログインができないのでとりあえずここに書き込みました。

  6. まも助’s avatar

    SECRET: 0
    PASS:
    >pshkさん

    たぶんpshkさんだろうと思われるアカウントがスパムらしき連中に混じって無効アカウントに入っていましたので、再度アクティベーションメールを送信しましたのでご確認ください。

    それから、exploit発見おめでとうございます。
    prxtoolで表示される関数リストのアドレスは
    0x08800000
    以降のユーザーメモリー領域のアドレスになるはずですので、0x08800000より前のアドレスしか出てこないであれば出力結果が間違っています。

    リストが出たと言うことは復号はできているはずですが、可能性があるとすればSYSDIRフォルダのEBOOT.BINではなく同じISOイメージ内の違うEBOOT.BINを復号化してしまったのかもしれません。
    (私も1回それやったことあります)

    うまくいったらGameGazフォーラムで報告してくださいね。

  7. pshk’s avatar

    SECRET: 0
    PASS:
    まもすけさん、回答ありがとうございます。
    おかげさまでバイナリローダーがh.binを読み込んで、Hello Worldが(たぶん)不完全ながらも動作するところまでこぎつくことができました!

    あのあと何度も正しいeboot.pbpを使用しているかなどを確認してprxtoolでアドレスの取得を試みたのですが、prxtoolでは正しいアドレスが見つかる気配がなかったため、NIDSの関連付けが一緒に表示されないので手間がかかりますがpsplinkのmodimpコマンドを利用して必要な関数のアドレスを調べました(そちらではちゃんと0x08800000〜のアドレスが表示されていました)。

    あと、まだGameGazフォーラムからメールが届いてないです・・・gmailで登録したのがまずかったのでしょうか?

  8. pshk’s avatar

    SECRET: 0
    PASS:
    すみません、GameGazのメール届いていました。
    迷惑メールフォルダに入っていたみたいです・・・

  9. まも助’s avatar

    SECRET: 0
    PASS:
    >pshkさん

    >すみません、GameGazのメール届いていました。
    >迷惑メールフォルダに入っていたみたいです・・・

    良かったです。
    他にも迷惑メール扱いになってしまっている方がいそうだなぁ。

Reply

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です