Skip to content

Instantly share code, notes, and snippets.

@rinsuki
Last active April 28, 2022 15:20
Show Gist options
  • Save rinsuki/3e19dcdd0a1de9bf8486666db7ac51d7 to your computer and use it in GitHub Desktop.
Save rinsuki/3e19dcdd0a1de9bf8486666db7ac51d7 to your computer and use it in GitHub Desktop.
ポケモンDPのASEで「てんかいのふえ」イベントを見る

ポケモンDPのASEを利用して「てんかいのふえ」イベントを見る

ポケモン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 の処理自体を書き換えてしまえばいいというアイデアが思い浮かんできました。

どうやってこの処理をしているアドレスを割り出すか?という問題がありますが、私が利用したのはこのような方法でした。

  1. 既存のチートコードを参考にふしぎなおくりものを発生させる
  2. 受け取る前と受け取った後でエミュレータの機能でメモリサーチをして変動した値を探す
    • 実際には0x11230000 なアドレスはここしかないので後から見ると変動した値を探す必要はありませんでした
  3. 変動したアドレスを見つけたら「そのアドレスを読んだら実行を一時停止する」というブレークポイントをしかける
    • DeSmuME をビルドし直さないと…とか言っていたのはDeSmuMEのビルド時にLuaを同梱しないとLuaスクリプトからブレークポイントを設定できないからでした
    • その後 BizHawk なら同等の機能が使えることがわかったのでそちらのほうに Lua スクリプトを書き直しました
  4. そのままやりのはしらまで行く
  5. ブレークポイントにかかったら1命令ずつ実行して付近のディスアセンブル結果を見る
    • エミュレータが自動でやってくれるのでラクチン
  6. アタリが付いたらエミュレータのメモリエディタで正規フラグを潰してから実際に命令を書き換えてみてうまくいくか試してみる

書き換える命令に関してはさすがにハンドアセンブルできるほど ARM の命令セットに詳しくないので適当なオンラインアセンブラを使いました。

ちなみに当初はメモリから読む部分の処理を上書きする想定だったのですが、DSのメインCPUの命令セットの ARMv5TE (のThumbモード)では16bit即値をレジスタに代入するのが素直にできなかったので一旦諦めかけました。

が、「それなら比較処理を変えたらいいんじゃないか?」と思いよくよくディスアセンブル結果を読んだ結果、 0x02063456 にある cmp r5, r0 (たぶんどちらかに期待した値、もう片方に現在の値が入っている)を cmp r0, r0 にしてしまう荒技で解決しました。

ところでこのプログラムにはASLRがかかっていないのか?というと、どうやら実際に実行されるプログラムにはASLRがかかっておらず、ASLRで変動するのはデータアドレスだけのようです。

(そもそもこれをASLRと読んでいいのかという問題があります。本当は ASLR もどきとか Pseudo ASLR と言うべきかもしれない)

おまけ

この手法を応用すれば他の伝説ポケモンも呼べたりするかもしれません。

質問等があればこのgistにコメントするか このツイート にリプライを送ってください。

(ブロックされてたら…ごめんなさい。結構雑にブロックしてるのでひょっとするとあなたのことをブロックしているかもしれません。どうしても聞きたい場合は https://rinsuki.net/ にメールアドレスが書いてあるのでこちらに送ってください)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment