Cheat Engine
Cheat Engine
Cheat Engine é uma ferramenta para modificação de jogos offline, voltada principalmente para jogos de um jogador. No entanto, ela oferece um conjunto robusto de utilitários que a tornam útil para diversas outras finalidades, não se limitando ao contexto de jogos.
Algumas das ferramentas mais úteis disponíveis são:
Scanner de memória;
Debugger;
Disassembler;
Assembler;
Speedhack;
Trainer Maker;
E muito mais...
Além disso, o Cheat Engine possui suporte a scripts, o que facilita o compartilhamento de modificações automatizadas.
Nas próximas seções, serão demonstradas as funcionalidades mais básicas da aplicação, utilizando como alvo o próprio Tutorial (x32) incluso com a instalação padrão. Note que os passos do tutorial não estarão em ordem, eles vão estar dentro da seção que descreve as funcionalidades dele.
Buscar valores na memória
Buscar por valores na memória é a funcionalidade mais básica do Cheat Engine, e já está presente logo na tela inicial:

O lado direito da interface é responsável pela configuração da busca: é possível definir o tipo de busca, o tipo do valor, o valor desejado, entre outras opções. O lado esquerdo mostra os resultados da busca, incluindo o endereço na memória, o valor atual armazenado e o valor encontrado na busca inicial.
Na parte inferior temos a Cheat Table, onde ficam armazenados os valores que queremos manipular ou monitorar, assim como scripts que podem ser ativados ou desativados. No topo da interface estão as opções para abrir um processo, carregar uma Cheat Table ou salvar a atual.
Para abrir o tutorial, vá em Help → Cheat Engine Tutorial, e em seguida abra o processo correspondente ao tutorial por meio do botão de seleção de processos. Este tutorial é um guia prático que ensina, passo a passo, as funcionalidades mais básicas do Cheat Engine. Cada etapa só pode ser completada utilizando as ferramentas ensinadas.
Passo 2: Buscar e modificar a vida
Ao avançar a introdução, chegamos ao Passo 2, que solicita a modificação do valor da vida para 1000. O primeiro passo é localizar esse valor na memória.

Neste caso, a configuração padrão da busca já é suficiente. Precisamos apenas:
Informar o valor atual da vida (
100
);Selecionar o tipo de valor como
4 Bytes
;Escolher o tipo de busca como Exact Value (Valor Exato).
Após definir os parâmetros corretamente, clique em First Scan para realizar a primeira varredura.

Como resultado, apareceram vários endereços com valor 100
(43 no exemplo). Uma abordagem ingênua seria alterar todos esses valores para 1000
, mas isso pode causar o encerramento do processo ou comportamentos indesejados.
O próprio tutorial fornece uma opção chamada Hit me, que diminui o valor da vida. Após clicar, o valor passou para 99
. No exemplo, apenas um dos 43 endereços mudou de 100
para 99
, facilitando sua identificação. Contudo, em muitos casos reais, vários valores podem mudar simultaneamente, e essa identificação requer uma busca mais refinada.
Neste momento, novas opções de busca se tornam úteis: é possível procurar por valores aumentados, diminuídos, alterados, ou inalterados. No caso, como sabemos o valor exato (99
), é mais eficaz continuar com uma busca exata.
Para refinar a busca, clique em Next Scan. A opção New Scan reinicia a busca do zero.
Resultado da segunda busca:

Dando dois cliques no endereço encontrado, ele será adicionado à Cheat Table. A partir dali é possível:
Travar o valor ativando a opção
Active
;Modificar o valor diretamente (basta dar dois cliques sobre ele);
Alterar o tipo de dado (isso muda apenas como o Cheat Engine interpreta o valor, e não como o jogo o trata);
Mudar o nome/descritivo da entrada.
Para completar o passo, basta alterar o valor da vida para 1000
.
Passo 3 e 4: Valores desconhecidos e ponto flutuante
O Passo 3 do tutorial trata de valores inicialmente desconhecidos, simulando uma barra de vida, onde é necessário usar buscas baseadas em mudanças (aumentou/diminuiu/etc). Já o Passo 4 introduz a busca de valores em ponto flutuante, como float
ou double
.
Apesar da diferença nos tipos de dado e na forma de busca, o procedimento geral continua o mesmo do Passo 2:
Realizar uma busca inicial;
Realizar ações no tutorial que alterem o valor;
Refinar a busca com base nas alterações observadas;
Localizar o endereço correto;
Adicionar à Cheat Table e modificar conforme necessário.
Ponteiros
Ponteiros são valores na memória que armazenam o endereço de outra região da memória, a qual pode conter dados importantes, como a vida de um personagem em um jogo. A importância de se encontrar ponteiros, ao invés de apenas endereços diretos, reside no fato de que sistemas operacionais modernos aplicam técnicas de segurança como o ASLR (Address Space Layout Randomization), que faz com que os endereços de memória utilizados por um processo sejam aleatórios a cada execução.
Com isso, todos os endereços encontrados nos passos anteriores serão inutilizados assim que o processo for encerrado.
O mesmo problema acontece com ponteiros simples: o endereço armazenado por eles pode mudar a cada execução. Felizmente, há dois conceitos que nos ajudam a contornar esse problema:
Offsets;
Endereços base (base addresses).
Offsets
Offsets são valores fixos, utilizados como deslocamento em relação a um endereço inicial para acessar uma posição específica da memória. Para ilustrar isso, considere a seguinte estrutura em C:
struct Teste {
int x;
int y;
};
Essa estrutura contém dois inteiros. O campo x
está no início da estrutura, portanto tem offset 0. Já o campo y
vem logo após x
. Como x
é um int
(4 Bytes
), o campo y
estará a um offset de 4.
Assim, se tivermos um endereço de uma estrutura Teste
, podemos acessar y
somando 4 a esse endereço.
Em resumo:
Os offsets são fixos e são independentes do ASLR ou da execução do processo;
Podem ser usados para navegar dentro de regiões da memória de forma confiável.
Endereços base (Base Addresses)
Endereços base são endereços fixos que servem como ponto de partida para cálculos de posições relativas. Eles representam o início de uma região alocada por um módulo carregado pelo processo, como o próprio executável (.exe
) ou bibliotecas dinâmicas (.dll
). Apesar do ASLR alterar esses endereços a cada execução, eles podem ser identificados por nome (por exemplo, Tutorial-i386.exe
) e o Cheat Engine sabe resolver esses nomes para o endereço correto a cada execução.
Isso significa que podemos usar nomes simbólicos para referenciar essas bases, o que torna possível criar ponteiros duráveis, mesmo em meio à aleatoriedade do ASLR. Você pode testar isso:
Vá em Add Address Manually;
No campo Address, digite
Tutorial-i386.exe
;Reinicie o tutorial algumas vezes, abra o processo novamente no Cheat Engine, e verá que o endereço base se manterá correto.
Esses endereços base, quando combinados com offsets, nos permitem calcular endereços relativos de forma consistente. Por exemplo, se sabemos que a vida do jogador está localizada a +28
do início do módulo Tutorial-i386.exe
, podemos sempre calcular esse valor independentemente da execução específica.
Ponteiros Multinível (Multilevel Pointers)
Quando o valor que queremos acessar não está diretamente no endereço base, mas em uma cadeia de ponteiros, temos o que chamamos de ponteiros multilevel.
Por exemplo:
Um ponteiro A armazena o endereço de B;
B armazena o endereço de C;
C contém o valor desejado (ex.: vida).
Nesse caso, para alcançar o valor final, você precisará de vários offsets, aplicados sequencialmente. Isso é importante:
Os offsets de ponteiros multinível não são somados de uma vez. Cada offset é aplicado ao conteúdo do ponteiro anterior.
Por exemplo, se você tem:
Endereço base
X
;Offsets:
[2, 5]
.
A sequência será:
Y = [X + 2]
→ leia o valor apontado porX + 2
;Z = [Y + 5]
→ leia o valor apontado porY + 5
;Z
contém o valor final.
Em Assembly, o acesso a ponteiros é feito com colchetes. Então:
mov eax, [edi+04]
Significa: carregue em EAX o valor armazenado no endereço EDI + 4
, onde EDI
pode conter um endereço base e 4
seria o offset.
Passo 6: Encontrando ponteiros com o Cheat Engine
Neste passo, o objetivo é encontrar um ponteiro que leve até um determinado valor no tutorial e, em seguida, fixar esse valor em 5000. Antes de explorarmos os métodos para encontrar ponteiros, precisamos primeiro localizar o valor desejado usando a ferramenta de busca do Cheat Engine.
Utilize o botão de alteração de valor no tutorial e a funcionalidade de busca do Cheat Engine para encontrar o endereço onde esse valor está armazenado. Uma vez identificado, há duas formas principais de localizar ponteiros que apontam para ele: através de uma busca manual na memória (scan) ou utilizando o recurso de pointer scan.
Achando ponteiros por meio de scan
Uma das abordagens para encontrar ponteiros consiste em procurar por regiões da memória que armazenam o endereço do valor que desejamos. Essas regiões funcionam como "ponteiros", ou seja, locais que contêm o endereço de outro local na memória.
Ponteiros têm tamanhos diferentes de acordo com a arquitetura do processo. Em processos de 32 bits, os ponteiros ocupam 4 Bytes
, enquanto em 64 bits ocupam 8 Bytes
. Portanto, certifique-se de configurar o tipo de dado corretamente ao fazer a busca.
Com isso em mente, execute uma busca pelo valor do endereço (por exemplo, 0x0178FA90
). Se o valor realmente for acessado via ponteiro simples, você poderá encontrar um endereço que contenha esse valor, o que indica um ponteiro direto.

Neste exemplo, encontramos um ponteiro que é calculado com base na imagem principal do executável (Tutorial-i386.exe
). Isso significa que o ponteiro usa um endereço base, que é mais estável mesmo após reiniciar o processo, tornando-o um bom candidato.
Por padrão, ao adicionarmos esse resultado à Cheat Table, ele é tratado como um valor comum, não como um ponteiro. Para torná-lo um ponteiro:
Clique duas vezes sobre o endereço adicionado;
Marque a opção Pointer;
No campo principal (acima de Add Offset), insira o endereço base, como
Tutorial-i386.exe+2426B0
;Como não há offset neste caso (o ponteiro acessa diretamente o valor), defina um offset de
0
.

Agora o valor pode ser alterado para 5000, e travado clicando na caixinha ao lado dele.
Se a busca não retornar resultados, isso pode indicar que:
O valor não é acessado diretamente por um ponteiro;
Ele é acessado via uma cadeia de ponteiros, cada um com seu offset. Para investigar isso, clique com o botão direito sobre o valor encontrado e selecione Find out what accesses this address. Esse recurso permite descobrir quais instruções estão manipulando o valor e nos ajudará na análise de ponteiros multilevel, como veremos mais adiante.
Usando Pointer Scan
O problema da abordagem anterior é que ela só encontra ponteiros diretos. Se o valor estiver acessível apenas através de uma cadeia de ponteiros com múltiplos offsets, essa busca não funcionará. É aí que entra o recurso Pointer Scan do Cheat Engine.
Esse recurso realiza uma varredura na memória em busca de cadeias de ponteiros (multilevel pointers) que levam até o endereço desejado. Ele considera automaticamente os offsets necessários em diferentes níveis.
Para usar:
Clique com o botão direito sobre o valor encontrado;
Selecione Pointer scan for this address.
Aparecerá uma janela com opções para configurar a busca. A configuração padrão (buscar por ponteiros que apontam diretamente para o endereço) já é suficiente para a maioria dos casos. No entanto, se a busca não retornar resultados, você pode tentar ajustar opções como o número máximo de níveis (max level), ou ampliar o intervalo de memória a ser escaneado.

Após clicar em OK, o Cheat Engine solicitará que você salve os resultados da varredura. Esse arquivo é útil para análises futuras ou para refinar os resultados. A varredura então será iniciada, e uma lista de possíveis ponteiros será exibida.

Nem todos os ponteiros retornados são válidos após reiniciar o processo. Para garantir que o ponteiro seja confiável, é necessário validar sua persistência.
Faça isso assim:
Use a opção Change Pointer no tutorial para forçar uma mudança no endereço do valor;
Selecione Pointer Scanner, selecionando Rescan memory e forneça o novo endereço do valor.

O objetivo é encontrar ponteiros que continuem funcionando mesmo após o endereço do valor ter mudado. Quando isso acontece, podemos ter mais confiança de que o ponteiro encontrado é estável. Se apenas um ponteiro persistir, como no exemplo acima, ele é um bom candidato.
Adicione-o à Cheat Table com um duplo clique. Diferente da busca manual, o Pointer scan já adiciona o ponteiro com seus respectivos offsets, sem necessidade de edição manual.
Com o ponteiro adicionado, basta travar o valor em 5000.
Passo 8: Ponteiros multinível
Este passo é bastante similar ao Passo 6: precisamos encontrar um ponteiro que aponte para o valor desejado e, em seguida, travar esse valor em 5000. No entanto, a diferença aqui é que estamos lidando com um ponteiro multinível, ou seja, um ponteiro que referencia outro ponteiro, que referencia outro, e assim por diante. Neste exemplo, são 4 níveis, portanto 4 offsets.
Embora possamos encontrar esse tipo de ponteiro facilmente com a funcionalidade Pointer scan do Cheat Engine, aqui demonstraremos como fazer isso manualmente, utilizando apenas a busca direta por ponteiros na memória.
Primeiro, encontramos o valor desejado no tutorial através da funcionalidade de alteração de valor. Suponha que o endereço encontrado seja 0x0173AD20
.
Com esse endereço, fazemos uma busca na memória procurando por qualquer local que contenha esse valor, ou seja, estamos procurando por ponteiros que apontem diretamente para ele.

No exemplo acima, nenhum resultado foi retornado. Isso geralmente indica que o valor não é acessado diretamente, mas sim por meio de um offset a partir de outro endereço.
Como a busca direta falhou, clicamos com o botão direito sobre o valor e selecionamos a opção: Find out what accesses this address.
Isso abrirá uma nova janela, inicialmente vazia. A partir desse momento, o Cheat Engine começará a monitorar o processo, observando quais instruções acessam o endereço monitorado.
Para ver as instruções, simplesmente alteramos o valor no tutorial, isso fará com que as instruções envolvidas no acesso apareçam na janela.

Duas instruções apareceram:
mov [esi + 18], eax
;mov eax, [esi + 18]
.
Essas instruções indicam que o valor desejado está localizado em ESI + 0x18
. Ou seja, ESI
contém o endereço-base, e o valor fica em um offset de 0x18
a partir desse endereço.
Esse método exige atenção aos detalhes. É comum que instruções como mov esi, [esi + 18]
confundam a análise, pois atualizam o registrador com um novo valor, e o valor mostrado pelo Cheat Engine será após a execução. Por isso, é essencial compreender o comportamento da instrução e o momento da captura.
Para descobrir qual valor ESI
continha no momento da execução, clicamos sobre a instrução (clicar duas vezes abre uma nova janela com as informações). O Cheat Engine mostrará os valores utilizados.

Neste exemplo, ESI
contém 0x0173AD08
, e: 0x0173AD08 + 0x18 = 0x0173AD20
.
Portanto, esse é o endereço intermediário, nosso próximo candidato a ser pesquisado. Buscamos por ele na memória da mesma forma que antes.

Agora a busca retorna um resultado, que precisa ser convertido para ponteiro para mostrar o valor esperado.

Com esse novo endereço encontrado, repetimos os mesmos passos:
Buscar pelo endereço na memória (se houver um retorno direto, o offset é 0);
Usar a opção Find out what accesses this address novamente, caso a busca não retorne mais ponteiros diretos;
Observar os registros e os offsets usados para chegar ao valor;
Repetir até obtermos um ponteiro com todos os níveis necessários.
Como estamos lidando com um ponteiro multinível de 4 níveis, esse processo deverá ser repetido até descobrirmos todos os níveis intermediários, ou seja, até montarmos a cadeia completa de ponteiros e offsets que levam ao valor final.
Assim que tivermos o ponteiro completo (com todos os níveis e offsets corretamente configurados), basta definir o valor como 5000 e ativar a opção para travá-lo, assim como nos passos anteriores.
Auto Assembler
Assembly é uma linguagem legível que serve para um "montador" converter em código binário que a máquina possa entender. O Auto Assembler é o montador usado pelo Cheat Engine, que consegue entender mais do que apenas Assembly.
Antes de nos aprofundarmos no Auto Assembler, é interessante ver alguns outros mecanismos que o Cheat Engine possui relacionados a Assembly.
O primeiro é a opção Memory View, que nos mostra a memória do processo, mais especificamente, a parte de código Assembly. Ou seja, podemos ver o código da aplicação em Assembly da mesma forma que faríamos em outras ferramentas, como o Ghidra. Aqui também podemos procurar por valores na memória, buscar instruções específicas, usar ferramentas de debug como breakpoints, entre outras.

O segundo é a opção Find out what writes to this address, que é muito similar à opção vista anteriormente, usada para ver o que acessa o endereço. Esta opção será discutida com mais detalhes no Passo 5.
Passo 5: Buscando uma instrução
Existem diversas formas de se modificar um valor. Uma delas é encontrar o ponteiro para ele e alterá-lo diretamente. Mas e se quisermos, por exemplo, não tomar dano? Podemos travar o ponteiro da vida, mas isso pode ser uma solução forçada. A outra opção é modificar o código que altera a vida.
Neste passo, devemos identificar o valor especificado e alterar a instrução que o modifica, para que ele não seja alterado. A primeira etapa é encontrar esse valor.
Após encontrá-lo, clique com o botão direito sobre ele e vá em Find out what writes to this address. Isso abrirá uma janela inicialmente vazia, que mostrará todas as instruções utilizadas para escrever nesse endereço. Para descobrir a instrução que modifica nosso valor, basta alterá-lo no tutorial.

Essa janela é muito similar à usada para descobrir o que acessa o endereço, mas aqui estamos vendo quais instruções modificam o valor. Também podemos ver os valores dos registradores e até usar o Show disassembler, que nos leva diretamente ao código no Memory View. Porém, como nossa intenção aqui é simplesmente impedir que o valor seja alterado, podemos usar a opção Replace, que substituirá a instrução inteira por um nop
, que é uma instrução que não faz nada.
Pronto, basta alterar o valor no tutorial e verificar que ele não será mais modificado.
Passo 7: Injeção de código
Neste passo, veremos o Auto Assembler em ação. O objetivo aqui é fazer com que o valor especificado não diminua, mas sim aumente em dois. Inicialmente, devemos procurar por esse valor e ver qual instrução o modifica.

Uma vez encontrada a instrução, usamos o Show disassembler para ir à janela de Memory View. Em seguida, vamos em Tools → Auto Assemble ou simplesmente pressionamos Ctrl + A
.
Isso abrirá uma nova janela, onde podemos escrever o script que o Cheat Engine montará e injetará no lugar da instrução original. O interessante é que podemos ir em Template e visualizar templates prontos.
É recomendado usar o Full injection, pois ele já vem com um template completo que permite ativar e desativar o script, mantendo-o na Cheat Table.

Esse script basicamente aloca um espaço para o novo código, identificado por newmem
. No endereço original da instrução (identificado por address
), ele altera o fluxo de execução para fazer um salto (jmp
) para o newmem
. Mas antes disso, ele salva a instrução original de address
, para restaurá-la quando o script for desativado.
A label code
contém o código original, e podemos escrever nela ou em newmem
, apenas mantendo o jmp return
no final. Substituindo a instrução para adicionar 2, o código fica assim:

Após modificar, podemos usar o botão Execute para injetar o código, ou ir em File → Assign to current cheat table para adicionar o script à Cheat Table, permitindo ativá-lo ou desativá-lo.
Feito isso, basta alterar o valor e verificar que ele aumenta em 2.
Passo 9: Código compartilhado
Esse passo não mostra nenhuma funcionalidade nova, mas sim uma situação comum que ocorre em jogos, à qual devemos ficar atentos: códigos compartilhados entre entidades. Por exemplo, o código de "levar dano" pode ser compartilhado entre o jogador e os inimigos. Nesse caso, se removermos a instrução de dano, todos ficarão imortais.
Nessas situações, precisamos encontrar algum valor que identifique apenas as entidades desejadas, e então, no código de injeção, fazer comparações com esse valor.
O tutorial nos fornece 4 valores, representando 4 entidades de dois times diferentes. Inicialmente, encontre esses valores.
Usando esse método de observar os endereços acessados pela instrução, uma funcionalidade adicional fica disponível: Open dissect data with selected addresses. Essa opção faz com que o Cheat Engine tente descobrir se os endereços fazem parte de uma mesma estrutura. Se encontrar algo coerente, ele exibirá os outros campos da estrutura. Note que é necessário marcar os endereços que serão usados na estrutura.
Selecionando os 4 endereços e usando essa opção, obtemos a seguinte estrutura:

Note que o valor no offset 0x10
parece servir como identificador: 1 para as duas primeiras entidades, 2 para as duas últimas. Com isso, podemos escrever um script que verifique se o valor é 1 e, nesse caso, impeça que o dano seja aplicado.

Com o script pronto, basta usar a opção do tutorial, e ele será concluído com sucesso.
Caso você não utilize a funcionalidade de estrutura, será necessário encontrar outra forma de identificar os times. Neste exemplo, é possível observar os valores dos registradores no momento da execução da instrução. O registrador ESI
contém o valor 1 para as entidades do time 2, enquanto para o time 1 os valores são 2 e 6.
Fontes
Atualizado