Cheat Engine Tutorial

Cheat Engine Guide


Beginner's Guide:

To get started with Cheat Engine, first download and install the software. Visit the official Cheat Engine website and download the latest version. During installation, be sure to uncheck any unwanted additional components that may be offered. Once installed, open Cheat Engine and get ready to configure your settings.

First, you need to click on "Edit" and then "Settings". At this point, go to the "Scan Settings" tab. In the section where it says:
The 'all' type includes
you need to enable all the checkboxes.

After that, in the section that says "Scan the following memory region types", you should also check the box for:
MEM_MAPPED: Memory that is mapped into the view of a section. (E.g., File mapping, emulator memory, slow).

Now, if the game crashes when trying to create a script, go to the "Debugging Options" tab and try switching from "Use Windows debugger" to "Use VEH Debugger" or vice versa, depending on which one causes the crash.

Once everything is set, click "OK" at the bottom.


2) How to Attach Cheat Engine to a Game

To attach Cheat Engine to a game, follow these steps:

  1. Launch the game you want to attach Cheat Engine to.
  2. Open Cheat Engine.
  3. Click the computer icon at the top left to open the process selection window.
  4. Select your game's process from the list and click "Open" or double click on Games ID.
  5. Once attached, you can start using Cheat Engine to modify game values.


3) How to Set Up Hotkeys

To set up hotkeys in Cheat Engine, follow these steps:

  1. Open Cheat Engine.
  2. Go to the "Edit" menu and select "Settings".
  3. In the settings menu, go to the "Hotkeys" section.
  4. Here you can assign hotkeys to different actions. In the 'Hotkey' section, press the key you want to associate with the shortcut.
  5. Press Ok to save the settings.



4) How to Find Values

Cheat Engine has several ways to find a specific value you are looking for. Below, I list the three most commonly used methods.

4.1) Exact value Search

To conduct an exact value search, follow these steps (Scan Type: Exact Value):

  1. In "Value:", enter the value you want to search for in the search box (for example 1000$).
  2. Select the type of value you think the value you're searching for is. Usually, it's "4 Bytes" or "Float"; if it's none of these, select "All" from the dropdown menu.
  3. Click "First Scan" to find all instances of that value.
  4. After this, sell or buy something and enter the new value in the "Value:" section.
  5. Now click on "Next Scan" and repeat this process until you have narrowed down the number of Addresses/Values that Cheat Engine finds.
  6. Once you have found the value you think is correct, double-click on the chosen value in the "Found:" section.
  7. Now you can modify the value as you wish.
[Note: Typically, these values change with each restart of the game because their addresses are dynamic, which can be resolved by using a pointer or a script.]





4.2) Increased/Decreased value Search

If you're unsure of the specific value, you can use the unknown initial value search. Here’s how:

  1. Start the game and attach Cheat Engine.
  2. In the 'Value Type' section, choose 'Float' or "Double" or "2 Bytes" to have a higher chance of finding the right value; if it's none of these, select "All" from the dropdown menu.
  3. Select "Unknown initial value" from the toolbar.
  4. Select "First Scan".
  5. After making changes in the game (such as changing scores or resources), select "Decreased value" then press "Next Scan" or "Increased value" then press "Next Scan" as needed.
  6. Repeat until you narrow down the results and identify the value.


4.3) Changed/Unchanged value Search (alternative search for Unknown Initial Value)

If you have difficulty finding a specific value, try using the Changed/Unchanged value method, you can use the unknown initial value search. Here’s how to search for a value that has changed or unchanged, follow these steps:

  1. Attach Cheat Engine to the game process.
  2. In the 'Value Type' section, choose 'All' to have a higher chance of finding the value you are looking for, but it will significantly slow down the search.
  3. Select "Unkown initial value" in the search box and then click "First Scan".
  4. Monitor the value that is changing (for example, health points or heat).
  5. Select "Changed value" (always select changed value for first) and click "Next Scan".
  6. Monitor the value that is NOT changing and select "Unchanged value" then click "Next Scan".
  7. Repeat the process to further refine your results.






5) How to make a Script


Once the reloaded value has been found, it is possible—and in many cases necessary—to create a script, since the value we find is almost certainly dynamic, meaning it changes with each restart of the game, and in some cases, even after every load. It depends on which game you are playing.
First, it is important to know that there are various methods to create a script, but I will explain the two (in my opinion) most commonly used ones:


Method One (Direct Method):

Please note that this method does not work for all games, and even when it does, it is advisable to use it only if you are sure that the game will not receive further updates or for most games that are not emulated (in any case, I always recommend using the second method).

There are two ways to start creating a script, namely "Find out what accesses this address" and "Find out what writes to this address". The difference is that the first method reads everything that accesses the address of our value (including what is written in the second method) while the second method only accesses what is written, usually when a specific action or interaction is performed in the game (such as shooting, reloading, selling, buying, jumping, etc... It depends on the cheat).

A) Find out what accesses this address

This type of search can read one of these structures (these are just examples):

mov eax,[rcx+00000470]

This structure only occurs if you do "Find out what accesses this address" and has the register (in this case, eax) placed in front of where our value is input. This means that the value previously found enters offset 470 (which is line/verse 1136 but written in hexadecimal) of the rcx register, and is then all placed into the eax register via the "mov" command.

or also:

mov [rcx+00000470],eax

In this structure, the value we found is placed into eax, which in turn is placed into the rcx register at offset 470.

What to do:

  1. Right-click on the found instruction, then click on "Find out what accesses this address."
  2. At this point, a screen will appear titled "The following opcodes accessed xxxxxxxxxxx," where the "x" will be replaced by a numerical value that represents the address to which Cheat Engine will try to read what accesses it.
  3. Depending on the type of cheat and the game, there may already be an "instruction" present at the top left under "Count", where you will see a count that increases over time. If there isn't, you may need to try performing an action/interaction; for example, if you're trying to modify the amount of ammunition, you will need to fire a shot to see what instruction is being read.
  4. Select the instruction you want to modify and click on "Show disassembler".
  5. Another screen will appear titled "Memory Viewer" where the modifiable instruction will be present.
  6. Without selecting other instructions on the "Memory Viewer" screen, click on "Tools" and then "Auto Assemble", or simply press Ctrl+A (which will directly open "Auto Assemble" without having to click on "Tools").
  7. At this point, another screen will appear titled "Auto Assemble". In this screen, click on "Template", then on "Cheat Table Framework Code", and finally click again on "Template" and then "Code Injection" (or just press Ctrl+Alt+T to then press Ctrl+I).
  8. A screen titled "Code inject template" will appear; just click "OK".
  9. Now the "Auto Assemble" screen will finally be populated, and we can start modifying the code to create our cheat, but it's advisable first to add it to the table. To do this, click on "File" and then "Assign to current cheat table".

Now we can finally modify our code, (click on "<script>" to open the Script)





B) Find out what writes to this address


This type of search can write only in this structure (these are just examples):

mov [rcx+00000470],eax


This type of instruction means that the value we previously found contained in eax is written to the rcx register at offset 470 through the command "mov".

What to do:

  1. Right-click on the found instruction, then click on "Find out what writes to this address".
  2. At this point, a screen will appear titled "The following opcodes write to xxxxxxxxxxx", where the "x" will be replaced by a numerical value that represents the address to which Cheat Engine will try to write what accesses it.
  3. Perform an action/interaction (like shoot, buy, sell, ecc...)
  4. Select the instruction you want to modify and click on "Show disassembler".
  5. Another screen will appear titled "Memory Viewer" where the modifiable instruction will be present.
  6. Without selecting other instructions on the "Memory Viewer" screen, click on "Tools" and then "Auto Assemble", or simply press Ctrl+A (which will directly open "Auto Assemble" without having to click on "Tools").
  7. At this point, another screen will appear titled "Auto Assemble." In this screen, click on "Template," then on "Cheat Table Framework Code," and finally click again on "Template" and then "Code Injection" (or just press Ctrl+Alt+T to then press Ctrl+I).
  8. A screen titled "Code inject template" will appear; just click "OK".
  9. Now the "Auto Assemble" screen will finally be populated, and we can start modifying the code to create our cheat, but it's advisable first to add it to the table. To do this, click on "File" and then "Assign to current cheat table".

Now you can modify the code (click on "<script>" to open the Script)







Method Two (AoB Method):


This is my preferred method, which is mainly used when you know that the game will be updated or for emulated games where the AOB changes every time the game is restarted (this often happens in PS2 games where the "direct" method cannot be used).

As a preamble, from now on, I will always use the "Find out what accesses this address" method (if you don't know what that means, please read the guide above) to find the instruction and then create the script.

  1. Select the value you previously found, right-click, and select "Find out what accesses this address".
  2. At this point, a screen will appear titled "The following opcodes accessed xxxxxxxxxxx", where the "x" will be replaced by a numerical value representing the address that Cheat Engine will try to read what accesses it.
  3. Depending on the type of cheat and the game, there may already be an "instruction" present at the top left under "Count," where you will see a count that increases over time. If there isn't, you may need to try performing an action/interaction; for example, if you're trying to modify the amount of ammunition, you will need to fire a shot to see which instruction is being read.
  4. Select the instruction you want to modify and click on "Show disassembler".
  5. Another screen will appear titled "Memory Viewer", where the modifiable instruction will be present.
  6. Without selecting other instructions on the "Memory Viewer" screen, click on "Tools" and then "Auto Assemble", or simply press Ctrl+A (which will directly open "Auto Assemble" without needing to click on "Tools").
  7. At this point, another screen will appear titled "Auto Assemble", In this screen, click on "Template", then on "AOB Injection" (or press Ctrl+Shift+A and you don't need to click on "Template").
  8. A screen titled "Code inject template" will appear; just click "OK".
  9. Now another screen named "Code inject template" will pop up where you can name the script. I strongly recommend doing this, replacing INJECT with the name you want to give to the script, for example, InfiniteAmmo or InfiniteMoney or OHK, which means One Hit Kill (I suggest naming it related to the cheat you want to create). Now, click "OK".
  10. Now the "Auto Assemble" screen will finally be populated, and we can start modifying the code to create our cheat, but it's advisable first to add it to the table. To do this, click on "File" and then "Assign to current cheat table".
Now you can modify the code (click on "<script>" to open the Script)








6) How to copy and paste elements from one Table to another


Useful if you want to merge two different tables (presumably from the same game, although some features may also be useful in other games, such as "Compact Mode" or "Auto Attach").

  1. Open both tables.
  2. Select an element in either of the two tables or multiple elements by holding down CTRL and then clicking on the desired elements with the left mouse button, or by holding down SHIFT to click on one element and then another one below (or above) it to select all those in between.
  3. Right-click and select "Copy".
  4. Click on the table to which you want to transfer the copied elements, right-click, and then select "Paste."






7) How to assign hotkeys to the elements in the Table


Useful for activating or deactivating a specific cheat without having to minimize the game screen. It can also be helpful for setting a specific value for a particular cheat.

  1. Select the element to which we want to assign a hotkey.
  2. After right-clicking on the selected element, click on "Set hotkeys" (or press Ctrl+H after selecting a specific element).
  3. Click on "Create hotkey".
  4. Click on the box that says "Type the keys you want to set the hotkey to" and press the key or key combination you want to set as the hotkey (if you make a mistake, just press "Clear" to empty the box).
  5. In the "Active sound" and "Deactivate sound" sections, you can set a beep to indicate whether the hotkey has been pressed (useful for knowing if the cheat has been enabled or disabled).
  6. Click on "Apply" and then "OK" to confirm everything.
  7. If you want to modify the hotkey, simply click on "Edit Hotkey" (or double-click on the previously assigned hotkey).
  8. If you want to delete the assigned hotkey, just select it and right-click on the hotkey, then select "Delete".




8) How to write and modify Code (code examples)


It primarily depends on what you want to accomplish. Below, I will provide examples of various types of code.

A) How to use "mov" to set your value

It primarily depends on what you want to accomplish. Below, I will provide examples of various types of code.


I will provide examples only for scripts created using the AoB method (which can be found earlier in this guide).

It is important to always indicate the correct type of value within the script, which is easily visible on the main Cheat Engine screen after the desired value has been found. There are several sections:

"Active" where you can activate and deactivate a specific cheat by checking the box (or you can freeze a specific number for your value).

"Description" where you can rename the cheat (or the header) as you wish.

"Address" which is the address where your value is located; normally, it should not be changed, and in most games, it is dynamic, meaning it changes with each restart of the game and sometimes even after every game load.

"Type" this section is very important because you choose how the value will be displayed in the Value section, and the types commonly used include: Float (decimal values), Double (very large values, separated into two parts), Byte: 0 to 255 (positive value) , 2 Bytes: 0 to 65,535 (positive) , 4 Bytes: 0 to 4,294,967,295 (positive) , 8 Bytes: 0 to 18,446,744,073,709,551,615 (positive).

Finally, "Value," which is the actual displayed value, can be replaced by "<script>" instead of a numerical value if it is a script instead of the found value or a pointer.

These examples are based on the value of ammunition, which is of type integer 4 Bytes to which I assign the value (int) 99.

↓↓↓

If an instruction with this structure is found:

mov eax,[rcx+00000470]

the code should be written like this:

[ENABLE]

aobscanmodule(Ammo,START.exe,8B 81 70 04 00 00 C3) // should be unique
alloc(newmem,$1000,Ammo)

label(code)
label(return)

newmem:

mov [rcx+00000470],(int)99

code:
mov eax,[rcx+00000470]
jmp return

Ammo:
jmp newmem
nop
return:
registersymbol(Ammo)

[DISABLE]

Ammo:
db 8B 81 70 04 00 00

unregistersymbol(Ammo)
dealloc(newmem)


Or like this:

[ENABLE]

aobscanmodule(Ammo,START.exe,8B 81 70 04 00 00 C3) // should be unique
alloc(newmem,$1000,Ammo)

label(code)
label(return)

newmem:

mov eax,(int)99
mov [rcx+00000470],eax
mov eax,[rcx+00000470]

code:
mov eax,[rcx+00000470]
jmp return

Ammo:
jmp newmem
nop
return:
registersymbol(Ammo)

[DISABLE]

Ammo:
db 8B 81 70 04 00 00

unregistersymbol(Ammo)
dealloc(newmem)


If a structure of this type is found (this type is usually write-type, meaning an action or interaction must occur to overwrite the value written in the script with the original one once the script is activated):

mov [rcx+00000470],eax

the code should be written like this:

[ENABLE]

aobscanmodule(Ammo,START.exe,89 81 70 04 00 00) // should be unique
alloc(newmem,$1000,Ammo)

label(code)
label(return)

newmem:

mov eax,(int)99

code:
mov [rcx+00000470],eax
jmp return

Ammo:
jmp newmem
nop
return:
registersymbol(Ammo)

[DISABLE]

Ammo:
db 89 81 70 04 00 00

unregistersymbol(Ammo)
dealloc(newmem)


Now I will provide an example of how to handle "movss," which is still a type of "mov." The value is a decimal value of type "Float" to which I will assign the numeric value (float) 9999.

↓↓↓

If a structure of this type is found:

movss xmm0,[rbx+00000528]

the code should be written like this:

[ENABLE]

aobscanmodule(Rope,START.exe,F3 0F 10 83 28 05 00 00 4C) // should be unique
alloc(newmem,$1000,Rope)

label(code)
label(return)

newmem:

mov [rbx+00000528],(float)9999

code:
movss xmm0,[rbx+00000528]
jmp return

Rope:
jmp newmem
nop 3
return:
registersymbol(Rope)

[DISABLE]

Rope:
db F3 0F 10 83 28 05 00 00

unregistersymbol(Rope)
dealloc(newmem)


Or it can also be written like this:

[ENABLE]

aobscanmodule(Rope,START.exe,F3 0F 10 83 28 05 00 00 4C) // should be unique
alloc(newmem,$1000,Rope)

label(code)
label(return)
label(InfRope)

newmem:

movss xmm0,[InfRope]
movss [rbx+00000528],xmm0
movss xmm0,[rbx+00000528]

code:
movss xmm0,[rbx+00000528]
jmp return

InfRope:
dd (float)9999

Rope:
jmp newmem
nop 3
return:
registersymbol(Rope)

[DISABLE]

Rope:
db F3 0F 10 83 28 05 00 00

unregistersymbol(Rope)
dealloc(newmem)


If the instruction is written with this structure:

movss [rcx+00000528],xmm1

the code should be written like this:

[ENABLE]

aobscanmodule(Rope,START.exe,F3 0F 11 89 28 05 00 00) // should be unique
alloc(newmem,$1000,Rope)

label(code)
label(return)
label(InfRp)

newmem:

movss xmm1,[InfRp]

code:
movss [rcx+00000528],xmm1
jmp return

InfRp:
dd (float)9999

Rope:
jmp newmem
nop 3
return:
registersymbol(Rope)

[DISABLE]

Rope:
db F3 0F 11 89 28 05 00 00

unregistersymbol(Rope)
dealloc(newmem)




Advanced Guide:

1) How to Auto Attach Cheat Engine to a Game

To perform the auto attach, there are at least two methods; I will try to explain both.

 

A) Auto Attach Script

With this method, we will create a script that, when activated, will automatically attach Cheat Engine to the game's process.

  1. Create a blank script. To do this, after opening Cheat Engine, you need to click on "Memory View," then "Tools," and then "Auto Assemble" (or simply press Ctrl+A). At this point, click on "Template" and then on "Cheat Table Framework Code" (or just press Ctrl+Alt+T). Now click on "File" (in the top left) and then on "Assign to current cheat table."
  2. Now that we have our cheat to compile, let's rename it as we prefer (I recommend something related, like "Auto Attach").
  3. Open the cheat by double-clicking on <script>, and at this point, you need to enter the code which is:
[ENABLE]
{$lua}
if syntaxcheck then return end

OpenProcess("Your Game Process Name.exe")

{$asm}

 
[DISABLE]

4. Obviously, instead of Your Game Process Name.exe, you will need to enter the name of the game's process.
5. To find the name of the process, you need to manually attach it (see point two of the "Beginner's Guide:"). After that, save the Cheat Engine table by clicking on "File" and then "Save As..." (or pressing Ctrl+Alt+S). At this point, copy the name of the saved file and replace "Your Game Process Name.exe" with it.

6. At this point, just activate the script to perform the auto-attach of the game to Cheat Engine.



B) Auto Attach Check


This method continuously monitors processes, searching for one with a specific name (defined in the code). For example, if Cheat Engine is launched before the game, it will continuously check if the game’s process is running. If it is, the game’s process will be automatically attached to Cheat Engine. This process will also occur if the game crashes or is closed; Cheat Engine will keep checking if the game’s process has restarted. If the game is restarted and the process is found, the auto-attach will be triggered again.


1. In the main screen of Cheat Engine, click on "Table" and then on "Show Cheat Table Lua Script" (or press Ctrl+Alt+L).

2. Then, simply paste this code:
function checkProcessStatus(procName) while true do if getProcessIDFromProcessName(procName) == nil then -- If the process is not found, update the label if getMainForm() then getMainForm().ProcessLabel.Caption = "No Process Selected" -- Update the label end break -- Exit the loop if the process is no longer there end sleep(1000) -- Check every second end end function monitorProcess(procName) while true do if getProcessIDFromProcessName(procName) == nil then -- If the process is not found, continue searching if getMainForm() then getMainForm().ProcessLabel.Caption = "Searching for Process: " .. procName -- Update the label end else -- If the process is found, open the process and start monitoring openProcess(procName) if getMainForm() then getMainForm().ProcessLabel.Caption = "Process Attached: " .. procName -- Update the label end checkProcessStatus(procName) -- Start monitoring the status end sleep(1000) -- Check every second end end local procName = ".exe" -- Start the main monitoring createThread(function() monitorProcess(procName) end)

3. Instead of    local procName = ".exe"   , you need to enter the name of the game's process, for example,    local procName = "Strike Team Hydra.exe".

4. At this point, simply save (with Ctrl+S or Ctrl+Alt+S) and restart Cheat Engine to begin executing the auto-attach.
 
 
 



2) How to find a specific value if you have a script

Basically, there are three methods to do this, and I will try to explain them.

A) Find with Module


Note that not all games have static modules, so this method does not always work. The modules can change with the game update.

  1. To find a value when you have already created a script previously, first you need to double-click on a <script> to access "Auto Assemble" (where you can modify the code).

  2. Look for the phrase // ORIGINAL CODE - INJECTION POINT: xxxxxx (the x's are replaced by the module) and copy the module, which could be something like GameName.exe+BA2A97.

  3. Click on "Memory View", then right-click anywhere and choose "Go to address".

  4. Paste the previously copied module and click "OK"; at this point, you will be transported directly to where that specific module is located.

  5. Right-click on the first result (which is the injection point of the module; in fact, if you look to the left, you can see the module) and select "Find out what addresses this instruction accesses".

  6. At this point, a screen will appear where you will find our value; just double-click on the value or right-click and then select "Copy selected addresses to addresslist".





B) Find with AoB

This method is a bit complex and requires a script created using the AoB method. Array of Byte (AoB) can change with the game update.

 

  1. To find a value when you have already created a script previously, first you need to double-click on a <script> to access "Auto Assemble" (where you can modify the code).

  2. Copy the array found just below [ENABLE] (it may look something like 8B B0 08 0B 00 00 48 85 DB 74 2D).

  3. In the section where you perform scans in Cheat Engine, select "Array of Byte" where it says "Value Type"; at this point, you need to paste the previously copied array.

  4. Below "Stop" in the scanning section, there is a checkbox labeled "Writable," which you need to double-click so it turns into a solid black square (which means it will scan all types of values, both writable and non-writable).

  5. Now click on "First Scan" and wait for Cheat Engine to complete the scan.

  6. Once the scan is complete, right-click on the result and select "Disassemble this memory region." Be careful; the injection point of the code may not correspond to the injection point of the array, so you need to select the correct injection point. Usually, just scrolling up with the middle mouse button is enough to select the correct injection point below.

  7. Right-click on the first result (if it is the injection point of the AoB code) and select "Find out what addresses this instruction accesses."

  8. At this point, a screen will appear where you will find our value; just double-click on the value or right-click and then select "Copy selected addresses to addresslist."

 

 

C) Find with simil Pointer


This method also works with non-AoB scripts.

First of all, I need to explain how to modify a script to create a Pointer.

  1. First, you need to double-click on a <script> to access "Auto Assemble" (where you can modify the code).

  2. Once in the script, above "newmem:", write label(YourNameHere) and registersymbol(YourNameHere). Remember to write everything attached without spaces for both label and registersymbol, and of course, they must have the same name.

  3. In "newmem:" (it works fine in code as well), write mov [YourNameHere], register (instead of register, you need to write the same register that is written in the first line under "code:"—that is the one in square brackets).

Example:
If "code:" says

mov esi,[rax+00000B08]

then in "newmem:" you should write

mov [YourNameHere], rax

If in "code:" it says

mov [ebx+28], esi

then you should write

mov [YourNameHere], ebx

  1. In the "code:" section, below "jmp return", you need to write YourNameHere: which is the name of your variable followed by a colon (you might also write dq 0 for 64-bit games and dd 0 for 32-bit games below this, but this is not necessary).

  2. Finally, in the [DISABLE] section, you need to add an unregistersymbol written as unregistersymbol(YourNameHere) or modify the existing unregistersymbol to put a * in place of what is written there (the name of the script), so you should write unregistersymbol(*). Now, the script is complete; just click "OK" to confirm everything.

  3. Click on "Add Address Manually," enter the name of your pointer, in this case, YourNameHere, and check the "Pointer" box. Where it says 0, place the correct offset that is written in "code:".

Example:

mov esi, [rax+00000B08]

instead of 0, you should put B08 (if there’s nothing written near the register, like mov esi,[rax], then you should leave it as 0). At this point, confirm everything by pressing "OK," and the pointer will be created.


Code Example:

[ENABLE]
aobscanmodule(Test,START.exe,8B B0 08 0B 00 00 48 85 DB 74 2D) // should be unique
alloc(newmem,$1000,Test)

label(code)
label(return)

label(seePointer)
registersymbol(seePointer)

newmem:

mov [seePointer],rax

code:
  mov esi,[rax+00000B08]
  jmp return

  seePointer:

Test:
  jmp newmem
  nop
return:
registersymbol(Test)

[DISABLE]
Test:
  db 8B B0 08 0B 00 00

unregistersymbol(*)
dealloc(newmem)

 


 

 

Now that we have our Pointer, we just need to activate the script, and we will be able to see the value we were looking for. You can also extract the value manually. To do this, you need to:

  1. Compile the pointer by activating the script. Under the "Address" section, double-click on the pointer (on something like P->223F73F6838) and copy the address.

  2. Click on "Add Address Manually" and paste the address, then press "OK."

 
 

 

3) How to Update an AoB Script

To update an AoB script, you need to take the old script, extract the AoB from it, which is found at the end of the script between the {} brackets in blue (this means it is commented out and commented-out code does not affect the functioning of the script). You do the same with the new script: extract the Array and then compare the differences between the two arrays; the parts that differ should be replaced with ? or ?? (you can also use x or xx).

Example:

Array of the old script:
0F B6 74 0D 00 48 89 35 3A D0 7B C8

Array of the new script:
0F B6 74 0C 00 48 89 35 E0 E0 7B C8

Final Array (to use in the script to be updated):
0F B6 74 0? 00 48 89 35 ?? ?0 7B C8

Personally, I like to use two ??, so in this case, you would get:
0F B6 74 ?? 00 48 89 35 ?? ?? 7B C8

or

0F B6 74 xx 00 48 89 35 xx xx 7B C8

is the same.

Now you just need to replace the array with the correct one (the aobscan is located just below [ENABLE]).

Example:

aobscan(Test,0F B6 74 0D 00) // should be unique

should be replaced with

aobscan(Test,0F B6 74 ?? 00 48 89 35 ?? ?? 7B C8) // should be unique


Be careful, if there are + signs (one under 'code' and one in [DISABLE]) next to the script name, it means that the original script ignored the code before the point where the injection point is actually allocated in memory to make modifications, which is what is below // ---------- INJECTING HERE ----------. If you do not put anything above this point, you need to remove the + (for example, +08) and its value; otherwise, the game will crash. On the other hand, if you do include something that is before // ---------- INJECTING HERE ----------, then you need to add the plus, count the bytes, and write it in hexadecimal...


 

Use this tool to extract the arrays:

https://sourceforge.net/projects/aob-comparator-extarctor-force/
 
 

4) How to Compare

Finally, we have arrived at the most problematic section.

First of all, you need to get used to checking the content of the script you want to use to understand if that part of memory also contains “unwanted” values. To do this, you need to follow these steps:

  1. Find the value if you haven't already. If you already have the script, follow the tutorial "How to find a specific value if you have a script", specifically points A and B (the tutorial is above).

  2. Now you need to right-click and select "Find out what accesses this address". Once the new window opens, choose an injection point and click on "Show Disassembler". Once you are here, right-click on the first element and select "Find out what addresses this instruction accesses".

  3. Here you can see if there are additional elements beyond what you previously found (such as enemy HP, enemy ammunition, opponent scores, etc...). Modifying the value with the script without a compare will also change the unwanted values.

 

A) How to compare using Dissect Data Structure

  1. To compare the data using "Dissect Data Structure," after right-clicking on the injection point in the "Memory View," you need to select "Find out what addresses this instruction accesses.” Once the data appears, you need to identify which is the correct value (by reading its value or its address), the one you want to change while excluding the others.

  2. Right-click on the chosen value and select "Open dissect data with selected addresses," then double-click on <New windows>. You can rename the dissect data if you wish, then click "OK" until the Dissect Data screen appears. Now hold down Ctrl and left-click to select the other values, then right-click on any value you want to exclude and select "Open dissect data with selected addresses." Choose "Structure Dissect:xxxxx" by double-clicking on it.

  3. Once this is done, click on "File" and then select "Save Values.” Give the file a name (for example, a1, or test1, or dissect1, etc.) and click "Save."

  4. At this point, you need to restart the game, reattach Cheat Engine to the game, find the desired value—the one you want to modify—and repeat the previous steps, saving a second file that will be compared with the first one. (The comparison can also be done manually by checking the differences between the first saved file and the dissected data opened after restarting the game, but I recommend using my tool, which I will post below.)

  5. Once the static value has been found (preferably 4 bytes, 2 bytes, but float and double are also acceptable) that is the same for both files (both dissected data), write in the script where it says "newmem:"


cmp [register+offset], (value type)value

                                          jne code

                                           

This means that the value of a certain type goes into the offset of a certain register (the offset to be inserted must be static, meaning it does not change when the game restarts) through the command cmp, while jne code means that the piece of code we do not want the script to execute will be executed if the value in the offset is the static and unique one; otherwise, it will execute what is written in "code:".

 Real Example:

 newmem:

{
The static value found is 1 in the offset 1FC in the register rcx (in this specific case, but it may vary in other scripts)
}

cmp [rcx+1FC], (int)1
jne code

mov r8d, (int)2000000
mov [rcx+00000508], r8d
jmp return

code:
mov [rcx+00000508], r8d
jmp return

 

 


 

 This is my Tool to use:
https://sourceforge.net/projects/auto-comparator-dissect-data/



Here I post a few links to learn how to do the compare without tools, for those who are a bit masochistic:


https://www.youtube.com/watch?v=oNMh7LYZ5yU

https://www.youtube.com/watch?v=H6eH6eSAL2w&list=PLkcoDCAtsJxLibqFRaL7AoH7uSyZbf0Eb

https://www.youtube.com/watch?v=-jBmeWXndKA






B) How to compare using Stacks:

Once we've found the value we want to modify and created a script for it, as usual, we need to check if other values besides the one we want to change are also being accessed at the injection point of the code.

I’ll skip the steps before the “Memory View” (they should already be known). In any case, once in “Memory View”, right-click on the correct injection point and select “Find out what addresses this instruction accesses”. Once you’ve identified the “unwanted” values, you can try to make the script ignore them.

To do this, follow these steps:

  1. Once you're in the window called “Accessed addresses by.....”, right-click on the value you want to modify.

  2. Click on “Show register states” and then left-click again on the “S” (if you hover over the “S” for a few seconds, a tooltip will appear showing “Stack view”).

  3. Once the “Stack View” window opens, right-click on any address and select the option “(RSP)”.

  4. After selecting the “(RSP)” option, select the very first element in the table and scroll to the bottom. Now hold down SHIFT and click on the last item in the list to highlight all elements in the table.

  5. Now right-click on the last item and select “Copy Line”.

  6. Paste everything you copied into a text file and save it with a name (for example: Player HP, Player Credits, Player Damage, etc.).

  7. At this point, select the value that you don’t want to be affected by the script, and repeat everything from step 1 to step 6. Just make sure to rename the files with clear and memorable names (e.g., Enemy HP, Enemy Credits, Enemy Damage, etc.).

  8. If there are other values, do the same process and restart the game.

  9. You’ll need to find the value you're working on again and repeat steps 1 to 7.

At this point, you can either use my tool to compare them automatically, or follow the video I posted below to do it manually.



Here is my Tool:
https://sourceforge.net/projects/auto-comparator-stack-viewce/


Video to do manually:
https://www.youtube.com/watch?v=D_i38SqjKBI




C) How to compare using Registers


This is another method to extract the static value we’re interested in, so we can perform the compare and exclude the changes to the values we don’t care about.

Premise: Personally, I use this method very rarely because it works infrequently, but it’s still necessary to know about it (you never know...).

  1. As usual, after pressing and selecting “Find out what addresses this instruction accesses” on the code injection point in the “Memory View,” the screen named “Accessed addresses by…..” will open, where there will be both the values you want to keep and those you want to exclude.

  2. Now, right-click on the (one or more) values you want to modify and select "Show register states."

  3. Once the “Registers” screen is open, right-click on any value and select "Copy all register values to clipboard."

  4. Paste everything into a text file, preferably with a name related to the content of your cheat (for example, P Hp V1, Only Money 1, My Score A, etc...) and save it.

  5. Close the register screen and repeat the process for all the values found in the “Accessed addresses by…..” screen, with the difference that for the values you want to exclude from the script’s modifications, it’s a good idea to give them an appropriate name (like Enemy Hp V1[V2, V3...], Other Currency 1, Others Score B, etc...) and save them in their respective text files.

  6. Restart the game and repeat the process up to step 5.

  7. If you have the tool, use it to compare, otherwise manually compare the values, being careful to keep the values that match the ones you want to modify, and ensure they’re different from the values you want to exclude.





Here is my Tool:
https://sourceforge.net/projects/auto-compare-registers-ce/


Video to do manually:
https://www.youtube.com/watch?v=7I5nUbcuQyQ




5) How to let set values to User:


To do this, you need to pay close attention while writing the code if you want to avoid game crashes.

There are two different cases in terms of code structure:

Case 1:

mov [register+offset], register
or
movss [register+offset], register (this could also be movsd and others...)

Real example:

mov [rbp+00000B08], eax
or

movss [rbx+00000B98], xmm1


Case 2:

mov register, [register+offset]
or
movss register, [register+offset]

Real example:

mov eax, [rbp+00000B08]
or
movss xmm1, [rbx+00000B98]



Now we can start defining what to do.

First, let's create some variable labels and registersymbol (the latter will be essential to allow the user to choose which value to set), and we can rename them however we want, but they must have the same name, and the name must be written all together (e.g., setMoney, changeHp, yourscore, etc.).

Example:


label(Test) registersymbol(Test)

Once the variables are defined, we can begin writing the code.



1) If the code has this structure:

mov [register+offset], register


Then, we should write the code like this:


[ENABLE] aobscanmodule(MaxPolpulationZa,$process,8B 85 08 0B 00 00 89 06 8B 85 10 0B) alloc(newmem,$1000,MaxPolpulationZa) label(code) label(return) label(TestA) registersymbol(TestA) newmem: mov eax,[TestA] mov [rbp+00000B08],eax jmp return code: mov [rbp+00000B08],eax jmp return TestA: dd (int)99 MaxPolpulationZa: jmp newmem nop return: registersymbol(MaxPolpulationZa) [DISABLE] MaxPolpulationZa: db 8B 85 08 0B 00 00 unregistersymbol(*) dealloc(newmem)



2) If the code has this structure:

mov register, [register+offset]


Then, we should write the code like this:


[ENABLE] aobscanmodule(MaxPolpulationZa,$process,8B 85 08 0B 00 00 89 06 8B 85 10 0B 00 00 89 01 48) alloc(newmem,$1000,MaxPolpulationZa) label(code) label(return) label(TestB) registersymbol(TestB) newmem: mov eax,[TestB] mov [rbp+00000B08],eax mov eax,[rbp+00000B08] jmp return code: mov eax,[rbp+00000B08] jmp return TestB: dd (int)99 MaxPolpulationZa: jmp newmem nop return: registersymbol(MaxPolpulationZa) [DISABLE] MaxPolpulationZa: db 8B 85 08 0B 00 00 unregistersymbol(*) dealloc(newmem)


But instead of:


mov eax,[Test] mov [rbp+00000B08],eax mov eax,[rbp+00000B08] jmp return


You can also write:

a;

push ecx mov ecx,Test mov rcx,dword ptr [ecx] mov [rbp+00000B08],ecx pop ecx

If it’s a 64-bit game, replace ecx with rcx.


b;

push eax push ebx mov eax,eax mov ebx,Test mov ecx,[ebx] mov [rbp+00000B08],ebx pop ebx pop eax

If it’s a 64-bit game, replace ebx and eax with rbx and rax.


c;

push rbx mov ebx,[Test] mov [rbp+00000B08],ebx pop rbx



You also need to be careful not to use the same registers that are in the code: otherwise, the game crashes.









Here is the Lua code to put in "Show cheat table Lua script" to ensure that the value set by the user is preserved.


local targetSymbols = {"setItemsQuantityOnUse", "addMoreWepExp", "subAragamiHpOnHit", "etc..."} local userDefinedValues = {} -- Table to store user values local lastValidAddresses = {} -- Table for valid addresses local monitorTimer = createTimer(nil, true) monitorTimer.Interval = 250 -- More responsive check -- File path local userValuesFilePath = "C:\\userValues.txt" -- You can change path -- Function to get a valid address local function getValidAddress(symbol) return getAddressSafe(symbol) end -- Function to check if an address is a float local function isFloatValue(address) return address % 4 == 0 -- Simple example: float addresses will be multiples of 4 end -- Function to save values local function saveValues() local file, err = io.open(userValuesFilePath, "w") if not file then return end for symbol, value in pairs(userDefinedValues) do file:write(string.format("%s=%s\n", symbol, tostring(value))) end file:close() end -- Function to load saved values local function loadValues() local file = io.open(userValuesFilePath, "r") if not file then file = io.open(userValuesFilePath, "w") file:close() return end for line in file:lines() do local symbol, value = line:match("([^=]+)=([^=]+)") if symbol and value then local numValue = tonumber(value) if numValue then userDefinedValues[symbol] = numValue -- Ensure to store the numeric value else userDefinedValues[symbol] = value -- Or the string value end end end file:close() end -- Monitoring function monitorTimer.OnTimer = function() for _, targetSymbol in ipairs(targetSymbols) do local currentAddr = getValidAddress(targetSymbol) if currentAddr and currentAddr ~= 0 then if lastValidAddresses[targetSymbol] == nil or currentAddr ~= lastValidAddresses[targetSymbol] then -- Address changed (script reenabled) if userDefinedValues[targetSymbol] then -- Overwrite with user value if isFloatValue(currentAddr) then writeFloat(currentAddr, userDefinedValues[targetSymbol]) else writeInteger(currentAddr, userDefinedValues[targetSymbol]) end end lastValidAddresses[targetSymbol] = currentAddr else -- Read the current value from the GUI local guiValue if isFloatValue(currentAddr) then guiValue = readFloat(currentAddr) else guiValue = readInteger(currentAddr) end -- Update the user value if changed if userDefinedValues[targetSymbol] ~= guiValue then userDefinedValues[targetSymbol] = guiValue saveValues() -- Save the values whenever they change end end else lastValidAddresses[targetSymbol] = nil -- Reset if the script is disabled end end end -- Initialization function local function initialize() loadValues() -- Load saved values for _, targetSymbol in ipairs(targetSymbols) do local initialAddr = getValidAddress(targetSymbol) if initialAddr and initialAddr ~= 0 then if isFloatValue(initialAddr) then userDefinedValues[targetSymbol] = userDefinedValues[targetSymbol] or readFloat(initialAddr) writeFloat(initialAddr, userDefinedValues[targetSymbol]) else userDefinedValues[targetSymbol] = userDefinedValues[targetSymbol] or readInteger(initialAddr) writeInteger(initialAddr, userDefinedValues[targetSymbol]) end lastValidAddresses[targetSymbol] = initialAddr end end saveValues() -- Immediately save current values at startup end -- Function to stop monitoring function stopMonitor() if monitorTimer then monitorTimer.destroy() end end -- Initialize the script initialize() monitorTimer.OnTimer()







6) How to activate a cheat with a separate script:


To do this, you need to define the variable above newmem that will enable or disable the cheat, using alloc and registersymbol.


Example:

alloc(StartWhenActiveSecondScript,4) // Or you need to set 8 for 64-bit games
registersymbol(StartWhenActiveSecondScript)

StartWhenActiveSecondScript:
db 0 // This means the initial state of the second cheat is 0, i.e., disabled

newmem:

// In newmem we write the initialization of the second script

cmp [StartWhenActiveSecondScript],1 // When we enable the script, this is set to 1
jne code

// Write the modifications to the code here...

code:

// Here is the original code


Once the main code structure is set up, we can write the secondary code by clicking on "Memory View", then "Tools", then "Auto Assemble", and finally "Cheat Table Framework Code". Now, click on "File" and then select "Assign to current cheat table". Once we have added the script to our table, we can modify it by writing:

[ENABLE]

StartWhenActiveSecondScript:
db 1

[DISABLE]

StartWhenActiveSecondScript:
db 0

This will activate the changes to our main script when the secondary script is enabled.


Of course, the name I gave to the variable, "StartWhenActiveSecondScript," can be changed as you wish, as long as it is written all together without spaces.










7) How to merge two different scripts:

To merge two different scripts into one, you need to modify them by replacing "code", "return", and "newmem" with other names, such as "codeB", "returnB", and "newmemB."

Copy the content from the modified script into the other script, making sure to copy and paste the pieces of code in the correct locations. For example:


[ENABLE]

//Code 1
aobscanmodule(ClipAmmo,START.exe,8B 81 70 04 00 00 C3) // should be unique
alloc(newmem,$1000,ClipAmmo)

label(code)
label(return)

//Code 2
aobscanmodule(AllAmmo,START.exe,8B 81 7C 04 00 00) // should be unique
alloc(newmemB,$1000,AllAmmo)

label(codeB)
label(returnB)


//Code 1
newmem:

mov [rcx+00000470],(int)200

code:
  mov eax,[rcx+00000470]
  jmp return

ClipAmmo:
  jmp newmem
  nop
return:
registersymbol(ClipAmmo)



//Code 2
newmemB:

mov [rcx+0000047C],(int)9999

codeB:
  mov eax,[rcx+0000047C]
  jmp returnB

AllAmmo:
  jmp newmemB
  nop
returnB:
registersymbol(AllAmmo)



[DISABLE]

// Code 1
ClipAmmo:
  db 8B 81 70 04 00 00

unregistersymbol(ClipAmmo)
dealloc(newmem)

// Code 2
AllAmmo:
  db 8B 81 7C 04 00 00

unregistersymbol(AllAmmo)
dealloc(newmemB)






8) How to implement an overlay on your screen:

To implement an Overlay in Cheat Engine, you need to insert a Lua script into an "empty" script. You can create an empty script by clicking on "Memory View," then "Tools," then "Auto Assemble," and finally "Cheat Table Framework Code." Now, click on "File" and then select "Assign to current cheat table." Once the script is added to our table, we can modify it by writing:

[ENABLE] {$lua} if overlayForm == nil then -- Create overlay window overlayForm = createForm(true) overlayForm.Caption = 'Overlay PointerValue' overlayForm.Color = clBlack overlayForm.BorderStyle = 'bsNone' overlayForm.AlphaBlendValue = 200 overlayForm.AlphaBlend = true overlayForm.Width = 270 overlayForm.Height = 50 overlayForm.Left = 0 overlayForm.Top = 0 overlayForm.Enabled = false -- Disable mouse interactions -- Label for Pointer value local label = createLabel(overlayForm) label.Caption = 'PointerValue: 0' label.Font.Color = clWhite label.Font.Size = 24 label.Left = (overlayForm.Width - label.Width) / 2 label.Top = (overlayForm.Height - label.Height) / 2 -- Timer for updating PointerValue overlayTimer = createTimer(nil) overlayTimer.Interval = 100 overlayTimer.OnTimer = function() local pointerRecord = getAddressList().getMemoryRecordByDescription("YourPointerDescription") -- Change "PointerValue" to your exact pointer description if pointerRecord then label.Caption = 'PointerValue: ' .. tostring(pointerRecord.Value) end end -- References for focus control local CEHandle = getMainForm().Handle local lastActive = 0 -- Timer for priority management overlayFocusTimer = createTimer(nil) overlayFocusTimer.Interval = 50 overlayFocusTimer.OnTimer = function() local activeWindow = getForegroundWindow() if activeWindow == CEHandle then if lastActive ~= 1 then overlayForm.FormStyle = 'fsNormal' getMainForm().BringToFront() lastActive = 1 end else if lastActive ~= 2 then overlayForm.FormStyle = 'fsStayOnTop' overlayForm.BringToFront() lastActive = 2 end end end overlayForm.show() end {$asm} [DISABLE] {$lua} if overlayFocusTimer ~= nil then overlayFocusTimer.destroy() overlayFocusTimer = nil end if overlayTimer ~= nil then overlayTimer.destroy() overlayTimer = nil end if overlayForm ~= nil then overlayForm.destroy() overlayForm = nil end {$asm}

Once the code is inserted, you need to modify the part:

local pointerRecord = getAddressList().getMemoryRecordByDescription("YourPointerDescription")


Just replace "YourPointerDescription" with the content of the pointer description that you want to display on the screen.

Of course, you also need to have created a pointer beforehand. To do that, simply follow the guide I wrote above, specifically in Section 2, see point C of the advanced tutorial.




Top Right:
        
[ENABLE]
{$lua}
if overlayForm ~= nil then
    overlayForm.Left = getScreenWidth() - overlayForm.Width
    overlayForm.Top = 0
end
{$asm}

[DISABLE]



Top Left:

[ENABLE]
{$lua}
if overlayForm ~= nil then
    overlayForm.Left = 0
    overlayForm.Top = 0
end
{$asm}

[DISABLE]



Center Right:

[ENABLE]
{$lua}
if overlayForm ~= nil then
    overlayForm.Left = getScreenWidth() - overlayForm.Width
    overlayForm.Top = (getScreenHeight() - overlayForm.Height) // 2
end
{$asm}
[DISABLE]

Center Left:

[ENABLE]
{$lua}
if overlayForm ~= nil then
    overlayForm.Left = 0
    overlayForm.Top = (getScreenHeight() - overlayForm.Height) // 2
end
{$asm}
[DISABLE]



Bottom Right:

[ENABLE]
{$lua}
if overlayForm ~= nil then
    overlayForm.Left = getScreenWidth() - overlayForm.Width
    overlayForm.Top = getScreenHeight() - overlayForm.Height
end
{$asm}
[DISABLE]




Bottom Left:

[ENABLE]
{$lua}
if overlayForm ~= nil then
    overlayForm.Left = 0
    overlayForm.Top = getScreenHeight() - overlayForm.Height
end
{$asm}
[DISABLE]






You need to remember to set the screen to "Borderless" because it doesn't work in "Fullscreen."












...
 
 


Comments