しかし、最初に最初のものが最初なので、私はあなたの下であなたを待っています!
免責事項:著者は、この記事で得た知識の使用またはそれらの使用に起因する損害について責任を負いません。 ここに記載されているすべての情報は、教育目的でのみ提供されています。 特に、ボットの処理を支援するためにMMORPGを開発している企業にとって。 そして、もちろん、この記事の著者はボットドライバーではなく、詐欺師でもありません。
前回の記事で思い出したように、DirectX EndScene関数のアドレスを見つけ、その最初の5バイトを読み取りました。 あなたが忘れてしまった場合、ここにコンテンツがあります。
内容
- パート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.実装計画の概要を説明します
今日は、自分自身を害することなく、この関数にコードを埋め込みます。 以下に、これがどのように起こるかを示します。
- HookAddressは、kernel32.dllのWinApi VirtualAllocEx関数を使用して、ゲーム中に割り当てられたメモリへのアドレスです。
- Addressは、EndSceneまたはChainSwap関数のDirectXメモリ内のアドレスです
- OpCodeは元の関数opcodeであり、保存する必要があります。 オリジナルでは、それらは変更されます。
2.実装操作
プロセスを開くには、WinApi OpenProcessを呼び出してデバッグを有効にし、プロセスのメインスレッドを開く必要があります。
var ProcessHandle = OpenProcess(processId); Process.EnterDebugMode(); var dwThreadId = Process.GetProcessById(dwProcessId).Threads[0].Id; var ThreadHandle = OpenThread(0x1F03FF, false, (uint)dwThreadId); var HookAddress = Memory.AllocateMemory(6000); var argumentAddress1 = Memory.AllocateMemory(80); Memory.WriteBytes(argumentAddress1, new byte[80]); var argumentAddress2 = Memory.AllocateMemory(BufferSize); Memory.WriteBytes(argumentAddress2, new byte[80]); var resultAddress = Memory.AllocateMemory(4); Memory.Write<int>(_resultAddress, 0);
ここで、0x1F03FF-ストリームへのアクセス権。 次に、コードにメモリを割り当て、それへのHookAddressポインターを取得します。また、 resultResultAddressの2つの引数argumentAddress1とargumentAddress2のメモリを予約し、ゼロで埋めます。 さて、約束したとおり、少し筋金入りです。
var asmLine = new List<string> { "pushfd", "pushad", "mov edx, 0", "mov ecx, " + resultAddress, "mov [ecx], edx", "@loop:", "mov eax, [ecx]", "cmp eax, " + 80, "jae @end", "mov eax, " + argumentAddress1, "add eax, [ecx]", "mov eax, [eax]", "test eax, eax", "je @out", "call eax", "mov ecx, " + resultAddress, "mov edx, " + argumentAddress2, "add edx, [ecx]", "mov [edx], eax", "mov edx, " + argumentAddress1, "add edx, [ecx]", "mov eax, 0", "mov [edx], eax", "@out:", "mov eax, [ecx]", "add eax, 4", "mov [ecx], eax", "jmp @loop", "@end:", "popad", "popfd" }; Memory.Asm = new ManagedFasm(ProcessHandle); Memory.Asm.Clear(); foreach (var str in asmLine) { Memory.Asm.AddLine(str); } Memory.Asm.Inject(HookAddress); var length = (uint) Memory.Asm.Assemble().Length; Memory.WriteBytes(HookAddress + length, OpCodes); Memory.Asm.Clear(); Memory.Asm.AddLine("jmp " + (Address + OpCodes.Length)); Memory.Asm.Inject((uint)((HookAddress + length) + OpCodes.Length)); Memory.Asm.Clear(); Memory.Asm.AddLine("jmp " + HookAddress); for (var k = 0; k <= ((OpCodes.Length - 5) - 1); k++) { Memory.Asm.AddLine("nop"); } Memory.Asm.Inject(Address);
上記のアセンブラコードはHookAddressに書き込まれ、制御をコードに転送します。テーブルに従って、処理後、制御をメインスレッドに戻します。 次に、その使用方法を示します。
public byte[] InjectAndExecute(IEnumerable<string> asm, bool returnValue = false, int returnLength = 0) { Memory.Asm.Clear(); foreach (var str in asm) { Memory.Asm.AddLine(str); } dwAddress = Memory.AllocateMemory(Memory.Asm.Assemble().Length + 60); Memory.Asm.Inject(dwAddress); Memory.Write<uint>(argumentAddress1, dwAddress); while (Memory.Read<int>(argumentAddress1) > 0) { Thread.Sleep(1); } byte[] result = new byte[0]; if (returnValue) { result = Memory.ReadBytes(Memory.Read<uint>(argumentAddress2), returnLength); } Memory.Write<int>(argumentAddress2, 0); Memory.FreeMemory(dwAddress); return result; }
その結果、インジェクションが動作すると、argumentAddress1およびargumentAddress2の値はゼロになるはずです。 InjectAndExecuteを呼び出すスレッドが多数ある場合は、キューを用意する必要があります。そのため、80バイトのサイズを使用し、その実装方法を考えてみてください。 そして次の記事では、実装とコードを隠す方法を示します。