Cheat Engineでゴッドイーター3をチートしよう! スクリプト編

Cheat Engineでよくあるのが、体力や弾丸のアドレスを見つけたのに再起動すると使えないといった問題です。
これは動的に確保されたメモリ領域の場合に起こる現象です。
今回はスクリプトを使ってアドレスを自動検出することで、その問題を解決してみようと思います。
これをしておくと、後々ポインタースキャンをする時に作業が楽になります。
このゲームの場合ミッションが変わるごとにアドレスが変わるようになっています。

この記事の内容はゴッドイーター3だけでなく、他のゲームにも応用できることなのでぜひ読んでみてください。

スクリプトでアドレスを自動検出する


HPのアドレスを見つけた状態から始めていきます。
HPのアドレスを見つける方法は後日追記します。


「Find out what accesses this address」を使用して、HPのアドレスにアクセスしている命令を見つけにいきます。


デバッガーでge3.exeにアタッチするのでYesをクリックします。


アクセスしている命令を見つけました。
左のCountにある数字がすごい勢いでカウントアップされているのを確認できます。
これはその命令が実行されている回数を表しています。
もうデバッグは必要ないので右下のStopをクリックして中止します。


スクリプトを組む命令を決めます。
どの命令でもできると思いますが一番上の命令に組むことにします。
ミッション開始と同時に実行される命令にスクリプトを組めば、スクリプトをオンにした瞬間に狙いの動作を実現できます。
スクリプトを組む命令を選択してShow disassemblerをクリックします。


逆アセンブラウィンドウが表示されました。
対象としている命令はアドレス 7FF74CB28FDA の movss xmm1, [rbx+10] です。
このアドレスは皆さんと異なるかもしれません。
同じゲームでもバージョンによってアドレスがずれている可能性があるからです。


対象の命令の上で右クリックから「Find out what addresses this instruction accesses」を選択します。
この命令がアクセスしているアドレスを見つけてくれます。
大変便利な機能で使う頻度も多いです。


Stopをクリックしてデバッグを中止します。
画像のように3つのアドレスにアクセスしているのを確認できます。
上からプレイヤーのHPのアドレス、hugoのHPのアドレス、zekeのHPのアドレスになっています。
実はこの命令、ブレークポイントを設置してみればわかるのですが、プレイヤー、hugo、zekeのように順々にアクセスしながらループしているため、このままスクリプトを組んでもうまく動作しません。
検出したいのはあくまでプレイヤーのアドレスだけです。
したがって、自分と味方1、味方2を区別できる値を見つける必要があります。


プレイヤーのアドレスを選択後、右クリックから「Find commonalities between addresses」、「Mark selection as group 1」を選択します。
プレイヤーのアドレスをグループ1にその他をグループ2に設定しています。
グループ1を設定すればその他は自動的にグループ2になります。


再度右クリックから「Find commonalities between addresses」、「Scan for commonalities」を選択します。


逆アセンブラ画面に戻り確認するとわかりますが、この命令ではRBXにベースアドレスが格納されているので、RBXの行をダブルクリックします。


Scanをクリックします。


画像のように3つのアドレスが保持している値の相違を一目で確認できるようになりました。
一番左の黒字の数字はオフセットです。
ここでは自分と味方1、味方2を区別できるような値をスクロールしながら探します。
そうするとオフセット150にそれらしい値がありました。


プレイヤーが0、hugoが1、zekeが2になっています。
ここで間違いないでしょう。
この「Find commonalities between addresses」は、例えば銃の打ち合いをするゲームで青チームが1、赤チームが2といった具合で共通する値を探すときにも使用します。
Cheat Engineの機能「Dissect data structure」でも同じことができます。

これでスクリプトを作る準備ができました。

スクリプトを作ろう!


逆アセンブラウインドウのメニューバーからTools、Auto Assembleを選択します。


TemplateからAOB Injectionを選択します。


AOB Injectionのテンプレートが挿入されました。
ここから新たにコードを追加していきます。


// <- の行が変更を加えた箇所です。

Cheat Engineのスクリプトは2つのセクションがあります。
[ENABLE] セクションに書いたコードはスクリプトがオンになった時に実行されます。
[DISABLE]セクションに書いたコードはスクリプトがオフになった時に実行されます。

aobscanmodule    -> プロセス内から指定された16進数コードを探し、そのアドレスを取得する。
label      -> アドレスにラベル名をつける。
alloc      -> allocateの略でメモリを確保する。
dealloc  -> 確保したメモリを開放する。
registersymbol     -> アドレスをシンボルに登録してスクリプト外でも使えるようにする。
unregistersymbol -> 登録したシンボルを解除する。
db -> 指定されたアドレスにバイト配列を書き込む。
          上のスクリプトだとINJECTに F3 0F 10 4B 10 の計5バイトを書き込んでいる。

cmp  -> compareの略で値を比較する。
jne    -> jmp not equalの略で比較した値が同じでなければ指定されたアドレスにジャンプします。
             cmpとセットで使われることが多い。
mov  -> 値をコピーする。

Cheat Engine7.1からの変更点
 dealloc(newmem)
 dealloc(healthBase)
 と従来2行にわたって書かなければならなかったのが
 dealloc(newmem healthBase)
 と間にスペースを入れることで1行で書けるようになりました。
 Cheat Engine7.1未満をお使いの方は各所変換しながらコードを書いてください。

スクリプトの詳細な説明はこちらから


メニューバーのFileからAssign to current cheat tableを選択します。


Cheat Engineのメインウインドウに戻ると Auto Assemble script というスクリプトが追加されているので、画像の赤枠部分をクリックしてスクリプトをオンにしましょう。
スクリプトを再編集したいときは、<script>のあたりをダブルクリックします。

Cheat Engineメインウインドウの右下にある「Add Address Manually」をクリックして手動でアドレスを設定します。


Pointerにチェックを入れます。


スクリプトでシンボルに登録したhealthBaseとオフセットの10を入力します。
TypeをFloatに変え、DescriptionはHPにしときます。


チートテーブルを見ると無事にHPのアドレスを検出できています。

チートテーブルを整理する

ここからする設定は見栄えの問題で必須ではありませんが、やっておくとチートテーブルがすっきりします。


HPのアドレスの行を左クリックしたままスクリプトの行に重ねるようにドラッグ&ドロップします。


スクリプトの行の上で右クリックから、「Group config」、「Hide children when deactivated」を選択します。
これでスクリプトをオフにするとHPのアドレスも自動で隠れるようになります。
Group configには他にも便利な設定があるのでいろいろ試してみてください。

OPのアドレスも検出する


HPとOPのアドレスを見てみるとアドレスが似ていることに気付きます。
これは2つのアドレスの距離が近いことを示しています。
OPのアドレスからHPのアドレスを減算してみると
1AA73AC6340 - 1AA73AC6424 = E4
になり、HPのアドレスからOPのアドレスまでの距離はE4であることが分かりました。
これを利用してついでにOPのアドレスも自動で検出できるように設定します。


HPのアドレスの行を選択し、Ctrl+C、Ctril+Vでアドレスを複製します。
右クリックからコピー、張り付けすることもできます。


Pasteをクリックします。


矢印のあたりをダブルクリックしてアドレスを編集します。


オフセットの10に+E4を付け足し、DescriptionをOPに変更します。


これでHP、OPと、2つのアドレスを検出できるようになりました。
もちろん値を固定することもできます。
ゲームを再起動したり、ミッションを変えても無事検出できることを確認できたら完成です。

スクリプト補足説明

以下のコードはコピペできます。
ピンク字が変更箇所です。
ge3.exe -> 7ff74c4f0000 モジュールのベースアドレス
ge3.exe+638FDA -> 7FF74CB28FDA  スクリプトを組んだ命令
ge3.exe+638FDF -> 7FF74CB28FDF  スクリプトを組んだ命令の次の命令
[ENABLE]

aobscanmodule(INJECT,ge3.exe,F3 0F 10 4B 10 F3 0F 10)  // ge3.exeプロセス内から指定された16進数コードを探しアドレスを取得する
alloc(newmem,$1000,"ge3.exe"+638FDA)  // スクリプト用に1000バイトのメモリを確保する
alloc(healthBase, 8)        // 8バイトのメモリを確保する

label(code)                 // アドレスにラベル名をつける
label(return)               // returnはge3.exe+638FDFを表している

newmem:
  cmp [rbx+150], 0          // プレイヤーのアドレスかそれ以外かを比較
  jne code                  // プレイヤーのアドレスでなければcode:へジャンプする
  mov [healthBase], rbx     // healthBaseにプレイヤーのアドレスをコピーする
code:
  movss xmm1,[rbx+10]       // プレイヤーのアドレス以外ならここにジャンプしてきてコードが実行される
  jmp return                // ge3.exe+638FDFにリターンする

INJECT:                     // INJECT:はアドレスge3.exe+638FDAを示している
  jmp newmem                // ge3.exe+638FDAのmovss xmm1, [rbx+10] を jmp newmem に書き換える
return:                     // ge3.exe+638FDAの次のコードge3.exe+638FDFにリターンする
registersymbol(INJECT healthBase)      // INJECTとhealthBaseをシンボルに登録する

[DISABLE]

INJECT:                    
  db F3 0F 10 4B 10        // 上で書き換えたge3.exe+638FDAのjmp newmemをmovss xmm1, [rbx+10]に戻す 
                           // movss xmm1, [rbx+10]は16進数コードだとF3 0F 10 4B 10になる
                            
unregistersymbol(INJECT healthBase)    // INJECTとhealthBaseをシンボルから解除する
dealloc(newmem healthBase)             // 確保したメモリを開放する(newmemとhealthBase)





関連記事

0 Comments

Post a comment