.:: Bots United ::.  
filebase forums discord server github wiki web
cubebot epodbot fritzbot gravebot grogbot hpbbot ivpbot jkbotti joebot
meanmod podbotmm racc rcbot realbot sandbot shrikebot soulfathermaps yapb

Go Back   .:: Bots United ::. > Developer's Farm > General Bot Coding
General Bot Coding See what a pain it is to get those little mechs shooting around

Reply
 
Thread Tools
Fake bot ping (SV_CalcPing() function injecting)
Old
  (#1)
Immortal_BLG
Member
 
Status: Offline
Posts: 171
Join Date: Nov 2007
Location: Russian Federation
Default Fake bot ping (SV_CalcPing() function injecting) - 05-02-2011

Code:
const unsigned char Pointer32Size (sizeof (void *));
const unsigned char WildCard (0x2A);	// Used for signature scanning.
const unsigned char Push32 (0x68);	// push '....' (encoding is <imm32>)
const unsigned char JumpImmediately32 (0xE9);	// jmp '....' (encoding is imm32)
const unsigned char JumpImmediately32Size (sizeof (JumpImmediately32) + Pointer32Size);	// size of the jump-to instruction

struct ModuleInformation_t
{
	void         *baseAddress;
	unsigned int  memorySize;

	inline ModuleInformation_t (void) :
		baseAddress (NULL),
		memorySize (0u)
	{ /* VOID */ }
};
inline const bool GetModuleInformation (const void *const libraryPointer, ModuleInformation_t &dynamicLibraryInformation)
{
	// Get base address of the module (dynamicLibraryInformation.baseAddress) and get its ending offset (dynamicLibraryInformation.memorySize)

	// First - reset dynamic library information structure....
	dynamicLibraryInformation.baseAddress = NULL;
	dynamicLibraryInformation.memorySize = 0u;

	// Reliability check.
	if (libraryPointer == NULL)	// GetModuleInformation() failed!
		return false;

	MEMORY_BASIC_INFORMATION info;

	// Reliability check.
	if (VirtualQuery (libraryPointer, &info, sizeof (info)) == 0)
		return false;

	/// @note THIS CHECK IS ADDED FROM CSigMngr.cpp
	if (info.AllocationBase == NULL)
		return false;

	// All this is for our insane sanity checks :O
	const IMAGE_DOS_HEADER *const dos (static_cast <IMAGE_DOS_HEADER *> (info.AllocationBase));
	const IMAGE_NT_HEADERS *const pe (reinterpret_cast <IMAGE_NT_HEADERS *> (reinterpret_cast <unsigned int> (info.AllocationBase) + dos->e_lfanew));

	// Check PE magic and signature
	/// @note IsBadReadPtr() CHECKS ARE ADDED FROM CSigMngr.cpp
	if
	(
		IsBadReadPtr (dos, sizeof (IMAGE_DOS_HEADER)) ||
		dos->e_magic != IMAGE_DOS_SIGNATURE           ||
		IsBadReadPtr (pe, sizeof (IMAGE_NT_HEADERS))  ||	// pe points to a bad location?
		pe->Signature != IMAGE_NT_SIGNATURE           ||
		pe->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC
	)
		return false;

	/* Check architecture, which is 32-bit/x86 right now
	* Should change this for 64-bit if Valve gets their act together
	*/
	if (pe->FileHeader.Machine != IMAGE_FILE_MACHINE_I386)
		return false;

	// Finally, we can do this
	dynamicLibraryInformation.baseAddress = info.AllocationBase;
	dynamicLibraryInformation.memorySize = pe->OptionalHeader.SizeOfImage;

	return true;
}
inline const bool CompareMemoryWithoutWildCard (const unsigned char *const startPointer, const unsigned char *const pattern, const unsigned char length)
{
	// Compare each byte, except wildcards....
	for (unsigned char index (0u); startPointer[index] == pattern[index]; /* Empty */)
		if ((index += sizeof (unsigned char)) == length)	// If 'index' reached the end, we know we have a match!
			return true;	// Found a match.

	return false;
}
inline void *const FindPatternWithoutWildCard (void *startPointer, const unsigned int searchLength, const unsigned char *const pattern, const unsigned char length, const unsigned char stepSize = sizeof (unsigned char))
{
	// Scan for the signature in memory then return the starting position's address.

	// Reliability checks.
	if (startPointer == NULL || searchLength < length || length < 2u)
		return NULL;

	const unsigned char *const endPointer (static_cast <unsigned char *> (startPointer) + searchLength);	// prevent a crash maybe?

	do
	{
		// Compare each byte, except wildcards....
		if (CompareMemoryWithoutWildCard (static_cast <unsigned char *> (startPointer), pattern, length))
			return startPointer;	// Found a match.
	} while ((reinterpret_cast <unsigned char *&> (startPointer) += stepSize/* search memory in an aligned manner, or not */) + length <= endPointer);	// prevent a crash maybe?

	return NULL;
}
inline const bool CompareMemory (const unsigned char *const startPointer, const unsigned char *const pattern, const unsigned char length, const unsigned char wildCard = WildCard)
{
	// Compare each byte, except wildcards....
	for (unsigned char index (0u); pattern[index] == wildCard || startPointer[index] == pattern[index]; /* Empty */)
		if ((index += sizeof (unsigned char)) == length)	// If 'index' reached the end, we know we have a match!
			return true;	// Found a match.

	return false;
}
/**
* @brief Searches for a pattern of bytes within the memory of a dynamic library.
*
* @param startPointer:	Pointer to memory to search for.
* @param searchLength:	Length of sequence of memory to search for.
* @param pattern:		Pattern of bytes to search for. 0x2A can be used as a wildcard.
* @param length:		Size of the pattern in bytes.
* @return				Pointer to pattern found in memory, NULL if not found.
*/
inline void *const FindPattern (void *startPointer, const unsigned int searchLength, const unsigned char *const pattern, const unsigned char length, const unsigned char stepSize = sizeof (unsigned char), const unsigned char wildCard = WildCard)
{
	// Scan for the signature in memory then return the starting position's address.

	// Reliability checks.
	if (startPointer == NULL || searchLength < length || length < 2u)
		return NULL;

	const unsigned char *const endPointer (static_cast <unsigned char *> (startPointer) + searchLength);	// prevent a crash maybe?

	do
	{
		// Compare each byte, except wildcards....
		if (CompareMemory (static_cast <unsigned char *> (startPointer), pattern, length, wildCard))
			return startPointer;	// Found a match.
	} while ((reinterpret_cast <unsigned char *&> (startPointer) += stepSize/* search memory in an aligned manner, or not */) + length <= endPointer);	// prevent a crash maybe?

	return NULL;
}
inline void *const FindMemoryChunkReference32 (void *const startPointer, const unsigned int searchLength, const void *const address, const unsigned char instruction)
{
	const union /* Unnamed */
	{
		const void    *pointer;
		unsigned char  byte[Pointer32Size];
	} pointerToByte = {address/*, Do not initialize me! */};
	const unsigned char pattern[sizeof (instruction) + Pointer32Size] =
	{
		instruction, pointerToByte.byte[0u], pointerToByte.byte[1u], pointerToByte.byte[2u], pointerToByte.byte[3u]	// instruction 'address'
	};

	return FindPattern (startPointer, searchLength, pattern, sizeof (pattern));
}
inline void *const GetRealAddressOfRelativeAddress32 (const void *const relativeAddress)
{
	// Reliability check.
	if (relativeAddress == NULL)
		return NULL;

	return reinterpret_cast <void *> (static_cast <const unsigned int *const> (relativeAddress)[0u] + reinterpret_cast <const unsigned int> (relativeAddress) + Pointer32Size);
}

struct Client_t;
typedef const unsigned int (*SV_CalcPingFunction_t) (const Client_t *const client);

inline SV_CalcPingFunction_t GetSV_CalcPingFunction (void)
{
	ModuleInformation_t engineModuleInformation;

	if (!GetModuleInformation (gEngfuncs.pfnGetPlayerUserId, engineModuleInformation))
		return NULL;

	const unsigned char string[] = {"%4i %s\n"};	// From Host_Ping_f() function.
	unsigned char *address (static_cast <unsigned char *> (FindPatternWithoutWildCard (engineModuleInformation.baseAddress, engineModuleInformation.memorySize, string, sizeof (string) - sizeof ('\0'))));

	if (address == NULL)
		return NULL;

	address = static_cast <unsigned char *> (FindMemoryChunkReference32 (engineModuleInformation.baseAddress, engineModuleInformation.memorySize, address, Push32));

	if (address == NULL)
		return NULL;

	address -= sizeof ("\x4D\x93\x04\x00\x83\xC4\x04\x50") - sizeof ('\0');

	return static_cast <SV_CalcPingFunction_t> (GetRealAddressOfRelativeAddress32 (address));
}

inline const unsigned int SV_CalcPing_IfFakeClient (const Client_t *const fakeClient)
{
	edict_t *const fakeClientEdict (reinterpret_cast <edict_t **> (fakeClient)[4839u/* For 4554 build! */]);

	gEngfuncs.pfnServerPrint ("SV_CalcPing_IfFakeClient(%s): called!", STRING (fakeClientEdict->v.netname));

	return 999u;	// YOUR CODE HERE!!!!
}

#define CALL_SV_CalcPing_IfFakeClient_FUNCTION								\
	{ push eax }						/* just for safety */				\
	{ push ecx }						/* push the fake client pointer */	\
	{ call SV_CalcPing_IfFakeClient }	/* call our function */				\
	{ add  esp, 8 }						/* correct stack */					\

inline const unsigned int __declspec (naked) SV_CalcPing_IfFakeClient_Gate_WithEpilogueOfListenServer (const Client_t *const fakeClient)
{
	__asm
	{
		CALL_SV_CalcPing_IfFakeClient_FUNCTION;

		pop  ebp;
		pop  ecx;

		retn;	// Return Near from Procedure
	}
}
inline const unsigned int __declspec (naked) SV_CalcPing_IfFakeClient_Gate_WithEpilogueOfDedicatedServer (const Client_t *const fakeClient)
{
	/// @todo THIS FUNCTION WORKS FINE, BUT I'M NOT SHURE....

	__asm
	{
		CALL_SV_CalcPing_IfFakeClient_FUNCTION;

		pop  esi;
		mov  esp, ebp;
		pop  ebp;

		retn;	// Return Near from Procedure
	}
}
inline void InjectInSV_CalcPingFunction (void)
{
	SV_CalcPingFunction_t SV_CalcPingFunction (GetSV_CalcPingFunction ());

	if (SV_CalcPingFunction == NULL)
	{
		gEngfuncs.pfnServerPrint ("InjectInSV_CalcPingFunction(): Can't find target function!");

		return;
	}

	const unsigned char signatureIfFakeClient[] = {"\x39\x2A\x48\x25\x00\x00"};	// cmp [ecx+2548h], (ebp/esi)	// Compare Two Operands (2548h - offset to Client_t::fakeclient member)
	unsigned char *addressIfFakeClient (static_cast <unsigned char *> (FindPattern (SV_CalcPingFunction, sizeof ("\x55\x8B\xEC\x51\x8B\x4D\x08\x56\x33\xF6\x39\xB1\x48\x25\x00\x00\x74\x07\x33\xC0\x5E\x8B\xE5\x5D\xC3") - sizeof ('\0')/* Signature from swds.dll (longer than in hw.dll) */, signatureIfFakeClient, sizeof (signatureIfFakeClient) - sizeof ('\0'))));

	// Reliability check.
	if (addressIfFakeClient == NULL)
		return;

	// Skip "cmp [ecx+2548h], (ebp/esi)" and "jz short loc_1D9B089" instructions....
	addressIfFakeClient += sizeof (signatureIfFakeClient) - sizeof ('\0') + sizeof ("\x74\x07")/* jz short loc_1D9B089 */ - sizeof ('\0');

	// Reliability checks.
	if (addressIfFakeClient[0u] != 0x33 || addressIfFakeClient[1u] != 0xC0)	// xor eax, eax	// Logical Exclusive OR
		return;

	unsigned long dummyOldProtectFlags;

	if (!VirtualProtect (addressIfFakeClient, JumpImmediately32Size, PAGE_EXECUTE_READWRITE, &dummyOldProtectFlags))
	{
		gEngfuncs.pfnServerPrint ("InjectInSV_CalcPingFunction(): VirtualProtect() filed!");

		return;
	}

	addressIfFakeClient[0u] = JumpImmediately32;

	reinterpret_cast <unsigned int *> (addressIfFakeClient + sizeof (JumpImmediately32))[0u] = reinterpret_cast <unsigned char *> (gEngfuncs.pfnIsDedicatedServer () ? SV_CalcPing_IfFakeClient_Gate_WithEpilogueOfDedicatedServer : SV_CalcPing_IfFakeClient_Gate_WithEpilogueOfListenServer) - addressIfFakeClient - JumpImmediately32Size;

	gEngfuncs.pfnServerPrint ("InjectInSV_CalcPingFunction(): Complete!");
}
It works fine for me!

P.S. 1 SORRY FOR BAD ENGLISH!
P.S. 2 With this method you can see fake ping for example in 'status' command
P.S. 3 I'm not good in ASM!!!
P.S. 4 If you need full Client_t structure I can post it. (But with changed names of structures)

Last edited by Immortal_BLG; 05-02-2011 at 14:44..
  
Reply With Quote
Reply


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump



Powered by vBulletin® Version 3.8.2
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
vBulletin Skin developed by: vBStyles.com