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 


Dereferencing multilevel pointer
Goto page 1, 2  Next
 
Post new topic   Reply to topic    Cheat Engine Forum Index -> General Gamehacking
View previous topic :: View next topic  
Author Message
zm0d
Master Cheater
Reputation: 7

Joined: 06 Nov 2013
Posts: 423

PostPosted: Thu Nov 21, 2013 3:46 am    Post subject: Dereferencing multilevel pointer Reply with quote

Hi Hitler,

I'm working on a x64 system with VS2012 and I've an injected DLL to my games process. The process of my game is a 32 bit one.
Now I want to dereference my base pointer to a crosshair value. I did something like this:



Code:

#define BASE_CROSSHAIR 0x00001337
#define OFFSET1_CROSSHAIR 0x337
#define OFFSET2_CROSSHAIR 0x37
#define OFFSET3_CROSSHAIR 0x7

[...]
DWORD processBase = (DWORD)GetModuleHandle(NULL);
float crosshairX = (float)(*(DWORD *)(*(DWORD *)(*(DWORD *)(processBase + BASE_CROSSHAIR + OFFSET1_CROSSHAIR)) + OFFSET2_CROSSHAIR) + OFFSET3_CROSSHAIR);
[...]

This part of code is the reason why the DLL isnt be able to get injected. If I comment it out, it can be injected (I use Winject).

DWORD is defined as an unsigned long.
Addresses have a 8 byte size on x64 machines, but how is it with Wow64 processes? Are the addresses 4 bytes long? If so, would a DWORD on a x64 machine be totally wrong to use for 32 bit processes?
Back to top
View user's profile Send private message
SteveAndrew
Master Cheater
Reputation: 30

Joined: 02 Sep 2012
Posts: 323

PostPosted: Thu Nov 21, 2013 6:58 am    Post subject: Re: Dereferencing multilevel pointer This post has 1 review(s) Reply with quote

zm0d wrote:
Hi SteveAndrew,

I'm working on a x64 system with VS2012 and I've an injected DLL to my games process. The process of my game is a 32 bit one.
Now I want to dereference my base pointer to a crosshair value. I did something like this:



Code:

#define BASE_CROSSHAIR 0x00001337
#define OFFSET1_CROSSHAIR 0x337
#define OFFSET2_CROSSHAIR 0x37
#define OFFSET3_CROSSHAIR 0x7

[...]
DWORD processBase = (DWORD)GetModuleHandle(NULL);
float crosshairX = (float)(*(DWORD *)(*(DWORD *)(*(DWORD *)(processBase + BASE_CROSSHAIR + OFFSET1_CROSSHAIR)) + OFFSET2_CROSSHAIR) + OFFSET3_CROSSHAIR);
[...]

This part of code is the reason why the DLL isnt be able to get injected. If I comment it out, it can be injected (I use Winject).

DWORD is defined as an unsigned long.
Addresses have a 8 byte size on x64 machines, but how is it with Wow64 processes? Are the addresses 4 bytes long? If so, would a DWORD on a x64 machine be totally wrong to use for 32 bit processes?


Well make sure you're compiling a 32-bit DLL and as long as you're truly dealing with a 32-bit process you can basically pretend you're on 32-bit lol!

Well not all addresses in x64 (with an .exe and its dll's all being actually 64-bit) are actually 8 bytes. It's mostly pointers that are 64-bits in size. For example you can still mov / copy a 32-bit value even in 64-bit code:
Code:

mov eax,[rbx+2c]
mov [rdx],eax


First instruction uses the 64-bit RBX register as a 64-bit pointer with '0x2c' offset added to it(pointers can only be 64-bit on 64-bit, makes sense) in order to copy a 32-bit value from the address which it pointed to ([rbx+2c])

Where are you putting the code? In DLL Main? or from a created thread from DllMain? lol...

Anyway I hope you're not actually using the 0x37's as offsets and asking why its crashing are you? You've used real offsets?

Here's a function that I use called 'GetPointer' in quick projects! It's a variable argument function where you pass the pointerbase / initial offset, then each offset, with a '-1' marking the end of the offsets arguments.

Example:
Code:

#include <Windows.h>
#include <stdio.h>

#define BASE_CROSSHAIR 0x00001337
#define OFFSET1_CROSSHAIR 0x337
#define OFFSET2_CROSSHAIR 0x37
#define OFFSET3_CROSSHAIR 0x7

int MainThread();
void *GetPointer(DWORD PointerBase, ...);

HINSTANCE hInst;

BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD Reason, LPVOID lpReserved)
{
   if(Reason == DLL_PROCESS_ATTACH)
   {
      hInst = hInstance;
      CreateThread(0, 0, (LPTHREAD_START_ROUTINE)MainThread, 0, 0, 0);
   }
   else if(Reason == DLL_PROCESS_DETACH)
   {
   }

   return TRUE;
}

int MainThread()
{
   OutputDebugStringW(L"DLL Loaded Successfully! Main Thread Started!");

   //cast it to a pointer of its proper data type (of what it actually is) and write to it
   DWORD *MyPointer = (DWORD*)GetPointer(BASE_CROSSHAIR, OFFSET1_CROSSHAIR, OFFSET2_CROSSHAIR, OFFSET3_CROSSHAIR, -1);

   if (MyPointer)
   {
      DWORD PointersValue = *MyPointer; //read value
      *MyPointer = 0x37373737; //write value
   }

   //make a void pointer and cast it later
   void *MyPtr2 = GetPointer(BASE_CROSSHAIR, OFFSET1_CROSSHAIR, OFFSET2_CROSSHAIR, OFFSET3_CROSSHAIR, -1);

   *(WORD*)MyPtr2 = 0x27a0;

   POINT *pt = (POINT*)MyPtr2; //perhaps it's a POINT type?
   pt->x = 27;
   pt->y = 157;

   float *x = 0, *y = 0; //or maybe two floats :)
   x = (float*)MyPtr2;
   y = x + 4;

   *x = 77;
   *y = -107;

   //Or just cast the call of the function itself
   (*(BYTE*)GetPointer(BASE_CROSSHAIR, OFFSET1_CROSSHAIR, OFFSET2_CROSSHAIR, OFFSET3_CROSSHAIR, -1)) = 0xeb;

   //So just so it's clear no matter how many offsets you add, -1 is last (I prefered this instead of having to specify a parameter count or the like)
   //If there was only 2 offsets for example:
   (*(BYTE*)GetPointer(BASE_CROSSHAIR, OFFSET1_CROSSHAIR, OFFSET2_CROSSHAIR, -1)) = 0xeb;

   OutputDebugStringW(L"Unloading...");
   //You definitely won't want to unload unless you provide the option,
   //and make sure its you've made any other running threads exit before
   //calling this on your last remaining thread! ;)
   //Safely unload DLL (well for the most part)
   FreeLibraryAndExitThread(hInst, 0);
   return 0;
}

void *GetPointer(DWORD PointerBase, ...)
{
   DWORD CurrentPointer = (PointerBase + (DWORD)GetModuleHandle(0));
   DWORD LastOffset = 0;
   va_list Params;
   va_start(Params, PointerBase);
   for(;;)
   {
      unsigned int CurrentOffset = va_arg(Params, unsigned int);
      if(CurrentOffset != 0xffffffff)
      {
         if(CurrentPointer == 0) break;
         CurrentPointer = *(DWORD*)(CurrentPointer + LastOffset);
         LastOffset = CurrentOffset;
      }
      else
      {
         CurrentPointer += LastOffset;
         break;
      }
   }
   va_end(Params);

   return (void*)CurrentPointer;
}


I'm sure you can see how to use it from there, for an alternative for heavier projects try the pointer helper class I did a while back:
http://forum.cheatengine.org/viewtopic.php?p=5422282

There that should help a bit, and I hope that my code is clear enough! Smile

_________________


Last edited by SteveAndrew on Fri Nov 22, 2013 6:38 am; edited 1 time in total
Back to top
View user's profile Send private message
zm0d
Master Cheater
Reputation: 7

Joined: 06 Nov 2013
Posts: 423

PostPosted: Thu Nov 21, 2013 7:29 am    Post subject: Reply with quote

SteveAndrew wrote:
Anyway I hope you're not actually using the 0x37's as offsets and asking why its crashing are you? You've used real offsets?

No, no, no I don't do that Razz Very Happy just used this to make a quick example, because I'm at work. Razz At home i have the real offsets (level 5 pointer)

Quote:
Where are you putting the code? In DLL Main? or from a created thread from DllMain?

Extra Thread, since putting everything in DllMain is not recommended! Smile (but you are knowing this Razz)

Well, thank you really... Your supersized explanation helped me much Smile
I will save your GetPointer function! Smile

+rep you Smile Smile
Back to top
View user's profile Send private message
zm0d
Master Cheater
Reputation: 7

Joined: 06 Nov 2013
Posts: 423

PostPosted: Thu Nov 21, 2013 6:11 pm    Post subject: Reply with quote

Okay... this seems not to work at all.
I have the process (Intake.exe) and get the the module base address, that is 00390000. Now cheat engine shows me the base address ("Intake.exe" +0095D254) => 02EB1FE0.

It calculates 00390000 + 0095D254 and then points to address 02EB1FE0.
If I use your function GetPointer (or use simple windows calculator) it also adds this 2 addresses but my result is 00CED254 (which is the correct result of this adding). WTF? Very Happy
Back to top
View user's profile Send private message
TsTg
Master Cheater
Reputation: 5

Joined: 12 Dec 2012
Posts: 340
Location: Somewhere....

PostPosted: Thu Nov 21, 2013 8:19 pm    Post subject: Reply with quote

"Intake.exe" +0095D254 ==> 00390000 + 0095D254 = 00CED254

where 00CED254 is the address of yours (the pointer static address)

then: value inside dword [00CED254] is 02EB1FE0 (the pointer address_level_1)

then next you add the first level offset [02EB1FE0 + XX] to get address_level_2

then next offset [address_level_2 + ZZ] to get next level, and so on
Back to top
View user's profile Send private message
SteveAndrew
Master Cheater
Reputation: 30

Joined: 02 Sep 2012
Posts: 323

PostPosted: Thu Nov 21, 2013 11:53 pm    Post subject: Reply with quote

zm0d wrote:
Okay... this seems not to work at all.
I have the process (Intake.exe) and get the the module base address, that is 00390000. Now cheat engine shows me the base address ("Intake.exe" +0095D254) => 02EB1FE0.

It calculates 00390000 + 0095D254 and then points to address 02EB1FE0.
If I use your function GetPointer (or use simple windows calculator) it also adds this 2 addresses but my result is 00CED254 (which is the correct result of this adding). WTF? Very Happy


As TsTg pointed out, you dereference it to get the next level in the pointer chain. (It's basically another pointer)

Anyway there was a slight issue with how I had it before, this has it fixed now:
Code:

void *GetPointer(DWORD PointerBase, ...)
{
   va_list Params;
   DWORD CurrentPointer = *(DWORD*)(PointerBase + (DWORD)GetModuleHandle(0));

   va_start(Params, PointerBase);
   for (;;)
   {
      unsigned int TheOffset = va_arg(Params, unsigned int);
      if(TheOffset == 0xffffffff || CurrentPointer == 0)
         break;
      else
      {
            CurrentPointer = *(DWORD*)(CurrentPointer + TheOffset);
      }
   }
   va_end(Params);

   return (void*)CurrentPointer;
}


Here's how it works:

1. Adds your passed in first parameter 'PointerBase' to what's returned from 'GetModuleHandle(0)' (executable's image base) dereferences it and stores it in 'CurrentPointer' 32-bit variable.

2. Declares the start of the variable arguments after 'PointerBase' argument /parameter!

3. Steps into an infinite loop and gets the first passed in offset argument (or the next offset argument depending on whether its passed the first iteration)
3a. If the passed offset argument retrieved is '-1' (previous passed offset was last offset) or 'CurrentPointer' is '0' (pointer perhaps not ready yet, dereferencing it would result in crash)

4. Adds the first/next offset needed to the current pointer we have, and dereference it again! (The act of dereferencing gets you to the next step, the next point where you can add the next offset and dereference again!)

5. Finally once it breaks return what we have for the current pointer.

(The idea with the initial script how I tried to change it to was to not dereference when its the last offset, but to just add it to the pointer getting it to the address ready to dereference. However it's probably better this way anyway! Smile )

I could have written it differently maybe, but I guess that's just how I wrote it at the time I did! lol!

_________________
Back to top
View user's profile Send private message
zm0d
Master Cheater
Reputation: 7

Joined: 06 Nov 2013
Posts: 423

PostPosted: Fri Nov 22, 2013 3:47 am    Post subject: Reply with quote

SteveAndrew wrote:
(The idea with the initial script how I tried to change it to was to not dereference when its the last offset, but to just add it to the pointer getting it to the address ready to dereference. However it's probably better this way anyway! Smile )

And the base pointer gets dereferenced now Smile

So if I understand you right I use this function like this:
Code:
float *crosshairX = (float *)GetPointer(BASE_ADDRESS, OFFSET_1, OFFSET_2, OFFSET_3, -1);
*crosshairX = 0.0 // Sets it into the middle of the x-axis


I tried this tomorrow early, right before driving to work, but when I wanted to dereference the crosshairX address, the game crashed.

With your old GetPointer function my game crashed immediatly after injecting. Now it crashes when I try to dereference my crosshairX address.
Back to top
View user's profile Send private message
SteveAndrew
Master Cheater
Reputation: 30

Joined: 02 Sep 2012
Posts: 323

PostPosted: Fri Nov 22, 2013 6:04 am    Post subject: Reply with quote

Alright zm0d this time I for sure have it right! I should've went with my gut, okay yes you don't dereference it when you get to the last one. So when you've gotten far enough to get to the last pointer offset you just add it to where your at and return that rather then dereferencing it also!

I'm willing to bet that what your derefercing now as a pointer is actually the crosshair coordinate value itself at present Wink

you have to add another include
Code:

#include <vector>

//[...]

void *GetPointer(DWORD PointerBase, ...)
{
   va_list Params;
   std::vector<unsigned int>OffsetsArray;

   va_start(Params, PointerBase);
   for (;;)
   {
      unsigned int TheOffset = va_arg(Params, unsigned int);
      if (TheOffset != 0xffffffff)
         OffsetsArray.push_back(TheOffset);
      else
         break;
   }
   va_end(Params);

   DWORD CurrentPointer = *(DWORD*)(PointerBase + (DWORD)GetModuleHandle(0));
   //for(std::vector<unsigned int>::iterator CurrentOffset = OffsetsArray.begin(); CurrentOffset != OffsetsArray.end(); CurrentOffset++)
   for(auto CurrentOffset = OffsetsArray.begin(); CurrentOffset != OffsetsArray.end(); CurrentOffset++)
   {
      if (CurrentOffset == (OffsetsArray.end()-1)) //last pointer in pointer chain don't dereference just add
         CurrentPointer += *CurrentOffset;
      else
         CurrentPointer = *(DWORD*)(CurrentPointer + *CurrentOffset); //Other wise add+dereference until then!
   }

   OffsetsArray.clear();
   return (void*)CurrentPointer;
}


This time it just grabs all variable argument offsets passed in and puts them into a vector array. Gets first initial pointer like before with game image base + 'PointerBase'. Then using C++ 11 style iterator (or comment it out; That 'for(auto' line and uncomment the other if your compiler's not on c++ 11 yet) update 'CurrentPointer' with next link in chain by adding the current offset to 'CurrentPointer' and dereferencing it! If it's the last offset entry in the array, don't dereference it but just add it to current pointer...


So basically it was working like this before (imagine this pointer as being real): [[[[Game.exe+773138]+154]+90]+28]
It is float value say, a health value containing 100.0 (full health)

Previously It was following the whole entire chain then at the last offset '28' also deferencing it after adding it so it already contained the health value after that!

float health = (float)GetPointer(0x773138, 0x154, 0x90, 0x28, -1);
if(health == 100.0f)
{
//this would be true (at least previously)
}

[Game.exe+773138] -> 246c2b14
[246c2b14+154] -> 29f0d700
[29f0d700+90] -> 2b6974c0
[2b6974c0+28] -> 27978e00

2b6974c0+28 == 2b6974e8; *2b6974e8 == 2797e00

Now it's like this, which is also matches how CE does it now...


[Game.exe+773138] -> 246c2b14
[246c2b14+154] -> 29f0d700
[29f0d700+90] -> 2b6974c0
2b6974c0+28 -> 2b6974e8

EDIT: Actually after posting I figured out a way for it to behave in exactly the same way, without having to use a vector, just another variable instead to back up the 'lastoffset' Smile

Code:

void *GetPointer(DWORD PointerBase, ...)
{
   DWORD CurrentPointer = (PointerBase + (DWORD)GetModuleHandle(0));
   DWORD LastOffset = 0;
   va_list Params;
   va_start(Params, PointerBase);
   for(;;)
   {
      unsigned int CurrentOffset = va_arg(Params, unsigned int);
      if(CurrentOffset != 0xffffffff)
      {
         if(CurrentPointer == 0) break;
         CurrentPointer = *(DWORD*)(CurrentPointer + LastOffset);
         LastOffset = CurrentOffset;
      }
      else
      {
         CurrentPointer += LastOffset;
         break;
      }
   }
   va_end(Params);

   return (void*)CurrentPointer;
}

_________________
Back to top
View user's profile Send private message
zm0d
Master Cheater
Reputation: 7

Joined: 06 Nov 2013
Posts: 423

PostPosted: Fri Nov 22, 2013 7:11 am    Post subject: Reply with quote

SteveAndrew wrote:
Alright zm0d this time I for sure have it right!

This sounds really good Smile Can't wait to get home and give it a try. I will ASAP post my results Smile

SteveAndrew wrote:
Previously It was following the whole entire chain then at the last offset '28' also deferencing it after adding it so it already contained the health value after that!

Ahhh I see.. Smile Well, I could find this out on my own if I'd had taken a closer look to your fundtion :/ Very Happy

SteveAndrew wrote:
EDIT: Actually after posting I figured out a way for it to behave in exactly the same way, without having to use a vector, just another variable instead to back up the 'lastoffset'

Oh I love it <3 Very Happy


EDIT: Oh this works so f****in awesome *.*
Back to top
View user's profile Send private message
Gniarf
Grandmaster Cheater Supreme
Reputation: 43

Joined: 12 Mar 2012
Posts: 1285

PostPosted: Fri Nov 22, 2013 11:52 am    Post subject: Reply with quote

@SteveAndrew: If I may suggest a slight improvement, it'd be a bit safer to use IsBadReadPtr(CurrentPointer + LastOffset, sizeof(DWORD*)) instead of CurrentPointer == 0. Just in case the game's memory manager initializes memory to 0x1badc0de, or there if is remnant data at this address.
Or since msdn says that IsBadReadPtr is obsolete, you could also use a try/catch/trow instead.
Anyway, I'm just raising the idea. Cool


@zm0d: if you're still on that aimbot, there is something I've got to take off my chest: PILLS HERE !! (l4d joke)

_________________
DO NOT PM me if you want help on making/fixing/using a hack.
Back to top
View user's profile Send private message
Dark Byte
Site Admin
Reputation: 468

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

PostPosted: Fri Nov 22, 2013 11:54 am    Post subject: Reply with quote

Even safer is using ReadProcessMemory on the local process. That way you won't mess up guarded memory ranges
_________________
Do not ask me about online cheats. I don't know any and wont help finding them.

Like my help? Join me on Patreon so i can keep helping
Back to top
View user's profile Send private message MSN Messenger
zm0d
Master Cheater
Reputation: 7

Joined: 06 Nov 2013
Posts: 423

PostPosted: Fri Nov 22, 2013 12:10 pm    Post subject: Reply with quote

Gniarf wrote:
@zm0d: if you're still on that aimbot, there is something I've got to take off my chest: PILLS HERE !! (l4d joke)


LOOOL Very Happy well I've less time at the moment... :'(

BTW: Is a game using ASLR, when my process base address changes on each start? I've read quite less about ASLR at the moment.. Razz
Back to top
View user's profile Send private message
Gniarf
Grandmaster Cheater Supreme
Reputation: 43

Joined: 12 Mar 2012
Posts: 1285

PostPosted: Fri Nov 22, 2013 12:48 pm    Post subject: Reply with quote

zm0d wrote:
Is a game using ASLR, when my process base address changes on each start?
Yes.
When an application does NOT use ASLR the exe is always loaded at 0x400000, unless the devs changed this default value which they never do.


@Dark Byte: hadn't thought about guard pages, thank for the tip.

_________________
DO NOT PM me if you want help on making/fixing/using a hack.
Back to top
View user's profile Send private message
zm0d
Master Cheater
Reputation: 7

Joined: 06 Nov 2013
Posts: 423

PostPosted: Fri Nov 22, 2013 4:33 pm    Post subject: Reply with quote

Gniarf wrote:
Yes.

Well, then I've to deal with it Very Happy
Back to top
View user's profile Send private message
Gniarf
Grandmaster Cheater Supreme
Reputation: 43

Joined: 12 Mar 2012
Posts: 1285

PostPosted: Fri Nov 22, 2013 7:11 pm    Post subject: Reply with quote

@zm0d: What's the problem with ASLR? Normally the GetModuleHandle(0) in SteveAndrew's code will give you the address at which the exe is loaded.

Yes msdn says it's a handle, but module handles are actually a dword that represent at which address they are loaded.

_________________
DO NOT PM me if you want help on making/fixing/using a hack.
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Cheat Engine Forum Index -> General Gamehacking 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