Skip to main content

Cube World Reversing - Cheat UI & LocalPlayer

·1245 words·6 mins
Game Hacking Reverse Engineering
Cube World Reversing - This article is part of a series.
Part 2: This Article

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.

Cube World ImGui
Cube World rendering breaks when ImGui menu is injected.

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.

adamhlt/ImGui-Standalone

D3D11 ImGui External (x86 / x64) - EXE / DLL ImGui External Menu

C++
217
35

Cube World External
Using external windows we keep the cheat internal and the rendering is fine.

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 :

  1. Find the health (scan then lose life, scan, repeat…).
  2. Check which instruction writes to this address with Cheat Engine.
  3. 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.

Scan 1
First scan for health in Cheat Engine.

Then I take some fall damage to lower my health. Then I rescan my health with the new value and remove false addresses.

Scan 2
A few addresses remain after several scans.

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.

Scan 3
I kept the address which is valid and filled the life bar of my character.

Now, to see which instruction writes to the health address, I attach the Cheat Engine debugger.

Scan 4
The debugger is attached, we just need to change the health value to see instructions.

After decreasing my health again with fall damage we can see the instructions that write to the health address.

Scan 5
Few instructions write to 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.

Scan 7
Details of the instruction.

Finally we got the LocalPlayer and the health address and offset.

Scan 8
Adress of the LocalPlayer in Cheat Engine.

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 in Cheat Engine and 0x1402BEC30 in IDA

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 in Cheat Engine and 0x1402BB969 in IDA

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.

Debug 1
Breakpoint hit in the Cheat Engine debugger.
Reclass 1
Analysis of the retrieved address in ReClass.NET.

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.

Health
Trying to change the value of the character’s health, using Cheat Engine.

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:

Gravity
Scheme representing the sum of the gravitational forces.

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 in Cheat Engine and 0x14009D443 in IDA

Jump 1
Instructions that make your character jump.

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.

Jump 3
Breakpoint hit in the Cheat Engine debugger.
Jump 4
LocalPlayer view in ReClass.NET.

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.

adamhlt/Cube-World-Reversing

Cube World Reversing & Cheat (x64) - Include IDA file and unpacked game

C++
10
3


Cube World Reversing - This article is part of a series.
Part 2: This Article