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)