Funcionamento da Memória no Windows e Game Hacking
1. Fundamentos da Memória no Windows
O Windows utiliza um sistema sofisticado de gerenciamento de memória que permite a execução eficiente de múltiplos processos e aplicativos simultaneamente.
1.1 Memória Física vs. Memória Virtual
A memória física (RAM) é um recurso limitado que o sistema operacional precisa gerenciar entre todos os processos em execução. Para contornar essa limitação, o Windows implementa um sistema de memória virtual que:
- Cria a ilusão de que cada processo tem acesso a um espaço de endereçamento contínuo e exclusivo
- Permite que o sistema execute mais processos do que a RAM física comportaria
- Mapeia endereços virtuais para endereços físicos através de tabelas de páginas
Em sistemas Windows modernos (x64), cada processo pode teoricamente acessar até 8TB de espaço de endereçamento virtual, embora a memória física disponível seja muito menor.
1.2 Páginas de Memória
O Windows gerencia a memória em unidades chamadas páginas:
- Cada página normalmente tem 4KB (4.096 bytes) em arquiteturas x86/x64
- As páginas podem ser movidas entre a RAM e o arquivo de paginação (pagefile.sys)
- O hardware MMU (Memory Management Unit) traduz endereços virtuais para físicos em tempo real
1.3 Estados da Memória
A memória alocada pode existir em diferentes estados: - Livre: Não está sendo usada - Reservada: Reservada para uso, mas sem espaço físico alocado - Comprometida: Memória que foi designada para uso e tem espaço físico alocado
2. Alocação de Memória por Aplicativos
2.1 APIs de Alocação de Memória no Windows
O Windows oferece diversas APIs para alocação de memória, sendo as principais:
2.1.1 VirtualAlloc
LPVOID VirtualAlloc(
LPVOID lpAddress, // Endereço desejado (ou NULL para qualquer)
SIZE_T dwSize, // Tamanho em bytes
DWORD flAllocationType, // Tipo (MEM_COMMIT, MEM_RESERVE)
DWORD flProtect // Proteções (PAGE_READWRITE, etc.)
);
Esta função permite: - Especificar o endereço base da alocação (ou deixar o sistema escolher) - Definir o tamanho necessário - Configurar o tipo de alocação (reserva ou comprometimento) - Estabelecer proteções de acesso (leitura, escrita, execução)
2.1.2 HeapAlloc
LPVOID HeapAlloc(
HANDLE hHeap, // Handle para o heap
DWORD dwFlags, // Flags de alocação
SIZE_T dwBytes // Tamanho em bytes
);
O HeapAlloc
é usado para alocações menores e mais granulares dentro de um heap já existente.
2.1.3 Malloc (C Runtime)
Por trás dos panos, malloc
utiliza as APIs do Windows como HeapAlloc
ou VirtualAlloc
.
2.2 Espaço de Endereçamento Virtual
Cada processo no Windows recebe seu próprio espaço de endereçamento virtual que é isolado dos outros processos:
- Em sistemas 32-bit: 4GB de espaço de endereçamento (2GB para o processo, 2GB para o kernel)
- Em sistemas 64-bit: Teoricamente 16 exabytes, mas na prática limitado a ~8TB por processo
Este isolamento significa que: - O endereço 0x00400000 em um processo refere-se a um local de memória completamente diferente do mesmo endereço em outro processo - Um processo não pode acessar diretamente a memória de outro processo sem permissões especiais - Se um processo falha, sua memória é liberada sem afetar outros processos
2.3 Proteções de Memória
Cada região de memória alocada tem flags de proteção que controlam como ela pode ser acessada:
- PAGE_READONLY: Permite apenas leitura
- PAGE_READWRITE: Permite leitura e escrita
- PAGE_EXECUTE: Permite execução (código)
- PAGE_EXECUTE_READ: Permite execução e leitura
- PAGE_EXECUTE_READWRITE: Permite execução, leitura e escrita
- PAGE_NOACCESS: Bloqueia todo acesso
3. Representação da Memória em Registradores
3.1 Registradores em Processadores x86/x64
Os registradores são pequenas áreas de armazenamento extremamente rápidas dentro da CPU:
3.1.1 Registradores de Propósito Geral em x64
- RAX, RBX, RCX, RDX: Registradores de 64 bits (extensões dos registradores EAX, EBX, ECX, EDX de 32 bits)
- RSI, RDI: Registradores de índice/fonte e destino
- RSP: Stack Pointer (aponta para o topo da pilha)
- RBP: Base Pointer (referência para variáveis locais)
- R8-R15: Registradores adicionais disponíveis em modo 64 bits
3.1.2 Registradores de Segmento
- CS, DS, SS, ES, FS, GS: Armazenam seletores que apontam para descritores de segmento
3.1.3 Registradores SIMD
- XMM0-XMM15: Registradores de 128 bits para operações SSE
- YMM0-YMM15: Extensões de 256 bits para AVX
- ZMM0-ZMM31: Extensões de 512 bits para AVX-512
3.2 Como os Registradores Interagem com a Memória
Os registradores são essenciais para operações de memória:
- Endereçamento: Registradores como RBP e RSP mantêm endereços de memória importantes
- Armazenamento Temporário: Dados são carregados da memória para registradores, manipulados, e depois escritos de volta
- Ponteiros: Registradores armazenam endereços usados para acessar dados na memória
3.3 Exemplos de Instruções de Acesso à Memória
3.3.1 Carregando da Memória para um Registrador
; Carrega o valor do endereço [RAX] para RBX
MOV RBX, [RAX]
; Carrega o valor do endereço [RAX+8] para RCX (indexação)
MOV RCX, [RAX+8]
; Carrega o valor do endereço [RAX+RCX*4] para RDX (indexação escalada)
MOV RDX, [RAX+RCX*4]
3.3.2 Armazenando da Memória para um Registrador
; Armazena o valor de RAX no endereço apontado por RBX
MOV [RBX], RAX
; Armazena o valor 42 no endereço [RCX+16]
MOV QWORD PTR [RCX+16], 42
4. Acesso à Memória de um Processo
4.1 APIs do Windows para Acessar Memória de Processos
O Windows fornece APIs específicas que permitem que um processo acesse a memória de outro, com as devidas permissões:
4.1.1 ReadProcessMemory
BOOL ReadProcessMemory(
HANDLE hProcess, // Handle para o processo alvo
LPCVOID lpBaseAddress, // Endereço de memória para ler
LPVOID lpBuffer, // Buffer para armazenar os dados lidos
SIZE_T nSize, // Número de bytes para ler
SIZE_T *lpNumberOfBytesRead // Saída: bytes realmente lidos
);
4.1.2 WriteProcessMemory
BOOL WriteProcessMemory(
HANDLE hProcess, // Handle para o processo alvo
LPVOID lpBaseAddress, // Endereço de memória para escrever
LPCVOID lpBuffer, // Buffer contendo dados para escrita
SIZE_T nSize, // Número de bytes para escrever
SIZE_T *lpNumberOfBytesWritten // Saída: bytes realmente escritos
);
4.2 Obtendo um Handle de Processo
Para acessar a memória de outro processo, primeiro é necessário obter um handle com permissões adequadas:
HANDLE hProcess = OpenProcess(
PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION,
FALSE,
dwProcessId // PID do processo alvo
);
4.3 Enumerando Módulos e Regiões de Memória
4.3.1 Módulos (DLLs)
Para localizar módulos carregados em um processo:
HMODULE hModules[1024];
DWORD cbNeeded;
if (EnumProcessModules(hProcess, hModules, sizeof(hModules), &cbNeeded)) {
for (unsigned int i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) {
// Trabalhar com cada módulo encontrado
}
}
4.3.2 Regiões de Memória
Para escanear regiões de memória dentro de um processo:
MEMORY_BASIC_INFORMATION mbi;
LPVOID address = NULL;
while (VirtualQueryEx(hProcess, address, &mbi, sizeof(mbi))) {
// Analisa as informações da região de memória
address = (LPVOID)((DWORD_PTR)mbi.BaseAddress + mbi.RegionSize);
}
4.4 Desafios e Limitações
- Proteções DEP (Data Execution Prevention): Impede a execução de código em regiões de dados
- ASLR (Address Space Layout Randomization): Randomiza os endereços base dos módulos
- Permissões de Acesso: Requer privilégios administrativos para acessar certos processos
- Anti-Cheats: Monitoram e bloqueiam tentativas de acesso à memória
5. Alteração da Memória de um Processo
5.1 Técnicas para Localizar Endereços de Memória
5.1.1 Varredura de Memória (Memory Scanning)
// Exemplo simplificado de varredura por um valor
for (BYTE* addr = startAddress; addr < endAddress; addr++) {
int currentValue;
ReadProcessMemory(hProcess, addr, ¤tValue, sizeof(int), NULL);
if (currentValue == targetValue) {
// Endereço encontrado
}
}
5.1.2 Padrões de Assinatura (Pattern Scanning)
// Procura por um padrão de bytes específico
bool CheckPattern(BYTE* addr, BYTE* pattern, char* mask) {
for (; *mask; ++mask, ++addr, ++pattern) {
if (*mask == 'x' && *addr != *pattern)
return false;
}
return true;
}
// Exemplo: "48 8B 05 ? ? ? ? 48 8B 08" (? são bytes ignorados)
5.1.3 Usando Offsets Conhecidos
// Localizar um valor usando base + offset
DWORD64 moduleBase = GetModuleBaseAddress(hProcess, L"game.exe");
DWORD64 targetAddress = moduleBase + 0x1ABCDEF; // Offset conhecido
5.2 Exemplos Práticos de Modificação
5.2.1 Alterando um Valor de Saúde em um Jogo
// Supondo que encontramos o endereço da vida do jogador
DWORD healthAddress = 0x12345678;
int newHealth = 999;
WriteProcessMemory(
hProcess,
(LPVOID)healthAddress,
&newHealth,
sizeof(int),
NULL
);
5.2.2 Freezing de Valores
// Cria uma thread que continuamente escreve o mesmo valor
DWORD WINAPI FreezeValue(LPVOID lpParam) {
FreezeParams* params = (FreezeParams*)lpParam;
while (!params->shouldStop) {
WriteProcessMemory(params->hProcess, (LPVOID)params->address,
¶ms->value, params->size, NULL);
Sleep(10); // Pequena pausa para não sobrecarregar a CPU
}
return 0;
}
5.3 Padrões Comuns de Armazenamento em Jogos
Os jogos geralmente armazenam dados do jogador em estruturas complexas:
// Exemplo de uma estrutura de player em C++
struct Player {
int health; // 0x00
int maxHealth; // 0x04
float position[3]; // 0x08 (x, y, z)
int ammo; // 0x14
int maxAmmo; // 0x18
int teamId; // 0x1C
char name[32]; // 0x20
};
// Acessando os campos
Player player;
ReadProcessMemory(hProcess, playerBaseAddress, &player, sizeof(Player), NULL);
6. Introdução ao Game Hacking
6.1 História e Evolução do Game Hacking
- Anos 80-90: Trainers simples modificando valores na memória de jogos DOS/early Windows
- Anos 2000: Surgimento de comunidades dedicadas a hacking de jogos como Counter-Strike e WoW
- Anos 2010: Sofisticação de técnicas e ferramentas, desenvolvimento de anti-cheats avançados
- Atualmente: Constante batalha entre hackers e desenvolvedores de anti-cheats
6.2 Técnicas Comuns de Game Hacking
6.2.1 Wallhacks
Permitem ver através de paredes, geralmente alterando a renderização:
// Simplificação conceitual - desabilitando oclusão
bool wallCheck = false;
WriteProcessMemory(hProcess, wallCheckAddress, &wallCheck, sizeof(bool), NULL);
6.2.2 Aimbots
Automatizam a mira, calculando ângulos para o alvo:
// Pseudo-código para cálculo de ângulo de mira
Vector3 CalculateAngle(Vector3 playerPos, Vector3 targetPos) {
Vector3 delta = targetPos - playerPos;
float distance = sqrt(delta.x * delta.x + delta.y * delta.y + delta.z * delta.z);
Vector3 angle;
angle.x = atan2(delta.z, distance) * (180.0f / 3.14159f);
angle.y = atan2(delta.y, delta.x) * (180.0f / 3.14159f);
return angle;
}
6.2.3 ESP (Extra Sensory Perception)
Exibe informações normalmente ocultas:
// Itera por todos os jogadores e exibe suas informações
for (int i = 0; i < playerCount; i++) {
Entity player = ReadEntity(hProcess, entityListBase + (i * entitySize));
if (player.team != localPlayerTeam) {
// Desenha ESP box, informações, etc.
}
}
6.3 Considerações Éticas e Legais
- Violação de ToS: A maioria dos jogos proíbe explicitamente qualquer forma de manipulação de memória
- Impacto na Comunidade: Cheats degradam a experiência de jogo de outros jogadores
- Consequências Legais: Em alguns países, hacking de jogos pode levar a processos legais sob leis de propriedade intelectual ou acesso não autorizado
- Jogos Offline vs. Online: Modificar jogos offline para uso pessoal geralmente é mais aceitável que hackear jogos online
7. O Conceito de Rings (Níveis de Privilégio)
7.1 Arquitetura de Proteção do Processador
Os processadores x86/x64 modernos implementam um sistema de proteção baseado em anéis concêntricos, onde os anéis internos têm mais privilégios:
- Ring 0: Kernel Mode - Acesso total ao hardware e aos recursos do sistema
- Ring 1: Drivers de dispositivos (raramente usado em sistemas modernos)
- Ring 2: Drivers de dispositivos (raramente usado em sistemas modernos)
- Ring 3: User Mode - Onde aplicativos comuns executam com privilégios limitados
7.2 Transições Entre Rings
A mudança entre rings é estritamente controlada:
- Syscalls: Quando um aplicativo precisa executar operações privilegiadas, ele faz uma chamada de sistema
- Interrupções: Eventos de hardware podem causar transições temporárias para Ring 0
- SYSENTER/SYSCALL: Instruções especializadas para transições eficientes entre User e Kernel Mode
; Exemplo simplificado de SYSCALL em x64
mov rax, SYSCALL_NUMBER ; Número da syscall em RAX
syscall ; Executa a transição para Ring 0
; O kernel executa a operação e retorna para Ring 3
7.3 Evolução Histórica dos Rings de Proteção
- Primeiros Dias: Sistemas operacionais antigos como MS-DOS não usavam proteção de rings
- Windows 9x: Implementação limitada, com muitas operações ainda em Ring 0
- Windows NT: Separação clara entre Ring 0 e Ring 3
- Windows 10/11: Adição de virtualization-based security (VBS) que isola ainda mais o kernel
- Hypervisors Modernos: Introdução do conceito de "Ring -1" (VMX root mode)
8. Exemplos de Aplicativos em Cada Ring
8.1 Ring 0 (Kernel Mode)
- Componentes do Kernel do Windows: ntoskrnl.exe, HAL (Hardware Abstraction Layer)
- Drivers de Sistema de Arquivos: NTFS, FAT32, exFAT
- Drivers de Dispositivo: Gráficos, áudio, rede, armazenamento
- Antivírus Kernelmode: Partes de soluções como Windows Defender, Kaspersky, etc.
- Anti-Cheats Kernelmode: Easy Anti-Cheat, BattlEye, Vanguard
Exemplo de Driver em Ring 0
// Fragmento de um driver de kernel
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) {
// Código inicializado no contexto do kernel (Ring 0)
// Configurar rotinas de tratamento
DriverObject->MajorFunction[IRP_MJ_CREATE] = DeviceCreate;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = DeviceClose;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DeviceControl;
// Criar dispositivo para comunicação com usermode
RtlInitUnicodeString(&deviceName, L"\\Device\\MyKernelDriver");
status = IoCreateDevice(DriverObject, 0, &deviceName,
FILE_DEVICE_UNKNOWN, 0, FALSE, &deviceObject);
return STATUS_SUCCESS;
}
8.2 Ring 3 (User Mode)
- Aplicativos Comuns: Navegadores, editores de texto, clientes de email
- Jogos: Desde simples jogos 2D até AAA como Call of Duty, Fortnite, CS:GO
- Utilitários de Sistema: Gerenciador de tarefas, explorador de arquivos
- Serviços: Muitos serviços do Windows rodam em modo usuário
- Ambientes Runtime: .NET CLR, Java VM, Python interpreter
Exemplo de Aplicativo User Mode
// Aplicativo Win32 básico
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow) {
// Este código roda em Ring 3
MessageBox(NULL, "Hello World!", "Ring 3 Application", MB_OK);
return 0;
}
8.3 Por Que Essas Separações São Importantes
- Estabilidade: Um aplicativo em Ring 3 que falha não pode derrubar o sistema inteiro
- Segurança: Aplicativos maliciosos não podem acessar diretamente o hardware
- Isolamento de Recursos: Processos não podem interferir uns com os outros sem permissão
- Performance: A separação permite implementações de hardware mais eficientes
9. O Jogo é Apenas um Processo
9.1 Estrutura de Memória Específica de Jogos
Os jogos modernos geralmente têm uma estrutura de memória complexa:
- Código do Jogo: Instruções executáveis (.text)
- Recursos Estáticos: Texturas, modelos, sons carregados na inicialização
- Estado do Jogo: Posições de entidades, saúde, munição, etc.
- Buffers de Renderização: Dados para o pipeline gráfico
- Pools de Memória: Alocações dinâmicas para objetos do jogo
9.2 Como Engines Específicas Gerenciam Memória
9.2.1 Unreal Engine
// Exemplo de alocador personalizado da Unreal
void* FMallocBinned::Malloc(SIZE_T Size, uint32 Alignment) {
// Lógica de alocação personalizada para performance em jogos
// Usa "bins" de tamanhos fixos para reduzir fragmentação
}
9.2.2 Unity
// Unity usa seu próprio sistema de gerenciamento de objetos
GameObject enemy = Instantiate(enemyPrefab, position, rotation);
// Por trás, isso aloca memória de forma otimizada para objetos de jogo
9.3 Vulnerabilidades Comuns em Jogos
- Falta de Validação de Input: Permite buffer overflows ou alterações de estado não intencionais
- Exposição de Dados Críticos: Armazenar informações sensíveis (como posições de inimigos) em locais previsíveis
- Confiança no Cliente: Quando jogos confiam em dados enviados pelo cliente sem verificação adequada
- Falta de Criptografia: Dados transmitidos ou armazenados em texto puro
- Previsibilidade: Algoritmos determinísticos que podem ser explorados
10. Tipos de Cheats: Externos vs Internos
10.1 Cheats Externos
São programas independentes que manipulam o jogo de fora, sem modificar o executável original:
10.1.1 Vantagens
- Menor risco de detecção (não alteram o código do jogo)
- Mais seguros para o usuário (menos chance de ban)
- Podem trabalhar com múltiplos jogos
10.1.2 Desvantagens
- Acesso mais lento à memória (precisam usar ReadProcessMemory/WriteProcessMemory)
- Menos funcionalidades avançadas
- Podem ser bloqueados por anti-cheats que monitoram processos externos
10.1.3 Exemplo de Cheat Externo
// Abre o processo e manipula a memória externamente
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, gamePID);
// Ciclo contínuo para ler/escrever na memória do jogo
while (true) {
// Lê a saúde atual
int currentHealth;
ReadProcessMemory(hProcess, (LPVOID)healthAddress, ¤tHealth, sizeof(int), NULL);
// Verifica se precisa ser aumentada
if (currentHealth < 100) {
int newHealth = 100;
WriteProcessMemory(hProcess, (LPVOID)healthAddress, &newHealth, sizeof(int), NULL);
}
Sleep(100); // Evita uso excessivo de CPU
}
10.2 Cheats Internos
São injetados diretamente no processo do jogo, tornando-se parte dele:
10.2.1 Vantagens
- Acesso direto e rápido à memória (sem API do Windows)
- Podem modificar funções e fluxo de execução
- Acesso a estruturas e funções internas do jogo
10.2.2 Desvantagens
- Maior risco de detecção
- Mais complexos de desenvolver
- Específicos para cada jogo/versão
10.2.3 Técnicas de Injeção de DLL
// Injeção de DLL usando CreateRemoteThread
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, gamePID);
// Aloca memória no processo alvo
LPVOID remoteString = VirtualAllocEx(hProcess, NULL,
strlen(dllPath) + 1,
MEM_RESERVE | MEM_COMMIT,
PAGE_READWRITE);
// Escreve o caminho da DLL na memória alocada
WriteProcessMemory(hProcess, remoteString, dllPath,
strlen(dllPath) + 1, NULL);
// Cria uma thread remota que carrega a DLL
HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0,
(LPTHREAD_START_ROUTINE)GetProcAddress(
GetModuleHandle("kernel32.dll"),
"LoadLibraryA"),
remoteString, 0, NULL);
10.2.4 Hooking de Funções
// Exemplo de hook em uma função de renderização
DWORD originalFunction;
DWORD hookAddress = 0x12345678;
// Função de detour
void __declspec(naked) HookFunction() {
__asm {
pushad // Salva todos os registradores
// Código personalizado aqui
// Ex: Desenhar wallhack, ESP, etc.
popad // Restaura registradores
jmp [originalFunction] // Pula para o código original
}
}
// Instalação do hook
void InstallHook() {
// Salva bytes originais
originalFunction = hookAddress + 5;
// Escreve jmp para nossa função
*(BYTE*)hookAddress = 0xE9; // Opcode para JMP
*(DWORD*)(hookAddress + 1) = (DWORD)HookFunction - hookAddress - 5;
}
11. Como Funciona um Anti-Cheat (Usermode)
11.1 Técnicas de Detecção em User Mode
11.1.1 Monitoramento de Processos
// Enumera processos em execução
DWORD processes[1024];
DWORD bytesReturned;
EnumProcesses(processes, sizeof(processes), &bytesReturned);
// Analisa cada processo
for (unsigned int i = 0; i < bytesReturned / sizeof(DWORD); i++) {
TCHAR processName[MAX_PATH] = TEXT("<unknown>");
// Abre o processo
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
FALSE, processes[i]);
// Obtém o nome do executável
if (hProcess) {
HMODULE hMod;
if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &bytesReturned)) {
GetModuleBaseName(hProcess, hMod, processName, sizeof(processName)/sizeof(TCHAR));
}
// Verifica se é um processo suspeito
if (_tcscmp(processName, TEXT("cheat.exe")) == 0) {
// Processo suspeito detectado
}
CloseHandle(hProcess);
}
}
11.1.2 Detecção de Injeção de Código
// Escaneia regiões de memória suspeitas
MEMORY_BASIC_INFORMATION mbi;
LPVOID address = NULL;
while (VirtualQuery(address, &mbi, sizeof(mbi))) {
// Verifica memória executável e com permissões de escrita
if (mbi.Protect == PAGE_EXECUTE_READWRITE) {
// Região suspeita - pode ser código injetado
// Escaneia por assinaturas de cheats conhecidos
}
address = (LPVOID)((DWORD_PTR)mbi.BaseAddress + mbi.RegionSize);
}
11.1.3 Verificação de Integridade
// Calcula hash de regiões críticas do jogo
BYTE gameCode[0x10000]; // Tamanho arbitrário
memcpy(gameCode, (void*)gameBaseAddress, 0x10000);
// Gera hash SHA-256
SHA256_CTX ctx;
SHA256_Init(&ctx);
SHA256_Update(&ctx, gameCode, 0x10000);
BYTE hash[SHA256_DIGEST_LENGTH];
SHA256_Final(hash, &ctx);
// Compara com hash original
if (memcmp(hash, originalHash, SHA256_DIGEST_LENGTH) != 0) {
// Código do jogo foi modificado
}
11.2 Limitações dos Anti-Cheats em User Mode
- Mesmo Nível de Privilégio: Anti-cheats em user mode operam no mesmo ring que os cheats
- Visibilidade Limitada: Não podem monitorar atividades do kernel
- Vulneráveis a Ocultação: Cheats avançados podem se esconder de detecção em user mode
- Restrições de API: Dependem das APIs limitadas disponíveis em Ring 3
12. Anti-Cheats em Kernelmode
12.1 Funcionamento Detalhado
Os anti-cheats kernelmode operam como drivers de kernel (Ring 0), oferecendo: - Acesso total ao sistema operacional - Capacidade de interceptar chamadas de sistema - Monitoramento de carregamento de drivers - Detecção de modificações de memória em nível baixo
12.2 Técnicas Avançadas de Proteção
12.2.1 Monitoramento de Chamadas de Sistema
// Intercepta a syscall NtReadVirtualMemory
NTSTATUS HookedNtReadVirtualMemory(
HANDLE ProcessHandle,
PVOID BaseAddress,
PVOID Buffer,
SIZE_T BufferSize,
PSIZE_T NumberOfBytesRead) {
// Obtém o processo atual
PEPROCESS currentProcess = PsGetCurrentProcess();
// Verifica se é um processo tentando ler o jogo protegido
if (IsTargetProcess(ProcessHandle)) {
// Ação: Bloquear, log, ou ban
return STATUS_ACCESS_DENIED;
}
// Chama a função original
return OriginalNtReadVirtualMemory(
ProcessHandle, BaseAddress, Buffer, BufferSize, NumberOfBytesRead);
}
12.2.2 Proteção contra Drivers Não Assinados
// Enumera drivers carregados
PRTL_PROCESS_MODULES moduleInfo = NULL;
ULONG moduleInfoSize = 0;
// Primeiro, determina o tamanho necessário
NTSTATUS status = ZwQuerySystemInformation(
SystemModuleInformation,
moduleInfo,
moduleInfoSize,
&moduleInfoSize);
// Aloca memória e obtém informações
moduleInfo = ExAllocatePool(PagedPool, moduleInfoSize);
status = ZwQuerySystemInformation(
SystemModuleInformation,
moduleInfo,
moduleInfoSize,
NULL);
// Verifica cada driver
for (ULONG i = 0; i < moduleInfo->NumberOfModules; i++) {
// Verifica assinatura digital do driver
if (!IsDriverSigned(&moduleInfo->Modules[i])) {
// Driver não assinado detectado
}
}
12.2.3 Prevenção de DMA (Direct Memory Access) Attacks
// Configura IOMMU/VT-d para impedir acesso direto à memória
status = MmSetDriverProtection(
driverObject,
MM_DRIVER_PROTECTED_SYSTEM,
NULL);
12.3 Problemas de Privacidade e Segurança
- Privilégios Excessivos: Anti-cheats com acesso Ring 0 têm controle total sobre o sistema
- Riscos de Segurança: Vulnerabilidades em código Ring 0 podem comprometer todo o sistema
- Preocupações de Privacidade: Podem monitorar toda a atividade do usuário
- Incompatibilidades: Podem causar BSODs (Blue Screen of Death) ou conflitos com outros drivers
Exemplos de Controvérsias
- Vanguard (Riot Games) - Opera mesmo quando o jogo não está rodando
- BattlEye - Problemas de compatibilidade com certos hardwares
- Easy Anti-Cheat - Casos de falsos positivos
13. Conclusão e Tendências Futuras
13.1 Resumo dos Conceitos-Chave
- A memória no Windows segue um modelo de espaços de endereçamento virtuais isolados
- Os jogos são apenas processos normais executando em Ring 3
- A batalha entre cheats e anti-cheats é uma constante evolução tecnológica
- A separação entre Ring 0 e Ring 3 é fundamental para entender as limitações e capacidades
13.2 Evolução das Tecnologias Anti-Cheat
- Análise Comportamental: Detecção baseada em padrões de jogo não-humanos
- Machine Learning: Algoritmos que aprendem a identificar comportamentos suspeitos
- Trusted Execution Environments: Uso de enclaves seguros como Intel SGX ou AMD SEV
- Server-Side Validation: Movimentação de mais lógica para servidores confiáveis
- Virtualização: Isolamento adicional através de tecnologias como Hyper-V
13.3 Futuro do Game Hacking
- Técnicas de Ofuscação: Cheats mais difíceis de detectar via ofuscação avançada
- Hardware Cheats: Dispositivos físicos externos que modificam inputs
- Ataques de Machine Learning: Uso de AI para burlar sistemas de detecção
- Exploração de Periféricos: Cheats que operam via firmware de mouse/teclado
13.4 Considerações Finais
O entendimento profundo de como o Windows gerencia memória e como os jogos funcionam como processos é fundamental tanto para o desenvolvimento de sistemas de proteção quanto para a compreensão de suas vulnerabilidades. A constante evolução desta área demonstra a complexidade dos sistemas modernos e a importância de abordagens de segurança em múltiplas camadas.
A separação entre os níveis de privilégio (Ring 0 e Ring 3) continua sendo a base arquitetural sobre a qual todo este ecossistema opera, criando o equilíbrio - às vezes frágil - entre funcionalidade, performance e segurança nos sistemas de jogos modernos.