Cheat Engine Forum Index Cheat Engine
The Official Site of Cheat Engine
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 


Tips you may not know.

 
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine Tutorials
View previous topic :: View next topic  
Author Message
Dread Pony Roberts
How do I cheat?
Reputation: 0

Joined: 12 Dec 2018
Posts: 6

PostPosted: Tue Oct 06, 2020 10:46 pm    Post subject: Tips you may not know. Reply with quote

This isn't meant to be a "your first table" tutorial, but it is instead a collection of methods that I have picked up over time. I will try to explain them as best as I can, but if you don't understand them then it is likely you still have more to learn.



How to update proof static address
Let's say your game has your health on a static address. Good, no need for pointers. The bad news is that the game keeps getting updates, and each update changes the static address location. What do you do?

If your address is ever read by code similar to this, even once, then you are in luck.
Code:
8B 0D 58129500        - mov ecx,[LEGOStarWarsSaga.exe+551258]


The address is right there in the bytes (58129500), all you need to do is read it.
Since you're just reading the bytes and not manipulating them, your script will be very simple.

Code:

[ENABLE]
aobscanmodule(Minikit_Reader,LEGOStarWarsSaga.exe,50 ?? ?? ?? ?? ?? ?? ?? ?? 51 83 EC 08 D9 5C 24 04)
alloc(minikit_base,4)
registersymbol(minikit_base)

minikit_base:
readmem(Minikit_Reader+5,4)

[DISABLE]
unregistersymbol(Minikit_Reader)
dealloc(minikit_base)
unregistersymbol(minikit_base)


readmem is the main function of the script. The +5 tells the readmem to read the bytes 5 bytes ahead of the aobscan, and the ,4 tells it to read the next 4 bytes. minikit_base will be the base pointer address that would be used in this table.
If done right the static address would work even if the game gets updated.



Easy player compare
Let's say your health and the enemy's health is being written to by the same address. Most methods I've seen involve going through the player and enemy structures to find one difference between them. While it is a useful method to know and can work if all else fails, there is an easier method which I believe is best to try first.

I've found that the player base is often addressed by an address which only addresses that one address (what a tongue twister). Basically, if you can find a code which only accesses the player base, and nothing else, then you have an easy compare.
If there's nothing which only addresses the player base, then it is still likely that something only addresses one of the offsets of the player base. Then you could still find the player base using that.

The script should look something like this.
Code:
aobscanmodule(Player_Base_Reader,halo3.dll,41 0F B7 4D 00 48 8D) // should be unique
alloc(newmem1,$100,"halo3.dll"+38B347)
alloc(p_base,8)
registersymbol(p_base)

label(code1)
label(return1)

newmem1:
  mov [p_base],r13
code1:
  movzx ecx,word ptr [r13+00]
  jmp return1

Player_Base_Reader:
  jmp newmem1
return1:
registersymbol(Player_Base_Reader)


All this script does is moves the player base (which is always in r13) into [p_base].

A later script could be
Code:

cmp [p_base],rbx
jne code


This would only allow the player address to go through, filtering out all other bases.



Advanced Methods
The following methods are for more advanced users, and as such I won't put as much time into trying to explain their finer details.
(basically this is my way of saying that I'm too lazy to explain everything in full detail)



Manipulator
Sometimes you just a general work script. This is a script which is always active and can be used to write max health to the player, save coordinates for teleportation, and whatever else you need.
This can be accomplished by using a lua timer, or making a new thread. But to keep it simple and in assembly, I just make a script from some code that is always active.

For safety sake, I like to push all the registers to keep everything I'm doing contained.

If you do something like
Code:
mov rax,[p_base]

be sure to add a compare to prevent it from being used when that base hasn't been read yet, else the game will crash.
Code:
cmp [p_base],0
je code




Teleportation
Code:
coordinate_save:
cmp byte ptr [save+0],1
jne @f
mov byte ptr [saved+0],1
mov byte ptr [save+0],0
mov eax,[r9+70]
mov [coordinates+0],eax
mov eax,[r9+74]
mov [coordinates+4],eax
mov eax,[r9+78]
mov [coordinates+8],eax
@@:
cmp byte ptr [save+1],1
jne @f
mov byte ptr [saved+1],1
mov byte ptr [save+1],0
mov eax,[r9+70]
mov [coordinates+C],eax
mov eax,[r9+74]
mov [coordinates+10],eax
mov eax,[r9+78]
mov [coordinates+14],eax
@@:
cmp byte ptr [save+2],1
jne @f
mov byte ptr [saved+2],1
mov byte ptr [save+2],0
mov eax,[r9+70]
mov [coordinates+18],eax
mov eax,[r9+74]
mov [coordinates+1C],eax
mov eax,[r9+78]
mov [coordinates+20],eax
@@:

teleportation:
cmp byte ptr [teleport+0],1
jne @f
cmp byte ptr [saved+0],1
jne @f
mov byte ptr [teleport+0],0
mov eax,[coordinates+0]
mov [r9+70],eax
mov eax,[coordinates+4]
mov [r9+74],eax
mov eax,[coordinates+8]
mov [r9+78],eax
@@:
cmp byte ptr [teleport+1],1
jne @f
cmp byte ptr [saved+1],1
jne @f
mov byte ptr [teleport+1],0
mov eax,[coordinates+C]
mov [r9+70],eax
mov eax,[coordinates+10]
mov [r9+74],eax
mov eax,[coordinates+14]
mov [r9+78],eax
@@:
cmp byte ptr [teleport+2],1
jne @f
cmp byte ptr [saved+2],1
jne @f
mov byte ptr [teleport+2],0
mov eax,[coordinates+18]
mov [r9+70],eax
mov eax,[coordinates+1C]
mov [r9+74],eax
mov eax,[coordinates+20]
mov [r9+78],eax
@@:


This is a teleportation script of mine. save is the flag that tells the script that I wish to save my coordinates. saved is the flag that prevents the teleportation from working if no coordinates have been saved (to prevent you from accidentally teleporting to 0,0,0). teleport is the flag that tells the script that I wish to teleport. coordinates are the saved coordinates. Lastly, the teleport and save flags are internally disabled, this is to ensure that the scripts are only used once until the flag is reset.



How to make a script disable from table view
Basically, this will make the checkmark go away as soon as the script is enabled. This is useful for teleportation since you'd want it to reset as soon as you pressed the button.

Code:

[Enable]
{$lua}
memrec.OnActivate = function(memrec, preState, curState)
  if (not preState) and curState then
    local t = createTimer()
    t.Interval = 100
    t.OnTimer = function(t)
      t.destroy() -- destroy timer so it doesn't run again
      memrec.Active = false -- disable this script
    end
  end
  return true -- don't interrupt, not sure how it'd be handled...
end
{$asm}

save+0:
db 1

[Disable]




On Hotkey Press
Some scripts you want to only run while a specific hotkey is pressed. It is easier to do it in lua, but it is still very possible in assembly.

Code:
  push RAX
  push RCX
  push RDX
  push R8
  push R9
  push R10
  push R11
  sub rsp,28
  mov rcx,[bind]
  call GetAsyncKeyState
  add rsp,28
  pop r11
  pop r10
  pop r9
  pop r8
  pop rdx
  pop rcx
  test ax,8001
  pop rax
  jz @f
  (your code you wish to use here)
  @@:

The most important part of this code is the bind that is being moved to rcx. You can set it directly in the script, but I prefer to make it easily customizable for the user. To make it customizable, you will want to alloc 4 bytes and registersymbol the bind. Then in the script that enables this one is where the user can set their bind.

Code:
bind:
db A0


The byte corresponds to a virtual key code. A list of them can be easily googled.

20=Spacebar
A0=Left Shift key
26=Up Arrow Key
49=I Key
A2=Left Control Key
A4=Left Alt Key
ect...



Flight
Flight is one of my most complicated scripts but I'll try to explain some of the basics.

First you will need to find and set the ground flag to whatever registers the player as on the ground, or else you will be flying but have little control (halo will even have you die because you've been "falling" for too long. You will also need to prevent anything else from writing to your z direction, or else you will slowly fall as this script tries to counter the game's code.

Code:

  cmp byte ptr [flight_smoother],1
  je Flight_Up
  cmp byte ptr [flight_smoother],2
  je Flight_Down

Flight_Up:
  push RAX
  push RCX
  push RDX
  push R8
  push R9
  push R10
  push R11
  sub rsp,28
  mov rcx,[up_bind]
  call GetAsyncKeyState
  add rsp,28
  pop r11
  pop r10
  pop r9
  pop r8
  pop rdx
  pop rcx
  test ax,8001
  pop rax
  jz @f
  fld [r9+F8]
  fadd [flight_speed]
  fstp [r9+F8]
  mov byte ptr [flight_smoother],1
  jmp flight_end
@@:
  mov byte ptr [flight_smoother],0

Flight_Down:
  push RAX
  push RCX
  push RDX
  push R8
  push R9
  push R10
  push R11
  sub rsp,28
  mov rcx,[down_bind]
  call GetAsyncKeyState
  add rsp,28
  pop r11
  pop r10
  pop r9
  pop r8
  pop rdx
  pop rcx
  test ax,8001
  pop rax
  jz @f
  fld [r9+F8]
  fsub [flight_speed]
  fstp [r9+F8]
  mov byte ptr [flight_smoother],2
  jmp flight_end
@@:
  mov byte ptr [flight_smoother],0

flight_end:

I try to keep the movement speed customizable using the same method as for the bind, this way the user can increase the speed easily.
flight_smoother is very important, it prevents one movement direction from having priority over the other. If this is removed, the up direction would always take priority over the down direction.



Built in Cheat Engine scripts
Here's some scripts to enable built in Cheat Engine features.

Compact Mode
Code:
[ENABLE]
LuaCall(function cycleFullCompact(sender,force) local state = not(compactmenuitem.Caption == 'Compact View Mode'); if force~=nil then state = not force end; compactmenuitem.Caption = state and 'Compact View Mode' or 'Full View Mode'; getMainForm().Splitter1.Visible = state; getMainForm().Panel4.Visible    = state; getMainForm().Panel5.Visible    = state; end; function addCompactMenu() if compactmenualreadyexists then return end; local parent = getMainForm().Menu.Items; compactmenuitem = createMenuItem(parent); parent.add(compactmenuitem); compactmenuitem.Caption = 'Compact View Mode'; compactmenuitem.OnClick = cycleFullCompact; compactmenualreadyexists = 'yes'; end; addCompactMenu(); cycleFullCompact(nil,true))

[DISABLE]
LuaCall(cycleFullCompact(nil,false))


Speedhack
Code:
[Enable]
{$lua}
memrec.OnActivate = function(memrec, preState, curState)
  if (not preState) and curState then
    local t = createTimer()
    t.Interval = 100
    t.OnTimer = function(t)
      t.destroy() -- destroy timer so it doesn't run again
      memrec.Active = false -- disable this script
    end
  end
  return true -- don't interrupt, not sure how it'd be handled...
end
{$asm}

LUACALL(speedhack_setSpeed(0.5)) {Edit this number to change speed}

[Disable]

_________________
How fair is it that you are the only one with a One Hit Kill? What if the AI had just as much power? That would definitely make the gameplay a bit more...EXTREME!
Back to top
View user's profile Send private message
sandsmaster
Newbie cheater
Reputation: 1

Joined: 21 Jan 2021
Posts: 24

PostPosted: Sun Sep 26, 2021 7:59 pm    Post subject: Reply with quote

Thanks for the tutorial. These are some great pieces of info on how to write cheats. Nothing too complex, but useful indeed. I'll definitely add some to my cheat-belt for the next games I try Smile.
Thanks again.
Cheers!

_________________
I don't post too much. yet.
Back to top
View user's profile Send private message Send e-mail
gibberishh
Cheater
Reputation: 1

Joined: 30 Aug 2021
Posts: 45

PostPosted: Wed Jun 22, 2022 5:37 am    Post subject: Re: Tips you may not know. Reply with quote

Dread Pony Roberts wrote:
Here's some scripts to enable built in Cheat Engine features.

Since you've included Lua code too, this is code that I always include in all my tables:
Code:
function Disconnect(sender)
  local addressList = getAddressList()
  for i=addressList.Count-1,0,-1 do addressList[i].Active = false end
  closeCE()
end
getMainForm().onClose = (Disconnect)

It goes about disabling every record from the bottom of the table to the top. This is important for scripts that manipulate memory. Without such a script, if you close a table with a few cheats active, you won't be able to disable/enable them any more until you restart the game. This script makes sure that all the [DISABLE] scripts (of any active cheats) are executed before CE is closed, so the user can close and open the table as many times as they like.
I've accidentally closed cheat tables several times when meaning to close a web browser or some other window instead!

_________________
It's not cheating. It's playing by my rules.
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine Tutorials All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Powered by phpBB © 2001, 2005 phpBB Group

CE Wiki   IRC (#CEF)   Twitter
Third party websites