Memory Search

Last-modified: 2012-02-07 (火) 12:39:38

ゲーム中のあらゆる値(キャラクターの体力、位置、速度など)は、メモリ(主にRAM)上の特定のアドレス(場所)に格納されています。画面からは読み取れない(読み取りにくい)ような情報でも、どの位置にどんな情報が格納されているのか知ることができれば、TASではそれを覗くことが出来ます。また、そういった情報を改造コードによって強制的に書き換えることで、特殊な状態での実験をおこなうこともできます。このページでは、特定のデータが格納されたメモリアドレスを探し出すための情報を示します。

目次

検索方法の概要

エミュレータの中にはメモリアドレス検索(Memory Search)機能を有するものがあります。これらは主に改造コード(Cheat)の検索に使われるため、Cheat Searchとも呼ばれ、検索機能も「Cheat」などのメニューに含まれていることが多いです(項目名は「Search for Cheats」など)。

検索用ウィンドウの多くは次のようなコントロールを持ちます(必ずしもすべてを有しているとは限らない)。

memorysearch.png
  • メモリアドレスの一覧。多くの場合「Old Value(古い値)」と「New Value(新しい値)」の表示を伴う。
  • 「Start(開始)」(「New Search(新規検索)」)、「Search(検索)」、「Add Cheat(改造コード追加)」のボタン。
  • 比較対象となる値を選択するグループボックス。「Old Value(古い値)」(「Previous Value(以前の値)」)、「Specific Value(特定値)」(「Entered Value(入力値)」)などのチェックを持つ。
  • 何かしらの値を入力するための入力ボックス(入力値との比較との比較を用いる際に使われる)。
  • 比較方法を選択するグループボックス。「< Less Than(未満)」、「>= Greater Than or Equal To(以上)」、「= Equal To(等価)」などのチェックを持つ。
  • 比較サイズを選択するグループボックス。「8 bits(8ビット=1バイト)」、「2 bytes(2バイト=16ビット)」などのチェックを持つ。
  • 値の種類を選択するグループボックス。「Unsigned(符号なし、正の数)」、「Signed(符号あり、正負の数)」、「Hexadecimal(16進数)」などのチェックを持つ。
  • 「Update Values(値の更新)」チェックボックス。「Search(検索)」時に比較対象となる「Old Value(古い値)」を更新するか否か。チェックを持たず常に更新される場合もある。
  • 「Watch(監視)」、「Clear Watches(監視状態のクリア)」のボタン。おそらく持たないエミュレータが大多数。

検索の流れは次に示すとおりです。最初に「検索開始」をします。ゲームを動かして探したい値を変化させ「比較」させて候補を絞り込みます。比較を繰り返して候補を絞ることで、特定のアドレスを見つけるのです。

目的のメモリアドレスを発見したら、それを選択して「Add Cheat(改造コード追加)」ボタンを押せば、そのアドレスの値を書き換えるための改造コードを追加できますし、「Watch(監視)」ボタンを押せば、そのアドレスの値を画面などに表示させることができます。

発見のための「比較」をおこなうには、関係ない値をうまく除外できるような検索の仕方が必要です。また、「比較」をおこなうためには「サイズ」や「符号」を適切に選ばなければなりません(でないと値が正しく認識されず、期待する比較がなされない)。以降の章では正しくて効率的な検索のためのヒントを示します。

検索結果がある程度まで絞り込めたら

検索結果が10個以下くらいまでに絞れたなら(それくらいまでしか絞れなかったなら)、特定には以下の方法が有効です。

  • すべての候補値をリアルタイムで監視する(連続的な変化が把握しやすい)
  • 改造コードで値を書き換えて変化を見る(ただし目的の変数であっても結果が現れないことはある)

同じもしくは非常に近い意味合いを持つ変数が複数あることもあります(保存用と処理用など)。

コンピュータにおける数値表現

値のサイズや符号の有無を推測するには、コンピュータの内部でどのように値が表現されているかという知識が必要です。でもたくさんのドキュメントを読むのは嫌という方のために、最初に便利な表を置いておきましょう。

サイズ最小値 (unsigned)最大値 (unsigned)最小値 (signed)最大値 (signed)
1 byte (8 bits)0 (0x00)255 (0xFF)-128 (0x80)127 (0x7F)
2 bytes (16 bits)0 (0x0000)65535 (0xFFFF)-32768 (0x8000)32767 (0x7FFF)
3 bytes (24 bits)0 (0x000000)16777215 (0xFFFFFF)-8388608 (0x800000)8388607 (0x7FFFFF)
4 bytes (32 bits)0 (0x00000000)4294967295 (0xFFFFFFFF)-2147483648 (0x80000000)2147483647 (0x7FFFFFFF)

サイズと符号によって値の表現範囲が異なることと、その具体的な表現範囲が一目でわかるかと思います。検索をおこなうときには、必要最低限のサイズと符号を設定しましょう。例を挙げれば、値の範囲が0?200であれば、負の数は必要ないので符号なし(unsigned)を選び、サイズには表現範囲が0?255の1 byteを選びましょうということです。必要以上のサイズを選ぶと他の値が比較に干渉してしまう可能性がありますし、符号を間違えると大小関係の扱いに違いが生じます。

なぜ上の表のようになるのか、コンピュータにおける数値表現について詳しく知りたい方は以下をご覧ください。知っておいて損はありません。

検索例/値が見える変数の検索

画面に値が表示されている変数のアドレスの探し方を示します(残り人数、所持金、スコアなど)。所持金のアドレスを探し方を例にすると、

  1. 適当な所持金で「検索開始」
  2. 所持金を変化させる(使る・得る)。入力値に現在の所持金を入力して「検索」
  3. 上のステップを繰り返し、検索結果を目的のものに絞り込む(先述の通り、改造コードで確認すると確実)

このようになります。もっともシンプルな例ですね。

例外: 特殊な方法で格納された値

画面に見える値で検索してもヒットしない場合があります。以下はそうなり得る一例です。

  • 表向きには10進数だが、値は16進数(Wikipedia:BCD)である(例:がんばれゴエモン)
  • 画面に表示される値の桁が底上げされている(例:スーパーマリオワールドのスコア、末尾の0は底上げであり、12340点のときの値はじつは1234である)
  • リトルエンディアンではなくビッグエンディアンで格納されている(例:ロックマンワールド5)

このような場合、値の相対的な変化から比較をおこなうか、その他推測で検索方法を工夫するしかありません。

検索例/相対的な変化から値を検索

具体的な値はわからないものの、相対的に大小どのような変化が生じているかは推測できる変数の探し方を示します(体力、位置、速度、時間など)。敵の体力を例にすると、

  1. 敵との戦闘が始まったところで「検索開始」
  2. 敵にダメージを与え、「古い値未満」で「検索」(この際、古い値を更新する)
    • 敵にダメージを与えず、「古い値と等価」で「検索」することも有効
  3. 上の検索ステップを繰り返し、検索結果を目的のものに絞り込む

誤って目的のアドレスを候補から除外しないよう、データサイズや符号の有無には注意しましょう。

検索例/不規則変化する値(乱数)の検索

乱数のアドレスを調べることで、乱数の変化するタイミングが調べられます。思い通りの値にすることができずとも、Luck Manipulationに役立つことはあり得ます。

  1. 乱数の値が異なるであろうと思われる数点でステートセーブ(乱数以外の条件は近い方がよい)
  2. それらを「等しくない」として比較、絞り込まれた候補を監視や改造コードで吟味する

このような手順で検索するのが一般的かと思われます。しかし、値の変化が不規則であること、検索条件の勘が外れやすいことなどから、正確に見つけ出すのはそれなりに困難です。

ありがちな変数ごとの特徴・注意点など

どのゲームにもありがちな変数に共通しがちなポイントなどについて考えます。

全共通

変数の意味を誤解(拡大解釈)しない、言い換えて変数の解釈を過信しないよう注意しましょう。でないと、かえって重大なものを見落とすかもしれません。

同じゲームの変数でも、バージョンによって違うアドレスに割り付けられていることがあります。複数のバージョンが存在する場合は情報交換に注意が必要です。

速度と位置

座標系は大抵、X軸(横軸)は左方向から右方向に向かうにつれて大きく、Y軸(縦軸)は上方向から下方向に向かうにつれて大きくなっています。クオータービューのように平面に加えて高さ(Z軸)を持つ場合、上下どちらが大きいかはわりとゲームに依ります。位置の値はそのような大小関係のうえで保持されていることが多いです(相対比較の際に重要)。

速度は負なら左、正なら右のように、符号で方向を併せ持つことが多いです。ただ、いつでも正の数を取り、別の値を元に方向を決める場合もあります(例:ドラえもん2)。

平面に高さを加えた3軸の場面で、Z座標を持つ代わりに、像と影の位置を別々に持っている場合もあるようです(例:がんばれゴエモン?ゆき姫救出絵巻?)。

速度や座標の変数が「pixel」と「sub-pixel」、言うなれば「整数部」と「小数部」に分かれていることもあります。

速度の変数が示さないところで移動に影響を与える要素が存在している可能性はあり得ます(ラグ、地形による直接効果など)。速度変数の値は役立ちますが、それがすべてではない可能性を頭の片隅に置いておくべきです。

速度変数が変化するような移動方法同士の比較をおこなう場合、大抵は周期あたりの総移動距離とフレーム数から平均速度を算出する方法が有効です。

敵のステータス

敵(ボス含む)のステータスは状況に応じて動的に割り付けられることが多いため、固定のアドレスを持たない可能性があり、以前に発見したアドレスが次回に通用しないことがあり得ます。このような場合、必要な状況になるたびに検索するほか仕方がないと思われます。

時間・フレームカウンタ

ゲームによってはプレイ時間用の内部タイマーを持つものがあります。また、アニメーションなどのためにフレーム毎にインクリメント(+1)される変数を持つものも多いです。

フレームカウンタの値はラグの確認に使えなくもないです(急激な変化が出るわけでもないので、便利とまでは言い難いところがある)。値が増加しないフレームはラグではないかという解釈です(もちろん、その解釈が正確だとは限りません)。

内部タイマーでは時折、単位がごまかされていることがあります。60FPSであれば当然60フレームで1秒ですが、処理の簡略化のために63フレームで1秒とされている場合もあります(例:メトロイドフュージョン)。こういった違いは検索結果を欺くことがあるので注意が必要です。

関連ページ

コメント (Comments / Discussions)

Tag: TAS教材