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: Select all
8B 0D 58129500 - mov ecx,[LEGOStarWarsSaga.exe+551258]
Since you're just reading the bytes and not manipulating them, your script will be very simple.
Code: Select all
[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)
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: Select all
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)
A later script could be
Code: Select all
cmp [p_base],rbx
jne code
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: Select all
mov rax,[p_base]
Code: Select all
cmp [p_base],0
je code
Teleportation
Code: Select all
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
@@:
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: Select all
[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: Select all
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)
@@:
Code: Select all
bind:
db A0
[Link]
20=Spacebar
A0=Left Shift key
26=Up Arrow Key
49=I Key
A2=Left Control Key
A4=Left Alt Key (It is also called the Left Menu Key in the website)
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: Select all
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:
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: Select all
[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))
Code: Select all
[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]