Cheat Engine Forum Index Cheat Engine
The Official Site of Cheat Engine
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 


Remeber: There's always more then 1 way to skin a cat...
Goto page 1, 2  Next
 
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine Tutorials -> Pointer tutorials
View previous topic :: View next topic  
Author Message
Zhoul
Master Cheater
Reputation: 1

Joined: 19 Sep 2005
Posts: 394

PostPosted: Thu Nov 24, 2005 10:00 am    Post subject: Remeber: There's always more then 1 way to skin a cat... Reply with quote

I just wrote this little how-to up for a friend. I sat back and looked at it after I was done, knowing it couldn't be 'wasted' on just 1 person Wink

IMHO, this is a very ghetto way to go about resolving pointers, or shall I say, making your own... But I've resorted to it once or twice because pointer levels were so entirely deep, it wasn't worth my time to keep back-tracking....

Remeber folks, this is 3 different variations on 1 tactic to pointers. I can think of another 6 ways to find pointers, but they are far harder to describe without a straight-up example to go with...

Have fun Wink

-------------------------------------------------------------------------

Quote:
Originally Posted by Laen
bla bla bla yackedy-schmackedy..... you have a (or any) link(s?) to any ASM or Pointer value tutorials, ive never been able to get pointers from games lol. if not thanks anyway


That is SUCH a broad topic and difficult to understand at first, that documentation on such things is far and few between, or completely to general. There are literally about a dozen different ways to resolve pointers and it's all really dependant on the game and how it functions as to which way is the best.
I'll quickly describe what I believe is the easiest way to secure pointers, but this is not the cleanest or best way to do it. If you're not way careful, you can wind up crashing the game eventually =) I'll also PM you with a few links.

The method I'm about to describe is what I consider the ghetto way to obtain pointers. With this method, you don't actually 'obtain' pointers at all... You create them your damn self. Finding memory that will *never* be written to is tricky, but you don't need all that much room anyhow. The best place to abuse, is the lower memory areas. Watch them for a good few games/reloads to make sure nothing is ever written, then proceed with the following steps. In 32 bit apps, lower mem would be considered anywhere from 00410000 to about 08FFFFFF, but it can vary depending on the game. (a bigger EXE means more 'lower mem' that doesn't change, usually.)

- Find the value you want to point to.
- Use a debugger to find out what ASM reads/writes/accesses this value. The more, the better, as some ASM is much easier to modify, then others. (due mostly to 'having enough space', at least to insert a jump).
- Launch a disassembler and look over the different ASM that you found. The ideal sitution, is something like this.... (we are assuming [ESI+1c] is the value address)

(ASMcodeASMcodeASMcode)
mov [esi+1c], edx
pop esi
pop edx
ret
int 3
int 3
int 3
int 3
int 3
int 3
int 3
int 3
int 3
int 3
int 3
(more ASM)

The int 3's signify 'nothing code'. That is, after it returns (from the ret command) there is usually space after to work with. This is why you want to gather as much ASM that touches it as possible.. because a great many of them will have maybe 2-3 bytes before the next ASM code, and this really isn't enough to work with cleanly.
(as a side note - when you go about finding pointers in other ways, read code usually has the shortest pointer path, as there can be many. Write code can confuse the heck outta you , if it writes to a lot of different values , i.e. health for all things.)
(side note: int 3 is just a common example of nothing code (CC in hex). Just make sure whatever it is you're over-writing isnt actual executable ASM

Lets say you get semi-lucky and find ASM just like this. What you want to do first is pause the game somehow, so you can mess with the live memory, without it blowing up in your face. Of course you don't have to... its just safer.

1 of 3 situations will occur. (none of which I opted for, with B&W2's trainer)

Situation 1: You have enough room to plop in your own ASM , which writes ESI to a 'static and never used address', Again, you can usually find this in the lower areas of memory and even stick it in between other ASM (where int 3's / nothing code is).

Situation 2: You don't have enough room to add your own code, and have to create a horiffic JUMP to your own code-cave, and the code-cave jumps back at the end. Jumps tend to be much much smaller then the code you're trying to write. This is a great deal more dangerous, as you'll likely have to find a good 16-32+ bytes of mem that is never written to.

Situation 3: You have enough room to over-write the code that is writing to the value to begin with (that is, if its write code). Usually, you don't want to even think about nullifying a read, but if you're going to be writing your own value anyhow, it usually doesnt hurt to over-write the original write code.
Below , are examples of all 3...

1. We have enough room, yay!
Original Code.
(ASMcodeASMcodeASMcode)
mov [esi+1c], edx (3 bytes long)
pop esi (1 byte)
pop edx (1 byte)
ret (1 byte)
int 3 (1 byte)
int 3 (1 byte)
int 3 (1 byte)
int 3 (1 byte)
int 3 (1 byte)
int 3 (1 byte)
int 3 (1 byte)
int 3 (1 byte)
int 3 (1 byte)
int 3 (1 byte)
int 3 (1 byte)
( more ASM )
We have 6 bytes that *have* to be a part of the final code, 11 bytes of int 3's, but only 10 real bytes we can use there. Things like MOV's aren't really important, unless the situation calls for it, however if that MOV was a FSTP, you DEFINATELY want to find a way keep this in the new code, else everything collapses. Basically, always try to preserve whats there, and simply add to it, unless you know it'll work without it. Another thing: ALWAYS try to leave AT LEAST 2 bytes (1 byte minimum) between the end of your code, and the begining of the next ASM. If they smash together, it is possible for the other ASM to 'turn into' something completely different, because of your code before it. Having that 1-2 byte buffer stops that from happening.
When writing to live memory, we usually have to do it in chunks of 4... We cant simply start over-writing whats there, because the program/game might wind up executing it as it's being written, at which point *crash* occurs. This is one place that jumps shine, because you can write the pre-code to memory, the overwrite an instruction with a 2-4 byte jump, which RARELY ever causes a crash.
What I would do here, is figure out how many of those bytes im going to be using, then write from the bottom up, like so...
Lets assume that I've been watching offset 00B0802C, which is between other ASM, but never written to from what I can tell. The ASM I would make would be something like this.
mov [00b0802c],esi (6 bytes)
If you wanted to actually get the +1c added to ESI before hand, you can do it with...
add [00b0802c], 1c
or, the more dangers version...
add esi,1c (3 bytes)

The 2nd example there is dangerous, only if ESI is used again in later code. Usually, it's really not important to save the 1c part of the offset, as trainer makers or your own code can add this.

Also , thats 3+ more bytes you'd be using, and you're surely pressed for space. On top of that.. holy s@#$!! our code is 6 bytes! that sounds familiar.. Thats exactly how much code we have to offset anyhow! EASY!
Your program would basically make a copy of the 6 bytes into the int 3's area...

i.e.

(ASMcodeASMcodeASMcode)
mov [esi+1c], edx (3 bytes)
pop esi (1 byte)
pop edx (1 byte)
ret (1 byte)
mov [esi+1c], edx (3 bytes)
pop esi (1 byte)
pop edx (1 byte)
ret (1 byte)
int 3 (1 byte)
int 3 (1 byte)
int 3 (1 byte)
int 3 (1 byte)
int 3 (1 byte)
( more ASM )

Then, it would replace the top-section ASM, with your new and improved ASM.

(ASMcodeASMcodeASMcode)
mov [00b0802c],esi (6 bytes)
mov [esi+1c], edx (3 bytes)
pop esi (1 byte)
pop edx (1 byte)
ret (1 byte)
int 3 (1 byte)
int 3 (1 byte)
int 3 (1 byte)
int 3 (1 byte)
int 3 (1 byte)
( more ASM )

Now, your trainer simply points to 00b0802c+1c and voila.

2. "Not enough room" Man, I hate having to do this one... Again, it's very messy, and not respected unless the amount of ASM being inserted is HUGE. I always seem to find a way to get around doing this, although I have had to do it on occasion.

Original Code:
Offset 00888887: (ASMcodeASMcodeASMcode)
Offset 00888888: mov [esi+1c], edx (3 bytes)
Offset 0088888B: pop esi (1 byte)
Offset 0088888C: pop edx (1 byte)
Offset 0088888D: ret (1 byte)
Offset 0088888E: int 3 (1 byte)
Offset 0088888F: ( more ASM )

Gee, a whole 1 byte extra to work with... No bother.. We have already located a place in memory (Offset 00800000) which has not been written to in the last 10 restarts of the game and hours of play (seriously, to find a good code cave, this is what it takes. That's ok though... making a trainer takes hours of testing anyhow.)

We have a few options as to how to get there and we must determine this, before writing the code in the new location.
- call 00800000 (5 bytes)
- js 00800000 (ouch, 6 bytes, because its so far.. js = jump short = can be only 2 bytes long, if close enough.)
- jmp 00800000 (5 bytes) - I'm not sure why I feel this way, but I'd rather jump then call. Calls have to 'ret' eventually. Jumps just simply jump (and your code at 00800000 must end in a jmp back to the original code area. Or, a ret, if you used Call)

Ok, now we got a game plan down and know that we're going to need 5 of the 6 bytes to do it. First step, insert our own code at 00800000, then re-code the first 5 bytes we're replacing.

Offset 00800000: mov [00b0802c], esi (3 bytes)
Offset 00800003: add [00b0802c], 1c (7 bytes! But hey, now we have a DIRECT pointer)
Offset 0080000A: mov [esi+1c], edx (3 bytes)
Offset 0080000D: pop esi (1 byte)
Offset 0080000E: pop edx (1 byte)
Offset 0080000F: jmp 0088888D (5 bytes) - This is the jump, back to where we 'left off'. Note, at this point we still havnt touched the target ASM. You want as little interruption in code as possible, and even the milliseconds it takes to write the above to memory can be catastrophic (had you ripped out the original code first).

Now all that's left is to replace the original 5 bytes with your jump...

Offset 00888887: (ASMcodeASMcodeASMcode)
Offset 00888888: jmp 00800000 (5 bytes)
Offset 0088888D: ret (1 byte)
Offset 0088888E: int 3 (1 byte)
Offset 0088888F: ( more ASM )

3. Lastly, the good ol over-write. Lets say it was ammo you were looking to affect, and the above code is what writes to your ammo value. Well we don't need to keep the ASM writing to it, if we're going to do that ourselves via a pointer/value.

Original:
(ASMcodeASMcodeASMcode)
mov [esi+1c], edx (3 bytes) - We want to replace this line with mov [00b0802c],esi (6 bytes)
pop esi (1 byte)
pop edx (1 byte)
ret (1 byte)
int 3 (1 byte)
int 3 (1 byte)
int 3 (1 byte)
int 3 (1 byte)
int 3 (1 byte)
( more ASM )

Here's the kicker. Almost ALWAYS, the code you want to replace, is 1-3 bytes shorter then the code you want there instead. This is when you start looking up ways to do something in less bytes, but realise its physically (really) impossible. Heres how i'd proceed:

We know this area is going to use 3 of the int 3's , because we're replacing a 3 byte code with a 6 byte one.

Step 1:
mov [esi+1c], edx (3 bytes)
pop esi (1 byte)
pop edx (1 byte)
ret (1 byte)
pop esi (1 byte)
pop edx (1 byte)
ret (1 byte)
int 3 (1 byte)
int 3 (1 byte)

Step 2:
mov [00b0802c],esi (6 bytes)
pop esi (1 byte)
pop edx (1 byte)
ret (1 byte)
int 3 (1 byte)
int 3 (1 byte)

Voila' ... A self-made pointer...

Keep in mind that the code has to execute before your pointer will be written. In this case, firing the gun once should do it

I just remembered, that I did use a tactic like this for the B&W2 trainer.

Villager age control! - It went something like this...

Original Code: movss [esi+00000634],xmm0
esi+634 being the current villager whos age was being updated. xmm0 being a calculation before hand.

I simply went above this line and found a good 16 bytes where it was 'figuring out' what xmm0 should be. Great! I then made the slider affect an address in lower memory which wasnt written to evar, then I simply did this...

movss xmm0, [01808080] (or something to that affect).

Jeebus... I hope after this, you feel repaid for giving me a much needed link

- Zhoul


Last edited by Zhoul on Wed Dec 14, 2005 4:01 am; edited 2 times in total
Back to top
View user's profile Send private message AIM Address
Zhoul
Master Cheater
Reputation: 1

Joined: 19 Sep 2005
Posts: 394

PostPosted: Fri Nov 25, 2005 8:37 am    Post subject: Reply with quote

The problem with static pointers, as I understand them, is that most games usually drill down past 3+ pointer levels.

Static pointers only give 1 total level , eh?

In the entirety of my B&W2 trainer, all the values start at the same exact base/static pointer, but branch out from there, up to 8 levels deep. The method above gives us all a way to ...

1. Bypass having to find 8 level deep pointer paths
2. A way to 'insert' this method into a trainer.

Code injection suxX0rs because you can't use CE's trainer maker to inject, and if you wanted to make a trainer that did inject, well then you'd also already know how to find pointers to begin with. Wink


Last edited by Zhoul on Fri Nov 25, 2005 9:16 am; edited 1 time in total
Back to top
View user's profile Send private message AIM Address
Dark Byte
Site Admin
Reputation: 338

Joined: 09 May 2003
Posts: 19827
Location: The netherlands

PostPosted: Fri Nov 25, 2005 8:40 am    Post subject: Reply with quote

in a few days you should be able to use auto assemble scripts in the ce trainers

and it'll have a pointer scanner that can go any level deep you want. keep in mind that every level exponentially increases time to find it, but if you have a few years you can find anything

_________________
Do not ask me about online cheats. I don't know any and wont help finding them.


Last edited by Dark Byte on Fri Nov 25, 2005 8:49 am; edited 2 times in total
Back to top
View user's profile Send private message MSN Messenger
Turtle
Advanced Cheater
Reputation: 7

Joined: 25 Jul 2004
Posts: 78

PostPosted: Fri Nov 25, 2005 8:45 am    Post subject: Reply with quote

Dynamic pointers are usually the ones with many "levels" (pointer to pointer).

With Static pointers you probably don't have to dig any deeper.
Back to top
View user's profile Send private message
Dark Byte
Site Admin
Reputation: 338

Joined: 09 May 2003
Posts: 19827
Location: The netherlands

PostPosted: Fri Nov 25, 2005 8:48 am    Post subject: Reply with quote

the problem with static pointers is that they only work for level 1 pointers.

but stuff like pointer1->struct1
struct1+12=pointer2->struct2
struct2+8=pointer3->struct3

will be a problem.

of course, pointer1 IS a static pointer, it's just that there comes a little bit after it

_________________
Do not ask me about online cheats. I don't know any and wont help finding them.
Back to top
View user's profile Send private message MSN Messenger
Turtle
Advanced Cheater
Reputation: 7

Joined: 25 Jul 2004
Posts: 78

PostPosted: Fri Nov 25, 2005 8:49 am    Post subject: Reply with quote

Dark Byte wrote:
in a few days you should be able to use auto assemble scripts in the ce trainers

and it'll have a pointer scanner that can go any level deep you want. kweep in mind that every level exponentially increases tuime to find it, but if you have a few years you can find anything


A few days? Cool!
Back to top
View user's profile Send private message
Zhoul
Master Cheater
Reputation: 1

Joined: 19 Sep 2005
Posts: 394

PostPosted: Fri Nov 25, 2005 8:52 am    Post subject: Reply with quote

Dark Byte wrote:
in a few days you should be able to use auto assemble scripts in the ce trainers

and it'll have a pointer scanner that can go any level deep you want. keep in mind that every level exponentially increases time to find it, but if you have a few years you can find anything


On this note....


Static pointers are found in ASM, by the use of [Address]

I tried to export all ASM from range 00400000 to 006FFFFF. Now I know that was asking a lot and I really didn't expect it to work, which it didn't, but what I was going for, is the ability to export all the ASM to a text file, then use filters, to find where ASM uses address values to write to registers.

I sware, there are many faster ways to find pointer paths that havn't been found yet, and I'm sure that the ability to do the above is the first step in one such method Smile All it would take after a good filtering, is to match up filtered results with in-game memory and voila, Pointer paths out the arse...

Turtle wrote:
Dynamic pointers are usually the ones with many "levels" (pointer to pointer).


All dynamic pointers start at a base static pointer. Like I said, with most games, they all use the same base pointer, so 'finding' static pointerS doesnt help much Smile

I suppose you could try to branch off, by using "find out what reads from this address" , but wow.. the ammt of results that would be returned would be HUGGGE and confusing.
Back to top
View user's profile Send private message AIM Address
Turtle
Advanced Cheater
Reputation: 7

Joined: 25 Jul 2004
Posts: 78

PostPosted: Fri Nov 25, 2005 8:56 am    Post subject: Reply with quote

Dark Byte wrote:
the problem with static pointers is that they only work for level 1 pointers.

but stuff like pointer1->struct1
struct1+12=pointer2->struct2
struct2+8=pointer3->struct3

will be a problem.

of course, pointer1 IS a static pointer, it's just that there comes a little bit after it


If you find a static pointer that always points to a value that is an offset of 15 from for example "ammo value". Then what's the problem?

How would the "only work for level 1 pointers" cause a problem? Or would it?
Back to top
View user's profile Send private message
Dark Byte
Site Admin
Reputation: 338

Joined: 09 May 2003
Posts: 19827
Location: The netherlands

PostPosted: Fri Nov 25, 2005 8:59 am    Post subject: Reply with quote

Zhoul wrote:

Static pointers are found in ASM, by the use of [Address]

exactly, that is what the static scanner in ce does. it disassembles all the code, and looks for [xxxxxxxx]parts where there is a 8 digit hexadecimal value and adds that to the list

_________________
Do not ask me about online cheats. I don't know any and wont help finding them.


Last edited by Dark Byte on Fri Nov 25, 2005 9:00 am; edited 1 time in total
Back to top
View user's profile Send private message MSN Messenger
Zhoul
Master Cheater
Reputation: 1

Joined: 19 Sep 2005
Posts: 394

PostPosted: Fri Nov 25, 2005 8:59 am    Post subject: Reply with quote

There is no problem. The point is, these days, damn near any value is nested deeper then 1 level. There is no such thing as a static pointer which points to another static pointer.
Back to top
View user's profile Send private message AIM Address
Dark Byte
Site Admin
Reputation: 338

Joined: 09 May 2003
Posts: 19827
Location: The netherlands

PostPosted: Fri Nov 25, 2005 9:03 am    Post subject: Reply with quote

Turtle wrote:

If you find a static pointer that always points to a value that is an offset of 15 from for example "ammo value". Then what's the problem?

How would the "only work for level 1 pointers" cause a problem? Or would it?


no problem, but if you're not 100% sure it's only a level 1 pointer, there is small chance that it isn't ALWAYS pointing at the right address.

_________________
Do not ask me about online cheats. I don't know any and wont help finding them.
Back to top
View user's profile Send private message MSN Messenger
Turtle
Advanced Cheater
Reputation: 7

Joined: 25 Jul 2004
Posts: 78

PostPosted: Fri Nov 25, 2005 9:08 am    Post subject: Reply with quote

I thought a static pointer was always useable, as long as it pointed to the same structure that my value was in.
Back to top
View user's profile Send private message
Dark Byte
Site Admin
Reputation: 338

Joined: 09 May 2003
Posts: 19827
Location: The netherlands

PostPosted: Fri Nov 25, 2005 9:11 am    Post subject: Reply with quote

that's right, and it usually is. But it may be that that pointer isn't always pointing at the structure you want. (e.g perhaps it sometimes points at the enemy)
e.g perhaps it only points to there when the mouse is over a certain object, or when you're in a specific menu, or when you've alt tabed out of the game

_________________
Do not ask me about online cheats. I don't know any and wont help finding them.


Last edited by Dark Byte on Fri Nov 25, 2005 9:13 am; edited 1 time in total
Back to top
View user's profile Send private message MSN Messenger
Zhoul
Master Cheater
Reputation: 1

Joined: 19 Sep 2005
Posts: 394

PostPosted: Fri Nov 25, 2005 9:12 am    Post subject: Reply with quote

Turtle wrote:
I thought a static pointer was always useable, as long as it pointed to the same structure as my value.


A static pointer is always usable...

Rarely these days, does a static pointer point directly to a value, or a block that contains a lot of values.

Usually, the static pointer will point to a block of DMA pointers, and branch out from there.

It's much easier to reverse engineer pointers, via figuring out how registers became what they were, then to try to start at a static pointer and go forward.
Back to top
View user's profile Send private message AIM Address
Turtle
Advanced Cheater
Reputation: 7

Joined: 25 Jul 2004
Posts: 78

PostPosted: Fri Nov 25, 2005 9:26 am    Post subject: Reply with quote

Dark Byte wrote:
that's right, and it usually is. But it may be that that pointer isn't always pointing at the structure you want. (e.g perhaps it sometimes points at the enemy)
e.g perhaps it only points to there when the mouse is over a certain object, or when you're in a specific menu, or when you've alt tabed out of the game


Yes, I have come across a problem like this.

When I selected a different type of character in a game, the values for that type of character were probably in a different structure.

Perhaps in cases like this, there are even deeper static pointers to be found. Like a static pointer that points to the structure where the value for "character type" is.

If you used that deep static pointer to first determine the character type being used, then would you know what structure was going to be used?
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine Tutorials -> Pointer tutorials All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Powered by phpBB © 2001, 2005 phpBB Group

CE Wiki   IRC (#CEF)   Twitter
Third party websites