Pular para conteúdo

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)

void* malloc(size_t size);

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, &currentValue, 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, 
                          &params->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, &currentHealth, 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.