2021/01/09

Unity 製ゲームの場合に使用できる、Autosplitter 用の asl で使用したいメモリアドレスの特定方法

Cheat Engine を使って asl ファイルで利用するための静的アドレスを特定する場合、一つの値に的を絞って値を検索して特定する方法があります
 が、その場合は欲しい値が存在している保証がなく、また、欲しい値の数だけ検索を繰り返す必要があります

Unity 製ゲームの場合は mono の分析機能を利用することで、欲しい値を格納しているフィールドの有無を知ることができ、さらにはクラス単位でフィールドの値を格納している静的アドレスを特定することができます

この記事はメモリアドレスを特定する方法のみの記事です
asl の全体的な説明や基本的な作り方などをまとめた記事もありますので、よろしければこちらもご覧ください

また、構造解析機能を使ってメモリアドレスを調べる部分の実演をした動画を公開しておりますので、よろしければこちらも参考としてご覧ください


1. 欲しいフィールドを含むクラスの探索
静的アドレスの特定をしたいゲームと Cheat Engine の両方を起動して、Cheat Engine の "Open Process" から Process List を開いて、ゲームを選択して "Open" を押します
ゲームプロセスのオープン

メニューバーから "Mono" -> "Dissect Mono" を選択して、開いた "Mono dissector" 画面から欲しいフィールドを含むクラスを探します
解析画面を開く 画面内の ">" を押すとツリーの下の階層が開き、Unity 製ゲームでは "Assembly-CSharp" の下の階層に各クラスが、クラスの下の階層の "fields" にそのクラスのフィールドが含まれています
 クラス名に +<> が含まれているものは、ここでは無視しても良いらしいです
ゲームのクラス一覧

注意
  • 全てのクラスを片っ端から開いてそれっぽい名前のフィールドを見つける、くらいのつもりで根気よく
  • フィールド名で当たりを付けて検索しても良いです
  • 特に、あるクラスが他のクラス内で実体化されている場合などは検索を使わないと見つけにくいです
  • 次の手順まで進めるとそのフィールドの現在の値を知ることができるので、その値や値の変動を見て、自分が欲しいと思っていたフィールドなのかを確認できます
     あるいは現在の値を見ながら、asl に使えそうなフィールドを探すこともできます

2. クラス内のフィールドの動的アドレスの特定
項目の Mono dissector で欲しいフィールドが含まれているクラスを選択してから右クリックして "Data Structure" -> "Dissect Structure" を選択して Sturucture dissect 画面を開きます
構造解析画面を開く

一旦、Mono dissector 画面に戻って、先ほど選択したクラスで右クリックして "Find instances of class" を選択して Instances of GameController 画面を開きます
 この画面は、メモリ上にクラスの実体が作られていればその動的アドレスの候補が表示されます
 もしクラスの実体がメモリ上に無い場合は何も表示されないため、ゲームを操作してクラスの実体が作られる場面まで進めてから開きなおします
実体化しているクラスの検索

大抵の場合は動的アドレスの候補が複数表示されるので、その中から正しい動的アドレスに絞り込む必要があります
 Instances of GameController 画面に表示されているアドレスを Ctrl+C でコピーして Sturucture dissect 画面の Group 1 の真下にあるテキストボックスに張り付けるとクラスのフィールドに対応した値が表示されます
 欲しいフィールドに限らず、そのクラスに含まれる全てのフィールドの値の整合性を見て、その動的アドレスの候補が正しい動的アドレスなのかを判断します
 整合性が確認できたアドレスが、そのクラスの動的アドレスです
正しい動的アドレスの確認

整合性の確認の例
  • bool 型のフィールドが bool 値になっている・いない
  • 使われているハズのフィールドのポインタが 0 になっている・いない
  • ゲームを操作すると値が変わる・変わらない
  • アイテムなどの数量がゲーム画面内の数量と一致している・していない
注意
  • 全てのアドレス候補をコピペする、くらいのつもりで根気よく
  • 役割を推測できるフィールドは全て判断材料に使うつもりで
  • Sturucture dissect 画面は一定時間ごとに自動更新されるため、ゲームを操作しながら値の変化を確認する場合にはこちらの画面で見ると良いです
  • Instances of GameController 画面のアドレス候補の ">" を押すとフィールドとその値が表示されるので、ここで判断することもできます
     ただし、表示されるフィールドの値はツリーを開いた時の値なので注意
ここまでで特定したメモリアドレスはあくまで動的アドレスで、ゲーム画面を切り替えたり、ゲームを再起動したりするとクラスのアドレスが変わってしまうため、フィールドの値を追うことができなくなります
 そのため、ポインタ検索を利用してアドレスの変わらない静的アドレスを特定する必要があります

正しい動的アドレスの特定作業は静的アドレスを見つけるまでの工程と同じ作業を複数回繰り返すことになるので、とにかく根気よく

3. フィールドのポインタ検索
Sturucture dissect 画面の Group 1 の真下にあるテキストボックスに動的アドレスがコピペしてある状態から始めます

ポインタ検索に使うフィールドを 1 つ決めます
  • ここで決めるフィールドはクラスの静的アドレスを検索するために使用するものであり、必ずしも欲しいフィールドである必要はありません
  • 意味のある値が入っていて、その値の正誤の判断ができて、ツリーを複数階層開いた場所にあるフィールドであることが望ましいです
  • ツリーの各階層の一番左に表示されている 16 進数 4 桁の数値はそのフィールドアドレスのクラスアドレスからのオフセット値で、ポインタ検索する時とクラスのアドレスからフィールドのアドレスを求める時に必要なので階層順にメモしておきます
  • オフセットを入力するとき、先頭の連続した 0 は省略できます
ポインタ検索に使うフィールド

決めたフィールドを選択してから右クリックして "Add to address list" を選択して、Cheat Engine 本体の address list に追加します

Cheat Engine 本体の address list に追加した、ポインタ検索用のフィールドのアドレスを右クリックして "Pointer scan for this address" を選ぶと Pointer scan 画面と Pointerscanner scanoptions 画面が開くので、Pointerscanner scanoptions 画面で検索条件の設定を行います
ポインタ検索

"Pointers must end with specific offsets" にチェックを入れて、下の階層のオフセット値から順に入力します
 基本的な設定項目については通常のポインタ検索と同じなので、各自で調べてください
 初期値のままでも割と何とかなる印象
ポインタ検索の設定

"OK" ボタンを押すとダイアログが開くので、ポインタリストファイルの名前を入力して決定するとポインタリストの作成が行われます
 ここで入力するファイル名は「フィールド名+通し番号」のようにしておくと良いと思います

最初のポインタ検索では、そのフィールドの静的アドレス候補が大量にリストアップされると思います(Pointer Paths の数字が候補の数)
 ここから、静的アドレス候補の絞り込みを行います
ポインタ検索結果

4. クラスの静的アドレスの特定
Mono dissector 画面、Sturucture dissect 画面、Instances of GameController 画面を閉じて、動的アドレスをあえて変えるためにゲームをいったん終了します
 Dissect mono を利用しているとゲームが終了できない場合があり、そのような時は私はタスクマネージャから終了しています

ゲームを再起動して「Open Process」から「ポインタ検索に使うフィールドの動的アドレスを特定する」ところまでの手順を改めて行います
 ゲームプロセスを開いた時にアドレスリストをキープするかを聞いてきますが、Yes でも No でも問題ありません

注意
  • ゲームを再起動したら "Open Process" を忘れずに!
  • Cheat Engine 本体と Pointer scan 画面は閉じないこと
     Pointer scan 画面は前の状態から継続して作業する必要があるので、もし閉じてしまった場合は本体の address list にある適当なアドレスを右クリックして "Pointer scan for this address" を選びます 自動的に開く設定画面を閉じてから "File" -> "Opne" で名前を付けて保存してあるファイルを開けば OK
  • 何度も言いますが、根気よく
Pointer scan 画面で "Pointer scanner" -> "Rescan memory" を選択して、新たに特定したフィールドの動的アドレスを入力して再度ポインタ検索します
 Pointer Paths の数が減っているのが分かるかと思います
ポインタ再検索

同様に、ゲームを再起動してフィールドの動的アドレスを特定してポインタ検索、という作業を数回繰り返します
 ゲームを再起動したら "Open Process" を忘れずに! そして根気よく

Pointer Paths の数が4桁になるかならないくらいまで減ってきたら、ポインターリストの Offset 6 の部分を押してオフセットの個数が少ない順にソートします

Pointer Paths の数がある程度まで減ってきたら、オフセットの個数が少ないアドレスの中から選んでダブルクリックして Cheat Engine 本体の address list に追加します
 これがポインタ検索用に 1 つ選んだフィールドの静的アドレスです
静的アドレスの決定

この静的アドレスからフィールドのオフセットを除いたアドレスが、このクラスの静的アドレスです
 address list に追加したアドレスをダブルクリックしてアドレスの設定画面を開き、ポインタ検索に使ったフィールドのオフセット分戻してクラスの静的アドレスにします
クラスの静的アドレス

5. 欲しいフィールドの静的アドレスを決定
クラスの静的アドレスを起点としてオフセットを設定すれば、クラス内のフィールドの静的アドレスになります
欲しかったフィールドの静的アドレス

これでようやく目的のフィールドの静的アドレスを特定することができました
 ポインタ検索するために address list に追加したフィールドはもう必要ないので、リストから消して OK です

静的アドレスを特定できたと思っても、実は動的アドレスだったということもあります
 時間をおいてゲームを起動したり、PC を再起動してからゲームを起動したり、他の PC でゲームを起動してもアドレスが変わらなければ OK です

保存してあるポインターリストファイルを読み込めば、静的アドレスを絞り込んだ工程から改めて絞り込みを行うことができます

0 件のコメント:

コメントを投稿