Does anyone know if this affects Guruds trainer? Been using it a for a long time and would like to know if its affected by this patch. I assume it is though.
Does anyone know if this affects Guruds trainer? Been using it a for a long time and would like to know if its affected by this patch. I assume it is though.
omg i got banned
lol jk
It's a Heartbeat anti-cheat. The client and server must send heartbeats to each other, and be validated. Or the player will be kicked from the server. It's really that simple. Freezing is irrelevant, because the heartbeet check command will be called from the server periodically and if the client is frozen (no data will be returned) you're kicked.
It should disconnect you if GGG was smart and implemented an intuitive anti cheat, but I'm not sure I havn't looked into the new patch yet.
why we can not just replace?
in sub_9C6360
from
toCode:mov al, 1
Code:mov al, 0
Actually i don't see links between creating threads and memory leaks. How can byte variable affect on CloseHandle or exiting from threads.the threads will keep being created and you'll have memory leak and probably unwanted effect
I didn't look deeper, is it problem that we send 0?And the heartbeat will be send regardless.
you need to send a valid checksum i think, i'm checking the packet structure atm.
One of the things they do is a signature scan over the client functions with one of the signatures being [D9 E8 8B 0C 24 D9 19 8B 0C 24 03 CA 89 0C 24 D9 E8] which is a pattern found in the function that is used when enabling maphack, and only when the maphack is already active. Safe to say that everyone that used maphack is flagged.
they hardcoded a lot of encrypted strings in this and whenever they're decrypted and read, they're immediately zero'd out.
here's the decrypter
Some reversed code from the first page (you should understand what this does)Code:char cryptedString[16] = "\x0D\x0E\x08\x6E\x32\xB8\x54\xFE\xE6\xF4\xF9\xC1\x60\x00\x00"; if (cryptedString[0]) { unsigned int key[8] = { 0x3D7C6B4A, 0x9B20CB4B, 0xA797BD8B, 0x04EFBA0F, 0x88FE173A, 0xB1A0186B, 0xC35114C0, 0x883ECE77 }; unsigned char* ptrToKey = (unsigned char*)&key[0]; unsigned char* currentByte = (unsigned char*)&cryptedString[0]; ptrToKey = ptrToKey - (int)&cryptedString[0]; do { *currentByte ^= *(ptrToKey + (unsigned int)currentByte); currentByte++; } while (currentByte[0]); } printf("%s", cryptedString);
When i put a c in front of a variable it means crypted, d means decrypted and l means the Loaded module addressCode:char __cdecl sub_9C6440() { char *dKernel32DLL; // eax@1 char *dNtdllDLL; // eax@1 char *dUser32DLL; // eax@1 unsigned int len1; // eax@1 int i; // ecx@1 unsigned int len2; // eax@3 int j; // ecx@3 unsigned int len3; // eax@5 int k; // ecx@5 dKernel32DLL = getDecryptedModuleName(cKernel32DLL); hKernel32DLL = GetModuleHandleA(dKernel32DLL); dNtdllDLL = getDecryptedModuleName(cNtdllDll); hNtdllDLL = GetModuleHandleA(dNtdllDLL); dUser32DLL = getDecryptedModuleName(cUser32DLL); hUser32DLL = GetModuleHandleA(dUser32DLL); // Once it gets the decrypted module name, it make sures the crypted/decrypted name are zero'd out len1 = strlen(cKernel32DLL); for ( i = cKernel32DLL; len1; --len1 ) *i++ = 0; len2 = strlen(cNtdllDll); for ( j = cNtdllDll; len2; --len2 ) *j++ = 0; len3 = strlen(cUser32DLL); for ( k = cUser32DLL; len3; --len3 ) *k++ = 0; lCloseHandle = GetProcAddressFromEncrypted(&cCloseHandle, hKernel32DLL); dword_C8FF28 = GetProcAddressFromEncrypted(&unk_C75500, hKernel32DLL); dword_C8FF38 = GetProcAddressFromEncrypted(&unk_C75514, hKernel32DLL); dword_C8FF24 = GetProcAddressFromEncrypted(&unk_C75540, hKernel32DLL); dword_C8FF30 = GetProcAddressFromEncrypted(&unk_C75554, hUser32DLL); dword_C8FF34 = GetProcAddressFromEncrypted(&unk_C75564, hKernel32DLL); dword_C8FF5C = GetProcAddressFromEncrypted(&unk_C75578, hKernel32DLL); lGetSystemInfo = GetProcAddressFromEncrypted(&cGetSystemInfo, hKernel32DLL); dword_C8FF40 = GetProcAddressFromEncrypted(&unk_C755C4, hUser32DLL); dword_C8FF20 = GetProcAddressFromEncrypted(&unk_C755D4, hKernel32DLL); dword_C8FF6C = GetProcAddressFromEncrypted(&unk_C755E4, hKernel32DLL); dword_C8F70C = GetProcAddressFromEncrypted(&unk_C755F4, hKernel32DLL); dword_C8FF68 = GetProcAddressFromEncrypted(&unk_C75604, hKernel32DLL); dword_C8FF78 = GetProcAddressFromEncrypted(&unk_C75614, hKernel32DLL); dword_C8FF74 = GetProcAddressFromEncrypted(&unk_C75624, hKernel32DLL); dword_C8FF2C = GetProcAddressFromEncrypted(&unk_C75638, hKernel32DLL); dword_C8FF64 = GetProcAddressFromEncrypted(&unk_C75648, hKernel32DLL); dword_C8FF44 = GetProcAddressFromEncrypted(&unk_C75658, hKernel32DLL); dword_C8FF48 = GetProcAddressFromEncrypted(&unk_C75668, hKernel32DLL); dword_C8FF4C = GetProcAddressFromEncrypted(&unk_C75678, hKernel32DLL); return 1; }
Last edited by Ouariasse; 01-14-2015 at 12:01 AM.
The decoded strings (starting from data:00C754C8 )
Kernel32.dll
ntdll.dll
User32.dll
CloseHandle
ContinueDebugEvent
CreateThread
CreateToolhelp32Snapshot
DebugActiveProcess
EnumWindows
GetCurrentProcess
GetCurrentProcessId
GetModuleHandleA
GetProcAddress
GetSystemInfo
GetWindowTextA
Module32First
Module32Next
OpenProcess
Process32First
Process32Next
ReadProcessMemory
VirtualAlloc
VirtualFree
VirtualQuery
VirtualQueryEx
WaitForDebugEvent
Last edited by Coyl; 01-14-2015 at 12:59 AM.
Here is the initialization of the anti cheat completely reversed, do not nop it, without these initialization you will be flagged 100%. I'll use this thread as my research place & to share stuff i find.
Code:char __cdecl LoadRoutine() { char result; // al@2 if ( loaded ) { result = 1; } else { if ( initializeModules() && lCreateThread(0, 0, sub_9C6210, 0, 0, 0) && lCreateThread(0, 0, sub_9C6140, 0, 0, 0) ) { result = 1; loaded = 1; } else { result = 0; } } return result; }It flags you if you inject dll, if there are 2 type of exceptions and if a thread is created :Code:char __cdecl initializeModules() { char *dKernel32DLL; // eax@1 char *dNtdllDLL; // eax@1 char *dUser32DLL; // eax@1 unsigned int len1; // eax@1 int i; // ecx@1 unsigned int len2; // eax@3 int j; // ecx@3 unsigned int len3; // eax@5 int k; // ecx@5 dKernel32DLL = getDecryptedModuleName(cKernel32DLL); hKernel32DLL = GetModuleHandleA(dKernel32DLL); dNtdllDLL = getDecryptedModuleName(cNtdllDll); hNtdllDLL = GetModuleHandleA(dNtdllDLL); dUser32DLL = getDecryptedModuleName(cUser32DLL); hUser32DLL = GetModuleHandleA(dUser32DLL); // Once it gets the decrypted module name, it make sures the crypted/decrypted name are zero'd out len1 = strlen(cKernel32DLL); for ( i = cKernel32DLL; len1; --len1 ) *i++ = 0; len2 = strlen(cNtdllDll); for ( j = cNtdllDll; len2; --len2 ) *j++ = 0; len3 = strlen(cUser32DLL); for ( k = cUser32DLL; len3; --len3 ) *k++ = 0; lCloseHandle = GetProcAddressFromEncrypted(&cCloseHandle, hKernel32DLL); lContinueDebugEvent = GetProcAddressFromEncrypted(&cContinueDebugEvent, hKernel32DLL); lCreateThread = GetProcAddressFromEncrypted(&cCreateThread, hKernel32DLL); lDebugActiveProcess = GetProcAddressFromEncrypted(&cDebugActiveProcess, hKernel32DLL); lEnumWindows = GetProcAddressFromEncrypted(cEnumWindows, hUser32DLL); lGetCurrentProcess = GetProcAddressFromEncrypted(&cGetCurrentProcess, hKernel32DLL); lGetCurrentProcessId = GetProcAddressFromEncrypted(&cGetCurrentProcessId, hKernel32DLL); lGetSystemInfo = GetProcAddressFromEncrypted(&cGetSystemInfo, hKernel32DLL); lGetWindowTextA = GetProcAddressFromEncrypted(&cGetWindowTextA, hUser32DLL); lModule32First = GetProcAddressFromEncrypted(&cModule32First, hKernel32DLL); lModule32Next = GetProcAddressFromEncrypted(&cModule32Next, hKernel32DLL); lOpenProcess = GetProcAddressFromEncrypted(&cOpenProcess, hKernel32DLL); lProcess32First = GetProcAddressFromEncrypted(&cProcess32First, hKernel32DLL); lProcess32Next = GetProcAddressFromEncrypted(&cProcess32Next, hKernel32DLL); lReadProcessMemory = GetProcAddressFromEncrypted(&cReadProcessMemory, hKernel32DLL); lVirtualAlloc = GetProcAddressFromEncrypted(&cVirtualAlloc, hKernel32DLL); lVirtualFree = GetProcAddressFromEncrypted(&cVirtualFree, hKernel32DLL); lVirtualQuery = GetProcAddressFromEncrypted(&cVirtualQuery, hKernel32DLL); lVirtualQueryEx = GetProcAddressFromEncrypted(&cVirtualQueryEx, hKernel32DLL); lWaitForDebugEvent = GetProcAddressFromEncrypted(&cWaitForDebugEvent, hKernel32DLL); return 1; }
Some code have trivial data because the hexray decompiler i have is quite old and i can't find a newer one sadly.Code:int __userpurge sub_9C6140<eax>(signed int a1<ebx>, int a2<edi>, int a3<esi>, int a4) { int v4; // eax@1 int lpDebugEvent; // esi@2 void *ptrToFlag; // eax@6 int result; // eax@10 int debugEventProcessId; // [sp-Ch] [bp-Ch]@2 int debugEventThreadId; // [sp-8h] [bp-8h]@2 signed int v10; // [sp-4h] [bp-4h]@2 v4 = lGetCurrentProcessId(); if ( lDebugActiveProcess(v4) ) { v10 = a1; debugEventThreadId = a3; debugEventProcessId = a2; lpDebugEvent = malloc(0x60u); while ( !null ) { lWaitForDebugEvent(lpDebugEvent, -1, debugEventProcessId, debugEventThreadId, v10); switch ( *lpDebugEvent ) { case 1: // EXCEPTION_DEBUG_EVENT sub_9C67A0(lpDebugEvent); break; case 2: // CREATE_THREAD_DEBUG_EVENT sub_9C6720(lpDebugEvent); break; case 6: // LOAD_DLL_DEBUG_EVENT ptrToFlag = flagStruct; if ( !flagStruct ) { ptrToFlag = malloc(4u); flagStruct = ptrToFlag; *ptrToFlag = 0; } *(ptrToFlag + 1) = 1; break; default: break; } v10 = 65538; debugEventThreadId = *(lpDebugEvent + 8); debugEventProcessId = *(lpDebugEvent + 4); lContinueDebugEvent(); } result = 0; } else { result = 0; } return result; }
Last edited by Ouariasse; 01-14-2015 at 01:19 AM.
Didn't Blizzard get in trouble in the EU for process enumeration (Process32First, Process32Next, etc)? This might violate EU privacy laws.
I'm reversing little by little, i haven't seen how they use process enum yet, i just know they load it dynamically.
I'm currently at work but since today is a calm day i can reverse at work without my boss getting mad hehe