top of page

Pseudo static stack addresses

So far we've seen how to locate static data in an application using pointer chains if necessary. This process assumes the existence of information in the applications data section. This is not always the case, and will vary from application to application.

Consider the following program

We could isolate the address of the health variable but we would not be able to trace it back to a static address. Does this mean that applications without global data cannot be breached? Not quite.

Lets attempt to use our current process of pointer chaining to see if we can isolate a static address which leads to our health variable. Here is the address storing health on my machine.

We find out what accesses the address. Here are the results I found on my machine. We're accessing the health variable inside the player object here, and can see the expected 4 byte offset caused by the filler_data int member.

We dig deeper into the pointer chain. Searching for memory which stored the base address of the player object returned the following results on my machine.

We repeat our established process and find out the instructions which access these memory locations. Only one of the memory addresses I found had any instructions accessing it. The memory access offset was 8 bytes this time, which is to be expected, as we are looking at an access into the Game object this time, and the 8 bytes represent the class member of type double (filler_data).

Lets attempt to dig further. We search the process for any memory storing the address of the game object (0x0018ECF0 in my case)

The only instructions I could find which accessed these addresses were

Attempting to dig any further is futile, as we will run into long pointer chains that seem to go nowhere. In general, if you see instructions involving the esp register (holds pointer to top of stack) or the ebp register (pointer for holding the address of the current stack frame), it is a good indication that the address you are trying to probe is a stack variable.

We're unable to trace our target data to a static memory address. We have to fall back on cheat engines "Pointer scan" feature. We tell pointer scan about the address value we are interested in, and an offset value. It scans the processes memory for all memory locations which hold our target address value first. Lets call these addresses level_one_addresses. Next, it takes each one of these level_one_addresses and scans for memory locations which hold addresses that fall into the level_one_address+-offset range. It does this recursively till it finds a static address or its recursion cap (which we specify). The great thing about this feature is that it also tells us about pointer chains originating from reliably traceable stack variables(We will discuss how it does this in a bit).

Let's try out this pointer scan feature. Right click on the address holding the health variable and select "Pointer scan for this address" (I restarted my program for this, so my address values have changed in subsequent pictures. I arrived at 0x009D67FC for health)

Make sure the "Allow stack addresses of the first thread(s) to be handled as static" is ticked. I left the number of threads to 6, if you want more feel free to change it. I changed the max level to 3, since I had an idea of how deep I needed the recursion to be.

This can generally take some time, depending on the depth and offset values you provide, and the complexity of your program, but since we're dealing with a simple program and didn't go too deep, it was fairly quick on my machine. You will probably end up with a large number of results. Here are the results from my pointer scan.

We see a bunch of references to "THREADSTACK0". Think of it as a static value for now, we will come back to it later. We also see some references to the executable image ("StackVariable.exe"), which we know is the starting address of our executable module in its virtual address space. Most of these results are false positives. To get a better picture, we need to restart our test application, open it up in cheat engine again (you do not need to close cheat engine!), find the address holding the health variable again (I got 0x008067FC this time), and re-do the pointer scan. This gets rid of pointer chains which did not point to our new health variable ( An accurate chain would point to the variable even after the application is restarted). To rescan, go to the pointer scan window and navigate to "Pointer Scanner-> Rescan Pointer"

We go with the first entry since we expected the offsets 8 and 4. Double clicking on the value moves it over to our address tracking window.

We can verify that if we restart the application and open it in cheat engine again (while maintaining the tracked addresses), it still points to our desired data.

Onto the technical part of this exercise: How does cheat engine arrive at this THREADSTACK0 value?

Every thread has certain predictable functions it calls before it begins executing, which can be looked for on its stack (Each thread is assigned its own stack). These could be calls to the kernel function BaseThreadInitThunk which initializes the thread and calls the entry function we provide, or the ExitThread function which each thread must call before it must exit. Cheat engine looks for the first call into the kernel.dll module, and treats it as a static address. This is possible because the first set of instructions performed by the program are generally predictable and constant, and if you can consistently find one of these function addresses on the stack, the offset to other data on the stack is constant (as long as the function calls are in order. This order would generally change when user input comes into play, or when certain program settings result in the program executing differently)

Lets write a small program to find ThreadStack0 for our target application.

We need to define some structs first, since we will be using "NtQueryInformationThread" in ntdll.dll to get thread information, but the function is not accessible to user applications and has to be accessed with the "GetProcAddress" function. This defines the structure of the data returned by the function.

Onto the main function. I've implemented it for 32 bit applications, it will need slight tweaking for 64 bit applications. You can find the cheat engine source here and some good forum posts here and here. We loop through all of the threads in the process and find the first call to a function in kernel.dll on the thread stack.

The value of ThreadStack on my machine was 0xEFFE28, and I was able to verify that cheat engine was using the same value for THREADSTACK0 in the pointerscan results we calculated above!


Comments


bottom of page