Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Collections.Generic;
- using System.Runtime.InteropServices;
- using Addon;
- namespace Addon
- {
- static class TestClients
- {
- #region Hooking Functions
- [DllImport("kernel32.dll", SetLastError = true)]
- static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);
- [DllImport("kernel32.dll", SetLastError = true)]
- static extern IntPtr VirtualAlloc(IntPtr lpAddress, UIntPtr dwSize, uint flAllocationType, uint flProtect);
- [DllImport("user32.dll", CharSet = CharSet.Auto)]
- static extern int MessageBox(IntPtr hWnd, string text, string caption, uint type);
- private const uint MEM_COMMIT = 0x1000;
- private const uint MEM_RESERVE = 0x2000;
- private const uint PAGE_EXECUTE_READWRITE = 0x40;
- private static readonly List<GCHandle> GCHandles = new List<GCHandle>();
- private static void PerformJmpHook(IntPtr original, byte[] destinationStub)
- {
- var stubAddress = VirtualAlloc(IntPtr.Zero, (UIntPtr) destinationStub.Length, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
- Marshal.Copy(destinationStub, 0, stubAddress, destinationStub.Length);
- PerformJmpHook(original, stubAddress);
- }
- private static void PerformJmpHook(IntPtr original, IntPtr destination)
- {
- uint oldProtect;
- VirtualProtect(original, (UIntPtr)5, PAGE_EXECUTE_READWRITE, out oldProtect);
- var hook = new byte[5];
- hook[0] = 0xE9;
- BitConverter.GetBytes((destination.ToInt32() - original.ToInt32()) - 5).CopyTo(hook, 1);
- Marshal.Copy(hook, 0, original, hook.Length);
- VirtualProtect(original, (UIntPtr)5, oldProtect, out oldProtect);
- }
- private static IntPtr GetUnmanagedFunctionPointerFromDelegate(Delegate d)
- {
- GCHandles.Add(GCHandle.Alloc(d));
- return Marshal.GetFunctionPointerForDelegate(d);
- }
- #endregion
- [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- private delegate bool SvCheckClientDelegate(IntPtr clientPart);
- [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- private delegate int FuncIntDelegate();
- [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
- private delegate void SvCmdTokenizeStringDelegate(string str);
- [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- private delegate void SvDirectConnectDelegate(netaddr_t adr);
- [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- private delegate void SvSendClientGameStateDelegate(IntPtr client);
- [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- private delegate void SvClientEnterWorldDelegate(IntPtr client, byte[] userCmd);
- private static readonly IntPtr SvCheckTimeoutAddress = (IntPtr) 0x4FE8A0;
- private static readonly IntPtr SteamCheckSvAuthAddress = (IntPtr) 0x599D20;
- private static readonly IntPtr ResetReliableCmdAddress = (IntPtr) 0x5029DB;
- private static readonly IntPtr SvMaxClientsDvarPtr = (IntPtr) 0x5787780;
- private static readonly IntPtr ClientAddress = (IntPtr) 0x4A0FE90;
- private static readonly IntPtr GetStatMajorAddress = (IntPtr) 0x4D0560;
- private static readonly IntPtr GetStatMinorAddress = (IntPtr) 0x4D05A0;
- private static readonly IntPtr GetChecksumAddress = (IntPtr) 0x40C8C0;
- private static readonly IntPtr SvDirectConnectAddress = (IntPtr) 0x4F7670;
- private static readonly IntPtr SvCmdArgsAddress = (IntPtr) 0x1B5B7D8;
- private static readonly FuncIntDelegate GetStatMajor;
- private static readonly FuncIntDelegate GetStatMinor;
- private static readonly FuncIntDelegate GetChecksum;
- private static readonly SvCmdTokenizeStringDelegate SvCmdTokenizeString;
- private static readonly SvDirectConnectDelegate SvDirectConnect;
- private static readonly SvSendClientGameStateDelegate SvSendClientGameState;
- private static readonly SvClientEnterWorldDelegate SvClientEnterWorld;
- private static ushort BotPort;
- private static byte[] SvCheckTimeoutHookStub = new byte[]
- {
- 0x56, // push esi
- 0xB8, 0x00, 0x00, 0x00, 0x00, // mov eax, <handler>
- 0xFF, 0xD0, // call eax
- 0x83, 0xC4, 0x04, // add esp, 4
- 0x84, 0xC0, // test al, al
- 0x68, 0xA7, 0xE8, 0x4F, 0x00, // push 4FE8A7h
- 0xC3, // retn
- };
- private static byte[] SteamCheckSvAuthHookStub = new byte[]
- {
- 0x56, // push esi
- 0xB8, 0x00, 0x00, 0x00, 0x00, // mov eax, <handler>
- 0xFF, 0xD0, // call eax
- 0x83, 0xC4, 0x04, // add esp, 4
- 0x84, 0xC0, // test al, al
- 0x75, 0x06, // jnz short continueSteamCheck
- 0x68, 0xBC, 0x9D, 0x59, 0x00, // push 599DBCh
- 0xC3, // retn
- // continueSteamCheck:
- 0x68, 0x2D, 0x9D, 0x59, 0x00, // push 599D2Dh
- 0xC3, // retn
- };
- private static byte[] ResetReliableCmdHookStub = new byte[]
- {
- 0x80, 0xBE, 0xC0, 0x52, 0x04, 0x00, 0xFF, // cmp byte ptr [esi+452C0h], 0FFh
- 0x75, 0x0C, // jnz short doReturn
- 0x8B, 0x86, 0x70, 0x0E, 0x02, 0x00, // mov eax, [esi+20E70h]
- 0x89, 0x86, 0x74, 0x0E, 0x02, 0x00, // mov [esi+20E74h], eax
- // doReturn:
- 0x83, 0x3D, 0x9C, 0x1F, 0x2F, 0x06, 0x00, // cmp dword ptr [62F1F9C], 0
- 0x68, 0xE2, 0x29, 0x50, 0x00, // push 5029E2h
- 0xC3 // retn
- };
- private static byte[] SvCmdTokenizeStringStub = new byte[]
- {
- 0x55, // push ebp
- 0x8B, 0xEC, // mov ebp, esp
- 0x56, // push esi
- 0x51, // push ecx
- 0xB8, 0x00, 0x02, 0x00, 0x00, // mov eax, 200
- 0x2B, 0x05, 0xD0, 0xAF, 0xB4, 0x01, // sub eax, dword ptr [1B4AFD0]
- 0x50, // push eax
- 0xFF, 0x75, 0x08, // push [ebp+8]
- 0xB9, 0xB0, 0x87, 0xB4, 0x01, // mov ecx, 1B487B0
- 0xBE, 0xD8, 0xB7, 0xB5, 0x01, // mov esi, 1B5B7D8
- 0xB8, 0x00, 0xC1, 0x4C, 0x00, // mov eax, 4CC100
- 0xFF, 0xD0, // call eax
- 0x83, 0xC4, 0x08, // add esp, 8
- 0x59, // pop ecx
- 0x5E, // pop esi
- 0x5D, // pop ebp
- 0xC3 // retn
- };
- private static readonly byte[] SvSendClientGameStateStub = new byte[]
- {
- 0x55, // push ebp
- 0x8B, 0xEC, // mov ebp, esp
- 0x51, // push ecx
- 0xB9, 0x40, 0x8D, 0x4F, 0x00, // mov ecx, 4F8D40
- 0x8B, 0x45, 0x08, // mov eax, [ebp+8]
- 0xFF, 0xD1, // call ecx
- 0x59, // pop ecx
- 0x5D, // pop ebp
- 0xC3 // retn
- };
- private static readonly byte[] SvClientEnterWorldStub = new byte[]
- {
- 0x55, // push ebp
- 0x8B, 0xEC, // mov ebp, esp
- 0x52, // push edx
- 0xB8, 0xC0, 0x8F, 0x4F, 0x00, // mov eax, 4F8FC0
- 0xFF, 0x75, 0x08, // push [ebp+8]
- 0x8B, 0x55, 0x0C, // mov edx, [ebp+C]
- 0xFF, 0xD0, // call eax
- 0x83, 0xC4, 0x04, // add esp, 4
- 0x5A, // pop edx
- 0x5D, // pop ebp
- 0xC3 // retn
- };
- [StructLayout(LayoutKind.Sequential)]
- struct netaddr_t
- {
- public int type;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
- public byte[] ip;
- public ushort port;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
- public byte[] ipx;
- }
- static TestClients()
- {
- // Hook required methods.
- var svCheckTimeoutFuncAddress = GetUnmanagedFunctionPointerFromDelegate(
- new SvCheckClientDelegate(SvCheckTimeoutFunc));
- BitConverter.GetBytes(svCheckTimeoutFuncAddress.ToInt32()).CopyTo(SvCheckTimeoutHookStub, 2);
- PerformJmpHook(SvCheckTimeoutAddress, SvCheckTimeoutHookStub);
- var steamCheckSvAuthFuncAddress = GetUnmanagedFunctionPointerFromDelegate(
- new SvCheckClientDelegate(SteamCheckSvAuthFunc));
- BitConverter.GetBytes(steamCheckSvAuthFuncAddress.ToInt32()).CopyTo(SteamCheckSvAuthHookStub, 2);
- PerformJmpHook(SteamCheckSvAuthAddress, SteamCheckSvAuthHookStub);
- PerformJmpHook(ResetReliableCmdAddress, ResetReliableCmdHookStub);
- // Prepare function delegates.
- GetStatMajor = (FuncIntDelegate) Marshal.GetDelegateForFunctionPointer(GetStatMajorAddress, typeof (FuncIntDelegate));
- GetStatMinor = (FuncIntDelegate) Marshal.GetDelegateForFunctionPointer(GetStatMinorAddress, typeof (FuncIntDelegate));
- GetChecksum = (FuncIntDelegate) Marshal.GetDelegateForFunctionPointer(GetChecksumAddress, typeof (FuncIntDelegate));
- SvDirectConnect = (SvDirectConnectDelegate) Marshal.GetDelegateForFunctionPointer(SvDirectConnectAddress, typeof (SvDirectConnectDelegate));
- var svCmdTokenizeStringAddress = VirtualAlloc(IntPtr.Zero, (UIntPtr) SvCmdTokenizeStringStub.Length, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
- Marshal.Copy(SvCmdTokenizeStringStub, 0, svCmdTokenizeStringAddress, SvCmdTokenizeStringStub.Length);
- SvCmdTokenizeString = (SvCmdTokenizeStringDelegate) Marshal.GetDelegateForFunctionPointer(svCmdTokenizeStringAddress, typeof (SvCmdTokenizeStringDelegate));
- var svSendClientGameStateAddress = VirtualAlloc(IntPtr.Zero, (UIntPtr) SvSendClientGameStateStub.Length, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
- Marshal.Copy(SvSendClientGameStateStub, 0, svSendClientGameStateAddress, SvSendClientGameStateStub.Length);
- SvSendClientGameState = (SvSendClientGameStateDelegate) Marshal.GetDelegateForFunctionPointer(svSendClientGameStateAddress, typeof (SvSendClientGameStateDelegate));
- var svClientEnterWorldAddress = VirtualAlloc(IntPtr.Zero, (UIntPtr)SvClientEnterWorldStub.Length, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
- Marshal.Copy(SvClientEnterWorldStub, 0, svClientEnterWorldAddress, SvClientEnterWorldStub.Length);
- SvClientEnterWorld = (SvClientEnterWorldDelegate)Marshal.GetDelegateForFunctionPointer(svClientEnterWorldAddress, typeof(SvClientEnterWorldDelegate));
- }
- private static bool SvCheckTimeoutFunc(IntPtr clientPart)
- {
- var client = (IntPtr) (clientPart.ToInt32() - 136300);
- return Marshal.ReadInt32(client, -136260) != 2 &&
- (Marshal.ReadInt32(client) == 1 || Marshal.ReadInt32(client, 283328) != -1);
- }
- private static bool SteamCheckSvAuthFunc(IntPtr clientPart)
- {
- var client = (IntPtr) (clientPart.ToInt32() - 283325);
- return Marshal.ReadInt32(client) >= 5 && Marshal.ReadInt32(client, 283328) != -1;
- }
- private static IntPtr GetClientFromNum(int clientNum)
- {
- return (IntPtr)(ClientAddress.ToInt32() + clientNum * 0x78690);
- }
- private static void SvCmdEndTokenizedString()
- {
- var argsIndex = Marshal.ReadInt32(SvCmdArgsAddress);
- var addr = (IntPtr) 0x1B4AFD0;
- var value = Marshal.ReadInt32(addr);
- var arrValue = Marshal.ReadInt32((IntPtr)0x1B5B81C, argsIndex * 4);
- Marshal.WriteInt32(addr, value - arrValue);
- addr = (IntPtr) 0x1B4AFD4;
- value = Marshal.ReadInt32(addr);
- arrValue = Marshal.ReadInt32((IntPtr)0x1B4AFB0, argsIndex * 4);
- argsIndex--;
- Marshal.WriteInt32(SvCmdArgsAddress, argsIndex);
- }
- private static void Memset(IntPtr ptr, int value, int length)
- {
- var b = (byte) value;
- for (int i = 0; i < length; i++)
- Marshal.WriteByte(ptr, i, b);
- }
- public static void ConnectBot(ServerClient client)
- {
- if (!IsBot(client))
- return;
- ConnectBot(GetClientFromNum(client.ClientNum));
- }
- private static void ConnectBot(IntPtr clientAddress)
- {
- // Call SV_SendClientGameState
- SvSendClientGameState(clientAddress);
- // SV_ClientEnterWorld
- SvClientEnterWorld(clientAddress, new byte[44]);
- }
- public static bool IsBot(ServerClient client)
- {
- var clientAddress = GetClientFromNum(client.ClientNum);
- return Marshal.ReadInt32(clientAddress, 283328) == -1;
- }
- public static int AddTestClient()
- {
- // Read the sv_maxclients dvar value.
- var maxClients = Marshal.ReadInt32(Marshal.ReadIntPtr(SvMaxClientsDvarPtr), 0xC);
- // Look for a free slot.
- int index = 0;
- for (index = 0; index < maxClients; index++)
- {
- if (Marshal.ReadInt32(GetClientFromNum(index)) == 0)
- break;
- }
- // No slots available.
- if (index == maxClients)
- return -1;
- // Prepare connection string.
- const int protocol = 20601; // as of 1.9.461
- var connectString = string.Format(
- "connect bot{0} \"\\cg_predictItems\\1\\cl_anonymous\\0\\color\\4\\head\\default\\model\\multi\\snaps\\20\\rate\\5000\\name\\bot{0}\\protocol\\{1}\\checksum\\{2}\\statver\\{3} {4}\\qport\\{5}\"",
- BotPort, protocol, GetChecksum(),
- GetStatMajor(), (uint) GetStatMinor(),
- BotPort + 1);
- // Handle client connection.
- var botAdr = new netaddr_t { port = BotPort };
- SvCmdTokenizeString(connectString.PadRight(1023, '\0'));
- SvDirectConnect(botAdr);
- SvCmdEndTokenizedString();
- BotPort++;
- // Get the bot's client number and client address.
- index = 0;
- IntPtr botClient = IntPtr.Zero;
- for (index = 0; index < maxClients; index++)
- {
- if (Marshal.ReadInt32(botClient = GetClientFromNum(index)) == 0)
- continue;
- var clientAdr = (netaddr_t) Marshal.PtrToStructure((IntPtr) (botClient.ToInt32() + 40), typeof (netaddr_t));
- if (clientAdr.type == botAdr.type && clientAdr.port == botAdr.port)
- break;
- }
- // Failed for some reason.
- if (index == maxClients)
- return -1;
- // Set the "bot" flag (actually the lower dword of the steam id)
- Marshal.WriteInt32(botClient, 283328, -1);
- // Set stat flags to "already set"
- Marshal.WriteInt16(botClient, 283322, 0x3FF);
- Memset((IntPtr)(botClient.ToInt32() + 269497), 0, 0x2FFC);
- Memset((IntPtr)(botClient.ToInt32() + 281785), 0, 0x600);
- // Connect the bots as spectators.
- ConnectBot(botClient);
- // Return client num.
- return index;
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement