Target

Our target in this lesson will be Wesnoth 1.14.9.

Identify

In this lesson, we will create a statistic hack, more commonly known as a stathack. This type of hack displays information to us about other players, such as their gold or number of units.

In this lesson, our stathack will display the gold of the second player.

Understand

To create our stathack, we need to accomplish two steps:

  1. Find the second player’s gold.
  2. Print this value to the screen.

In previous lessons, we covered the techniques to do both of these steps.

Second Player’s Gold

Back in the Game Fundamentals lesson, we explored how games will often allocate similar data and classes in arrays. These arrays can then be iterated over by the game to locate and update data. While we do not know if this is how Wesnoth works, we can use it as a model to try to locate the second player’s gold value.

We know from the Defeating DMA lesson that the game dynamically allocates player classes based on a base pointer. We also identified the game’s and first player’s base pointers. By closely examining the code we located in that lesson, we can determine if the game uses an array for its player classes and, if so, locate the second player’s base pointer.

First, create a local game with two local players. Make sure both players receive income each turn. Start the game and attach x64dbg. Play one turn for each player to make sure any first-turn initialization code has executed. Next, set a breakpoint in x64dbg on 0x9B4CE3, the same call we identified before. In Wesnoth, end the first player’s second turn and the breakpoint should pop:

Income Breakpoint

The value in ebx indicates that this function is invoked for every player each turn. Furthermore, we know that the value in ecx is the game’s base pointer. From these two facts, we can assume that the game has an array of player classes.

Our next step is to determine the size of each player in the array. The game must know this size to advance to the next player in the array. Step into the call at 0x9B4CE3 and step through each line of code. From the previous lesson, we know that this code will return the player’s gold address in eax. For the majority of this function, the addresses and values used are identical to the values we observed when looking for the first player’s gold address. However, near the bottom of the function is an imul (signed multiply) instruction:

imul Instruction

When we step through this function as the first player, edx is set to the value of 0. However, when we step through with the second player, edx is set to the value of 1. From this code, it appears that the game uses edx to offset the current player and then multiplies edx by the value of 0x270 to identify the current player. If we step down a few more lines of code, we see that this value is then added to the value of eax to get our current player’s gold address:

Offsetting the Player

From this code, we can identify how to offset our second player’s gold value. Like we have found previously, we will use [[0x017EED18] + 0xA90] to offset the game’s base pointer. If we add 4, we will get the first player’s gold address. To get the second player’s gold address, we can instead add 0x270 + 4, or 0x274. We can verify this calculation using Cheat Engine:

Verifying Second Player's Gold Address

In previous lessons, we have already written code to offset the first player’s gold address. We can modify this code with the new value of 0x274 to retrieve the second player’s gold address like so:

player_base = (DWORD*)0x017EED18;
game_base = (DWORD*)(*player_base + 0xA90);
gold = (DWORD*)(*game_base + 0x274);

Printing Value

In the previous lesson, we covered a method to print text. We determined that by creating a code cave, we could access the text for the Terrain Description method by referencing the value pointed at by edx. Once we accessed it, we could store bytes in this location to be displayed by the game.

Using the method from the Code Caves & DLL’s lesson, we can implement this functionality in a DLL. Since we already discussed the method to redirect code, we will examine only the code cave function now. We will start with the skeleton:

DWORD ori_call_address = 0x5E9630;
DWORD ret_address = 0x5ED12E;

__declspec(naked) void codecave() {
    __asm {
        pushad
    }

    // new code

    _asm {
        popad
        call ori_call_address
        jmp ret_address
    }
}

We have seen this code before. The major difference is that the instruction we are replacing for the text printing is a call.

This code cave will be called each time the Terrain Description method is invoked. In it, we want to retrieve the second player’s gold value. We can do this using the code we discussed in the previous section:

__asm {
    pushad
} 

player_base = (DWORD*)0x017EED18;
game_base = (DWORD*)(*player_base + 0xA90);
gold = (DWORD*)(*game_base + 0x274);

We now have the second player’s gold value stored in the gold variable. To display this value in the game, we need to convert it to a string of characters. To understand what we are trying to accomplish, here is the memory dump containing the text string we found in the previous lesson:

Memory Dump of Text String

Looking at this, we see that even though the game displays Lhen, the values stored in memory are 0x4C 68 65 6E. This is due to the game using ASCII encoding to encode character values as certain numbers. The game then knows to decode these values and display the corresponding character in game.

Therefore, if our gold value to display is 225, we cannot simply write 225 into the game and expect the game to display it successfully. Instead, we need to convert it to 2 2 5, or 0x32 32 35. There are several ways to do this, the easiest being through the use of the sprintf_s API:

#include <stdio.h>

char gold_byte_array[4] = { 0 };

...
gold = (DWORD*)(*game_base + 0x274);

sprintf_s(gold_byte_array, 4, "%d", *gold);

This will convert the value pointed at by the gold variable into its string representation and store that value in gold_byte_array.

Finally, we will move this converted value into the memory that will be displayed. Since sprintf_s alters several registers, we will first restore them and save them again to ensure that the game does not crash:

__asm {
    popad
    pushad
    mov eax, dword ptr ds:[edx]

In the previous lesson, we simply incremented the first character pointed to by eax. To display our gold value, we will move the values stored in the gold_byte_array:

mov bl, gold_byte_array[0]
mov byte ptr ds:[eax], bl

First, we move the first byte of the gold_byte_array into bl. To understand why we are using bl, we need to understand the different sizes of data used by the CPU. A bit is the smallest unit of data, representing either 0 or 1. A byte is 8 bits. A word is 16 bits. A double word (or DWORD) is 32 bits. When looking at the memory dump in x64dbg, we are looking at byte values. 4 of these byte values combined together form a DWORD.

Currently, all the registers we have seen, like ebx, are DWORD’s. Early Intel CPU’s, like the 8088, used 16-bit or WORD registers, like bx. To access each byte in the bx register, you would use h and l, such as bh and bl. On modern CPU’s, even though we are using extended (or DWORD) forms of these registers, these same rules apply. Since we are moving individual bytes, we need to move them into a value that can hold a byte. We then move this value into the location pointed at by eax, which is also a byte long.

This code will move our first character into the text. We can repeat it several times to move additional characters. For this lesson, we will only display 3 characters’ worth of data:

mov bl, gold_byte_array[1]
mov byte ptr ds:[eax + 1], bl
mov bl, gold_byte_array[2]
mov byte ptr ds:[eax + 2], bl

Finally, identically to the Code Caves & DLL’s lesson, we will redirect the game’s print text function to our code cave in DllMain:

DWORD old_protect;
unsigned char* hook_location = (unsigned char*)0x5ED129;

if (fdwReason == DLL_PROCESS_ATTACH) {
    VirtualProtect((void*)hook_location, 5, PAGE_EXECUTE_READWRITE, &old_protect);
    *hook_location = 0xE9;
    *(DWORD*)(hook_location + 1) = (DWORD)&codecave - ((DWORD)hook_location + 5);
}

Build and inject this the same exact way we did it in previous lessons. Finally, go inside a game and open up the Terrain Description on a tile. We should see the second player’s gold value printed several times due to how we hooked the function:

Stathack

The full code for this lesson is available on github.

 

results matching ""

    No results matching ""