EDF4.1で学ぶ、Cheat Engineでメモリを覗く方法

Table of Contents

ゲーム内データをプログラムから覗こう

この記事は、下記記事の続きだ。
https://drroot.page/wp/?p=222

概要

前回は人力で引っこ抜いてきた静的メモリアドレスだが、Cheat Engineにはポインタスキャンというステキ機能が備わっている。
通常のスキャンだけでは静的アドレスを特定できない場合、特定したいメモリアドレスの共通の親ポインタを探す必要がある。
今回はSteam版EDF4.1を例に、Cheat Engineで静的メモリを探し当てる方法を纏めてみた。
尚、中間言語を介するUnity製のゲームなんかはこの方法が使えないので注意。あくまでネイティブバイナリ限定だ。

前提

ゲームでよくあるチートは「HPをいじる」だ。EDFでは体力値をアーマーというので、以下APと表記する。
メモリスキャンでAPのアドレスを見つけ、エディットすればゲーム内のAPを幾らでも上げられる…というところまでは多くの解説が転がっている。
しかし、「このアドレスを対象に、別のプログラムからAPを監視する」なんてことをやろうとすると躓く事になる。
APのアドレスはゲームを起動する度に(何ならミッションを選び直す度に)変化するからだ。

何故このような挙動をするかというと、ゲームに関わらず多くのプログラムは、メモリを必要な時に確保して必要な時に開放する。
Cなら昔ながらのmallocによる動的確保、オブジェクト指向言語ならnew演算子によるインスタンスの生成などがそうだ。
つまりどこかに静的=何度起動し直しても同じメモリに配置されるポインタ変数があり、そいつが目的のAPのアドレスを指している事が予想される。
ポインタスキャンとは、目的の変数を元に、その変数を指し示すポインタを探してくれる機能だ。

共通ポインタを見つける

ポインタスキャン

毎回起動したらアドレスが変わるのだから、最低でも2回ほどゲームを起動し直し、目的の変数への道筋を探す必要がある。
2パターンのスキャンマップを生成し、どちらの場合でもヒットする変数が見つかれば勝ちと言えるだろう。

まずは目的の変数を見つけ、変数リストに突っ込んでおく。今回の例はAPの最大値だ。
次に右クリメニュー→Generate Pointermapを選択。ファイル保存画面が出るので、わかりやすい名前をてきとーにつけて保存。
早い話がメモリをダンプしてるので、若干時間はかかるものの特に設定等は不要で終わる。

ゲーム一式を再起動したら、もう一度AP最大値を探し直す。
見つかったらそのアドレスに対し、今度は「Pointer scan for this address」を選ぶ。
すると下記画像のような画面が出る。

ここで「Use saved pointer map」にチェックするとファイル選択ダイアログが出るので、さっき保存したポインタマップを選択。
その後セレクトボックスから最大アーマーの値を選ぶと、手元の変数も含めて共通の親ポインタをスキャンしてくれる。
設定周りは適当で構わないが、「Max different offset per node」はチェックした上でせいぜい5か6くらいがお勧めだ。
このオプションは何世代まで親の変数を探すかの設定だが、1増やす毎に計算量が指数関数で増える。
なので4あたりから始めて、ヒットしなければ増やすくらいの感覚で良い。

スキャン結果を読む

ポインタスキャンが終わると、共通の親ポインタの一覧がどかっと出てくる。

この時、"~exe"+XXXXXXXXの形式になっている事が重要だ。
exeファイルの配置されるアドレスは不定だが、その後ろのオフセットアドレスは静的だからだ。
なので、OSにexeファイルのアドレスを聞く→オフセット値を足す→そのアドレスの値を読む→オフセットを足す…としていけば目的のアドレスに辿り着ける。

さて、スキャン結果をざっと見た感じ、どうやら目的地への道筋は無数にあるようだ。
何も長ったらしい道筋をわざわざ選ぶ理由は無いので、今回は決め打ちでOffset 3までで辿り着ける下記ルートを選択する。
"EDF41.exe"+00CC84E8 -> 28 -> 130 -> 8 -> 168

あとはコードを書けばプログラムから各種値をすっこ抜ける。
コードは前回記事とほぼほぼ共通なのでそっち参照。
ただし、前回が32ビットアプリ向けだったのに対し、今回は64ビット長でメモリを扱う必要があるので注意。

カテゴリー: IT パーマリンク

コメントを残す

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