 |
Cheat Engine The Official Site of Cheat Engine
|
View previous topic :: View next topic |
Author |
Message |
zm0d Master Cheater
Reputation: 7
Joined: 06 Nov 2013 Posts: 423
|
Posted: Thu Nov 21, 2013 3:46 am Post subject: Dereferencing multilevel pointer |
|
|
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 |
|
 |
SteveAndrew Master Cheater
Reputation: 30
Joined: 02 Sep 2012 Posts: 323
|
Posted: Thu Nov 21, 2013 6:58 am Post subject: Re: Dereferencing multilevel pointer |
|
|
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!
_________________
Last edited by SteveAndrew on Fri Nov 22, 2013 6:38 am; edited 1 time in total |
|
Back to top |
|
 |
zm0d Master Cheater
Reputation: 7
Joined: 06 Nov 2013 Posts: 423
|
Posted: Thu Nov 21, 2013 7:29 am Post subject: |
|
|
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 just used this to make a quick example, because I'm at work. 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! (but you are knowing this )
Well, thank you really... Your supersized explanation helped me much
I will save your GetPointer function!
+rep you
|
|
Back to top |
|
 |
zm0d Master Cheater
Reputation: 7
Joined: 06 Nov 2013 Posts: 423
|
Posted: Thu Nov 21, 2013 6:11 pm Post subject: |
|
|
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?
|
|
Back to top |
|
 |
TsTg Master Cheater
Reputation: 5
Joined: 12 Dec 2012 Posts: 340 Location: Somewhere....
|
Posted: Thu Nov 21, 2013 8:19 pm Post subject: |
|
|
"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 |
|
 |
SteveAndrew Master Cheater
Reputation: 30
Joined: 02 Sep 2012 Posts: 323
|
Posted: Thu Nov 21, 2013 11:53 pm Post subject: |
|
|
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?  |
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! )
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 |
|
 |
zm0d Master Cheater
Reputation: 7
Joined: 06 Nov 2013 Posts: 423
|
Posted: Fri Nov 22, 2013 3:47 am Post subject: |
|
|
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
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 |
|
 |
SteveAndrew Master Cheater
Reputation: 30
Joined: 02 Sep 2012 Posts: 323
|
Posted: Fri Nov 22, 2013 6:04 am Post subject: |
|
|
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
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'
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 |
|
 |
zm0d Master Cheater
Reputation: 7
Joined: 06 Nov 2013 Posts: 423
|
Posted: Fri Nov 22, 2013 7:11 am Post subject: |
|
|
SteveAndrew wrote: | Alright zm0d this time I for sure have it right! |
This sounds really good Can't wait to get home and give it a try. I will ASAP post my results
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.. Well, I could find this out on my own if I'd had taken a closer look to your fundtion :/
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
EDIT: Oh this works so f****in awesome *.*
|
|
Back to top |
|
 |
Gniarf Grandmaster Cheater Supreme
Reputation: 43
Joined: 12 Mar 2012 Posts: 1285
|
|
Back to top |
|
 |
Dark Byte Site Admin
Reputation: 468
Joined: 09 May 2003 Posts: 25719 Location: The netherlands
|
Posted: Fri Nov 22, 2013 11:54 am Post subject: |
|
|
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 |
|
 |
zm0d Master Cheater
Reputation: 7
Joined: 06 Nov 2013 Posts: 423
|
Posted: Fri Nov 22, 2013 12:10 pm Post subject: |
|
|
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 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..
|
|
Back to top |
|
 |
Gniarf Grandmaster Cheater Supreme
Reputation: 43
Joined: 12 Mar 2012 Posts: 1285
|
Posted: Fri Nov 22, 2013 12:48 pm Post subject: |
|
|
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 |
|
 |
zm0d Master Cheater
Reputation: 7
Joined: 06 Nov 2013 Posts: 423
|
Posted: Fri Nov 22, 2013 4:33 pm Post subject: |
|
|
Well, then I've to deal with it
|
|
Back to top |
|
 |
Gniarf Grandmaster Cheater Supreme
Reputation: 43
Joined: 12 Mar 2012 Posts: 1285
|
Posted: Fri Nov 22, 2013 7:11 pm Post subject: |
|
|
@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 |
|
 |
|
|
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
|
|