Как EAC обнаруживает окна читов через EnumWindows и как это обойти
EAC (Easy Anti-Cheat) - это программное обеспечение, используемое для защиты онлайн-игр от читеров. Одной из его функций является обнаружение процессов и окон, связанных с читом. В этой статье мы рассмотрим, как EAC использует функцию EnumWindows для обнаружения читерских окон.
Функция EnumWindows является частью библиотеки Windows API и используется для перечисления всех окон в системе. Когда EAC запускается, он начинает перечислять все верхние окна в системе с помощью этой функции. Однако EAC не просто перечисляет все окна, он ищет определенные характеристики окон, связанные с читом.
Какие именно характеристики EAC ищет в окнах? Некоторые из них могут быть:
- Имя окна: некоторые читы имеют уникальные имена окон, которые могут быть использованы для их обнаружения.
- Размер окна: если окно читера имеет фиксированный размер, EAC может проверить все окна на этот размер.
- Стили окна: например, окно пропускает клики или отображается на весь экран.
- Идентификатор процесса: если EAC уже знает идентификатор процесса читера, он может проверить все окна на принадлежность к одному процессу.
Если EAC находит окно, которое соответствует одной из этих характеристик, то он может сделать вывод, что в системе запущен чит. В этом случае EAC может "пометить" игрока или даже заблокировать доступ к онлайн-игре.
Функция EnumWindows является очень мощным инструментом обнаружения чит-окон для EAC. Однако разработчики читов могут попытаться обойти это обнаружение, используя такие методы, как изменение имени или размера окна, внедрение его в легитимный (подписанный) процесс, удаление окна из NtUserBuildHwndList и подобных функций.
- В Windows легитимный процесс с подписью означает процесс, который подписан цифровой подписью с действительным сертификатом, выданным доверенным центром сертификации. Цифровая подпись обеспечивает надежный способ проверки подлинности и целостности программного обеспечения перед его выполнением.
- NtUserBuildHwndList - это функция в операционной системе Windows, которая строит список всех окон верхнего уровня, принадлежащих рабочему столу вызывающего потока. Эта функция является частью Win32 API и используется приложениями для итерационного просмотра всех окон, которые в данный момент открыты на рабочем столе.
Псевдокод от chatgpt >3:
void __fastcall enum_windows_callbacks(__int64 context) { struct_v10* v10 = v1; __int64 window1 = context; __int64 window2 = getGetForegroundWindow_pid(context, v2); // Check if windows are valid if (!window2 || window2 == window1) return; // Get window styles and check if window is visible eAc_Get_api_callback(&unk_D8CB8, Get_GetWindowLongPtrW, &GetWindowLongPtrW); __int64 window_exstyle = GetWindowLongPtrW ? GetWindowLongPtrW(window1, 0xFFFFFFECi64) : 0i64; if (_bittest64(&window_exstyle, 0x13u)) { unsigned int (__fastcall* IsWindowVisible)(__int64); __int64 user32 = get_user32(); IsWindowVisible = (unsigned int(__fastcall*)(__int64))get_exp(user32, &unk_C9288, 0i64); if (!IsWindowVisible || !IsWindowVisible(window1)) return; // Get window dimensions and check if it's within foreground window tagRECT window_rect, window_Rect; eAc_Get_api_callback(&unk_D8CC0, Get_GetWindowRect, &GetWindowRect); if (!GetWindowRect || !(unsigned int)GetWindowRect(window1, &window_rect)) return; if (!GetWindowRect || !(unsigned int)GetWindowRect(window2, &window_Rect)) return; int width = window_rect.right - window_rect.left; int height = window_rect.bottom - window_rect.top; if (width <= 0 || height <= 0) return; if (window_rect.left >= window_Rect.right || window_rect.right <= window_Rect.left || window_rect.top >= window_Rect.bottom || window_rect.bottom <= window_Rect.top) return; // Get window title and class name __int128 WindowText, ClassName; sub_59E58(&WindowText, 0i64, 148i64); if ((signed int)imp_GetWindowTextW(window1, &v51, 0x40i64) > 0) cus_memcpy(&WindowText, 0x40i64, &v51); if ((signed int)imp_GetClassNameW(window1, &v51, 0x40i64) > 0) cus_memcpy(&ClassName, 0x40i64, &v51); // Get window thread/process IDs and styles eAc_Get_api_callback(&unk_D8CB8, Get_GetWindowLongPtrW, &GetWindowLongPtrW); int window_style = GetWindowLongPtrW ? GetWindowLongPtrW(window1, 0xFFFFFFF0i64) : 0; int window_exstyle_1 = window_exstyle; int pid = 0, tid = imp_GetWindowThreadProcessId(window1, &pid); int pid_1 = 0, tid_2 = tid_1 = imp_GetWindowThreadProcessId(window1, &pid_1); tagRECT window_rect_1 = window_rect; // Check window properties if ((unsigned int)eAc_Crc_or_Xor(&WindowText, get_bytes_Count(&WindowText), 0i64) != 0x3BC41165 || (unsigned int)eAc_Crc_or_Xor(&ClassName, get_bytes_Count(&ClassName), 0i64) != 0x3BC41165 || window_style != 2483027968 || window_exstyle_1 != 0x8280028 || pid != pid_1 || tid_2 != tid_1 || (unsigned int)cmp_window_size((unsigned __int8*)&window_Rect, (unsigned __int8*)&window_rect, 16i64)) { return; } // Store window data in struct and increment result count __int64 v29 = v10->qword10; __int64 v30 = *(_QWORD*)(v29 + 8); if ((_QWORD*)(v29 + 0x10) == v30) sub_AB2E4(v29, v30, &WindowText); else { *(_OWORD*)v30 = WindowText; *(_OWORD*)(v30 + 16) = ClassName; *(_DWORD*)(v30 + 48) = pid; *(_DWORD*)(v30 + 52) = tid; *(_QWORD*)(v30 + 56) = window_style; *(_QWORD*)(v30 + 64) = window_exstyle_1; *(_QWORD*)(v30 + 72) = width; *(_QWORD*)(v30 + 80) = height; v10->qword10 += 88i64; ++v10->dword8; } }
Источники:
https://blog.adeltax.com/window-z-order-in-windows-10/
https://blog.renjing.wang/702.html
https://www.unknowncheats.me/forum/anti-cheat-bypass/581931-fullscreen-overlays-window-bands.html
https://www.unknowncheats.me/forum/anti-cheat-bypass/306271-ring-1-bypass.html
0 Comments
Recommended Comments
There are no comments to display.