About Pointers | ![]() |
![]() |
Pointers are 4-byte (this is machine-dependant) integral values like any other. Literally, they are nothing but unsigned longs (or dwords). Pointers are not magic, and have no special properties that make them confusing. Why are so many people confused about pointers? Because they have been led to believe they are more than they are—they have been given a misunderstanding. Pointers themselves are not magic; you can not normally look at a chunk of RAM and determine what are pointers and what are not. The only thing that separates pointers from any other unsigned long is how they are used. For the sake of clarity, pointers are always displayed in hexadecimal format. See Introduction to Number Systems. On the Data Types page, you can see that each data type has specific properties and specific uses. Since pointers are unsigned longs, they have the same range and sign as unsigned longs. Unsigned longs are used to perform mathematical operations on numbers with a large range. Chars are usually used to hold text strings. Shorts are also used for math, but with a smaller range, and floats are used for math, but on a much more precise scale. Doubles are used for even more precise math. Now it becomes clear that data types are actually defined by how they are used rather than their properties—the usage of a data type is defined first, and then it is given properties to facilitate that use.
So What About Pointers?Now that it is clear that the only true separation between data types is the way they are intended to be used, we can discuss pointers, which are nothing more than another data type with an intended usage. Pointers, however, are not intended to be used for mathematical operations. Pointers are used to indicate the locations of objects (structures, classes, functions, data types, anything) in the RAM space of your game. That means to understand pointers, you need to understand the RAM in your game.
The Real Definition of Static AddressesThe final, real, true, undisputable definition of static addresses is, “Addresses that move predictably in relation to the module that owns them.” 99.999% of the time your game will always be loaded to 0x00400000, and thus 99.999% of the time, it is accurate to think of static addresses as being data that never moves. But it’s still a dirty lie that has millions of people fooled. Using the diagram above, we defined addresses from 0x00330000 to 0x0037C000 as being static. Static addresses are relative to the module that owns them, and in this case that means logger.dll. Thus if logger.dll decides to relocate to 0x05000000, it is no problem, because all the values from 0x00330000 to 0x0037C000 have now moved to addresses from 0x05000000 to 0x0504C000. Static addresses are noted in the format [module+offset]. For example, In logger.dll, we may have discovered a valuable integer at address 0x003304C0. Since logger.dll may move, we don’t just use this address directly. Instead, we use [logger.dll+0x4C0]. Therefore, when logger.dll decides to packs its things and move on to 0x05000000, [logger.dll+0x4C0] gives us 0x050004C0, and we still have our valuable integer.
The Other Kind of AddressBetween modules there are many pockets of empty space, as shown in both diagrams above. Not all, but many of these addresses are available to the game to use as it pleases. This is the free store, where the game can use undefined amounts of RAM for undefined purposes. Games never know exactly how much RAM they are going to need at any given moment. Literally, this is up to the user to decide. For example, the user decides which map to play in a first-person shooter. Each map contains different data, and thus will consume different amounts of RAM. When the game needs more memory, it asks Windows® to give it some. Windows® will create an area of usable RAM and give the game a pointer to it. Ah! Now we are starting to see the so-called magic behind pointers. Windows® will create an area of usable RAM at any location where there is enough unused RAM available. The only way the game is ever going to know where that new RAM is located is by the pointer that Windows® gives back to the game. Because the location where Windows® will find enough free RAM for the game changes, it is called dynamic. When the game requests new RAM, it is called allocation. Thus the process is called dynamic memory allocation, or DMA.
How a Pointer is UsedRemember, a pointer is just another data type, and data types are defined by how they are used. During dynamic memory allocation, Windows® will find an arbitrary address that can not be predicted, thus pointers are used to tell the game where the requested memory has been allocated. A pointer is an unsigned long that, instead of being used for math, is used to indicate the locations of various data the game needs to run. The game knows where the pointer itself is, and then by using that pointer it can determine where other things are—and so can we. All data in all games have addresses and values. An integer can have an address of 0x00443C0C and have a value of 100 (0x64), and this value is used for mathematical purposes. Likewise, a pointer can have an address of 0x0042104C and a value of 0x004AE804, but this value isn’t used for math. This value is yet another address.
So How is This Useful for Hacking?Surely you jest. If the game knows how to locate the data for our player, we know how to locate the data for our player. And that means always. Every time we die, every time the game is restarted, etc. The only thing important to note that is that if the value of a pointer is 0x00000000, it does not mean there is actually an object at address 0x00000000. Value 0x00000000 is reserved to tell the game that the pointer itself is invalid, and points to nothing. It is also worthy of noting that the values of pointers will be divisible by 4 in 99% of all cases. Windows® always gives the game pointers that are aligned on 4-byte boundaries because the architecture of x86 processors allows them to work faster on data that is aligned this way. If data is not aligned by every 4 bytes, the game may suffer from slowdown. Thus the only way pointers can point to addresses that are not divisible by 4 is if the programmers specifically go out of their ways to change the pointers. This is sometimes done as an optimization technique when performing some string-based parsing, but it is never done on objects that are frequently and randomly accessed throughout the execution of the game. Incidentally, these objects are the very objects we are interested in hacking, and thus it is always safe to assume that the data you are trying to find will have its base along a 4-byte boundary.
Structures, and the Pointers that Love ThemIn our above examples, the pointer is pointing to our player data. Our player has a weapon, health, magic, experience, a level, gold, and a position in the 3-D game space. Games organize sets of related data into structures and classes. Because your player has a lot of related data, it will always be organized a structure or class. This is actually done simply so that the programmers themselves (the ones making the games you hack) can work in an organized fashion, making complicated sets of data easier to manage.
Notice that the positions of each data element (officially called members) inside the structures are the same distance from each other, no matter where the structure itself is located in RAM. That is, our GOLD is always 0x10 bytes after the start of the structure. Structures and classes share something in common with modules: when they move in RAM, the data that is related to them also moves exactly with them. For this reason, we note their members the same way as we note addresses in modules: [structbase+offset]. In this case, HEALTH is offset 0x4, MP is offset 0x8, LEVEL is offset 0xA, etc. We know quite a bit now. Let’s assume we wanted to know our player’s health at any given moment.
Pointers to PointersWe have covered a static pointer ([lspiro.exe+0x2104C]) that points to dynamic data. But pointers are not limited to being static themselves. In the above player structure, the very first member (WPN PTR *) is a pointer to the player’s weapon data. Luckily, this has no special meaning what-so-ever. We already discussed everything there is to know about pointers, and, just because this particular pointer is moving around with our player structure, it does not mean it follows any special set of rules apart from other pointers. The value of this pointer is 0x028F3B0C, and like every other pointer we turn this value into an address. Now we know that at address 0x028F3B0C there is another set of data that is used to give details regarding the weapon our player is using. Pointers can point to pointers that point to pointers that point to pointers that point to pointers. It doesn’t matter how many layers of pointers there are, because you now know everything there is to know about pointers, and they all work the same.
And So the Magic Behind Pointers Is… |
Copyright © 2006 Shawn (L. Spiro) Wilcoxen |