実践:考察の連鎖 --- 題材/シャングリラ2[マルチパック](エルフ)


『味方ユニット無限行動可能化のコードを作成する』
[使用ツールollydbg]

殊にストラテジータイプのSLGにおいては、ユニット単位の行動とターンによる攻守変動が大きな意味を持ちます。 バランスの要でもありますが、同時に脱落者の発生やストレスを感じる箇所にもなりえます。自分はアクションやシナリオ に興味があるが、SLGは苦手…。そういう方であれば、この無限行動可能化解析によって利を得ることもあるでしょう。


< 前置き >
解析にあたって、まずは「行動」という概念が件のシステム上どのようになりたっているかを分析しましょう。

[1]
A/ 味方ターンには、敵ユニットは動かせない
B/ 一度行動したユニットは動かせない
C/ 行動済ユニットには大抵それを示すマーカー等がつく
D/ 味方ターンにユニットをクリックすると行動メニューが発生する
E/ 行動済ユニットがあっても、味方ターンが来ることで一斉に動かせるようになる

以上を踏まえ、件のソフトにおける簡単な行動制御フローを考えて見ます。

[2]
A/ ゲームにフォーカスが移っているかの判定
B/ 味方のターンであるかどうかの判定
・敵のターンであれば、選択行動を受付けない

C/ 味方ユニットの検索
D/ 行動済ユニットであるかどうかの判定
・行動済であればマーカー付着

E/ 選択されたのは敵ユニットであるかどうかの判定
・敵のユニットであれば、行動選択無しで、移動範囲のみ表示

F/ ユニットの行動
・行動後マーカーを付着し、行動済扱いとする

おおまかな流れですが、この流れを確実に把握しておきましょう。
これができていないと、今後辿るであろう各所で、混乱を招く可能性が少なからず生じます。


< 解析の基点 >
無限行動化のプロセスに置いて、最も重要なことは何かを考えます。

そもそも行動という概念をプログラム上でファジーに制御することは、当然ながら不可能です。 換言すれば、行動を制御する支柱となる印が存在するはずで、例えばこれ以上は行動できないとか、 行動可能かを判断する根拠です。ターン毎に変動・各ユニット毎に存在していないとゲームが 成立しませんので、これを所謂汎用フラグと考えます。またそのフラグは行動或いは 行動不可能を判断する材料である以上、各々において定まったフォーマット を持っているであろうとも推測できます(一見値が流動しているように見えても、必ず何らかの法則性がそこに存在します)。 よって、この行動可能或いは行動不可判断の支柱となる汎用フラグを探し、データの型を見極めることを 解析の基点に定めましょう。

< 解析の手がかり >
行動制御の根拠となるであろう汎用フラグの存在を発見します。

このフラグの特徴は、定まった2種の型(行動と行動不可)を持ちながら、行動ターンに 依存せずに、プレイヤーの操作によって変動するという点です。幸運なことに、 このソフトには「中断」コマンドが存在します。何ができるかというと、ユーザーの操作に よって行動・行動不可になった状態をデータに分けることができるということ。 この利点を衝きましょう。中断コマンドによって保存されるデータは、タイムスタンプを 参考にすると、全部で6種類あります。が、データ差し替え等で検証すると、 "SaveData.dat"に、汎用フラグの痕跡が残ることを確認。では、ここからメモリ上にある その値を探しましょう


< 解析 >

[3]
A/ ゲームにollydbgでアタッチ
B/ ゲーム側で中断コマンドを実行し、「はい/いいえ」の確認メッセージを出現させる
C/ ollydbgにフォーカスを戻し、モジュールAI5WIN.exe内のラベル名検索を行う
D/ 以下のインポート関数にブレークポイントを設置する



Q)何故、このようなことをするのですか?
A)プログラムに教えてもらう方が楽だし、信頼という意味において確実だから

E/ 中断データを保存する(前記通り、6ファイル対応なので6回ブレークする)



F/ 引数データを参考に、目的のデータに移動する。 ※WriteFile関数については、プラットフォームSDK等を参照

HANDLE hFile, // ファイルのハンドル
LPCVOID lpBuffer, // データバッファ
DWORD nNumberOfBytesToWrite, // 書き込み対象のバイト数
LPDWORD lpNumberOfBytesWritten, // 書き込んだバイト数
LPOVERLAPPED lpOverlapped // オーバーラップ構造体のバッファ

この環境下では、アドレス 0x07BA0000 からファイル"SaveData.dat"へ 0x0C80 バイトのデータが 書き込まれています。つまり、目的のデータは 0x07BA0000-0x07BA0C80 の間に存在する ということですね。

任意ユニットの行動前:
任意ユニットの行動後:

解析の基点において目標の一つとしたデータの型が判明しました。
1または2バイトの変数で、行動前が0x01h/行動後が0x02hになります。

ただし、これらは現段階、あくまで"SaveData.dat"に書き込まれるそれです。そもそも画像に 従えば、型以前にアドレスも判明しているのに、位置が判明したと述べなかったのはそういった 不安定材料が存在するからです。ソフトによっては、セーブデータに書き込まれるデータと 実際のゲーム上のデータ(メモリ上の実データ)は同一であるケースは少なくありません。 ですが、このソフトにおいてはそれは通用せず、件の画像中のデータを変更しても、ゲーム上 のユニットの行動を制御することはできませんでした。では、どうするか?… これらの情報から実データを探せばよいのです。

このデータは"SaveData.dat"に書き込まれるデータでしかありませんでしたが、ゲーム上の データと同様、状況によって変動しています。つまりは、中断処理を行う際、この領域が 受け皿にされて、"SaveData.dat"が更新されるということ。ここから、中断処理を行う際、 件のアドレスに対し、実データがコピーされる瞬間が必ず存在するということになりますその処理からコピーされる値の出元を調べれば、実データも判明しますね。

G/ 判明したフラグアドレスにメモリライトブレークポイントを設置し、中断処理を行う。

00476328 8A48 6C MOV CL,BYTE PTR DS:[EAX+6C]
0047632B 884E 06 MOV BYTE PTR DS:[ESI+6],CL

EAX 0B107B10/ EIP 47632B であることを確認し、



任意ユニットの実データを発見することができました。汎用フラグが同一ブロックにある保障は無い/ この領域はユニット別に存在し、各々が(セーブ&ロード・戦闘毎)頻繁に変動するというソフト特有の 状況を踏まえれば、最初から信頼性が高いと言える今回の解析手順は、あながち遠回りではないのかもしれません。 行動制御用フラグはベースアドレスから相対オフセット+0x6Chにある4バイトの変数です。内容は、"SaveData.dat"に 保存されるそれと同じ。手動で行動可能/行動不可を操作することができました。基点において目標としたデータ と考えてよいでしょう。

以上をもって解析の基点/手がかりに関する調査・考察は終了。ここから、実践的なコード作成手順に入ります。


< 実践:コード作成 >

[4]
A/ 6Chで全定数検索する

残念ながら、数値自体が然程特殊な大きさでないために、かなりの数がかかってしまいます。試しに、一括 でブレークポイントを設置してみましたが、無関係の箇所で10箇所以上かかるのを確認し、実アドレスに 設置する方向に決定。

B/ ベースアドレス+0x6Chにメモリアクセスブレークポイントを設置

ここでの狙いは、先の考察[1-C][2-C/D]です。表面的にはユニットの見栄えを変えるだけなので、 実用性はありません。見た目に拘る余裕があればどうぞ…というところです。基本的には私も 注目しませんが、今回は場の関係上触れておきます。具体的には、ブレークした箇所より行動可能 か、行動済みであるかというような判定部分に注目。

[1-C][2-C/D]:行動済ユニットをグレー反転させる判定

00476B92 837B 6C 02 CMP DWORD PTR DS:[EBX+6C],2 // 2 は行動済を示す
00476B96 75 31 JNZ SHORT AI5WIN.00476BC9 //行動済でなければ00476BC9hへ誘導

00476B96-EB で常に明色表示。
----------------------------------------------------------------------------------------------------------

[1-C][2-C/D]:行動済ユニットにEマークをつける判定

00476D17 837B 6C 02 CMP DWORD PTR DS:[EBX+6C],2 // 2 は行動済を示す
00476D1B 0F85 91000000 JNZ AI5WIN.00476DB2 //行動済でなければ00476DB2hへ誘導

00476D1B-E99200000090 で常にマーク消去。
----------------------------------------------------------------------------------------------------------

C/ ベースアドレス+0x6Chにメモリアクセスブレークポイントを設置しつつ、任意ユニットをクリック

無限行動可能化解析の本命箇所とも言える判定ですね。行動/攻撃等を無限に行えるようになります。 なお、[1-D][2-E]は同時に、その判定の前段階にユニットの敵味方識別判定をもっていると推測でき、 実際同ブロック内の相対オフセット+0x60hに識別情報が格納されています。0が味方であり、1が 敵。処理の関係上、メニュー出現判定は敵には存在しませんが、 ここで得た情報は、敵味方識別要素付機能に流用することが可能です。

[1-D][2-E]:行動済でなければ行動メニューを出現させる判定

0046B584 837D 60 01 CMP DWORD PTR SS:[EBP+60],1 // 1 は敵ユニットを示す
0046B588 0F84 26030000 JE AI5WIN.0046B8B4 //敵ユニットであれば0046B8B4hへ誘導
0046B590 837D 6C 02 CMP DWORD PTR SS:[EBP+6C],2 // 2 は行動済を示す
0046B594 0F84 1A030000 JE AI5WIN.0046B8B4 //行動済であれば0046B8B4hへ誘導



0046B594-EB0490909090 でフラグに関係なく常に行動メニュー表示。
----------------------------------------------------------------------------------------------------------

D/ ベースアドレス+0x6Chにメモリライトブレークポイントを設置しつつ、任意ユニットを行動させる

一見、強力そうなステップCのコードですが、一箇所致命的な欠点を有します。これまでのコードは、 常に判定結果を操作するだけのコードでしたので、全ユニットに行動済フラグが起った場合、強制的に ターンが入れ替わってしまう事態に対処できません。そこで、実際にフラグ操作する系統のコードに 触れておきます。

0046F910 8B41 6C MOV EAX,DWORD PTR DS:[ECX+6C]
0046F913 85C0 TEST EAX,EAX
0046F915 74 07 JE SHORT AI5WIN.0046F91E
0046F917 C741 6C 02000000 MOV DWORD PTR DS:[ECX+6C],2
0046F91E C3 RETN



0046F91A-01 で常に行動後、行動前状態のフラグを格納。
[4-C]で、敵側はこのフラグによる行動判定を用いないことが判明しているので、識別の必要はない。
----------------------------------------------------------------------------------------------------------


ただし、[4-D]も、コード実行前に行動済になっているユニットは動かせないという欠点があります。
よって、最終的なコードとしては、[4-C/D]の併用が望ましいと考えられます。
※[4-B]が気になる方は[4-C]で得た識別情報をもとにパラサイトルーチンを組んでください。

0046B594-EB0490909090
0046F91A-01

以上が、シャングリラ2の無限行動可能化コードの完成形です。ここまで、お付き合い頂いた方々にはお疲れ様でした。


< まとめ >
さて、ここまで御覧になった方のうち、「なんだ、意外に簡単」…そう考えた方が少なからずいらっしゃると思います。 結論から申せば、構成要素の一つ一つ自体は極々初歩的なものばかりです。ただし、重要なのは、 それらの要素を必要に応じて適切に構成できますか?ということだと思います。必要なことは、でじたるとらべしあさんのQ&Aにもある 通り、自分が解析する対象・自身の解析すべき方向性・必要な参考情報・実際の解析段階等を、常に多角的に眺め、 補填・補正しつつ、対象の最も付入りやすい隙を見つけることです。ある解析手法を眺めた際、「○○はこうやるのだ」 ではなく、「○○って書いてあるけど、□□でも使えるよね」…そう言えるようになった時、 本来の意味で参考としたアプローチ手法を活用できるようになったのだろうと考えます。

…最後に、今回の解析ですが、意図的に一度もワークデータに関するメモリサーチを行っておりません。 お気づきでしたか? これも自身の環境や解析対象・解析方針・解析段階を総合的に考察・対処することで 可能となった1ケースとお考え頂ければ幸いです。


■今ページ開設のきっかけを与えて下さった有志の開発者・解析者の皆様に深く感謝いたします。 2005/11/12 REDCAT記



△戻る / →TopPageへ