Algoritmos de protección de Anti-Cheats (Sólo la parte cliente)
#1
En este post detallaré "algunos de los métodos" que la mayoría de los Anti-Cheats utilizan para detectar o bloquear Cheats (los que he tenido el gusto de ver en acción, aunque no aclararé cual método utiliza tal Anti-Cheat), lo cual también servirá a quien esté interesado en proteger alguna aplicación de este tipo de intrusiones.
De más está decir que todo esto está enfocado a programadores con conocimientos altos sobre modo usuario (ring3), modo kernel (ring0), apis de Windows, C++ y ASM.

1º Parte: Bloqueo de inyección de módulos

Se basa en hookear diferentes funciones a nivel ring3 o ring0, con el fin de evitar que un módulo (dll) se cargue dentro de nuestro proceso.

Protección en Modo Kernel (ring0): Este tipo de protección chequea cuando un módulo se intenta anexar al espacio de memoria de un proceso, para eso existen varios métodos para detectarlos hookeando determinadas funciones del kernel, por ejemplo:

Código PHP:
NtCreateThread (intenta crear un thread)
NtOpenFile (intenta abrir una dll)
NtCreateSection (intenta crear espacio para la dll en memoria)
NtMapViewOfSection (intenta cargar la dll en memoria

Entre otras... (las otras son funciones que ya dependen mucho de la Versión de Windows en que se ejecute y no vale la pena detallarlas).

Pros: Si está bien implementado funciona bien.
Contras: Se necesitan firmas digitales para cargar drivers en Windows 64bits y salen bastantes caras...

Bloqueo de principio de inyección: Si analizamos los inyectores de dll's, el 90% de ellos hacen uso de la función CreateRemoteThread con el argumento LoadLibrary, entonces, solo hace falta hookear esa función para ver cuando una dll se carga... simple no? pero... si leyeron algún artículo sobre carga de dll's descubrirán que hay unas cuantas funciones más que pueden ser utilizadas para lo mismo (aunque aumenta la complejidad del algoritmo), es por eso que lo ideal sería ir a la mayor función exportada por Windows NT: "LdrLoadLibrary", hookeando esa función podríamos ver todas las dll's que se cargan en nuestro programa.

Pros: Es un muy buen método de detectar inyecciones.
Contras: Se necesita una lista "blanca" de dll's o realizar un escaneo CRC para ver si no son malas.

2º Parte: Detectar firmas de módulos / escaneo de signatures

Se basa en detectar códigos de módulos en nuetro proceso, mediante la generación de un Hash (CRC32) de la parte CODE de los mismos.

Detección CRC32: Este tipo de protección sigue siendo bastante utilizado (aunque con variantes), la idea de esta protección es analizar la parte CODE de los módulos cargados en la memoria del juego (dll's) y compararla contra una base de datos de CRC de Cheats detectados.

Pros: Es bastante rápido a la hora de detectar.
Contras: Solo se necesita cambiar una instrucción para que el chequeo falle.

Detección CRC32 (Semi Heurístico): No busca analizar toda la sección CODE de los módulos del juego (dll's), solo busca si alguna parte del mismo se corresponde con un CRC detectado.

Pros: Es un poco más lento que el anterior pero más efectivo.
Contras: Se pueden cambiar determinadas instrucciones para que el checkeo falle.

3º Parte: Detectar comportamientos extraños

Se basa en detectar comportamientos extraños de cualquier módulo (o espacio de memoria) en nuestro proceso.

Protección Anti-Calling 1 (funciones específicas): Este chequeo se basa en hookear determinadas funciones específicas y controlar la dirección del Caller (quien llama a nuestra función), esta dirección (offset) del Caller se encuentra en la Pila o Stack y es utilizada para que al terminar nuestra función retorne de quien nos llamó.
Lo que se hace es tomar esa dirección y compararla con una lista blanca de quienes tienen permiso de llamarnos, y en caso de no estar en dicha lista devolver algún error (Ej: Bloc de Notas que el Injected solía tirar).

Pros: Funciona bastante bien dada la dificultad de detectar cuales o que funciones están con esta protección.
Contras: Una vez detectadas (y sin son wrapers) se puede hacer uso de las funciones originales.

Protección Anti-Calling 2 (chequeo de argumentos): Este tipo de protección es parecido al anterior pero la diferencia es que se busca hookear la función real (no sirve o no tiene sentido con wrappers) y se comprueban los argumentos en busca de parámetros extraños (por ejemplo "threadproc" en "createthread"), luego se hace lo mismo que en el anterior caso comparándolo con una lista blanca.

Pros: Funciona bastante bien dada la dificultad de detectar cuales o que funciones están con esta protección.
Contras: Al igual que el anterior exige tener una lista blanca.

4º Parte: Protección Anti-Patching (modificación) de memoria

Suponiendo que el Anti-Cheat no pudo evitar la inyección, ahí no termina la cosa, existen métodos para evitar/detectar modificaciones en la memoria...

Protección en Modo Kernel: Este tipo de protección checkea cuando proceso externo intenta leer o escribir en el espacio de memoria de un proceso, para eso deberemos hookear determinadas funciones del kernel:

Código PHP:
NtReadVirtualMemory (intenta leer la memoria)
NtWriteVirtualMemory (intenta escribir en la memoria

Entre otras... (las otras funciones ya serían una mezcla de funciones de inyección).

Pros: Si está bien implementado funciona bien.
Contras: Al igual que con las otras funciones en modo kernel, se necesitan firmas digitales para cargar drivers en Windows 64bits y salen bastantes caras...

Protección en modo Usuario (Checkeo CRC): Este tipo de protección Anti-Patching es bastante simple de implementar y es utilizado no solo por los Anti-Cheats (muchos programas lo utilizan para evitar ser crackeados), la lógica de funcionamiento es simple, una vez cargado el proceso en memoria se calcula un CRC32 del código del mismo (en algunos casos este CRC ya fue calculado por lo que este paso se omite), luego cada X cantidad de tiempo, se vuelve a calcular y en caso de ser distinto significa que la memoria ha sido modificada.

Pros: Es bastante simple de implementar.
Contras: Debe ser ejecutado ni bien se termina de cargar el programa en memoria, dado que si no, podría calcular el primer CRC con las modificaciones ya echas y el checkeo sería inútil (en el caso de no haber sido calculado con anterioridad).

Protección en modo Usuario (Doble mapeo de módulos con acceso protegido): Este tipo de protección es uno de los últimos que vi y en mi opinión uno de los mejores, se basa en el principio de controlar la carga de módulos (LdrLoadDll) de los módulos que son comúnmente modificados (opengl32.dll, hw.dll, client.dll, etc), el proceso es el siguiente: se mapea la dll en una dirección distinta a la que debería (bloquea auto-offsets), se realiza el proceso de carga (manual map) y una vez completado, se mueve el espacio de memoria a su lugar original (remapea) con acceso de solo lectura (no es lo mismo que hacer VirtualProtect), de esta forma no se podrán modificar los permisos de acceso sobre dicho espacio de memoria (lo que significa que no se podrá modificar, osea, parchear direcciones, hookear funciones, etc... para hacerlo hay que volver a remapear, lo cual requeriría volver a iniciar el juego, pero el Anti-Cheat al volver a hacer este trabajo, queda completamente nulo cualquier intento de patching).

Pros: Es un método muy complicado de burlar.
Contras: Es complicado de implementar dada la poca información sobre este tipo de operaciones (funciones indocumentadas/poco documentadas de windows).

Información & Transcript originalmente echas por Karman & Rainnegan.

Nota: @Neeeeeeeeeel.- avisame si hay algo que no va dentro del post ...
Si alguien no comprende alguna parte del Thread, siéntase libre de preguntar ...
Cualquiera que quiera aportar nuevas ideas a ésto, ¡va a ser bienvenido! ...
(15/12/2020, 07:06 PM)Mario AR. escribió: Cuando tu acatante conozca de tu nuevo puerto, te volverá a atacar
Responder


Salto de foro:


Usuarios navegando en este tema: 1 invitado(s)