Accessing a processes address space

Questions about programming languages and debugging
Post Reply
User avatar
ayu
Staff
Staff
Posts: 8109
Joined: 27 Aug 2005, 16:00
18
Contact:

Accessing a processes address space

Post by ayu »

I have been experimenting with some Windows specific code for all day, lots of fun. But I have been having some trouble, that I can't really figure out how to solve at this late hour.

I found some example on Google that would explain how it should be done, but then I discovered that they had done something similar to what I did, yet they claimed that their code works.

Anyway, so let me explain this ...

I will use an easy example, now, this is not what I am trying to do, but I feel that more people will understand if I tell it like this.

You know those "trainers" for games that you can download? You start the game and then you start the trainer, and you click like "unlimited health", and the trainer either sets your health to 99999 or freezes it in the game.

This "trainer" writes to an address in the processes (the games) own address space. I have been playing around with two applications to accomplish this, but I can't seem to figure out how to get the processes own address space.

I created one application, "var" and one application "read_mem". The var application would simply declare and define a variable and print it in a loop with a pause between (so that I could change the value and see it happening), the "read_mem" would simply read the value and output it.

Now the idea was that the "read_mem" was to use the address of the variable in the "var" application, read it, and simply output it every time the two applications started. But I can't seem to find or use that address.

I can find the value in the memory using tsearch and then use that address in my "read_mem", and that works like a charm, no problem at all. But the issue is that when I restart the application, the address has changed.

Which confuses me ...

As far as I know, the address that I am using IS an address from the processes own address space, but yet it changes? It's a statically initialized variable, and as far as I know it should stay on the same address in the processes own address space.

I am using

Code: Select all

http://msdn.microsoft.com/en-us/library/ms680553%28VS.85%29.aspx
to read memory in the process.

Now, my code is messy since I have been experimenting all day, so I wont paste it (getting flamed for bad coding just doesn't float my boat). But the code shouldn't be needed since everything works .. kinda.


Anyway, if anyone has any kind of useful knowledge on this, then I would be really happy if you could share it :)

PS: Go easy on me ... long day, and it's late ^^
"The best place to hide a tree, is in a forest"

User avatar
ayu
Staff
Staff
Posts: 8109
Joined: 27 Aug 2005, 16:00
18
Contact:

Post by ayu »

I found the solution rather quickly now .... amazing since I have been at this for some time now.

It only applies to global vars, since vars in a function is pushed of the stack when they go out of scope.

The explanation is here

Code: Select all

http://annwm.lbl.gov/~leggett/vars.html
"The best place to hide a tree, is in a forest"

User avatar
IceDane
Fame ! Where are the chicks?!
Fame ! Where are the chicks?!
Posts: 197
Joined: 12 Aug 2009, 16:00
14

Post by IceDane »

cats wrote:I found the solution rather quickly now .... amazing since I have been at this for some time now.

It only applies to global vars, since vars in a function is pushed of the stack when they go out of scope.

The explanation is here

Code: Select all

http://annwm.lbl.gov/~leggett/vars.html
I know you have already gotten it working, but your post was pretty ambiguous. It was hard to tell which application you were actually restarting.

If you had a var, declared in main, and looped it sleeping in between, printing its address, it shouldn't change at all(The address). If you declare the var inside the loop, it might just change, since it would go out of scope every iteration.

But yes, global variables are put in the .bss section and stay there.

User avatar
ayu
Staff
Staff
Posts: 8109
Joined: 27 Aug 2005, 16:00
18
Contact:

Post by ayu »

IceDane wrote: I know you have already gotten it working, but your post was pretty ambiguous. It was hard to tell which application you were actually restarting.

If you had a var, declared in main, and looped it sleeping in between, printing its address, it shouldn't change at all(The address). If you declare the var inside the loop, it might just change, since it would go out of scope every iteration.

But yes, global variables are put in the .bss section and stay there.

Yeah sorry that it was hard to read, but I'm really tired, it's 3 AM here ^^

The problem wasn't that the address changed when the program was running, it was that it was changing when I restarted it ^^

Thanks for pointing it out though, so that we could clear that up =)


Now ... it's time for me to get some sleep, else I wont be able to get out of bed tomorrow >_>
"The best place to hide a tree, is in a forest"

User avatar
IceDane
Fame ! Where are the chicks?!
Fame ! Where are the chicks?!
Posts: 197
Joined: 12 Aug 2009, 16:00
14

Post by IceDane »

cats wrote:
IceDane wrote: I know you have already gotten it working, but your post was pretty ambiguous. It was hard to tell which application you were actually restarting.

If you had a var, declared in main, and looped it sleeping in between, printing its address, it shouldn't change at all(The address). If you declare the var inside the loop, it might just change, since it would go out of scope every iteration.

But yes, global variables are put in the .bss section and stay there.

Yeah sorry that it was hard to read, but I'm really tired, it's 3 AM here ^^

The problem wasn't that the address changed when the program was running, it was that it was changing when I restarted it ^^

Thanks for pointing it out though, so that we could clear that up =)


Now ... it's time for me to get some sleep, else I wont be able to get out of bed tomorrow >_>
Hmm. Well, that's actually perfectly normal. There is no guarantee that your address space layout looks the same every time you run a program, in spite of virtual addressing. Also, it might be worsened by address-space layout randomization, but I *think* that needs to be enabled specifically on windows.. Or it might just be default for MSVS stuff. Not sure.

No matter, you fixed it.

User avatar
ayu
Staff
Staff
Posts: 8109
Joined: 27 Aug 2005, 16:00
18
Contact:

Post by ayu »

hmm ok, but what about those "trainer" applications?

I mean there's like one for every game.
How can the creator of those, be sure that the layout is the same every time?
"The best place to hide a tree, is in a forest"

User avatar
IceDane
Fame ! Where are the chicks?!
Fame ! Where are the chicks?!
Posts: 197
Joined: 12 Aug 2009, 16:00
14

Post by IceDane »

cats wrote:hmm ok, but what about those "trainer" applications?

I mean there's like one for every game.
How can the creator of those, be sure that the layout is the same every time?
If I'm not mistaken, ASLR(Address space layout randomization) was introduced in Vista. It might have to be enabled by the compiler when you compile your application, and I'm not sure if anything but the MSVC++ compiler supports it on Windows currently.

Regarding the trainer issue; well, to be perfectly honest, I'm not entirely sure if my statement about the address space being different every time you restart the program. The loader dictates which parts of the executable go where, but I would think if the executable looks the same way two separate runs, addresses shouldn't be modified. Maybe someone else can confirm it.

However, there is also the chance that the trainers are actually searching the address space for desired value. That's the way cheat engine works, but then again, that's a 'universal trainer'.

If you find out whether trainers just use hardcoded addresses for every version of the executable, then we've got our answer. If you find out, let me know =)

User avatar
ayu
Staff
Staff
Posts: 8109
Joined: 27 Aug 2005, 16:00
18
Contact:

Post by ayu »

IceDane, I so love you right now <3

I realized today when I woke up, that the experiment had failed, because it didn't hold the same address every time after all. And I couldn't figure out why.

Then you mentioned ASLR, and AHA! Now it works like a charm, thanks to you ;)

I'll create a new thread about it in a little while, just need to clean up the code from all the commented code.

And about the trainer, I found this. It's from a Diablo 2 trainer

Code: Select all

//---------------------Player Info Offset-------------------
#define PLAYER_INFO_OFFSET			0x006506E0
//--------------------Player Info Structure-----------------
//#define PLAYER_NAME					(PLAYER_INFO_OFFSET + 0)	//18 char
#define PLAYER_CURRENT_HP			(PLAYER_INFO_OFFSET + 36)	//int
#define PLAYER_CURRENT_MP			(PLAYER_INFO_OFFSET + 40)	//int
The trainer uses hard coded offsets to read the games memory

Code: Select all

ReadProcessMemory(this->m_Process, offset, &buffer, sizeof(TYPE), &read);
"The best place to hide a tree, is in a forest"

User avatar
IceDane
Fame ! Where are the chicks?!
Fame ! Where are the chicks?!
Posts: 197
Joined: 12 Aug 2009, 16:00
14

Post by IceDane »

cats wrote:IceDane, I so love you right now <3
Yes, I have been known to be pretty fucking fantastic.
I realized today when I woke up, that the experiment had failed, because it didn't hold the same address every time after all. And I couldn't figure out why.

Then you mentioned ASLR, and AHA! Now it works like a charm, thanks to you ;)

I'll create a new thread about it in a little while, just need to clean up the code from all the commented code.

And about the trainer, I found this. It's from a Diablo 2 trainer

Code: Select all

//---------------------Player Info Offset-------------------
#define PLAYER_INFO_OFFSET			0x006506E0
//--------------------Player Info Structure-----------------
//#define PLAYER_NAME					(PLAYER_INFO_OFFSET + 0)	//18 char
#define PLAYER_CURRENT_HP			(PLAYER_INFO_OFFSET + 36)	//int
#define PLAYER_CURRENT_MP			(PLAYER_INFO_OFFSET + 40)	//int
The trainer uses hard coded offsets to read the games memory

Code: Select all

ReadProcessMemory(this->m_Process, offset, &buffer, sizeof(TYPE), &read);
What did you have to do then? Did you just remove some compiler flag to disable ASLR?

User avatar
ayu
Staff
Staff
Posts: 8109
Joined: 27 Aug 2005, 16:00
18
Contact:

Post by ayu »

IceDane wrote: What did you have to do then? Did you just remove some compiler flag to disable ASLR?
yupp

I changed

Code: Select all

/DYNAMICBASE
to

Code: Select all

/DYNAMICBASE:NO
And it worked perfectly :)

Now I only have the Debug VS Release issue left to solve, but that shouldn't be too hard, most likely a flag that I missed in the release settings.
"The best place to hide a tree, is in a forest"

Post Reply