BattlEye es predominantemente un anti-engaño de un tercero alemán, desarrollado principalmente por
Bastian Heiko Suter , de 32 años. Proporciona (o intenta proporcionar) a los editores de juegos un sistema anti-trampa fácil de usar que utiliza mecanismos de protección generales, así como la detección de trampas para juegos específicos para optimizar la seguridad. Como se indica en el sitio web del producto, siempre se mantiene en la cima de la tecnología moderna y utiliza métodos innovadores de protección y detección; obviamente esto es consecuencia de la nacionalidad del desarrollador:
QUALITY MADE IN GERMANY
. BattlEye consta de muchos elementos que trabajan juntos para encontrar tramposos en los juegos que han pagado por el uso del producto. Los cuatro elementos principales son:
- BEService
- Un servicio del sistema de Windows que se comunica con el servidor BattlEye BEServer , que proporciona comunicación cliente-servidor con BEDaisy y BEClient .
- BEDaisy
- Un controlador de kernel de Windows que registra mecanismos de procesamiento de eventos preventivos y mini filtros para evitar que los tramposos modifiquen ilegalmente el juego
- Becient
- Una biblioteca de Windows conectada dinámicamente que es responsable de la mayoría de los vectores de detección, incluidos los descritos en este artículo. Después de la inicialización, se adjunta al proceso del juego.
- Beserver
- Servidor backend patentado, responsable de recopilar información y tomar medidas específicas contra los tramposos.
Shellcode
Recientemente, un volcado del código de shell BattlEye apareció en Internet, y decidimos escribir sobre lo que está buscando exactamente la versión actual de BattlEye. No analizamos BattlEye durante seis meses, por lo que nuestro último volcado del shellcode probablemente esté desactualizado. Varias partes del código se recuperaron solo de la memoria de este último volcado, suponiendo que BattlEye solo completó el código de shell y no eliminó los procedimientos de detección anteriores.
Como?
BattlEye supuestamente transmite código shell desde su servidor a un servicio de Windows llamado BEService. Este servicio se comunica con el módulo BEClient ubicado dentro del juego. El intercambio de datos se realiza a través de la
\.namedpipeBattleye
y hasta 2018 no se cifró. Ahora, todos los datos transmitidos se cifran con un xor-encryptor con claves muy pequeñas, lo que hace que sea extremadamente fácil realizar ataques de texto sin formato conocidos. Cuando el código de shell se transmite al cliente, se ubica y ejecuta fuera de todos los módulos conocidos, lo que facilita su determinación. Para crear un volcado de shellcode, puede procesar las funciones estándar de la API de Windows, como CreateFile, ReadFile, etc., y volcar el área de memoria correspondiente de todos los módulos de llamada (solicitando información de memoria para la dirección devuelta) que están fuera de todos los módulos conocidos, o escanee periódicamente el espacio de memoria virtual del juego en busca de memoria ejecutable fuera de todos los módulos conocidos, y vuélvala al disco. Al mismo tiempo, debe realizar un seguimiento de las áreas que ya se han volcado, de modo que no obtendrá muchos volcados idénticos.
Explicación
Los fragmentos de pseudocódigo presentados en el artículo están
fuertemente modificados por el bien de la belleza. No podrá volcar el código de shell BattlEye e inmediatamente reconocer estas partes; el shellcode no contiene llamadas a funciones, y se implementan muchos algoritmos en el artículo. Pero, de hecho, esto no es importante, porque cuando termine de leer sobre esta terrible antigüedad, tendrá la oportunidad de sortearla (:
Clasificación de memoria
El mecanismo de detección más común en anti-trampas es la enumeración de memoria y el escaneo de memoria para buscar imágenes de trampas
conocidas . Es fácil de implementar y, como se muestra en el pasado, con el enfoque correcto, es bastante efectivo si no ha olvidado los conceptos básicos del ensamblador y ha incluido en la lista negra el prólogo de una función común.
Battleye itera sobre todo el espacio de direcciones del proceso del juego (el proceso actual en este contexto) y realiza varias comprobaciones sobre el rendimiento de la página y encuentra el código de shell fuera del espacio de memoria correspondiente.
Así es como se implementa en Battleye:
Anomalías de memoria
BattlEye marca todas las anomalías en el espacio de direcciones de memoria, principalmente la memoria de módulos ejecutables que no corresponden a la imagen cargada:
void memory::anomaly_check(MEMORY_BASIC_INFORMATION memory_information) {
Escaneo de patrones
Como se mencionó anteriormente, BattlEye también escanea la memoria de los procesos locales en busca de varios patrones claramente definidos, como se puede ver en la implementación que se muestra a continuación.
Al leer este pseudocódigo, puede adivinar que
estas comprobaciones pueden eludirse reescribiendo el área de código de cada módulo cargado, ya que no escanearán en busca de patrones en imágenes conocidas. Para no caer en las verificaciones de integridad, debe descargar todas las áreas empaquetadas y en la lista blanca y volver a escribir las áreas de código marcadas como
RWX , porque no podemos realizar verificaciones de integridad sin emular el empaquetador. En la versión actual del código de shell BattlEye, estos patrones de memoria están codificados:
[05 18] ojectsPUBGChinese [05 17] BattleGroundsPrivate_CheatESP [05 17] [%.0fm] %s [05 3E] 0000Neck0000Chest0000000Mouse 10 [05 3F] PlayerESPColor [05 40] Aimbot: %d02D3E2041 [05 36] HackMachine [05 4A] VisualHacks.net [05 50] 3E232F653E31314E4E563D4276282A3A2E463F757523286752552E6F30584748 [05 4F] DLLInjection-master\x64\Release\ [05 52] NameESP [05 48] Skullhack [05 55] .rdata$zzzdbg [05 39] AimBot [05 39] EB4941803C123F755C623FEB388D41D0FBEC93C977583E930EB683E1DF [05 5F] 55E9 [05 5F] 57E9 [05 5F] 60E9 [05 68] D3D11Present initialised [05 6E] [ %.0fM ] [05 74] [hp:%d]%dm [05 36] 48836424380488D4C2458488B5424504C8BC848894C24304C8BC7488D4C2460 [05 36] 741FBA80000FF15607E0085C07510F2F1087801008B8788100EB [05 36] 40F2AA156F8D2894E9AB4489535D34F9CPOSITION0000COL [05 7A] FFE090 [05 79] %s00%d00POSITION0000COLOR0000000 [05 36] 8E85765DCDDA452E75BA12B4C7B94872116DB948A1DAA6B948A7676BB948902C [05 8A] n<assembly xmlsn='urn:schemas-mi
Estos patrones de memoria también contienen un encabezado de dos bytes, es decir, el valor estático desconocido
05
y un identificador único.
Lo que no veremos es que BattlEye también transmite dinámicamente patrones desde
BEServer y los envía a
BEClient , pero no discutiremos esto en el artículo.
Son escaneados iterativamente por el siguiente algoritmo:
void memory::pattern_check(void* current_address, MEMORY_BASIC_INFORMATION memory_information) { const auto is_user32 = memory_information.allocation_base == GetModuleHandleA("user32.dll"
Validación de módulos específicos (Microsoft)
Las verificaciones de módulos informan la presencia de módulos específicos cargados en el juego:
void memory::module_specific_check_microsoft(MEMORY_BASIC_INFORMATION memory_information) { auto executable = memory_information.protect == PAGE_EXECUTE || memory_information.protect == PAGE_EXECUTE_READ || memory_information.protect == PAGE_EXECUTE_READWRITE auto allocated = memory_information.state == MEM_COMMIT if (!allocated || !executable) continue auto mmres_handle = GetModuleHandleA("mmres.dll" auto mshtml_handle = GetModuleHandleA("mshtml.dll" if (mmres_handle && mmres_handle == memory_information.allocation_base) { battleye_module_anomaly_report module_anomaly_report module_anomaly_report.unknown = 0 module_anomaly_report.report_id = 0x5B module_anomaly_report.identifier = 0x3480 module_anomaly_report.region_size = memory_information.region_size battleye::report(&module_anomaly_report, sizeof(module_anomaly_report), 0 } else if (mshtml_handle && mshtml_handle == memory_information.allocation_base) { battleye_module_anomaly_report module_anomaly_report module_anomaly_report.unknown = 0 module_anomaly_report.report_id = 0x5B module_anomaly_report.identifier = 0xB480 module_anomaly_report.region_size = memory_information.region_size battleye::report(&module_anomaly_report, sizeof(module_anomaly_report), 0 } }
Comprobación de módulos específicos (desconocido)
Se ha agregado una comprobación de módulos específicos al sistema, que indica al servidor que ha cargado módulos que satisfacen
cualquiera de estos criterios:
void memory::module_specific_check_unknown(MEMORY_BASIC_INFORMATION memory_information) { const auto dos_header = (DOS_HEADER*)module_handle const auto pe_header = (PE_HEADER*)(module_handle + dos_header->e_lfanew const auto is_image = memory_information.state == MEM_COMMIT && memory_information.type == MEM_IMAGE if (!is_image) return const auto is_base = memory_information.base_address == memory_information.allocation_base if (!is_base) return const auto match_1 = time_date_stamp == 0x5B12C900 && *(__int8*)(memory_information.base_address + 0x1000) == 0x00 && *(__int32*)(memory_information.base_address + 0x501000) != 0x353E900 const auto match_2 = time_date_stamp == 0x5A180C35 && *(__int8*)(memory_information.base_address + 0x1000) != 0x00 const auto match_2 = time_date_stamp == 0xFC9B9325 && *(__int8*)(memory_information.base_address + 0x6D3000) != 0x00 if (!match_1 && !match_2 && !match_3) return const auto buffer_offset = 0x00
No sabemos qué módulos satisfacen estos criterios, pero sospechamos que este es un intento de detectar un conjunto muy limitado de módulos de trucos específicos.
Anexo: @ how02 nos informó que el módulo
action_x64.dll
tiene una
0x5B12C900
tiempo
0x5B12C900
y contiene un área de código en la que puede escribir; Como se mencionó anteriormente, esto se puede utilizar para explotar.
Protección de la memoria
BattlEye también implementa un procedimiento de detección muy dudoso, que, en nuestra opinión, busca memoria con el
conjunto de indicadores
PAGE_GUARD , sin verificar realmente si el indicador
PAGE_GUARD está
configurado :
void memory::guard_check(void* current_address, MEMORY_BASIC_INFORMATION memory_information) { if (memory_information.protect != PAGE_NOACCESS) { auto bad_ptr = IsBadReadPtr(current_address, sizeof(temporary_buffer auto read = NtReadVirtualMemory( GetCurrentProcess(), current_address, temporary_buffer, sizeof(temporary_buffer), 0 if (read < 0 || bad_ptr) { auto query = NtQueryVirtualMemory( GetCurrentProcess(), current_address, 0, &new_memory_information, sizeof(new_memory_information), &return_length memory_guard_report.guard = query < 0 || new_memory_information.state != memory_information.state || new_memory_information.protect != memory_information.protect if (memory_guard_report.guard) { memory_guard_report.unknown = 0 memory_guard_report.report_id = 0x21 memory_guard_report.base_address = memory_information.base_address memory_guard_report.region_size = (int)memory_information.region_size memory_guard_report.memory_info = memory_information.type | memory_information.protect | memory_information.state battleye::report(&memory_guard_report, sizeof(memory_guard_report), 0 } } } }
Ordenar ventanas
El código de shell BattlEye itera sobre cada una de las ventanas que están visibles actualmente durante el juego, pasando por alto las ventanas de arriba a abajo (por valor z). Los
GetWindowThreadProcessId
ventana dentro del juego se excluyen de esta enumeración, y esto se determina llamando a
GetWindowThreadProcessId
. Por lo tanto, puede vincular la función correspondiente al falso propietario de la ventana para que
BattlEye no compruebe su ventana .
void window_handler::enumerate() { for (auto window_handle = GetTopWindow window_handle window_handle = GetWindow(window_handle, GW_HWNDNEXT),
Anomalía de búsqueda
Si se marcan menos de dos ventanas, se envía una notificación al servidor. Esto probablemente se haga para evitar parchear las funciones correspondientes que no permiten que el código de shell BattlEye examine ninguna ventana:
void window_handler::check_count() { if (window_handler::windows_enumerated > 1) return
Clasificación de procesos
Al llamar a
CreateToolhelp32Snapshot
itera sobre todos los procesos en ejecución, pero
no procesa ningún error , por lo que es muy fácil parchear y evitar los siguientes procedimientos de detección:
Comprobación de ruta
Si la imagen está dentro de al menos dos subdirectorios (contando desde la raíz del disco), el sistema marcará los procesos si la ruta a la imagen correspondiente contiene al menos una de estas líneas:
Desktop Temp FileRec Documents Downloads Roaming tmp.ex notepad. ...\. cmd.ex
Si la ruta al archivo ejecutable corresponde a una de estas líneas, el servidor recibe una notificación sobre la ruta al archivo ejecutable, así como información sobre si el proceso padre es uno de los siguientes (contiene el bit de bandera correspondiente enviado al servidor):
steam.exe [0x01] explorer.exe [0x02] lsass.exe [0x08] cmd.exe [0x10]
Si el cliente no puede abrir el descriptor con los derechos de información
QueryLimitedInformation
apropiados, establecerá el bit de indicador
0x04
, si la causa del error cuando falla la llamada de
OpenProcess
no es
ERROR_ACCESS_DENIED
, que nos proporciona el último contenedor de enumeración para el valor de indicador correspondiente:
enum BATTLEYE_PROCESS_FLAG { STEAM = 0x1, EXPLORER = 0x2, ERROR = 0x4, LSASS = 0x8, CMD = 0x10 }
Si el proceso principal es steam, entonces el indicador se establece instantáneamente para el usuario y se informa al servidor sobre esto con la identificación de notificación
0x40
Nombre de la imagen
Si el proceso cumple con alguno de los muchos criterios que se presentan a continuación, se establece una
0x38
instante y esto se informa al servidor con la identificación de notificación
0x38
"Loadlibr" "Rng " "A0E7FFFFFF81" "RNG " "90E54355" "2.6.ex" "TempFile.exe"
Steam Game Overlay
BattlEye supervisa el proceso de superposición de juegos de Steam, que es responsable de la superposición en el juego, conocida por la mayoría de los usuarios de Steam. El nombre de host completo de la superposición de Steam Games es
gameoverlayui.exe
; se sabe que a menudo se usa para renderizar exploits, porque es bastante fácil de hackear y realizar renderizaciones ilegales en la ventana del juego. La verificación tiene la siguiente condición:
file size != 0 && image name contains (case insensitive) gameoverlayu
Las comprobaciones adicionales específicas para la superposición de juegos de Steam son casi idénticas a los procedimientos realizados para el proceso del juego en sí, por lo tanto, se omiten en el pseudocódigo.
Escaneo de memoria de superposición de vapor
El proceso de superposición de juegos de Steam se analiza en busca de patrones y anomalías. No pudimos profundizar en la madriguera del conejo y descubrir para qué sirven estos patrones, porque son muy generalizados y muy probablemente asociados con módulos de trucos.
void gameoverlay::pattern_scan(MEMORY_BASIC_INFORMATION memory_information) {
El procedimiento de escaneo también busca cualquier anomalía en forma de código ejecutable fuera de las imágenes descargadas, lo que sugiere que los crackers inyectaron el código en el proceso de superposición:
void gameoverlay::memory_anomaly_scan(MEMORY_BASIC_INFORMATION memory_information) {
Protección de superposición de juegos de Steam
Si el proceso de superposición de juegos de Steam está protegido por alguna protección de procesos de Windows como
Light (WinTcb) , entonces el servidor recibirá una notificación al respecto.
void gameoverlay::protection_check(HANDLE process_handle) { auto process_protection = 0 NtQueryInformationProcess( process_handle, ProcessProtectionInformation, &process_protection, sizeof(process_protection), nullptr if (process_protection == 0)
Además, si la llamada correspondiente de
OpenProcess devuelve
ERROR_ACCESS_DENIED al proceso de superposición, se envía una notificación sobre el usuario con id
3B
.
Módulos de clasificación
También se buscan módulos de proceso de superposición de juegos de Steam, en particular, se
vgui2_s.dll
y
gameoverlayui.dll
. Se realizan varias verificaciones para estos módulos, comenzando con
gameoverlayui.dll
.
Si se cumple esta condición:
[gameoverlayui.dll+6C779] == 08BE55DC3CCCCB8????????C3CCCCCC
, entonces el
[gameoverlayui.dll+6C779] == 08BE55DC3CCCCB8????????C3CCCCCC
escanea la vtable en la dirección almacenada en bytes
????????
. Si alguno de estos elementos vtable está fuera del módulo fuente gameoverlayui.dll o apunta a una instrucción
int 3
, el usuario es informado al servidor con una identificación de notificación de
3B
.
void gameoverlay::scan_vtable(HANDLE process_handle, char* buffer, MODULEENTRY32 module_entry) { char function_buffer[16 for (vtable_index = 0 vtable_index < 20 vtable_index += 4) { NtReadVirtualMemory( process_handle, *(int*)&buffer[vtable_index], &function_buffer, sizeof(function_buffer), 0 if (*(int*)&buffer[vtable_index] < module_entry.modBaseAddr || *(int*)&buffer[vtable_index] >= module_entry.modBaseAddr + module_entry.modBaseSize || function_buffer[0] == 0xCC )
También se realiza un procedimiento de verificación específico para el módulo
vgui2_s.dll
:
void vgui::scan() { if (!equals(vgui_buffer, "6A08B31FF561C8BD??????????FF96????????8BD????????8B1FF90")) { auto could_read = NtReadVirtualMemory( process_handle, module_entry.modBaseAddr + 0x48338, vgui_buffer, 8, 0) >= 0 constexpr auto pattern_offset = 0x48378
Este procedimiento busca cambios en el desplazamiento 48378
, que es la ubicación del área de código: push 04 push offset aCBuildslaveSte_4 ; "c:\buildslave\steam_rel_client_win32"... push offset aAssertionFaile_7 ; "Assertion Failed: IsValidIndex(elem)"
El procedimiento luego verifica un cambio muy específico y aparentemente basura: push 04 push 00 push 02 push ??
No hemos podido encontrar una copia de vgui2_s.dll que no coincida con la primera de las dos comprobaciones anteriores, por lo que no podemos averiguar qué tabla comprueba.Steam Overlay Streams
Las secuencias en el proceso de superponer juegos de Steam también se mueven: void gameoverlay::check_thread(THREADENTRY32 thread_entry) { const auto tread_handle = OpenThread(THREAD_SUSPEND_RESUME|THREAD_GET_CONTEXT, 0, thread_entry.th32ThreadID if (thread_handle) { suspend_count = ResumeThread(thread_handle if (suspend_count > 0) { SuspendThread(thread_handle gameoverlay_thread_report.unknown = 0 gameoverlay_thread_report.report_id = 0x3B gameoverlay_thread_report.suspend_count = suspend_count battleye::report(&gameoverlay_thread_report, sizeof(gameoverlay_thread_report), 0 } if (GetThreadContext(thread_handle, &context) && context.Dr7) { gameoverlay_debug_report.unknown = 0 gameoverlay_debug_report.report_id = 0x3B gameoverlay_debug_report.debug_register = context.Dr0 battleye::report(&gameoverlay_debug_report, sizeof(gameoverlay_debug_report), 0 } } }
LSASS
El espacio de direcciones de memoria del proceso Windows lsass.exe , también conocido como proceso de la Autoridad de Seguridad Local, también se escanea y todas las anomalías se informan al servidor, como en el caso de las dos comprobaciones anteriores: if (equals(process_entry.executable_path, "lsass.exe")) { auto lsass_handle = OpenProcess(QueryInformation, 0, (unsigned int)process_entry.th32ProcessID if (lsass_handle) { for (address = 0 NtQueryVirtualMemory(lsass_handle, address, 0, &lsass_memory_info, 0x30, &bytes_needed) >= 0 address = lsass_memory_info.base_address + lsass_memory_info.region_size) { if (lsass_memory_info.state == MEM_COMMIT && lsass_memory_info.type == MEM_PRIVATE && (lsass_memory_info.protect == PAGE_EXECUTE || lsass_memory_info.protect == PAGE_EXECUTE_READ || lsass_memory_info.protect == PAGE_EXECUTE_READWRITE)) {
LSASS se utilizó anteriormente en exploits para realizar operaciones con memoria, ya que cualquier proceso que necesite una conexión a Internet debe proporcionarle acceso LSASS. BattlEye está lidiando actualmente con este problema borrando manualmente el identificador de proceso de las operaciones de lectura / escritura y luego adjuntando ReadProcessMemory
/ WriteProcessMemory
redirigiendo las llamadas a su controlador BEDaisy. Luego, BEDaisy decide si la operación de memoria es legal. Si cree que la operación es legal, entonces la continúa, y de lo contrario enciende deliberadamente la máquina con una pantalla azul.Varias notificaciones
BattlEye recopila información diversa y la envía al servidor con la identificación de notificación 3C
. Esta información consta de los siguientes elementos:- Cualquier ventana con el indicador WS_EX_TOPMOST o sus análogos:
- (Unicode)
- (Unicode)
- Window style
- Window extended style
- -
- -
- (VM_WRITE|VM_READ)
- :
- ….ContentPaksTslGame-WindowsNoEditor_assets_world.pak
- ….ContentPaksTslGame-WindowsNoEditor_ui.pak
- ….ContentPaksTslGame-WindowsNoEditor_sound.pak
- :
- ….BLGameCookedContentScriptBLGame.u
- NtGetContextThread
NoEye
BattlEye implementa una comprobación bastante perezosa para detectar un rootkit de acceso público para evitar este anti-trampa llamado NoEye: el sistema usa GetFileAttributesExA para verificar el tamaño del archivo BE_DLL.dll
si esta biblioteca se encuentra en el disco. void noeye::detect() { WIN32_FILE_ATTRIBUTE_DATA file_information if (GetFileAttributesExA("BE_DLL.dll", 0, &file_information)) { noeye_report.unknown = 0 noeye_report.report_id = 0x3D noeye_report.file_size = file_information.nFileSizeLow battleye::report(&noeye_report, sizeof(noeye_report), 0 } }
Disponibilidad del conductor
Comprobaciones para dispositivos Beep y Null; si lo hay, se genera una notificación. En el estado normal, estos dos dispositivos no están disponibles en el sistema, y esto puede indicar que alguien encendió el dispositivo manualmente. Esta técnica se llama secuestro del dispositivo del controlador. Esto es para garantizar que los datos IOCTL se intercambien con el controlador malicioso sin la necesidad de un objeto de controlador separado para este controlador. void driver::check_beep() { auto handle = CreateFileA("\\.\Beep", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0 if (handle != INVALID_HANDLE_VALUE) { beep_report.unknown = 0 beep_report.report_id = 0x3E battleye::report(&beep_report, sizeof(beep_report), 0 CloseHandle(handle } }
void driver::check_null() { auto handle = CreateFileA("\\.\Null", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0 if (handle != INVALID_HANDLE_VALUE) { null_report.unknown = 0 null_report.report_id = 0x3E battleye::report(&null_report, sizeof(null_report), 0 CloseHandle(handle } }
Delta del sueño
Además, BattlEye puede solicitar un segundo de inactividad del hilo actual y mide la diferencia en el número de ciclos antes y después de la inactividad (suspensión): void sleep::check_delta() { const auto tick_count = GetTickCount Sleep(1000 const auto tick_delta = GetTickCount() - tick_count if (tick_delta >= 1200) { sleep_report.unknown = 0 sleep_report.report_id = 0x45 sleep_report.delta = tick_delta battleye::report(&sleep_report, sizeof(sleep_report), 0 } }
7zip
Se ha agregado una verificación de integridad muy perezosa a BattlEye para que los usuarios no puedan cargar la biblioteca 7zip en los procesos del juego y sobrescribir áreas. Los usuarios hicieron esto para reducir la gravedad de los escaneos de patrones y la detección de anomalías descritos anteriormente. BattlEye simplemente decidió agregar verificaciones de integridad para esta biblioteca particular de 7zip. void module::check_7zip() { constexpr auto sz_7zipdll = "..\..\Plugins\ZipUtility\ThirdParty\7zpp\dll\Win64\7z.dll" const auto module_handle = GetModuleHandleA(sz_7zipdll if (module_handle && *(int*)(module_handle + 0x1000) != 0xFF1441C7) { sevenzip_report.unknown_1 = 0 sevenzip_report.report_id = 0x46 sevenzip_report.unknown_2 = 0 sevenzip_report.data1 = *(__int64*)(module_handle + 0x1000 sevenzip_report.data2 = *(__int64*)(module_handle + 0x1008 battleye::report(&sevenzip_report, sizeof(sevenzip_report), 0 } }
Capa de abstracción de hardware
BattlEye busca una biblioteca de capa de abstracción de hardware de Windows vinculada dinámicamente (hal.dll) y le dice al servidor si está cargada dentro del juego. void module::check_hal() { const auto module_handle = GetModuleHandleA("hal.dll" if (module_handle) { hal_report.unknown_1 = 0 hal_report.report_id = 0x46 hal_report.unknown_2 = 2 hal_report.data1 = *(__int64*)(module_handle + 0x1000 hal_report.data2 = *(__int64*)(module_handle + 0x1008 battleye::report(&hal_report, sizeof(hal_report), 0 } }
Verificaciones de imagen
BattlEye también verifica varias imágenes cargadas en el juego. Se supone que estos módulos son imágenes firmadas que de alguna manera se manipulan, cambiando su comportamiento a malicioso, pero no podemos decir nada más sobre ellos, solo sobre su detección:nvToolsExt64_1
void module::check_nvtoolsext64_1 { const auto module_handle = GetModuleHandleA("nvToolsExt64_1.dll" if (module_handle) { nvtools_report.unknown = 0 nvtools_report.report_id = 0x48 nvtools_report.module_id = 0x5A8 nvtools_report.size_of_image = (PE_HEADER*)(module_handle + (DOS_HEADER*)(module_handle)->e_lfanew))->SizeOfImage battleye::report(&nvtools_report, sizeof(nvtools_report), 0 } }
ws2detour_x96
void module::check_ws2detour_x96 { const auto module_handle = GetModuleHandleA("ws2detour_x96.dll" if (module_handle) { ws2detour_report.unknown = 0 ws2detour_report.report_id = 0x48 ws2detour_report.module_id = 0x5B5 ws2detour_report.size_of_image = (PE_HEADER*)(module_handle + (DOS_HEADER*)(module_handle)->e_lfanew))->SizeOfImage battleye::report(&ws2detour_report, sizeof(ws2detour_report), 0 } }
networkdllx64
void module::check_networkdllx64 { const auto module_handle = GetModuleHandleA("networkdllx64.dll" if (module_handle) { const auto dos_header = (DOS_HEADER*)module_handle const auto pe_header = (PE_HEADER*)(module_handle + dos_header->e_lfanew const auto size_of_image = pe_header->SizeOfImage if (size_of_image < 0x200000 || size_of_image >= 0x400000) { if (pe_header->sections[DEBUG_DIRECTORY].size == 0x1B20) { networkdll64_report.unknown = 0 networkdll64_report.report_id = 0x48 networkdll64_report.module_id = 0x5B7 networkdll64_report.data = pe_header->TimeDatestamp battleye::report(&networkdll64_report, sizeof(networkdll64_report), 0 } } else { networkdll64_report.unknown = 0 networkdll64_report.report_id = 0x48 networkdll64_report.module_id = 0x5B7 networkdll64_report.data = pe_header->sections[DEBUG_DIRECTORY].size battleye::report(&networkdll64_report, sizeof(networkdll64_report), 0 } } }
nxdetours_64
void module::check_nxdetours_64 { const auto module_handle = GetModuleHandleA("nxdetours_64.dll" if (module_handle) { nxdetours64_report.unknown = 0 nxdetours64_report.report_id = 0x48 nxdetours64_report.module_id = 0x5B8 nxdetours64_report.size_of_image = (PE_HEADER*)(module_handle + (DOS_HEADER*)(module_handle)->e_lfanew))->SizeOfImage battleye::report(&nxdetours64_report, sizeof(nxdetours64_report), 0 } }
nvcompiler
void module::check_nvcompiler { const auto module_handle = GetModuleHandleA("nvcompiler.dll" if (module_handle) { nvcompiler_report.unknown = 0 nvcompiler_report.report_id = 0x48 nvcompiler_report.module_id = 0x5BC nvcompiler_report.data = *(int*)(module_handle + 0x1000 battleye::report(&nvcompiler_report, sizeof(nvcompiler_report), 0 } }
wmp
void module::check_wmp { const auto module_handle = GetModuleHandleA("wmp.dll" if (module_handle) { wmp_report.unknown = 0 wmp_report.report_id = 0x48 wmp_report.module_id = 0x5BE wmp_report.data = *(int*)(module_handle + 0x1000 battleye::report(&wmp_report, sizeof(wmp_report), 0 } }
Identificadores de enumeración de módulos
Como referencia, le damos la identificación de enumeración para los módulos: enum module_id { nvtoolsext64 = 0x5A8, ws2detour_x96 = 0x5B5, networkdll64 = 0x5B7, nxdetours_64 = 0x5B8, nvcompiler = 0x5BC, wmp = 0x5BE
Escanear tablas TCP
El código de shell BattlEye busca una lista de conexiones TCP para todo el sistema (conocida como la tabla TCP) e informa si el usuario está conectado al menos a una de las direcciones IP de la puerta de enlace Cloudflare que pertenecen al sitio web alemán de pago -cheat llamada xera.ph . Este mecanismo se ha agregado al código de shell para detectar usuarios que tienen el iniciador en ejecución cuando el juego se está ejecutando, haciéndolos fáciles de reconocer. El único problema con este mecanismo es que las direcciones IP de la puerta de enlace de Cloudflare pueden cambiar de propietario más adelante. y si su nuevo propietario distribuye software que se conecta a sus servidores a través de un puerto específico, entonces se producirán disparadores falsos positivos contra trampas sin ninguna duda.Pagar para engañar a los usuarios del proveedor de servicios xera.phDurante mucho tiempo han estado informando que están siendo atrapados, y los desarrolladores no pueden lidiar con eso de ninguna manera. Nos pusimos en contacto con los desarrolladores de xera.ph para informarles de su comportamiento estúpido, pero nos entendieron mal y nos enviaron una copia gratuita, sin pensar que podríamos piratearla y liberarla. No haremos esto, pero probablemente no debería enviar archivos binarios con licencia de propiedad de forma gratuita a las personas involucradas en ingeniería inversa y esperar que no sean pirateados. void network::scan_tcp_table { memset(local_port_buffer, 0, sizeof(local_port_buffer for (iteration_index = 0 iteration_index < 500 ++iteration_index) {
Tipos de notificaciones
Aquí hay como referencia todos los tipos conocidos de notificaciones del código de shell: enum BATTLEYE_REPORT_ID { MEMORY_GUARD = 0x21, MEMORY_SUSPICIOUS = 0x2F, WINDOW_TITLE = 0x33, MEMORY = 0x35, PROCESS_ANOMALY = 0x38, DRIVER_BEEP_PRESENCE = 0x3E, DRIVER_NULL_PRESENCE = 0x3F, MISCELLANEOUS_ANOMALY = 0x3B, PROCESS_SUSPICIOUS = 0x40, LSASS_MEMORY = 0x42, SLEEP_ANOMALY = 0x45, MEMORY_MODULE_SPECIFIC = 0x46, GENERIC_ANOMALY = 0x48, MEMORY_MODULE_SPECIFIC2 = 0x5B, }