3: ポインタリストを使ってアドレスランダム化に対応
概要
CheatEngineでお金の値が格納されているアドレスが特定できたとして、ゲーム再起動時にまたそのアドレスにお金の値が格納されているとは限りません。 こういったアドレスランダム化に対応するために、お金の値が格納されている絶対アドレスを覚えておくのではなく、あるPEファイル(ゲームの実行ファイル自体など)の先頭アドレスからの相対アドレスを使うという方法があります。 この相対アドレスは、厳密にはファイルの先頭から何番目のオフセットにあるアドレスが指しているアドレス...のように複数のポインタを連結した形(マルチレベルポインタ)で表現されています。今回は、CheatEngineで特定したゲーム上のお金の値が入っているアドレスの、ポインタリストを作成することを目標とする。
Unityで作ったゲームを対象にやっていき、ゲームのサンプルはココからダウンロードできる。
アドレスランダム化のざっくり仕組み
お金の値が格納されている絶対アドレスを覚えておくのではなく、あるPEファイル(ゲームの実行ファイル自体など)の先頭アドレスからの相対アドレスを使うと書いたが、なんで相対アドレスにするとランダム化を回避できるのかという点が気になると思う。
実は、アドレスランダム化は完全にただ不規則にアドレスがランダムになっているのでは無い。 例えばDLLファイル(動的にリンクされる実行ファイルのライブラリ)なら、そのファイルがロードされるアドレスだけランダムであって、DLL内部のコードの配置はランダム化されていないので、DLLの先頭アドレスからのオフセットは各々変わらない。 あるいは、スタック領域(関数呼び出し時の引数やリターンアドレスなどが置かれる領域)も、どのアドレスからをスタック領域とする、というのはランダムだが、スタックの開始アドレスからの相対的なアドレスは不変になっている。
図で表せば以下のようなイメージである。

Base Address
と言う。よって、
Base Address
からのオフセットでポインタをマルチレベルで辿っていくという表現方法でアドレスを表すとランダム化に対応できる。
とりあえずポインタリストを作成してみる
ポインタリストの作成はCheatEngineが自動化してやってくれるので、まずはやってみる。前回の記事などを参考に、お金のアドレスを特定できたとします。
そしたら下図のように、AddressListにある特定したお金のアドレスを右クリックし、
Pointer scan for this address
を選択します。

OK
を押しちゃいましょう。
押すと、ポインターマップ(要はスキャン結果)をどこに保存するかが出てくるので、適当な所を指定しておきましょう
(結構一杯ファイルが出てくる場合があるので、専用のフォルダの中に作るといいと思います)。

スキャンが終わると、下図のように多くのお金のアドレスへのポインタリストが出てるかと思います。

これはあくまで自動で総当たりで見つけてくれる機能なので、今回たまたま、この経路でお金のアドレスにたどり着いただけで、実際はゲーム起動毎にポインタの値が意図するアドレスを指していなかったりすることがあります。
それなので、一回CheatEngineをそのままにしたまま、ゲームだけ再起動して、下図のようにまたCheatEngineをアタッチします。

Yes
を押しましょう。

20G
にした後、先ほど作成したポインタリストを見てみると、下図のようにちゃんとお金を指しているポインタリストと、そうではないポインタリストがあると思います。

まずは下図のように、
Pointer Scanner > Rescan memory
を押しましょう。

251B7FB94A0=20
)からわかる通り、お金のアドレスは0x251B7FB94A0
であることがわかります。
よって、下図のようにこのアドレスを出てきたウィンドウに打ち込みます。

.PTR
ファイルに上書き保存しちゃいましょう。これで、下図のように候補が半分以下に絞られました。

- CheatEngineつけっぱなしで、ゲームだけ再起動
- CheatEngineをアタッチして、ゲーム内でお金を拾う
- お金の値をちゃんと指せているポインタリストを探し、今回のお金のアドレスを見つける
Pointer Scanner > Rescan memory
で再び今回のお金のアドレスでスキャンして絞る
繰り返したら、下記画像のようにダブルクリックするとAddressListの方に追加されるので、いくつか追加しておきましょう。

うまく行ってれば、お金の値をちゃんと見つけられているはずです!

ポインタリストの読み方
ポインタリストのあの表をどうやって読むのかを理解することは、後にチートコードを書くときに必要となる。もうポインタスキャンのウィンドウを閉じてしまったという場合は、AddressListにある適当なアドレスを右クリックして再び
Pointer scan for this address
を押してから、
こんどは出てきたウィンドウでキャンセル
を押せば、ポインタスキャンのウィンドウを再び出すことができ、下図のようにFile > Open
でポインタリストを作成する時に保存しておいた.PTR
ファイルを開く。


a = (mono.dllの先頭アドレス + 0x00264110) のアドレスに入ってる値
b = (a + 0x310) のアドレスに入ってる値
c = (b + 0x38) のアドレスに入ってる値
(c + 0x4A0) のアドレスに入ってる値 = 0x192FC0694A0
実際にコーディングする際は、mono.dllの先頭アドレス(BaseAddress)を取得する必要があります。