実践:思索多様化の応用 --- 題材/英雄伝説6空の軌跡SC(日本ファルコム)


『自動早釣り機能の内訳その1』
[使用ツールollydbg/うさみみハリケーン]

改造コードの中には、それ一つでは然程意味が無いと感じるものの、数個が同時に実行されることにより、大きな効果を 発揮するものがあります。意味的には2種類あって、同系統の効果を重複させるもの(戦闘時MP減らないとフィールド上で MP減らないの複合等)と各々が全く独立した役割をもつものがあります。後者は解析における思索多様化の一つとして、 自らが行いたい事象すらも多角的に考察・システムに併せた分解を施すことによって成立させるもので、 当方で公開している対戦格闘ゲーム系パッチ等は、この系統の発想を基点にしています。


英雄伝説6SCにおける「釣り」は、竿と餌の選択→竿を振る→魚が掛かるまで待つ→タイミングよくクリックして釣る の 4項目で構成されています。前者2つは動作・手順共に流れ作業的ですが、3番目の手順でウエイトが、4番目の手順でリスクが 発生します。また、魚がヒットすれば必ず餌が減り、このソフトで最もアイテム消費の激しい部分でもあります。

1)魚が掛かるまで待つ=無駄に待ち時間が発生する
2)タイミングよくクリックして釣る=外せばこれまでの手順が無駄になり危険
3)魚がヒットすれば餌が減る=回数に限りがあって不便

この部分を同時に解決すれば、素早く魚を釣れまくることが可能です。 よって、解析自体もこの3つを各々独立させての対処が基本方針。結論から申せば、今回の3つの解析のうち上二つは同系統の解析でしたので、 前編である今回は、3番目の餌が減らない効果についてのアプローチの記録です。


< 魚がヒットしても餌が減らない解析 >

題目から、『「○○減らない」の解析』じゃないの?と思った方、ご明察です。 ただし、今回はその過程における思索や、応用に関する内容を扱っています。 いずれにせよ初心者向けではありますが。


◆解析の基点
行うべきことは実際に餌を減らしている処理を見つけ出し、対処することです。 とはいえ残念ながら、超能力でもない限りダイレクトにその箇所を特定することはできません。 ですが、件の箇所の周囲を推測すると…

1)どのアイテムを減らすかの決定
2)そのアイテムがどのアドレスにあるかの検索
3)減らす値の決定
4)対象アイテム数をロード
5)減らしても0以下にならないかの判定
6)対象アイテム数を減算
7)対象アイテム数をストア
8)5)に追随するアイテムが足りない場合の処理

ざっと挙げただけでも、これだけの要素が存在するわけです。 中でも共通要素として多いのが「対象アイテム数」。これはベタで扱っている限り、 比較的容易に判別できる要素です。 ですから、この関連要素を元に該当箇所を辿る解析をします。

「アイテム数にブレークポイントを設置して〜」で始まる解説を多く見かけますが、 ほとんどがこれに近似した思索を前提に成り立っています。高名な方のテキスト にはAPI関数を基点とした解説が比較的多いですが、この場合も関連要素を Windows自体の汎用ライブラリに求めているからであって、原始的なレベルに 遡ればほぼ同じ基点に到達します。

解析手法上「〜は、こうするものなのだ」は存在しません。 (省略されているものも含めた上で)全てに意味があり、 その各々を理解することが応用への第一歩に繋がると思います。


◆◆◆解析の実践

釣りを実際に行うなどして、対象アイテム数を変動させ、数値・変動サーチします。


アドレス0x2CBE9F4hより、4バイトを1単位として、
前2バイト:アイテムの種類
後2バイト:アイテムの個数 であることが判明。
word[E?X*4+2CBE9F6](アドレス0x2CBE9F6hより、4の倍数を足した先の2バイトの値)で 、値が表せる簡易なものであることがわかりましたので、デバッガで"ED6_WIN2.exe"にアタッチし、 対象アイテム数の格納アドレスにメモリライトブレークポイントを設置してから、 再度同じ餌で釣りをします。

<補足1>
このケースでは、E?Xレジスタが対象アイテム数のアドレスを示す手がかりになりますが、 多くの場合において、この値が実際のゲーム上でのアイテムスロット番号にあたります

<補足2>
E?Xが格納アイテムのスロット番号になりますので、02CBE9F6hという即値とモジュール エリアのサイズを考慮することで、この値は当該モジュール内の絶対アドレスに存在するものとわかります。 アドレス変動するかしないかは、こうした構成式から容易に判断できるものも多いです。


004C8850 // EDXレジスタにスロット番号を格納 004C8854 // ESIレジスタの中身を退避 004C8855 // EDIレジスタの中身を退避 004C8856 // EDIレジスタに減算値を格納 004C885A // AXレジスタに対象アイテム数をロード 004C8862 // ESIレジスタの対象アイテム数のアドレスをロード 004C8869 // ECXレジスタに対象アイテム数をコピー 004C886B // ECXレジスタを下判定用に整理 004C8871 // アイテムを減らすことが可能かの判定 004C8873 // 不可能であった場合の誘導指定 004C8875 // 対象アイテム数を減らす 004C8877 // EDIレジスタの中身を復帰 004C8878 // 減算後の対象アイテム数をストア 004C887B // 減算の正常終了フラグをセット 004C887D // ESIレジスタの中身を復帰 004C887E // コール元へリターン

◆◆◆対処の実践

基本方針は3通り。
即ち減算の無効化・減算値の無力化・減算の回避です。


1)減算の無効化
減算そのものを無かったことにする・減算の結果を反映させない方法


2)減算値を無力化してしまう方法
減算を無意味にするため、減算値を0にする方法


3)バイパスジャンプやサブルーチンの簡略化による回避方法
必要なデータを見切ったうえで、他の判定ジャンプを流用する・処理群自体をスキップする方法
※このケースは他にも数通りの書き換え方があります。


<補足3>
SUB命令以外に減算する方法について
以下、いずれも値を1減らす結果になります。
1)   48              DEC EAX
デクリメント命令を使う方法

2)   81C0 FFFFFFFF   ADD EAX,0FFFFFFFFh
補数を採って加算する方法 近辺のNOT/NEG命令に注目

3)   8D40 FF         LEA EAX,DWORD PTR DS:[EAX-1]
ロードアドレス命令を使う方法

以上、件の対処自体はいたって簡単でした。せっかくなので、 ここでは対処そのものよりも、一つの点に関して多くの視点を 得ることに留意して頂けますと幸いです。




……………………………………………………が、ここで一つ問題発生。




「このコードを使ったら、なんか他のアイテムも減らなくなってました。 特に害はありませんけど、参考までに報告しときます」

…対処が簡単とはいえ、このまま公開していたら、こんな指摘が ほぼ確実に行われたことでしょう。無論気にしないのも自由ですが、 自動早釣りと銘打った限り、釣りに関係ない部分にまで影響を 及ぼすと、不安がる方がいらっしゃるのもまた事実

ですから、今回は敢えて「釣り餌のみ減らない」を追求します。 いずれ要望等があればこのコードを公開すれば良いでしょう。


◆◆◆対処の実践その2

では、何故このような状況になったか。以下のコードに注目します。
004C887E   C3              RETN
間違いなくサブルーチンです。そこで、サブルーチンの始点アドレス 0x4CC850hで、ollyの「参照を検索」を試してみます。
004C88E9   CALL ED6_WIN2.004C8850
一件しかかかりませんでした。サブルーチン化する意味は当該処理群の汎用化 にありますので、複数箇所からコールされているはずです。0x4CC850h以降の 処理群も値を減算する役割のみでした。ここで、先に述べた推測を振り返ります。

1)どのアイテムを減らすかの決定
2)そのアイテムがどのアドレスにあるかの検索
3)減らす値の決定

少なくとも3)は可変要素ですね。2)もアイテムを減らす処理以外での利用法 がありそうです。ですから、件のサブルーチンは複数箇所からコールされている ルーチン或いはそれに追随するルーチンからコールされているのだろうと考えられます。 つまりは複重連鎖しているであろうということです。

「釣り餌のみ減らない」ためには、釣りの場合に 3)減らす値の決定 を行って いる箇所を叩く必要があります。この箇所を特定するため、サブルーチンを遡って いきます。方法としては、ステップ実行機能やコード実行ブレークポイント等が有効です。


<補足4>
スタック始点に変動を及ぼす状況
1)CALL命令の実行
ジャンプに際し、リターンアドレスをスタックにPUSHします。

2)PUSH/POP系命令の実行
特定レジスタの値を退避・復帰する目的で使用されます。

3)ESPレジスタへの直接演算

4)ret命令の実行
サブルーチンから戻る際に使用されます。
以上の補足3/4のようなものに関しましては、インテルマニュアル他、 最近出版されました、アセンブリ言語の知識・クラッキング手法について触れられた書籍にて、 より詳しい解説を得ることが可能です。興味がおありであれば、 当サイトリンク先にあります「でじたるとらべしあ」さんの紹介ページへどうぞ。 …ただし、専門書故に少々お高く感じるものもあるやもしれません、あしからず。

004C8854   56               PUSH ESI
004C8855   57               PUSH EDI
004C8856   8B7C24 10        MOV EDI,DWORD PTR SS:[ESP+10]
004C885A   66:8B0495 F6E9CB>MOV AX,WORD PTR DS:[EDX*4+2CBE9F6]
004C8875   2BC7             SUB EAX,EDI

0x4C8856h時点のスタック上
+0	+04	+08	+0C	+10
EDI	ESI	ret先	xxx	減算値

コール元->0x4C88E9

004C88E3   8B4C24 0C        MOV ECX,DWORD PTR SS:[ESP+C]
//このECXレジスタが減算値
004C88E7   51               PUSH ECX
004C88E8   50               PUSH EAX
004C88E9   E8 62FFFFFF      CALL ED6_WIN2.004C8850

0x4C88E3h時点のスタック上
+0	+04	+08	+0C
xxx	xxx	xxx	減算値	

004C88D0   56               PUSH ESI
004C88D1   8B7424 08        MOV ESI,DWORD PTR SS:[ESP+8]
004C88D5   56               PUSH ESI
004C88D6   E8 E5FCFFFF      CALL ED6_WIN2.004C85C0
//このサブルーチンが 推測2)そのアイテムがどのアドレスにあるかの検索 部分
004C88DB   83C4 04          ADD ESP,4

0x4C88D0h時点のスタック上
+0	+04	+08	+0C
ret先	xxx	減算値

コール元->0x4EB2A6

004EB2A3   6A 01            PUSH 1
004EB2A5   52               PUSH EDX
004EB2A6   E8 25D6FDFF      CALL ED6_WIN2.004C88D0

0x4EB2A6h時点のスタック上
+0	+04
xxx	減算値


処理の流れ自体はこちらの推測2)と3)が逆でしたが、
目的の減算値を引数としている箇所は以下になります。

004EB2A3   6A 01            PUSH 1
よって、「釣りをしても餌が減らない」の改造コードは 4EB2A4-00
※対処の実践内 2)減算値を無力化してしまう方法 を採ります。


さて、以上いかがでしたでしょうか?当たり前のように思えることにも意味が あるの前言通り パラメータをメモリサーチし、ブレークポイントを設置、 ブレークした周囲の命令や判定ジャンプを潰すことも、適当にやったら…では なくて、きちんと意味がありますことをご理解頂けましたでしょうか?

プログラマさんが100人居れば、100通りのプログラムが出来ますが、 とあるソフトで通じた手法が、そのまま別のソフトでは通用しないという時も、 何か一つの知識・視点の追加によって、なし崩しに解決できてしまうこと も往々にしてあります。

今回は単に対処の方法を語るよりも、そこに至る理由・処理を読み取ること・ そこから派生するより多くの視点を得ることに重点をおきました。 対処方法の基本自体に関しましては、当サイトリンク先にあります 「DANAの部屋」さんの改造講座にて丁寧に触れられています。そちらも参考にされますと、 より深い理解が得られるのではないかと考えます。

それでは本日はこれにて。次回は「自動」「早釣り」についての補足に移ります。…1回でまとめきれるかな?(^^;



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



△戻る / →TopPageへ