
免責事項:著者は、この記事で得た知識の使用またはそれらの使用に起因する損害について責任を負いません。 ここに記載されているすべての情報は、教育目的でのみ提供されています。 特に、ボットの処理を支援するためにMMORPGを開発している企業にとって。 そして、もちろん、この記事の著者はボットドライバーではなく、詐欺師でもありません。
過去の記事を見逃した方のために、ここにコンテンツがあります。
内容
- パート0-コードインジェクションポイントを見つける
- パート1-サードパーティコードの実装と実行
- パート2-pr索好きな目からコードを隠す
- パート3-World of Warcraft 5.4.xの視界(構造)
- パート4-World of Warcraft 5.4.xの視界(移動)
- パート5-World of Warcraft 5.4.xの視界(カスタムファイアボール)
1.ゲーム保護のトピックに関する議論
ゲームに関連するアンチチート、プロテクター、およびその他の保護に謎の雲を分散させたいと思います。 保護オプションがそれほど多くないため、主なものをリストします。
1.ゲームファイルの独創性を確認する
ここではすべてが簡単です。ゲームはサーバーにゲームファイルのチェックサムを要求し、検証の結果と照合します。 この場合、実行可能ファイルの検証アルゴリズムを変更するだけです。 ただし、Wardenの場合のように、検証アルゴリズムもサーバーからロードされると、すべてがはるかに複雑になります。
2.接続されたDLLの分析
この場合、人気のあるもののみを使用するリスクがあります。 ほとんどの場合、開発者はすでにこれに関する情報を持っています。ValveAnti Cheatの場合と同様に、疑わしい場合は、不明なライブラリが分析のためにサーバーに直接送信されます。 したがって、あなたの禁止は無期限に遅らせることができます。
3.インポートされた傍受ライブラリのVMT分析
ここではすべてが複雑です。TeamViwerやFrapsの場合でも、ゲームの開発者が望んでいて何も証明できない場合は禁止を取得できます。 Alexey2005がパート0で述べたように-コードインジェクションポイントを見つける
防御が偏執的になればなるほど、それはより多くの誤検知を起こします。 あらゆる種類のキーボードクリックインターセプター、アンチウイルススキャナー、ビデオとサウンドのあらゆる種類の「コントロールセンター」、マウスなどの入力デバイス設定コンポーネントなど、あらゆるものが大量に侵入してプロセスに導入されているためです。
4.読み書きからのゲームメモリの保護
Easy Anti Cheat ProtectionはSteamで人気を集めています。 Windowsは、ゲームのメモリを読み書きから保護するEasyAntiCheatサービスを開始します。 サービスが実行されていない場合、ゲームはサーバーへの接続を拒否します。 この点でhabrasocietyの考えを聞きたいと思います。
5.ゲームのメモリの特定のセクションを確認する
繰り返しますが、これは有名な監視員がいないわけではありません。 正直に言って、彼女は何をしていないのですか。 ワーデンは、メモリチェックモジュールとハッシュテーブルをサーバーからロードし、値をテーブルと比較します。 このようにして、ゲームのメモリを変更して、速度の向上、空中や壁を歩くなどの利点を得る不正行為者を簡単に特定できます。
まとめ
上記のすべてから、一般的なプログラムと方法を使用すると禁止に陥る危険性が非常に高く、これを回避するために、実装を決定するのが難しいことが明らかになります。 今何をしますか。 まず、GetFakeCommandメソッドとObfuscateAsmメソッドを記述します。
internal static string GetFakeCommand() { var list = new List<string> { "mov edx, edx", "mov edi, edi", "xchg ebp, ebp", "mov esp, esp", "xchg esp, esp", "xchg edx, edx", "mov edi, edi" }; int num = Random.Int(0, list.Count - 1); return list[num]; } internal static IEnumerable<string> ObfuscateAsm(IList<string> asmLines) { for (var i = asmLines.Count - 1; i >= 0; i--) { for (var k = Random.Int(1, 4); k >= 1; k--) { asmLines.Insert(i, GetFakeCommand()); } } for (var j = Random.Int(1, 4); j >= 1; j--) { asmLines.Add(GetFakeCommand()); } return asmLines; }
ご覧のとおり、GetFakeCommandはレジスタとフラグの状態を変更しないアセンブラーコマンドを返します。このリストは必要に応じて数回展開でき、ObfuscateAsmはこれらのコマンドをサブルーチン内のランダムな場所で実行します。 HookAddressを受け取った場所で最後の記事のアドレス置換コードを変更します。コード全体を複製するのではなく、変更された部分のみを表示します。
// var RandomOffset = (uint)Random.Int(0, 60); var HookAddress = Memory.AllocateMemory(6000 + Random.Int(1, 2000)) + RandomOffset; // Memory.Asm = new ManagedFasm(Memory.ProcessHandle); Memory.Asm.Clear(); foreach (var str in ObfuscateAsm(asmLine)) { Memory.Asm.AddLine(str); }
引数argumentAddress1およびargumentAddress2のメモリを使用して、同じフェイントを実行できます。 HookAddressメモリを解放する場合のRandomOffsetの値を忘れないでください。
Memory.FreeMemory(HookAddress - RandomOffset); Memory.FreeMemory(argumentAddress1 - RandomOffsetArgs1); Memory.FreeMemory(argumentAddress2 - RandomOffsetArgs2);
そして、InjectAndExecuteメソッドを変更し、約束どおりに、マルチスレッドメソッド呼び出しのキューを実装します。
public byte[] InjectAndExecute(IEnumerable<string> asm, bool returnValue = false, int returnLength = 0) { lock (Locker) { var offset = 0; var randomValue = (uint)Random.Int(0, 60); // 80/4 = 20 while (Memory.Read<int>(argumentAddress1 + offset) != 0 || Memory.Read<int>(argumentAddress2 + offset) != 0) { offset += 4; if (offset >= 80) { offset = 0; } } Memory.Asm.Clear(); foreach (var str in asm) { for (var i = Random.Int(0, 3); i >= 1; i--) { Memory.Asm.AddLine(ProtectHook()); } Memory.Asm.AddLine(str); } dwAddress = Memory.AllocateMemory(Memory.Asm.Assemble().Length + Random.Int(60, 80)) + randomValue; Memory.Asm.Inject(dwAddress); Memory.Write<uint>(argumentAddress1, dwAddress + offset); } while (Memory.Read<int>(argumentAddress1 + offset) > 0) { Thread.Sleep(1); } byte[] result = new byte[0]; if (returnValue) { result = Memory.ReadBytes(Memory.Read<uint>(argumentAddress2 + offset), returnLength); } Memory.Write<int>(argumentAddress2 + offset, 0); Memory.FreeMemory(dwAddress - randomValue); return result; }
最初のwhileループでは、順番に移動して、引数用に予約された2つのアドレスで同時にオフセットの空き領域を探します。見つからなかった場合は、最初から開始します。 マスクするために、偽のコマンドと、割り当てられたメモリのランダムなオフセットとサイズが追加されました。 これですべてです。コメント、ヒント、興味深い解決策をお待ちしています。