Cube World Reversing - Cheat UI & LocalPlayer
Table of Contents
Cube World Reversing - This article is part of a series.
Setting up the Cheat UI #
The first thing we need to do is set up a menu for our cheat, the most common technique is to hook DirectX
and integrate ImGui
to make our menu. We can try this approach as Cube World uses DirectX 11
.
After trying different techniques, the hook works but it breaks the Cube World rendering.
As you can see, we cannot use this technique to create our menu.
The second solution is to create a new window with DirectX 11
and integrate ImGui
, the menu will be on an external window but the cheat will still be internal.
To do this I will use my project and compile it as DLL
, you can look at the project, everything is set up and you just have to choose if you want to compile it as DLL
or EXE
.
D3D11 ImGui External (x86 / x64) - EXE / DLL ImGui External Menu
Now the UI is set up and our cheat is internal, so it will be developed as a DLL
.
Finding out the address of the LocalPlayer #
The best thing to do now is to get the LocalPlayer
.
In my opinion the best way to find the LocalPlayer
address is to :
- Find the health (scan then lose life, scan, repeat…).
- Check which instruction writes to this address with Cheat Engine.
- Then subtract the health address with the health offset we found.
So the first thing we need to do now is scan for health. In my case my character has 128hp
, you should note that health in Cube World is a float
.
Then I take some fall damage to lower my health. Then I rescan my health with the new value and remove false addresses.
Next, when there are only a few addresses left, I test the addresses by changing or blocking their values. To find the good address, I looked at the change in value.
Now, to see which instruction writes to the health address, I attach the Cheat Engine debugger.
After decreasing my health again with fall damage we can see the instructions that write to the health address.
We have the instruction that writes to the address, as you can see the R13
register contains the address of the LocalPlayer
and the health offset is 0x180
. I chose this instruction because after some investigation this corresponds to the fall damage calculation and the health decrease, a good clue is the count
, since I only take fall damage once, the third instruction is the best candidate.
Finally we got the LocalPlayer
and the health address and offset.
Since the LocalPlayer
address or the health address are not static addresses, we need to find a way to retrieve the LocalPlayer
address each time the game starts. There are several techniques to do this, such as pointer scan, hook…
Hook the game loop #
Trying pointer scan #
The first approach when trying to find a static address is to retrieve the LocalPlayer
and then do a pointer scan after restarting the game.
Pointer scan is basically brute forcing offsets, I will not explain how it works, it is a basic technique and you can find lots of resources on Google.
If you don’t know how to do a pointer scan with Cheat Engine
look at this. In my case I had no result with the pointer scan, every time I restarted the game the formers addresses were invalid.
Look into the game #
Previously we found an instruction that modifies our health, with this logic the game must retrieve the LocalPlayer
to modify his health. So we can try to find out how the game finds the LocalPlayer
. We can start by looking at the instruction we found before, which is at :
cubeworld.exe + 0x2BEC30
inCheat Engine
and0x1402BEC30
inIDA
0x1402BEC23 movss xmm0, dword ptr [r13+180h]
0x1402BEC2C subss xmm0, xmm6
0x1402BEC30 movss dword ptr [r13+180h], xmm0
Decompilation :
*(float*)(player + 0x180) = *(float*)(player + 0x180) - fall_damage;
To retrieve the address of the LocalPlayer
we need to find out in IDA
where the R13
register is set in the function. We can see that the R13
register is set at :
cubeworld.exe + 0x2BB969
inCheat Engine
and0x1402BB969
inIDA
0x1402BB969 mov r13, rdx
Decompilation :
player = param_2
Since the game architecture is x64
, this means that RDX
is the second parameter of the function according to the x64 calling convention and it implies that RDX
is an INT64
.
To confirm that we have successfully retrieved the LocalPlayer
by hooking this function, we can set a breakpoint at this address and look at the value of RDX
.
As we have successfully retrieved the address of the LocalPlayer
, we should find the character’s health at offset 0x180
, which is the case here.
Unfortunately, when we try to change the health of the character using Cheat Engine
, the health is not updated and this has no effect. So this address seems to be a “copy” of the LocalPlayer
.
Find another way #
Even if the first attempt was not successful, it is not a problem, the game needs to retrieve the LocalPlayer
in many places. Fortunately, when I was looking for fall damage, I found another offset, LocalPlayer + 0x3C
, which gives the “sum of gravitational forces”, I explain:
If the float
at LocalPlayer + 0x3C
is positive, the Z axis
of the LocalPlayer
will increase, otherwise if the value is negative, the LocalPlayer
will decrease. When your player jumps, the value is set to 10.0f
. This is the code that makes your character jump by changing the value of the Z axis
.
cubeworld.exe + 0x9D443
inCheat Engine
and0x14009D443
inIDA
Decompilation :
*(uint32_t*)(*(uint64_t*)(*(uint64_t*)(first_parameter + 0x8) + 0x448) + 0x3C) = 10.0f;
With the code above we can easily analyse how the game retrieves the LocalPlayer
and then puts it into the RCX
register. Then make the character jump by setting the value at RCX + 3C
to 0x41200000
which is 10.0f
in hexadecimal.
Here is the code to retrieve the LocalPlayer
:
mov rax, [rdi+8]
mov rcx, [rax+448h]
Decompilation :
uint64_t LocalPlayer = *(uint64_t*)(*(uint64_t*)(first_parameter + 0x8) + 0x448);
As before we can try to get the LocalPlayer
using a breakpoint in the Cheat Engine
debugger.
As you can see, we have successfully retrieved the LocalPlayer
and can now modify the health or gravity value. The last step is to hook the function and get the LocalPlayer
using the first argument of the function we found earlier.
Cube World Reversing & Cheat (x64) - Include IDA file and unpacked game