Como configurar anti-tamper (proteção) do cliente de MU Online
Blinde o Main.exe do seu servidor de MU Online contra edição, injeção e memory hacks combinando checksum de integridade, anti-debug, verificação de módulos e um handshake assinado com o servidor.
Proteger o cliente de MU Online é uma corrida armamentista permanente. Do outro lado estão editores hexadecimais, injetores de DLL, trainers de memória e cheats de speed, wallhack e auto-combo que se aproveitam de um Main.exe desprotegido. O anti-tamper é o conjunto de defesas que dificulta editar o
Proteger o cliente de MU Online é uma corrida armamentista permanente. Do outro lado estão editores hexadecimais, injetores de DLL, trainers de memória e cheats de speed, wallhack e auto-combo que se aproveitam de um Main.exe desprotegido. O anti-tamper é o conjunto de defesas que dificulta editar o binário, anexar um debugger, injetar código e alterar valores em memória — e, tão importante quanto, permite que o servidor detecte quando o cliente não é confiável. Neste tutorial você vai montar essas camadas de forma prática: integridade por checksum, anti-debug, verificação de módulos carregados, proteção de memória e um handshake assinado com o servidor. Todos os valores concretos (offsets, portas, nomes de seção) aparecem como exemplo e variam por season/cliente.
Pré-requisitos
Antes de blindar qualquer coisa, você precisa de uma base funcional. Se ainda está montando o servidor, comece por como criar um servidor de MU Online e volte aqui quando o cliente já conectar normalmente. Blindar um cliente que ainda nem loga só multiplica variáveis quando algo quebrar.
| Requisito | Detalhe (exemplo — varia por season/cliente) |
|---|---|
| Cliente funcional | Main.exe que conecta e loga sem proteção ainda |
| Backup do binário | Cópia intocada Main_original.exe fora da pasta do cliente |
| Ferramentas de análise | HxD, CFF Explorer, x64dbg, Process Hacker |
| Launcher próprio | Executável que valida e inicia o cliente (ideal) |
| Acesso ao ConnectServer | Para adicionar validação server-side |
| Ambiente de teste isolado | Máquina limpa, separada da de desenvolvimento |
O item menos óbvio é o launcher próprio. Muita proteção fica melhor num componente que você controla totalmente e pode recompilar à vontade, em vez de tentar remendar o Main.exe que veio no pacote. O launcher verifica integridade, conversa com o servidor e só então dispara o cliente.
Modelo de ameaças: contra o que você está protegendo
Antes de escolher técnicas, defina o que o atacante quer fazer. Proteção genérica desperdiça CPU e gera falso positivo; proteção dirigida ao ataque real vale o esforço.
| Ataque | Vetor típico | Defesa principal |
|---|---|---|
| Editar IP/versão no binário | HxD, patcher | Checksum de integridade |
| Anexar debugger | x64dbg, Cheat Engine | Anti-debug |
| Injetar DLL de cheat | Injector, LoadLibrary | Verificação de módulos |
| Alterar valores em memória | Cheat Engine, trainer | Cifragem/ofuscação de variáveis + validação server-side |
| Speed hack | Aceleradores de clock | Checagem de tempo + validação server-side |
| Forjar pacotes | Proxy, bot | Handshake assinado + validação server-side |
Repare que validação server-side aparece em quase toda linha. Essa é a lição central: o cliente roda na máquina do inimigo e nunca será totalmente confiável. O anti-tamper eleva o custo do ataque e alimenta o servidor com sinais; o veredito final é do servidor.
Camada 1 — Integridade por checksum
A defesa mais barata contra edição do binário é conferir se ele é bit a bit igual ao que você distribuiu. Gere um hash forte do Main.exe original e verifique-o em dois lugares: no launcher, antes de iniciar, e no servidor, durante o handshake.
Passo 1 — Gerar o hash de referência
No Windows, com o binário final já pronto (já patchado com IP e versão corretos):
certutil -hashfile Main.exe SHA256
Guarde esse hash. Ele é a "verdade" contra a qual todo cliente será comparado. Sempre que você reeditar o Main.exe, o hash muda — automatize a regeneração para não distribuir cliente com hash desatualizado.
Passo 2 — Verificar no launcher
O launcher calcula o SHA-256 do Main.exe em disco e compara com o valor esperado antes de executar. Exemplo em C++ (esboço):
// Pseudocódigo — varia por season/cliente e por como você embute o hash
bool VerificarIntegridade(const wchar_t* caminho, const std::string& hashEsperado) {
std::string hashAtual = CalcularSHA256(caminho); // via CryptoAPI / bcrypt
if (hashAtual != hashEsperado) {
MostrarErro(L"Cliente adulterado. Baixe novamente pelo launcher.");
return false;
}
return true;
}
> Não embuta o hash esperado como string em texto plano fácil de achar. Ofusque, quebre em partes ou derive de outra coisa. Um atacante que localiza a string simplesmente troca pelo hash do binário editado dele.
Passo 3 — Checksum de seção em runtime (self-check)
Além do check em disco, o próprio cliente pode conferir a soma da sua seção de código (.text) em memória enquanto roda. Isso pega patches aplicados após a carga (injeção de código). A ideia: no build, calcule o CRC/hash da seção .text e, em runtime, recalcule periodicamente comparando com o valor gravado. Se divergir, reporte ao servidor.
Como o .text é mapeado com relocations e o valor esperado precisa bater, esse check normalmente exige controle do processo de build ou um protector que já faça isso por você (ver Camada 6).
Camada 2 — Anti-debug
Cheat Engine e x64dbg dependem de anexar um debugger ao processo. Detectar essa presença encarece a análise dinâmica.
Passo 4 — Checagens básicas
// Exemplos clássicos — combine vários, nunca confie em um só
bool DebuggerPresente() {
if (IsDebuggerPresent()) return true;
BOOL remoto = FALSE;
CheckRemoteDebuggerPresent(GetCurrentProcess(), &remoto);
if (remoto) return true;
// PEB->BeingDebugged e NtGlobalFlag também são checados por proteções mais fundas
return false;
}
Passo 5 — Detectar ferramentas por janela/processo
Varra janelas e processos por assinaturas conhecidas (nomes de classe e títulos de Cheat Engine, x64dbg, OllyDbg, Process Hacker). Mantenha a lista externa e atualizável, porque nomes mudam.
> Não trave o cliente ao detectar. Overlays de gravação, ferramentas de acessibilidade e até alguns antivírus disparam esses checks. O padrão seguro é reportar ao servidor com o sinal e deixar o ban para análise humana ou heurística acumulada. Matar o processo na hora é a receita de fórum cheio de reclamação de jogador legítimo.
Camada 3 — Verificação de módulos carregados
Cheats frequentemente entram como DLL injetada. Enumerar os módulos do processo e comparar com uma allowlist detecta injeções óbvias.
Passo 6 — Enumerar e classificar módulos
// Esboço — a allowlist varia MUITO por season/cliente e por drivers do usuário
void VarrerModulos() {
// EnumProcessModules -> para cada módulo, GetModuleFileName
// Classifique: sistema (system32), do próprio cliente, e "desconhecido"
// Módulos desconhecidos e não assinados -> sinal para o servidor
}
Cuidado com falsos positivos: overlays (Discord, Steam, GPU), IMEs e software de áudio injetam DLLs legítimas. Por isso a saída ideal é um relatório ao servidor com os módulos suspeitos, não um bloqueio local cego. Assinar digitalmente e conferir a assinatura (Authenticode) reduz muito o ruído.
Camada 4 — Proteção de valores em memória
Trainers editam HP, zen, coordenadas e velocidade direto na RAM com Cheat Engine. Você não impede a leitura, mas dificulta a escrita útil.
- Não guarde valores sensíveis em texto plano. Armazene HP, zen e velocidade cifrados/ofuscados e decifre só no uso. Cheat Engine acha o valor
1000fácil; achar o valor cifrado que muda de representação, nem tanto. - Guarde uma cópia sombra. Mantenha um segundo valor derivado (soma de verificação) e, periodicamente, confira se batem. Divergência = alguém escreveu direto.
- Valide no servidor. HP, zen, posição e velocidade que só existem no cliente são inúteis: o servidor deve ser a autoridade. Se o cliente diz que andou 50 células em 100 ms, o servidor rejeita, independentemente de qualquer proteção local.
Camada 5 — Handshake assinado com o servidor
Esta é a camada que o atacante não controla, e por isso a mais valiosa. Em vez de confiar que o cliente é íntegro, o servidor exige uma prova a cada sessão.
Passo 7 — Desafio-resposta na conexão
- Ao conectar, o ConnectServer/GameServer envia um nonce aleatório (valor de uso único).
- O cliente combina esse nonce com o hash do próprio binário e com um segredo embutido, e responde com um HMAC.
- O servidor recalcula o HMAC com o hash esperado e o mesmo segredo. Se não bater, recusa a sessão.
Servidor -> Cliente : nonce = 0x9F3A... (aleatório por sessão)
Cliente -> Servidor: resp = HMAC_SHA256(segredo, nonce || hashBinario)
Servidor : recalcula e compara. Diferente => derruba a conexão.
Como o nonce muda toda sessão, um atacante não pode gravar uma resposta válida e reproduzir depois (anti-replay). E como o servidor conhece o hashBinario esperado, um Main.exe editado produz HMAC diferente e é barrado — mesmo que o atacante tenha neutralizado o check local.
> O segredo embutido no cliente é o elo fraco: quem engenharia reversa o binário pode extraí-lo. Rotacione o segredo a cada atualização de cliente, combine-o com dados de build e trate-o como algo que eventualmente vaza. A força real vem de somar isso à validação de comportamento no servidor.
Camada 6 — Packers e protectors comerciais
Se você não tem o código-fonte do cliente, os protectors aplicados ao binário pronto entregam grande parte das camadas 1, 2 e parte da 4 de uma vez.
| Ferramenta | Foco | Contrapartida (exemplo) |
|---|---|---|
| Themida | Anti-debug, virtualização, integridade | Pesado; falsos positivos de AV; inicialização lenta |
| VMProtect | Virtualização de trechos críticos | Perda de FPS se virtualizar código quente |
| Enigma Protector | Integridade, licenciamento, anti-dump | Configuração extensa |
Regras de ouro ao usar protector: virtualize apenas as rotinas críticas (handshake, checks), nunca o loop de render, senão o FPS despenca em máquinas fracas; mantenha uma build interna sem proteção para você depurar; e teste antivírus antes de lançar, porque packers disparam heurística e você precisará de whitelist/reputação.
Erros comuns e soluções
| Sintoma | Causa provável | Solução |
|---|---|---|
| Cliente fecha ao abrir para muitos jogadores | Anti-debug agressivo pegando overlay/AV | Trocar bloqueio por report; refinar allowlist |
| Antivírus deleta o Main.exe | Packer sem reputação | Assinar binário; submeter para whitelist; reputação no VirusTotal |
| Hash sempre inválido no launcher | Hash de referência desatualizado após reedição | Automatizar regeneração do hash no build |
| FPS caiu muito após proteger | Virtualização do loop de render | Virtualizar só rotinas críticas |
| Handshake recusa clientes legítimos | Relógio/nonce dessincronizado ou versão errada | Conferir tolerância de tempo e AcceptVersion |
| Falso positivo com Discord/Steam | Verificação de módulos cega | Assinar/allowlist módulos assinados conhecidos |
| Segredo do handshake vazou | String em texto plano no binário | Ofuscar/rotacionar segredo a cada update |
Distribuição e rotação
Proteção não é "configura e esquece". Cada nova versão do cliente deve gerar novo hash, novo segredo de handshake e, se possível, pequenas variações nas rotinas de check para evitar que uma solução pública de bypass valha para sempre. Distribua sempre pelo launcher (que valida antes de rodar), publique o hash junto ao download e escaneie o binário final antes de subir. Trate cada bypass reportado no seu Discord como um bug de prioridade alta.
Checklist de lançamento
- Backup
Main_original.exeguardado fora da pasta do cliente - Hash SHA-256 de referência gerado a partir do binário final
- Verificação de integridade ativa no launcher (hash ofuscado)
- Anti-debug em modo report, não em modo kill
- Verificação de módulos com allowlist de assinados conhecidos
- Valores sensíveis (HP/zen/velocidade) cifrados no cliente
- Validação server-side de HP, posição, velocidade e pacotes
- Handshake nonce + HMAC ativo no ConnectServer/GameServer
- Segredo do handshake rotacionável e ofuscado
- Protector aplicado só em rotinas críticas (FPS testado em PC fraco)
- Binário assinado e submetido para reputação de antivírus
- Testado em máquina limpa, separada da de desenvolvimento
- Build de debug interna sem proteção guardada para você depurar
- Plano de rotação de hash/segredo a cada atualização documentado
Perguntas frequentes
Anti-tamper substitui o anticheat do servidor?
Não. O anti-tamper protege o binário do cliente e a memória local, enquanto a validação server-side confere se ações e valores recebidos fazem sentido. São camadas complementares: um cliente blindado com servidor ingênuo ainda cai por pacotes forjados, e vice-versa. Sempre valide no servidor além de proteger o cliente.
Posso usar Themida ou VMProtect no Main.exe?
Sim, packers comerciais como Themida, VMProtect e Enigma são bastante usados para dificultar engenharia reversa e debugging. O custo é maior consumo de CPU/RAM, tempo de inicialização mais lento e falsos positivos em alguns antivírus. Teste desempenho em máquinas fracas antes de lançar e mantenha uma build de debug sem packer para você mesmo depurar.
O checksum do cliente pode ser burlado?
Um atacante determinado sempre pode neutralizar um check local, porque o código que verifica roda na máquina dele. O objetivo do anti-tamper não é ser inquebrável, e sim elevar o custo do ataque e permitir que o servidor detecte inconsistências. Por isso o handshake assinado com o servidor, que o atacante não controla, é a parte mais valiosa.
Anti-debug vai atrapalhar jogadores legítimos?
Pode, se for agressivo demais. Técnicas como IsDebuggerPresent e checagem de janelas de ferramentas raramente afetam jogadores, mas travar o processo ao detectar qualquer coisa suspeita gera falsos positivos com overlays, gravadores de tela e software de acessibilidade. Prefira reportar ao servidor e deixar a decisão de ban para análise, em vez de matar o cliente na hora.
Preciso recompilar o Main.exe para adicionar proteção?
Depende. Se você tem o código-fonte do cliente (raro), compila a proteção junto. Sem fonte, o caminho é aplicar um packer/protector externo ao binário e, se houver suporte via loader ou DLL injetada pelo seu launcher, adicionar checks nesse componente. A verificação de integridade e o handshake podem viver no launcher e no ConnectServer sem tocar no Main.exe.