# Cheat Externo

## Cheat Externo

Um *cheat* externo é um software, ou até mesmo hardware, que opera fora do processo do jogo para manipular a experiência do jogo, modificando algum comportamento e podendo oferecer algum tipo de vantagem.

Esses *cheats* em essência leem a memória do processo e usando chamadas específicas manipulam a memória do jogo. Além disso, eles também podem interceptar informações, como dados gráficos, e tomar algumas decisões em cima disso.

## Classe básica para a criação de um *cheat* externo

O interessante de criar um *cheat* externo é a possibilidade de aprender mais aprofundadamente sobre processos, e principalmente como eles se comportam, e como eles podem manipular uns aos outros.

{% hint style="warning" %}
Os *cheats* não devem ser criados para atrapalhar a experiência de outros jogadores, então se você for criar um, teste em um jogo *offline*, ou em partidas personalizadas com seus amigos.
{% endhint %}

A classe abaixo representa uma estrutura básica para fazer a manipulação dos jogos, e ela utiliza principalmente a Windows API, fazendo com que o *cheat* não possa ser utilizado em jogos com anti-cheat, uma vez que eles detectam a chamada dessas funções.

{% code title="memory.h" lineNumbers="true" %}

```cpp
#ifndef MEMORY_H
#define MEMORY_H

#include <Windows.h>
#include <iostream>
#include <vector>

class Memory {
private:
    DWORD id;
    HANDLE process;

public:
    Memory(const char *processName);
    ~Memory();

    DWORD getPID();
    HANDLE getProcess();

    uintptr_t getModuleAddress(const char *moduleName);
    uintptr_t locateMemoryAddress(uintptr_t ptr, std::vector<unsigned int> offsets);

    template <typename T>
    T Read(uintptr_t address) {
        T value;
        ReadProcessMemory(this->process, (LPCVOID)address, &value, sizeof(T), NULL);
        return value;
    }

    template <typename T>
    bool Write(uintptr_t address, T value) {
        bool ret;
        DWORD oldProtection;
        VirtualProtect((BYTE*)address, sizeof(value), PAGE_EXECUTE_READWRITE, &oldProtection);
        ret = WriteProcessMemory(this->process, (LPVOID)address, &value, sizeof(value), NULL);
        VirtualProtect((BYTE*)address, sizeof(value), oldProtection, &oldProtection);
        return ret;
    }
};

#endif
```

{% endcode %}

{% code title="memory.cpp" lineNumbers="true" %}

```cpp
#include "memory.h"
#include <TlHelp32.h>

Memory::Memory(const char *processName){
    const auto snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    PROCESSENTRY32 entry;

    entry.dwSize = sizeof(PROCESSENTRY32);

    if(snapshot != INVALID_HANDLE_VALUE) {
        if(Process32First(snapshot, &entry)) {
            do {
                if(!strcmp(entry.szExeFile, processName)) {
                    this->id = entry.th32ProcessID;
                    this->process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, this->id);
                    break;
                }
            }while(Process32Next(snapshot, &entry));
        }
    }

    if(snapshot) {
        CloseHandle(snapshot);
    }
}

Memory::~Memory() {
    if(this->process) {
        CloseHandle(this->process);
    }
}

DWORD Memory::getPID() {
    return this->id;
}

HANDLE Memory::getProcess() {
    return this->process;
}

uintptr_t Memory::getModuleAddress(const char *moduleName) {
    const auto snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, this->id);
    MODULEENTRY32 module;
    uintptr_t address = 0;

    module.dwSize = sizeof(MODULEENTRY32);

    if(snapshot != INVALID_HANDLE_VALUE) {
        if(Module32First(snapshot, &module)) {
            do {
                if(!strcmp(module.szModule, moduleName)) {
                    address = reinterpret_cast<uintptr_t>(module.modBaseAddr);
                    break;
                }
            }while(Module32Next(snapshot, &module));
        }
    }

    if(snapshot) {
        CloseHandle(snapshot);
    }

    return address;
}

uintptr_t Memory::locateMemoryAddress(uintptr_t ptr, std::vector<unsigned int> offsets) {
    uintptr_t address = ptr;

    for(unsigned int i = 0; i < offsets.size(); ++i) {
        if(i < offsets.size() - 1) {
            address = this->Read<uintptr_t>(address + offsets[i]);
        }else {
            address += offsets[i];
        }
    }

    return address;
}
```

{% endcode %}

{% hint style="warning" %}
Esta classe foi criada para jogos em 32-bits, então ela está sendo compilada em um compilador de 32-bits.

Também é possível compilar a classe usando um compilador de 64-bits, porém caso o jogo alvo seja 32-bits, é necessário alterar os `uintptr_t` para `uint32_t`, com exceção dos endereços que serão em 64-bits, como o endereço do módulo.
{% endhint %}

### Explicação das funções

O construtor basicamente salva as informações de um processo usando a biblioteca `TlHelp32.h`, fazendo a mesmo coisa na função `getModuleAddress`, porém salvando as informações do módulo especificado.

Já função `locateMemoryAddress` busca o endereço final de uma cadeia de *offsets* a partir do endereço inicial `ptr`. Note que o último *offset* é somente somado ao endereço, não tendo que ver o que ele aponta, pois neste caso ele apontaria direto para o valor final, e não um endereço.

E por fim, as funções `Read` e `Write` utilizam a Windows API para manipular os processos, com a `Read` sendo usada para ver o que o endereço `address` armazena (ou aponta), e a `Write` para escrever o valor `value` no endereço `address`. Note que no caso da função `Write` é necessário garantir que a parte da memória, que estamos modificando, tem permissão de escrita, então é usado uma função para alterar essa permissão, mas é importante sempre voltar as proteções anteriores para evitar *bugs*.

## Fontes

[Microsoft](https://learn.microsoft.com/pt-br/windows/win32/api/tlhelp32/)
