In previous lessons, we modified the player’s gold in Wesnoth. Whenever we restarted the game, we had to repeat the process of finding the player’s gold memory address, as it was different each time. This is because of Dynamic Memory Allocation, or DMA. To write hacks that can be reused and distributed, we will need to somehow convert these “random” addresses into consistent addresses. There are many methods to accomplish this task, but first we need to discuss how DMA works and why it exists.
As we discussed in the Game Fundamentals lesson, games are large programs with many resources. There is no way to fit all of a game’s data into RAM at one time, so it must be loaded when it is needed. For example, a game will not load an enemy’s model or image until the player is about to encounter them. This process is known as dynamic loading of resources.
These dynamically loaded resources must be placed in some section of memory so that the game can access them again. The game is responsible for creating and destroying these sections of memory. The creation is known as allocation, and the destruction is known as deallocation. Dynamic Memory Allocation is therefore the process of creating memory sections to hold resources when they are needed by the game. The game can only ask the OS for memory and cannot control where this memory is located.
Let’s consider the player’s gold in Wesnoth and how it is created. When Wesnoth is started, a player’s profile is loaded into the game’s Player class. The player can then select from a variety of game modes and other options in the main menu. If the player then starts a game, several items are allocated and placed in the Player class, such as the player’s race, their available units, and their gold. When the player quits the game, these values are then destroyed. This is why the player’s gold address is always different.
To program hacks, we need some way to consistently find the gold address without searching in Cheat Engine. There are several ways to accomplish this:
- Use an automated scanner, such as Cheat Engine
- Code Caves
These methods can be used to find any dynamic address. We will discuss each of these briefly in this lesson, but in future lessons we will use all of the methods.
When using Cheat Engine or reversing, our goal will be to find something known as the base pointer. In general, the base pointer represents a memory address that is always consistent and can be used to offset to the values we care about. This method works because there are some addresses that must be constant for the game to find them. For example, in Wesnoth, the game needs to know where the Player class is. If we find the Player class, we can then use it as a base pointer to offset to our gold address.
One feature of Cheat Engine is the ability to conduct a pointer scan. This can be done by finding an address (such as the player’s gold) and then right-clicking on it to bring up a context menu. This context menu contains all the pointer scanning functions.
This feature returns all the memory locations that currently reference the selected address. These addresses can then be saved to a scanfile. After that, the game can be reloaded and the address can be found again. By then comparing the new memory locations to the scanfile, only the consistent locations can be narrowed down, similar to regular memory searching. Eventually, we will be left with only the pointers that always point to our selected address.
Another method to defeat DMA is using a code cave. With this approach, a location is found where the desired value is accessed. For our Wesnoth example, this can be anywhere that gold is changed. Immediately after this location, the code is redirected to our code cave. In our code cave, we can then save the current value to a piece of memory we control. This memory can then be accessed consistently by our hack.
For example, the code in Wesnoth responsible for decreasing our gold when recruiting a unit looks like:
sub dword ptr ds:[edx+4], ecx
When this instruction executes, edx + 4 contains a reference to the gold memory address and ecx contains a reference to the cost of the unit just recruited. By redirecting the code immediately following this address to a cave, we can then save the address’s value in the cave. An example cave is shown below that would accomplish this:
mov dword ptr ds:[0x12345678], edx+4
...original instruction replaced...
With this done, our hack could then reference
0x12345678 to get the current value of the gold address.
The final method of dealing with DMA is reversing the target. This method uses a combination of the previous two methods and is the most versatile. In this approach, we first find an instruction that modifies the value we care about, such as the sub instruction in the previous section. Then, we analyze the function before that instruction and determine where the register we care about (in this case, edx) is assigned. Often, this will be assigned the value of another register with an offset, such as eax+60.
We then repeat this process to find where this previous register is assigned. Eventually, we will find the base value or pointer used to assign all these values. This base pointer can then be combined with all the offsets we reversed to retrieve the address we care about.