O Cheat Engine (CE) é uma ferramenta local de modificação de memória. Sua lógica central é bem direta: ao escanear e localizar dados que um programa mantém na memória física do computador enquanto está em execução, você pode forçar a alteração desses valores. Embora historicamente tenha ganhado fama em engenharia reversa de jogos e na exploração de falhas em jogos (o popular “hack/cheat” ou “alterar memória”), seu uso está longe de se limitar a isso. Com a mesma abordagem, é possível tentar encontrar vulnerabilidades de lógica de negócio em diversos apps e até em cenários de Web.

Para obter o software, basta acessar o site oficial do Cheat Engine, baixar a versão mais recente e instalá-la sem complicações. O processo de instalação é simples, então não vamos nos alongar aqui. Para tornar as capacidades do CE mais fáceis de visualizar, neste tutorial vamos abrir qualquer jogo como alvo de teste e, a partir dele, explicar passo a passo as funções essenciais do CE, como pesquisar e modificar dados na memória e, por fim, como transformar isso em ideias práticas para exploração de vulnerabilidades.


1. Preparação do ambiente e mecanismo de anexar (attach) ao processo

Antes de fazer qualquer operação com o Cheat Engine, o pré-requisito mais importante é anexar-se a um processo. Isso porque os dados na memória existem vinculados a um processo em execução.

1.1 Encontrando o processo-alvo

Após abrir o Cheat Engine, no canto superior esquerdo da interface, você verá um botão em formato de computador com um ícone de lupa. Ao clicar nele, será aberta a janela Process List (lista de processos). Essa lista mostra todos os processos ativos que estão rodando no computador naquele momento.

1.2 A particularidade do processo em emuladores

Se o que você quer testar é um jogo mobile ou um app de celular, normalmente você vai usar um emulador Android no PC (por exemplo, o LDPlayer). Na lista de processos, procure com atenção um processo chamado headless (o nome completo geralmente vem com um prefixo específico; no LDPlayer pode aparecer algo como leidian ou LdBox + headless).

Cada emulador usa um prefixo diferente, mas se você observar o processo de renderização/back-end ou o processo central de execução, é bem comum existir um headless no final. Ao encontrá-lo, selecione-o e clique no botão Open (abrir) no canto inferior direito para injetar o CE e anexá-lo ao espaço de memória do emulador.


2. Tipos de dados e modos de busca

Depois de anexar ao processo, a tela principal do CE pode parecer cheia de parâmetros, mas a lógica para iniciar em exploração de falhas por modificação de memória é simples: digite no campo de busca o valor que você quer alterar e encontre onde ele está.

2.1 Entendendo os tipos de dados

No lado direito da área de busca do CE existe um menu suspenso para escolher o tipo de dado. Os dados na memória não são todos iguais; eles são armazenados em tipos diferentes conforme a necessidade:

  • 4 Bytes: é a opção padrão do CE. Na maioria dos jogos e aplicações comuns, variáveis como quantidades, estados, moedas etc. costumam ser armazenadas como inteiros de 4 bytes (Integer). Em testes de jogos, na prática o padrão de 4 bytes costuma cobrir 90% dos casos.
  • Outros tipos (visão geral): para lógicas mais complexas, o CE também suporta outros tipos. Por exemplo, 8 Bytes para números muito grandes; Float e Double para valores com casas decimais (como coordenadas X/Y/Z ou multiplicadores de atributos); além de String para textos e vários tipos de arrays. Eles podem existir na memória, mas para iniciantes é importante manter o foco em “4 Bytes”.

2.2 Estratégias de busca exata e por intervalo

Depois de escolher o tipo de dado, é preciso definir o tipo de varredura (scan). O CE oferece muitas formas de filtrar condições:

  1. Valor exato: a opção mais comum. Quando você sabe exatamente o valor (por exemplo, “tenho 10 moedas”), você busca esse número.
  2. Maior que...: quando o valor está oculto/indefinido, mas você sabe que é maior do que um limite.
  3. Menor que...: o equivalente para filtrar valores menores que um limite.
  4. Entre...: permite delimitar um intervalo (por exemplo, entre 10 e 100).

3. Busca exata de um valor conhecido e o caso “1≠1”

Quando o valor é conhecido, parece simples, mas na prática há muito ruído. Vamos usar um exemplo para ilustrar.

3.1 A “explosão de informações” da primeira varredura

Suponha que você queira encontrar o valor 10. Digite 10 e clique em First Scan (primeira varredura).

Naquele momento, a lista de endereços à esquerda vai encher rapidamente, possivelmente com centenas de milhares de resultados.

  • O que é um endereço de memória? É como um “número de quarto”/“coordenada” na RAM do computador onde um dado está armazenado. À esquerda aparece o endereço (em hexadecimal) e à direita o valor atual naquele endereço.

Entre centenas de milhares de endereços, apenas um ou poucos são os que você realmente quer; o resto é cache irrelevante do sistema, de outros apps etc.

3.2 Na memória do jogo, “1” nem sempre é “1”

Imagine que dentro do jogo algum item/estado aparece como 1. Se o tipo de dado for 4 bytes e a lógica do programa realmente fizer “o 1 exibido = 1 na memória”, basta buscar 1 e clicar em First Scan.

O resultado pode ser assustador: você pode obter mais de 5 milhões de endereços cujo valor é 1.

  • Isso ocorre porque, dentro do emulador (incluindo Android, apps de fundo e o jogo), o número 1 é usado o tempo todo para representar estado. Por exemplo, 1 para “ativado” e 0 para “desativado”. Por isso, buscar apenas 1 produz milhões de resultados.

3.3 Refinando aos poucos

Diante de milhões de endereços, a solução é fazer o valor mudar dentro do jogo.

  1. O valor vira 2: por alguma ação no jogo, o valor que era 1 aumenta e vira 2.
  2. Next Scan (nova varredura): volte ao CE, digite 2 e clique em Next Scan. Atenção: isso não é uma nova busca do zero, é um filtro sobre os resultados anteriores. A lógica é: “dos endereços que antes eram 1, quais agora viraram 2?”.
  3. O total pode cair rapidamente para cerca de 2.000.
  4. Continue: faça virar 3, rode Next Scan com 3 e o total pode cair para 17.
  5. A realidade (aviso em vermelho): se você tentar mudar para 6 e buscar 6, de repente a lista pode ficar vazia; os endereços restantes aparecem em vermelho (vermelho indica que o valor naquele endereço mudou automaticamente), mas nenhum deles é 6.
  • “No jogo, 1 pode não ser 1. Ele pode ser qualquer outro valor esquisito.”

4. Valor inicial desconhecido e filtragem dinâmica

Quando acontece “1≠1”, ou quando você quer atributos como HP/MP ou tamanho de modelo sem número visível, você não sabe qual valor buscar. Nesse caso, é necessário usar o modo Unknown initial value (valor inicial desconhecido).

4.1 Um oceano de centenas de milhões de endereços

Selecionar “Unknown initial value” significa pedir ao CE para listar todos os endereços de memória do emulador. Após o First Scan, por não haver filtro por valor, o CE captura uma quantidade gigantesca de dados (no exemplo, chegando a “centenas de milhões”, e no texto original, “até 900 milhões” de endereços).

Como encontrar um único endereço que controla um atributo específico nesse mar? A chave é observar o padrão de mudança.

4.2 Rastreando aumentos e diminuições

Suponha que você esteja testando um controle deslizante (slider) de tamanho do modelo.

  1. Arraste o slider para a direita (você não sabe o número interno, mas sabe que aumentou).
  2. No CE, mude o tipo de varredura para Increased value (valor aumentou).
  3. Clique em Next Scan. A lógica é: “entre todos os endereços, quais aumentaram em relação ao valor registrado anteriormente?”.
  4. A quantidade pode cair drasticamente.
  5. Repita o processo, aumentando novamente o slider e filtrando por “aumentou”, até reduzir o conjunto.

4.3 A utilidade do “Unchanged value” (valor inalterado)

Durante o processo, pode acontecer de você chegar ao máximo (por exemplo, 10) e não conseguir aumentar mais. Se você voltar para 0 e depois retornar para 10, surge um problema lógico:

A última referência registrada era 10, e agora você voltou a 10. Se você buscar “aumentou”, não encontrará o alvo — porque não aumentou nem diminuiu, apenas ficou igual.

Aqui entra o filtro mais importante: Unchanged value (sem mudança).

  • Removendo ruído do sistema: inúmeros endereços mudam o tempo todo (tempo do sistema, frames, heartbeats etc.). Se você filtrar por “sem mudança”, muitos desses dados “barulhentos” são eliminados.
  • Filtragem repetida: você pode clicar várias vezes em “Next Scan (Unchanged value)” sem mudar nada no jogo, e o CE vai continuar removendo endereços que mudam por conta própria até estabilizar.

Após alternar entre “aumentou”, “diminuiu” e “sem mudança”, a redução pode ficar lenta e “travar” em alguns milhares de endereços.


5. Método de bisseção e mecanismo de travamento (freeze) de memória

Por que, mesmo com tanta filtragem, ainda sobram milhares de endereços mudando ao mesmo tempo?

Porque certas ações (como arrastar um slider) afetam muitos subsistemas (UI, renderização, sombras, colisões etc.). Todos esses endereços mudam junto, mas só um é o “controle principal”.

Para achar o endereço certo, existe um método simples e extremamente eficaz: a bisseção com travamento de memória.

5.1 Área de valores a modificar e função de travamento

Na lista de endereços à esquerda, pressione Ctrl + A para selecionar todos os ~2.000 endereços e clique na seta vermelha diagonal para enviar tudo para a área de valores a modificar.

Nessa área:

  1. Dê duplo clique no valor de um endereço para forçar qualquer valor.
  2. Mais importante: a caixinha (freeze/lock) na frente. Ao marcar, o CE congela aquele endereço com alta frequência. Independentemente do que você fizer no jogo, o valor travado não muda.

5.2 Exercício prático de eliminação por travamento

Use esse travamento para fazer eliminação:

  1. Estado máximo: coloque o slider no máximo e observe a mudança visual.
  2. Trave metade: na área inferior, selecione aproximadamente metade dos endereços (use Shift para selecionar um intervalo) e pressione barra de espaço para marcar o travamento.
  3. Valide no jogo: volte ao jogo e tente reduzir o slider.
    • Lógica: se o endereço principal estiver travado, o modelo deveria permanecer no máximo.
    • Resultado: se o modelo diminui normalmente, significa que a metade travada não contém o endereço principal.
  4. Exclua sem dó: clique com o botão direito nessa metade e escolha Delete (ou Del) para remover.
  5. Repita: pegue a metade do que restou, trave, valide e elimine.
  6. Sinal de progresso: quando você travar um conjunto que contém o endereço correto, você verá o comportamento “estranho” (por exemplo, o modelo ficando menor demais, deformado etc.). Isso indica que você finalmente travou algo relevante.
  7. Reverta e refine: desmarque o travamento para voltar ao normal, elimine o resto, e continue dividindo até sobrar poucos endereços.
  8. Encontre o definitivo: teste os últimos endereços um a um até achar o único que realmente controla o atributo.

6. Da modificação de memória para vulnerabilidades de lógica de negócio no back-end

Depois de tanta explicação sobre busca e alteração de memória, muitas pessoas (especialmente quem trabalha com pentest Web) perguntam: “Se eu altero a memória localmente e só eu vejo isso na minha tela, qual é a utilidade real?”

6.1 Caso 1: bypass com número negativo na compra de itens

Imagine uma loja de itens em um jogo. Ao comprar “1” unidade, o cliente (front-end) monta uma requisição para o servidor (back-end) com dois dados principais:

  1. ID do item (ex.: 1001)
  2. Quantidade de compra (ex.: 1)

Esses parâmetros existem, antes de serem enviados, na memória local.

Se você localizar o endereço que guarda a “quantidade” e, antes do envio, alterar de 3 para -3 (menos três), e então clicar em comprar, o cliente enviará -3 ao servidor.

Se o back-end só validar “se há moedas suficientes” e esquecer de validar se a quantidade é negativa, o servidor pode processar -3. Muitas vezes o resultado é: em vez de gastar moedas, o jogador ganha moedas (porque “descontar -3” vira um crédito). Isso é uma vulnerabilidade grave de lógica de negócio gerada pela confiança excessiva no cliente. Da mesma forma, se parâmetros de modelagem forem enviados e persistidos, você pode criar personagens fora do padrão para todo mundo ver.

6.2 Caso 2: usar um ID de profissão oculto para criar com privilégio indevido

Além de alterar dados externos, a modificação de memória pode revelar e permitir uso antecipado de funções não liberadas.

Troca/criação de profissão (classe) é um caso clássico. Suponha que o back-end já tenha implementado uma classe futura (“Artilheiro”), mas o cliente ainda não exibiu o botão na UI.

  1. Busca difusa do ID: na tela de criação, alterne entre classes existentes e use buscas do tipo “Unknown initial value” + filtros de mudança para localizar o endereço que representa o ID da classe.
  2. Padrão bem definido: IDs principais costumam ter regras. Ex.: Guerreiro 10101, Mago 20101, Sacerdote 30101.
  3. Chute e envio indevido: com esse padrão, dá para supor que a classe oculta seja 40101 (ou similar). Altere o ID na memória.
  4. Golpe final: clique em “criar personagem”. Se o servidor confiar na UI do cliente e não fizer autorização (verificação) no endpoint, o pedido de criar a classe oculta pode ser aceito — um caso típico de bypass/IDOR lógico.

6.3 Por que não usar interceptação de tráfego (proxy)?

Aqui surge outra pergunta: “Se a ideia é alterar dados enviados ao servidor, não é mais fácil usar Burp Suite/Fiddler e editar o request?”

Muitas vezes é mais fácil — mas esbarra no protocolo e na criptografia.

  1. Protocolos não HTTP: muitos jogos e apps usam TCP/UDP direto (por baixa latência), e ferramentas tradicionais de proxy HTTP não ajudam.
  2. Dados criptografados: além disso, quase tudo é criptografado antes do envio; mesmo capturando o pacote no Wireshark, você verá apenas “lixo”.
  3. Custo de descriptografar: descriptografar pode exigir engenharia reversa pesada ou scripts pagos.

Por que o CE contorna isso?

Porque, independentemente do que será criptografado no tráfego, no momento em que o dado é gerado no cliente (antes da criptografia) ele está em texto claro na memória. Ao alterar na memória, você troca o dado antes de “subir no ônibus” da criptografia — e o próprio cliente criptografa e envia normalmente. Isso é uma forma elegante de “ataque por redução de dimensão”.

6.4 Caso 3: vulnerabilidade de abrir live em sala alheia ao quebrar criptografia

Essa ideia também funciona fora de jogos. Em apps de live streaming, certos fluxos podem ser TCP/UDP e totalmente criptografados, tornando impossível interceptar e modificar.

A modificação de memória vira a saída:

  1. Abra o CE e anexe ao processo do app.
  2. Use padrões de mudança para localizar o endereço do “ID da sala da minha live”.
  3. Antes de clicar em “iniciar live”, altere o valor para o ID de outra pessoa.
  4. Clique em iniciar. O app pega o ID alterado, criptografa localmente e envia.
  5. Se o servidor confiar demais no dado do cliente e não checar autorização (se o usuário tem permissão para iniciar live naquela sala), a falha ocorre: você inicia live na sala de outra pessoa.

Isso mostra que, quando há criptografia e protocolos não padrão, a modificação de memória pode ser uma ferramenta muito útil.


7. Não há segredo, é prática

O que é um modificador de memória e como usar? No fim, tudo se resume a duas etapas:

  1. Encontrar o valor que eu quero
  2. Modificar o valor que eu quero

O Cheat Engine é apenas a espada na sua mão. Os movimentos parecem simples — buscar e modificar —, mas o quão fundo você consegue “cortar” depende da habilidade de quem segura a espada.

Não existe atalho. É preciso colocar a mão na massa: desmontar dezenas de jogos, analisar centenas de apps, e repetir filtragens e tentativas em dados massivos até se aproximar da resposta correta. O processo pode ser tedioso, mas justamente por isso, quando a verdade aparece, ele se torna ainda mais fascinante.