ポケモンDPで昨年12月から話題となっている Arbitrary Script Execution (ASE) を利用した「てんかいのふえ」イベントを見る方法を発見したので紹介します。
質問等があればこのgistにコメントするか このツイート にリプライを送ってください。
(ブロックされてたら…ごめんなさい。結構雑にブロックしてるのでひょっとするとあなたのことをブロックしているかもしれません。どうしても聞きたい場合は https://rinsuki.net/ にメールアドレスが書いてあるのでこちらに送ってください)
- これを実行してからのレポートはあんまりおすすめしません (理由は後述)
- エミュレータでしか試してないのでもしかすると実機だと動かないかもしれません
- あともしかすると自分のセーブデータ依存かもしれません (たぶんないと思うけど…)
- 追試求む!
- データに何があっても泣かない強い心、もしくはデータに何があっても泣かないROMを用意する
- ASE ができる状態を作る前に以下の2点を確認しておくとよいでしょう (条件を満たしていると不必要なスクリプト入力をスキップできます)
- 全国図鑑を持っているか
- だいじなものの中にてんかいのふえがあるか (入手方法は問わない…多分)
- 電卓の計算結果に応じてASEができる状態 (参考: http://detelony.blog.fc2.com/blog-entry-23.html)
- 検証環境は初期版ダイアモンドなのでパールだとだめかもしれません
- 試してないので普通にできるかもしれないしできないかもしれない (追試求む)
- 初期版でない (四天王の部屋でドアに向かってなみのりができない) ROM は以下の理由でたぶんできません
- ASE環境が現状構築できない/しづらい
- たぶんスクリプトで書き換える必要があるアドレスが変わってる
ASEができる状況下で以下のスクリプトを実行(現状のASEだと電卓で計算→リタイア→鳴き声が鳴ったらA)してください (電卓リミッター解除以外はたぶん順不同。上から順に実行して通ったのでダメそうだったら上から順に実行すると良いでしょう)
かけ算が書いていないものは * 1 = とか + 0 = とかして結果を出してください (計算結果にしないと実行されるスクリプトの場所に書かれません)
(16進数内のアンダーバーは見やすさのために引数/コマンドの境に入れてるだけなので消しても問題ありません)
内容 | 16進数 | 電卓入力用 |
---|---|---|
電卓リミッター解除(おなじみ) 実行後に適当にでかい値×1をして本当に解除できているか確認しておくといいかも |
0x2_28_02258A97_0007 |
124286369 × 1250149543 |
全国図鑑開放 (全国図鑑をもう開放済みならスキップしてよい) |
0x2_800C_01_022D |
21991843697 × 125 もしくは 2748980462125 |
フラグ0x11Eをオフにする アルセウスに会ったことないならいらないかも |
0x2_011E_001F |
8608677919 |
cmp書き換え レポート書いても再起動すると消える |
0x2_80_02063456_0007 |
180146210765930503 |
てんかいのふえ入手 (もう手に入れているならスキップしてよい) 危険かも? コマンド0002を呼び出せていないのでメモリの状態によっては変なスクリプトを実行してしまうかもしれない マーキングACEで入手したほうがいいかも |
0x8000_0001_01C7_007B |
9223372041179562107 |
各スクリプトの実行が終わったら、
- 今のASEの手順であれば右の方にあるはずのパルパークでリタイア
- (全国図鑑を実行前に手に入れていなかった場合は、全国図鑑が使えること、パルパーク前のとおせんぼしている係員がいないことを確認)
- だいじなものに「てんかいのふえ」があることを確認して
問題がなければやりのはしらに向かってください。うまくいっていればてんかいのふえを吹くか聞かれるはずです。
以下の理由によりレポートは書かないほうがいいと思います (がまあ ASE やってる時点で気にしないといえば気にしないか)
- てんかいのふえ入手時にコマンド0002が書けないことによりちょっとだけその後の何が入っているかわからないスクリプトを実行してしまうので未知の影響があるかもしれない
- この方法だと正規フラグを立てていないのにてんかいのふえを持っていることになるのでチート感が出る (まあそもそもてんかいのふえを持っている時点で…)
- 一部コマンドの命令を書き換えているのでひょっとすると未知の副作用があるかもしれない?
てんかいのふえを使うには以下の条件を満たしている必要があります。
- 現在場所がやりのはしらの特定座標 (他の条件を満たしていると確認メッセージが出るところ。出入口のタイルの真ん中)
- 殿堂入りしている (現状のASEでは殿堂入りが必須なので関係ない)
- 全国図鑑を持っている
コマンド028B 0x02
が 1 を返す- フラグ 0x11E が立っていない
- てんかいのふえを持っている (まあ使えるなら持っているでしょう)
これらの条件を満たしていないと「てんかいのふえ は むなしく なりひびいた…」というメッセージが出て不発になります。
以下のコマンドの内容はそのまんまなので省きます。
- 全国図鑑を開放するコマンド (単に正規の図鑑開放イベントから持ってきただけ)
- フラグ0x11Eを消す (スクリプトコマンド一覧から引いてきただけ)
- てんかいのふえを持つ (スクリプトコマンド一覧から引いてきただけ)
一番の問題はコマンド028B 0x02
が1を返すようにすることでした。
このコマンドは本来ふしぎなおくりもので当該アイテムを受け取る時にオンになるようで、普通のフラグON/OFFコマンドでは関与できませんでした。
内部処理としては何だかんだでどこかのメモリを読んで中身が0x1123
(=4387)であれば1、そうでなかったら0を返すというコマンドになっているようです。
最初は当時出回っていたらしい(当時は身近にそんな野蛮な環境がなかったので今になって調べた)チートコード同様に、
- まずふしぎなおくりものをASEで作り出す
- 後は正規(だったはずの)ルートと同様にフレンドリィショップで受け取る
というルートを考えていましたが、ASLR (Address Space Layout Randomization) により書き込む必要のあるアドレスがゲームを起動/リセットするごとに変わってしまい、スクリプト内からどこに書けばいいのかの推測ができなかったので、この手法は諦めました。
次にふしぎなおくりものを配達員から受け取るスクリプトを再現できないか試しましたが、変数にまず値を設定する必要があるようで、電卓で書けるスクリプトの長さである8バイトに収まりませんでした。
万策付きたと考えていたうちにミーアさんが成功ツイートを投稿していたのでちょっとここで飽きが来た………のですが、飽きたので情報をまとめておくか…とツイートを書いている時にマーキングACEの解説サイトでコマンド0005の処理コードを書き変えて便利にする方法が書かれていたことを思い出し、そこからインスピレーションを得てコマンド 0x28B 0x02
の処理自体を書き換えてしまえばいいというアイデアが思い浮かんできました。
どうやってこの処理をしているアドレスを割り出すか?という問題がありますが、私が利用したのはこのような方法でした。
- 既存のチートコードを参考にふしぎなおくりものを発生させる
- 受け取る前と受け取った後でエミュレータの機能でメモリサーチをして変動した値を探す
- 実際には
0x11230000
なアドレスはここしかないので後から見ると変動した値を探す必要はありませんでした
- 実際には
- 変動したアドレスを見つけたら「そのアドレスを読んだら実行を一時停止する」というブレークポイントをしかける
- DeSmuME をビルドし直さないと…とか言っていたのはDeSmuMEのビルド時にLuaを同梱しないとLuaスクリプトからブレークポイントを設定できないからでした
- その後 BizHawk なら同等の機能が使えることがわかったのでそちらのほうに Lua スクリプトを書き直しました
- そのままやりのはしらまで行く
- ブレークポイントにかかったら1命令ずつ実行して付近のディスアセンブル結果を見る
- エミュレータが自動でやってくれるのでラクチン
- アタリが付いたらエミュレータのメモリエディタで正規フラグを潰してから実際に命令を書き換えてみてうまくいくか試してみる
書き換える命令に関してはさすがにハンドアセンブルできるほど ARM の命令セットに詳しくないので適当なオンラインアセンブラを使いました。
ちなみに当初はメモリから読む部分の処理を上書きする想定だったのですが、DSのメインCPUの命令セットの ARMv5TE (のThumbモード)では16bit即値をレジスタに代入するのが素直にできなかったので一旦諦めかけました。
が、「それなら比較処理を変えたらいいんじゃないか?」と思いよくよくディスアセンブル結果を読んだ結果、 0x02063456
にある cmp r5, r0
(たぶんどちらかに期待した値、もう片方に現在の値が入っている)を cmp r0, r0
にしてしまう荒技で解決しました。
ところでこのプログラムにはASLRがかかっていないのか?というと、どうやら実際に実行されるプログラムにはASLRがかかっておらず、ASLRで変動するのはデータアドレスだけのようです。
(そもそもこれをASLRと読んでいいのかという問題があります。本当は ASLR もどきとか Pseudo ASLR と言うべきかもしれない)
この手法を応用すれば他の伝説ポケモンも呼べたりするかもしれません。
質問等があればこのgistにコメントするか このツイート にリプライを送ってください。
(ブロックされてたら…ごめんなさい。結構雑にブロックしてるのでひょっとするとあなたのことをブロックしているかもしれません。どうしても聞きたい場合は https://rinsuki.net/ にメールアドレスが書いてあるのでこちらに送ってください)