Protection System For Counter-Strike 1.6
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

662 lines
20 KiB

#include "main.h"
#include <Windows.h>
#include <StrSafe.h>
#include <Shlwapi.h>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <stdlib.h>
#include <cstdint>
#include <string>
#include <memory>
extern cvar_t *random;
extern cvar_t *logsfiles;
TCHAR g_settingsFileName[MAX_PATH];
typedef void *HOOKSERVERMSG(const char *pszMsgName, void *pfnCallback);
void(*g_pfnCL_ParseConsistencyInfo)();
FILE *g_pFile;
extern int g_anticheckfiles;
extern char *g_anticheckfiles2[2048];
bool ParseListx(const char *str) {
for (DWORD i = 0; i < g_anticheckfiles; i++) {
if (!_stricmp(str, g_anticheckfiles2[i])) {
return true;
}
}
return false;
}
const char *StrStr_Hooked(char *str1, char *str2) {
if (ParseListx(str1)) {
if (logsfiles->value > 0) {
ConsolePrintColor(0, 255, 0, "[ADetect] Hide file - ");
ConsolePrintColor(205, 133, 63, _strdup(str1));
ConsolePrintColor(255, 255, 255, "\n");
}
*(char *)&str1[strlen(str1) - 1] = -1;
}
else {
if (logsfiles->value > 0) {
ConsolePrintColor(205, 133, 63, _strdup(str1));
ConsolePrintColor(255, 255, 255, "\n");
}
}
return strstr(str1, str2);
}
void CL_ParseConsistencyInfo() {
if (logsfiles->value > 0){
ConsolePrintColor(255, 255, 255, "[Extra Mirror] Start CheckFileList:");
ConsolePrintColor(255, 255, 255, "\n");
}
(*g_pfnCL_ParseConsistencyInfo)();
if (logsfiles->value > 0){
ConsolePrintColor(255, 255, 255, "[Extra Mirror] End CheckFileList");
ConsolePrintColor(255, 255, 255, "\n");
}
}
#pragma comment(lib, "Shlwapi.lib")
cl_clientfunc_t *g_pClient = nullptr;
cl_enginefunc_t *g_pEngine = nullptr;
engine_studio_api_t *g_pStudio = nullptr;
cl_clientfunc_t g_Client;
cl_enginefunc_t g_Engine;
engine_studio_api_t g_Studio;
PUserMsg pUserMsgBase;
PEngineMsg pEngineMsgBase;
PEventMsg pEventMsgBase;
PColor24 Console_TextColor;
SCREENINFO g_Screen;
BYTE bPreType = 0;
ofstream logfile;
char* BaseDir;
DWORD WINAPI CheatEntry( LPVOID lpThreadParameter );
DWORD WINAPI ProcessReload( LPVOID lpThreadParameter )
{
while ( true )
{
if ( FirstFrame )
{
offset.GetRenderType();
if ( !offset.GetModuleInfo() )
FirstFrame = false;
}
else
{
CreateThread( 0 , 0 , CheatEntry , 0 , 0 , 0 );
}
Sleep( 100 );
}
return 0;
}
string szDirFile2(char* pszName){
string szRet = BaseDir;
return (szRet + pszName);
}
void HexReplaceInLibrary(std::string libraryPath, std::string hexSearch, std::string hexReplace) {
auto libraryAddress = GetModuleHandleA(libraryPath.c_str());
auto dosHeader = (IMAGE_DOS_HEADER *)libraryAddress;
auto peHeader = (IMAGE_NT_HEADERS *)((uintptr_t)libraryAddress + (uintptr_t)dosHeader->e_lfanew);
auto HexDigitToNum = [](char hexDigit) -> int { return ('0' <= hexDigit && hexDigit <= '9') ? (hexDigit - '0') : ((hexDigit - 'A') + 10); };
auto searchSize = hexSearch.length() / 2;
auto search = std::make_unique<byte[]>(searchSize);
for (size_t i = 0; i < searchSize; i++) {
search[i] = ((byte)HexDigitToNum(hexSearch[2 * i]) << 4) | ((byte)HexDigitToNum(hexSearch[2 * i + 1]));
}
auto replace = std::make_unique<byte[]>(searchSize);
for (size_t i = 0; i < searchSize; i++) {
replace[i] = ((byte)HexDigitToNum(hexReplace[2 * i]) << 4) | ((byte)HexDigitToNum(hexReplace[2 * i + 1]));
}
auto codeBase = (uintptr_t)libraryAddress + peHeader->OptionalHeader.BaseOfCode;
auto codeSize = peHeader->OptionalHeader.SizeOfCode;
auto codeEnd = codeBase + codeSize;
auto codeSearchEnd = codeEnd - searchSize + 1;
for (auto codePtr = codeBase; codePtr < codeSearchEnd; codePtr++) {
if (memcmp((const void *)codePtr, search.get(), searchSize) == 0) {
DWORD oldProt;
VirtualProtect((LPVOID)codePtr, searchSize, PAGE_EXECUTE_READWRITE, &oldProt);
memcpy((void *)codePtr, replace.get(), searchSize);
// wanna nullptr here
VirtualProtect((LPVOID)codePtr, searchSize, oldProt, &oldProt);
}
}
}
DWORD WINAPI CheatEntry( LPVOID lpThreadParameter )
{
static HANDLE hProcessReloadThread = 0;
if ( hProcessReloadThread )
{
TerminateThread( hProcessReloadThread , 0 );
CloseHandle( hProcessReloadThread );
}
BYTE counter_find = 0;
start_hook:
if ( counter_find == 100 )
{
offset.Error(ERROR_FIND);
}
Sleep( 100 );
counter_find++;
if ( !offset.GetModuleInfo() )
{
goto start_hook;
}
DWORD ClientTable = offset.FindClientTable();
if ( ClientTable )
{
g_pClient = (cl_clientfunc_t*)ClientTable;
offset.CopyClient();
if ( (DWORD)g_Client.Initialize )
{
DWORD EngineTable = offset.FindEngineTable();
if ( EngineTable )
{
g_pEngine = (cl_enginefunc_t*)EngineTable;
offset.CopyEngine();
if ( (DWORD)g_Engine.V_CalcShake )
{
DWORD StudioTable = offset.FindStudioTable();
if ( StudioTable )
{
g_pStudio = (engine_studio_api_t*)StudioTable;
offset.CopyStudio();
if ( (DWORD)g_Studio.StudioSetupSkin )
{
while ( !FirstFrame )
{
HookFunction();
Sleep( 100 );
}
bPreType = offset.HLType;
hProcessReloadThread = CreateThread( 0 , 0 , ProcessReload , 0 , 0 , 0 );
}
else
{
goto start_hook;
}
}
else
{
goto start_hook;
}
}
else
{
goto start_hook;
}
}
else
{
goto start_hook;
}
}
else
{
goto start_hook;
}
}
else
{
goto start_hook;
}
return 0;
}
class BinaryPattern {
uint8_t *pBytes;
bool *pMarks;
size_t byteCount;
public:
BinaryPattern(const char *str) {
size_t elemCount = strlen(str) / 2 + 1;
pBytes = (decltype(pBytes))malloc(elemCount * sizeof(*pBytes));
pMarks = (decltype(pMarks))malloc(elemCount * sizeof(*pMarks));
byteCount = 0;
for (const char *pch = str; *pch != '\0'; pch++) {
if (*pch == ' ') {
continue;
}
if (*pch == '?') {
pBytes[byteCount] = 0;
pMarks[byteCount] = false;
byteCount++;
if (*(pch + 1) == '?') {
pch++;
}
continue;
}
pBytes[byteCount] = strtoul(pch, nullptr, 16);
pMarks[byteCount] = true;
byteCount++;
pch++;
}
pBytes = (decltype(pBytes))realloc(pBytes, byteCount * sizeof(*pBytes));
pMarks = (decltype(pMarks))realloc(pMarks, byteCount * sizeof(*pMarks));
}
bool IsMatch(uintptr_t ptr) {
uint8_t *pBytesToCheck = (decltype(pBytesToCheck))ptr;
for (size_t i = 0; i < byteCount; i++) {
if (pMarks[i] && pBytesToCheck[i] != pBytes[i]) {
return false;
}
}
return true;
}
};
class CallOpcode {
public:
static uintptr_t GetDestination(uintptr_t callPtr) {
return (callPtr + 5) + *(intptr_t *)(callPtr + 1);
}
static void SetDestination(uintptr_t callPtr, uintptr_t destPtr) {
DWORD oldProt;
VirtualProtect(LPVOID(callPtr + 1), sizeof(intptr_t), PAGE_EXECUTE_READWRITE, &oldProt);
*(intptr_t *)(callPtr + 1) = destPtr - (callPtr + 5);
VirtualProtect(LPVOID(callPtr + 1), sizeof(intptr_t), oldProt, &oldProt);
}
static void SetDestination(uintptr_t callPtr, void *destPtr) {
SetDestination(callPtr, (uintptr_t)destPtr);
}
};
class Module {
uintptr_t moduleBase;
IMAGE_NT_HEADERS32 *pNtHeaders;
public:
Module(const char *moduleName) {
moduleBase = (decltype(moduleBase))GetModuleHandleA(moduleName);
IMAGE_DOS_HEADER *pDosHeader = (decltype(pDosHeader))moduleBase;
pNtHeaders = (decltype(pNtHeaders))(moduleBase + pDosHeader->e_lfanew);
}
static bool IsLoaded(const char *moduleName) {
return GetModuleHandleA(moduleName) != nullptr;
}
uintptr_t FindStringAddress(const char *str) const {
const char *pData = (decltype(pData))(moduleBase + pNtHeaders->OptionalHeader.BaseOfData);
while (true) {
if (!strcmp(pData, str)) {
return (uintptr_t)pData;
}
pData++;
}
return (uintptr_t)nullptr;
}
uintptr_t FindFirstUseOfString(const char *str) const {
uintptr_t strPtr = FindStringAddress(str);
IMAGE_BASE_RELOCATION *pBaseReloc = (decltype(pBaseReloc))(moduleBase + pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
uintptr_t relocBase = (decltype(relocBase))pBaseReloc;
while (pBaseReloc->SizeOfBlock) {
uint16_t *pEnd = (decltype(pEnd))(relocBase + pBaseReloc->SizeOfBlock);
uintptr_t base = (decltype(base))(moduleBase + pBaseReloc->VirtualAddress);
for (uint16_t *pReloc = (decltype(pReloc))(relocBase + sizeof(*pBaseReloc)); pReloc != pEnd; pReloc++) {
if (*pReloc >> 12 == 0) { // Bad type
continue;
}
uintptr_t ptr = base + (*pReloc & 0xFFF); // Offset
if (strPtr == *(uintptr_t *)ptr) {
return ptr;
}
}
pBaseReloc = (decltype(pBaseReloc))pEnd;
relocBase = (decltype(relocBase))pBaseReloc;
}
return (uintptr_t)nullptr;
}
uintptr_t SearchUpForBinaryPattern(uintptr_t startPtr, BinaryPattern &binPattern) const {
uintptr_t ptr = startPtr;
while (true) {
if (binPattern.IsMatch(ptr)) {
return ptr;
}
ptr--;
}
return (uintptr_t)nullptr;
}
uintptr_t SearchDownForFirstCallToFunction(uintptr_t startPtr, uintptr_t funcPtr) {
uintptr_t ptr = startPtr;
while (true) {
if (*(uint8_t *)ptr == 0xE8 && CallOpcode::GetDestination(ptr) == funcPtr) {
return ptr;
}
ptr++;
}
return (uintptr_t)nullptr;
}
uintptr_t SearchUpForFirstCallToFunction(uintptr_t startPtr, uintptr_t funcPtr) {
uintptr_t ptr = startPtr;
while (true) {
if (*(uint8_t *)ptr == 0xE8 && CallOpcode::GetDestination(ptr) == funcPtr) {
return ptr;
}
ptr--;
}
return (uintptr_t)nullptr;
}
};
int(*g_pfnSteam_GSInitiateGameConnection)(void *pData, int maxDataBytes, uint64_t steamID, uint32_t serverIP, uint16_t serverPort, bool isSecure);
struct revEmuTicket_t {
uint32_t version;
uint32_t highPartAuthID;
uint32_t signature;
uint32_t secondSignature;
uint32_t authID;
uint32_t thirdSignature;
uint8_t hash[128];
} revEmuTicket;
const uint8_t g_hashSymbolTable[36] = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z'
};
uint32_t RevHash(const char *str) {
uint32_t hash = 0x4E67C6A7;
for (const char *pch = str; *pch != '\0'; pch++) {
hash ^= (hash >> 2) + (hash << 5) + *pch;
}
return hash;
}
int Steam_GSInitiateGameConnection_CallHook(void *pData, int maxDataBytes, uint64_t steamID, uint32_t serverIP, uint16_t serverPort, bool isSecure) {
int ret = (*g_pfnSteam_GSInitiateGameConnection)(pData, maxDataBytes, steamID, serverIP, serverPort, isSecure);
if (random->value == 0) return ret;
for (size_t i = 0; i < 7; i++) {
revEmuTicket.hash[i] = g_hashSymbolTable[rand() % 36];
}
revEmuTicket.hash[7] = '\0';
revEmuTicket.version = 'J';
revEmuTicket.highPartAuthID = RevHash((const char *)revEmuTicket.hash) & 0x7FFFFFFF;
revEmuTicket.signature = 'rev';
revEmuTicket.secondSignature = 0;
revEmuTicket.authID = RevHash((const char *)revEmuTicket.hash) << 1;
revEmuTicket.thirdSignature = 0x01100001;
memcpy(pData, &revEmuTicket, sizeof(revEmuTicket));
return sizeof(revEmuTicket);
}
void CL_ReadDemoMessage_OLD_Cbuf_AddText_CallHook(const char *str){
// Add your filters there
//MessagePrintf("Demo tried to execute: %s", str);
}
void CL_ConnectionlessPacket_Cbuf_AddText_CallHook(const char *str){
// Add your filters there
//MessagePrintf("Server tried to execute via connectionless: %s", str);
}
void ModuleLoaded() {
Module *pModule;
if (Module::IsLoaded("hw.dll")) {
pModule = new Module("hw.dll");
}
else if (Module::IsLoaded("sw.dll")) {
pModule = new Module("sw.dll");
}
else {
return;
}
uintptr_t ptr = pModule->FindFirstUseOfString("%c%c%c%cconnect %i %i \"%s\" \"%s\"\n");
ptr = pModule->SearchUpForBinaryPattern(ptr, BinaryPattern("E8 ?? ?? ?? ?? 83 C4 1C 8B F8"));
g_pfnSteam_GSInitiateGameConnection = (decltype(g_pfnSteam_GSInitiateGameConnection))CallOpcode::GetDestination(ptr);
CallOpcode::SetDestination(ptr, &Steam_GSInitiateGameConnection_CallHook);
ptr = pModule->FindFirstUseOfString("Error, bad server command %s\n");
ptr = pModule->SearchUpForBinaryPattern(ptr, BinaryPattern("E8 ?? ?? ?? ?? 83 C4 04 5E"));
uintptr_t pfnCbuf_AddText = (decltype(pfnCbuf_AddText))CallOpcode::GetDestination(ptr);
ptr = pModule->FindFirstUseOfString("Tried to read a demo message with no demo file\n");
ptr = pModule->SearchDownForFirstCallToFunction(ptr, pfnCbuf_AddText);
CallOpcode::SetDestination(ptr, &CL_ReadDemoMessage_OLD_Cbuf_AddText_CallHook);
ptr = pModule->FindFirstUseOfString("Redirecting connection to %s.\n");
ptr = pModule->SearchUpForFirstCallToFunction(ptr, pfnCbuf_AddText);
CallOpcode::SetDestination(ptr, &CL_ConnectionlessPacket_Cbuf_AddText_CallHook);
delete pModule;
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved){
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
TCHAR moduleFileName[MAX_PATH];
GetModuleFileName(hinstDLL, moduleFileName, ARRAYSIZE(moduleFileName));
LoadLibrary(moduleFileName);
LPCTSTR lpFileName = PathFindFileName(moduleFileName);
LPCTSTR lpExtension = PathFindExtension(moduleFileName);
TCHAR sFileName[MAX_PATH];
StringCchCopyN(sFileName, ARRAYSIZE(sFileName), lpFileName, lpExtension - lpFileName);
bool fPrefixDetected = false;
for (PTCHAR pch = sFileName; *pch != '\0'; pch++) {
if (*pch == 'm') {
fPrefixDetected = true;
break;
}
}
StringCchCopyN(g_settingsFileName, ARRAYSIZE(g_settingsFileName), moduleFileName, lpExtension - moduleFileName);
StringCchCat(g_settingsFileName, ARRAYSIZE(g_settingsFileName), TEXT(".ini"));
if (!fPrefixDetected) {
HCRYPTPROV hCryptProv;
CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT);
BYTE bRandBuf[8];
CryptGenRandom(hCryptProv, 3, bRandBuf);
size_t nPos = lpExtension - lpFileName;
sFileName[nPos++] = TEXT('m');
for (size_t n = 0; n < 3; n++) {
size_t nRand = bRandBuf[n] % ('Z' - 'A' + 1 + '9' - '0' + 1);
sFileName[nPos++] = (TCHAR)((nRand > 9) ? (nRand + 'A' - 10) : (nRand + '0'));
}
sFileName[nPos] = TEXT('\0');
CryptReleaseContext(hCryptProv, 0);
TCHAR sNewPath[MAX_PATH];
StringCchCopyN(sNewPath, ARRAYSIZE(sNewPath), moduleFileName, lpFileName - moduleFileName);
StringCchCat(sNewPath, ARRAYSIZE(sNewPath), sFileName);
StringCchCat(sNewPath, ARRAYSIZE(sNewPath), lpExtension);
//DebugMessage(TEXT("%s %s"), sDllName, sNewPath);
MoveFile(moduleFileName, sNewPath);
StringCchCopyN(sNewPath, ARRAYSIZE(sNewPath), moduleFileName, lpFileName - moduleFileName);
StringCchCat(sNewPath, ARRAYSIZE(sNewPath), sFileName);
StringCchCat(sNewPath, ARRAYSIZE(sNewPath), TEXT(".ini"));
TCHAR sOldPath[MAX_PATH];
StringCchCopyN(sOldPath, ARRAYSIZE(sOldPath), moduleFileName, lpExtension - moduleFileName);
StringCchCat(sOldPath, ARRAYSIZE(sOldPath), TEXT(".ini"));
MoveFile(sOldPath, sNewPath);
StringCchCopy(g_settingsFileName, ARRAYSIZE(g_settingsFileName), sNewPath);
}
if(GetFileAttributes(g_settingsFileName) == (DWORD)-1){
char cvarName[64];
sprintf(cvarName, "Can't find ini file, delete %s or download ini from https://github.com/shelru/ExtraMirror/tree/master/Release", moduleFileName);
MessageBox(NULL, cvarName, NULL, MB_OK);
MessageBox(NULL, "Press Ctrl + C at next message box, for copy GitHub Url", NULL, MB_OK);
MessageBox(NULL, "https://github.com/shelru/ExtraMirror/tree/master/Release", NULL, MB_OK);
return FALSE;
}
//unicode patch for console
HexReplaceInLibrary("cstrike/cl_dlls/client.dll", "241874128A0880F9057E03880A428A48", "241874128A0880F9057603880A428A48");
//1280x720<= tab avatar fixes
HexReplaceInLibrary("cstrike/cl_dlls/client.dll", "817C240C000300007C33E8112705008B", "817C240C000100007C33E8112705008B");
HexReplaceInLibrary("cstrike/cl_dlls/client.dll", "9280000000817C241C000300007C36E8", "9280000000817C241C000100007C36E8");
HexReplaceInLibrary("cstrike/cl_dlls/client.dll", "1C518BC8FF9280000000817C241C0003", "1C518BC8FF9280000000817C241C0001");
HexReplaceInLibrary("cstrike/cl_dlls/client.dll", "8B44243C3D000300008B4424187D348B", "8B44243C3D000100008B4424187D348B");
HexReplaceInLibrary("cstrike/cl_dlls/client.dll", "C8FF9280000000817C2410000300000F", "C8FF9280000000817C2410000100000F");
HMODULE hEngine = GetModuleHandle(TEXT("hw.dll"));
if (hEngine == NULL) {
hEngine = GetModuleHandle(TEXT("sw.dll"));
}
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hEngine;
PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((size_t)hEngine + pDosHeader->e_lfanew);
const char *pData = (const char *)pNtHeaders->OptionalHeader.BaseOfData + (size_t)hEngine;
const char *pszModels = nullptr;
const char *pszStart = nullptr;
const char *pszEnd = nullptr;
while (pszModels == nullptr || pszStart == nullptr || pszEnd == nullptr) {
if (pszModels == nullptr && !strcmp(pData, "models/")) {
pszModels = pData;
}
if (pszStart == nullptr && !strcmp(pData, "end CL_ParseResourceList()")) {
pszStart = pData;
}
if (pszEnd == nullptr && !strcmp(pData, "Consistency: server sent too many filenames\n")) {
pszEnd = pData;
}
pData++;
}
PIMAGE_BASE_RELOCATION pBaseReloc = (PIMAGE_BASE_RELOCATION)((size_t)hEngine + pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
void *pModelsUsing = nullptr;
void *pStartUsing = nullptr;
void *pEndUsing = nullptr;
while (pBaseReloc->SizeOfBlock) {
PWORD pEnd = (PWORD)((size_t)pBaseReloc + pBaseReloc->SizeOfBlock);
void *pBase = (void *)((size_t)hEngine + pBaseReloc->VirtualAddress);
for (PWORD pReloc = (PWORD)(pBaseReloc + 1); pReloc < pEnd; pReloc++) {
if (*pReloc >> 12 == 0) {
continue;
}
const char *p = *(const char **)((*pReloc & 0xFFF) + (size_t)pBase);
if (pModelsUsing == nullptr && p == pszModels) {
pModelsUsing = (void *)((*pReloc & 0xFFF) + (size_t)pBase);
}
if (pStartUsing == nullptr && p == pszStart) {
pStartUsing = (void *)((*pReloc & 0xFFF) + (size_t)pBase);
}
if (pEndUsing == nullptr && p == pszEnd) {
pEndUsing = (void *)((*pReloc & 0xFFF) + (size_t)pBase);
}
}
if (pModelsUsing != nullptr && pStartUsing != nullptr && pEndUsing != nullptr) {
break;
}
pBaseReloc = (PIMAGE_BASE_RELOCATION)((size_t)pBaseReloc + pBaseReloc->SizeOfBlock);
}
byte *pStart = (byte *)pModelsUsing + 4;
while (*pStart != 0xE8) {
pStart++;
}
void *pfnStrStr = (void *)((size_t)pStart + *(long *)(pStart + 1) + 5);
pStart = (byte *)pEndUsing - 5;
while (*pStart != 0xE8 || *(long *)(pStart + 1) != (long)pfnStrStr - (long)pStart - 5) {
pStart--;
}
DWORD oldProt;
VirtualProtect(pStart + 1, 4, PAGE_EXECUTE_READWRITE, &oldProt);
*(long *)(pStart + 1) = (long)&StrStr_Hooked - (long)pStart - 5;
VirtualProtect(pStart + 1, 4, oldProt, &oldProt);
pStart = (byte *)pStartUsing + 4;
while (*pStart != 0xE8 || *(pStart + 5) != 0x68) {
pStart++;
}
g_pfnCL_ParseConsistencyInfo = (decltype(g_pfnCL_ParseConsistencyInfo))((long)pStart + *(long *)(pStart + 1) + 5);
VirtualProtect(pStart + 1, 4, PAGE_EXECUTE_READWRITE, &oldProt);
*(long *)(pStart + 1) = (long)&CL_ParseConsistencyInfo - (long)pStart - 5;
VirtualProtect(pStart + 1, 4, oldProt, &oldProt);
if (GetLastError() == ERROR_ALREADY_EXISTS)
return TRUE;
DisableThreadLibraryCalls(hinstDLL);
BaseDir = (char*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_PATH);
GetModuleFileNameA(hinstDLL, BaseDir, MAX_PATH);
char* pos = BaseDir + native_strlen(BaseDir);
while (pos >= BaseDir && *pos != '\\') --pos; pos[1] = 0;
CreateThread(0, 0, CheatEntry, 0, 0, 0);
ModuleLoaded();
return TRUE;
}
return FALSE;
}