Target
Our target in this lesson will be Wesnoth 1.14.9.
Identify
Our goal in this lesson is to locate the base pointer for our Player class. After that, we need to figure out how to offset our gold address from this base pointer.
Understand
When a player begins a game, Wesnoth uses DMA to allocate several values, including the player’s gold. This means that the player’s gold address will be at a different address for each game. By contrast, there are several values that remain constant between games, like the player’s profile name. These constant values must be stored in some sort of Player class. Since these values persist for every game, there must be a static address that Wesnoth uses to locate them. If we can find this static address, we can then offset to our dynamic gold address while in game.
To visualize this, let’s imagine that Wesnoth’s Player class looks something like:
class Player {
string player_name = "IEUser";
int wins = 100;
Game game = null;
}
And the Game class looks something like:
class Game {
string side;
int gold;
int turn;
}
When a player enters a game, the game’s code will allocate memory for this game object and all the values that it contains:
player.game = new Game("Human", 100, 1);
By finding the value of the gold address, we can reverse the game to find the value of the Game address for the current game. We can then use that address to find the address of the Player class. Since the Player class is always loaded, it will be a consistent address. From the Player class, we can then use the addresses we found while reversing to offset to the current gold address.
Locating Gold
For the last time in these lessons, we will need to find the address of our gold value. Our first step is opening up Wesnoth and creating a local game. Unlike the previous lesson, make sure that you give yourself Income to make the reversing process easier. Also, make sure the second player is set to a Computer opponent.
Then follow the steps in the Memory Hack lesson to find your gold address. Once you have found your new gold address, close down Cheat Engine but keep Wesnoth open.
Base Pointer
Next, attach x64dbg to Wesnoth and set a breakpoint on write on the gold address that you found. Unlike previous lessons, do not recruit a unit. Instead, choose to end your turn. Upon ending your turn, your breakpoint should pop as income is added to your gold.
Let’s briefly examine the instruction that our breakpoint popped on:
009B4D00 add dword ptr ds:[eax+4], edx
When this instruction is executed, eax+4 holds the value
of our gold address (in this instance, 0x0D70B9AC
). Our next
step is to determine how eax is assigned. If we look
above the add instruction, we see several
mov instructions that reference the value of
eax. Above these, we have a
call instruction to an unknown function. To determine if
this function is responsible for setting eax, we can set
a breakpoint on this call and then resume Wesnoth. When
we end our turn again, this breakpoint will be hit.
Observing the registers, we see that eax is set at 0 entering this function, meaning this function must be acquiring the correct value for eax. We can confirm this by stepping over the function and noting the new value of eax.
With this confirmed, resume Wesnoth and end your turn again to trigger the same breakpoint. This time, step into the function. After stepping through a few lines, we see that eax is being set based on the value of ecx + 60.
For now, we will note that we need to determine the value of
ecx. However, eax is still not close to
the value of our gold address. Before we move on to determining the value
of ecx, we need to determine how eax is
modified from the initial assignment to reach the gold address. If we
continue down the function, we see that the value of 0xA90
is
being added to eax. After that, edx is
loaded with the value of eax + 4. Let’s step to the
address after that code to see what value is being loaded into
ecx.
We can see here that ecx’s value is only 4 away from our gold address, identical to how the initial add instruction referenced it. From this, we know so far that [[ecx + 60] + 0xA90] + 4 is our gold address. Our next step is determining ecx at the start of this function.
When locating base pointers, it’s important to stop each time a new
register or address is introduced and ensure that it is actually random.
To do this, first make a current note of ecx’s value when
it is loaded into eax. In this case, that value is
0x017EECB8
. Next, make a note of the address of the
instruction that assigns the value so that you can place another
breakpoint here. In this case, it will be the
mov instruction at 0x009AE7F7
.
Now, detach x64dbg and then close Wesnoth. Once it is closed, start
Wesnoth again, recreate a game with the same income settings, and reattach
x64dbg. Place a breakpoint at the address noted (0x009AE7F7
)
and then end your turn. When the breakpoint pops, observe the new value of
ecx. In this case, it’s the exact same as the last time
(0x017EECB8
). Therefore, we know that this must represent a
base pointer that doesn’t change. If it did change, we would have to
continue with the reversing process.
Change
With our base pointer found, we can now save its value for use in future
projects. From our reversing, we know that the value of the player’s gold
in Wesnoth is always at: [[0x017EECB8 + 0x60] + 0xA90] + 4
.
To simplify, we know that 0x017EECB8 + 0x60
will always be
0x017EED18
, so the actual offset can be represented as:
[[0x017EED18] + 0xA90] + 4
.
Cheat Engine allows us to manually add pointers with offsets as addresses. We can use this to verify that our value is correct. First, open Cheat Engine and attach it to Wesnoth. After attaching, select the Add Address Manually button.
In the box that pops up, select the checkbox for Pointer. When
doing this, Cheat Engine will prompt you for a base address and one
offset. Type in 0x017EED18
as the base address and
0xA90
as the offset. Then add another offset and type in 4.
This is all the information we found while reversing.
In the Address box at the top, you should notice that Cheat Engine has correctly resolved our offset to the current amount of gold that we have. If you close and restart Wesnoth, this pointer will then change to the new value for gold.