 |
Cheat Engine The Official Site of Cheat Engine
|
View previous topic :: View next topic |
Author |
Message |
Cren How do I cheat?
Reputation: 0
Joined: 05 Oct 2015 Posts: 7
|
Posted: Mon Oct 05, 2015 6:50 am Post subject: Pointers and offsets with esi, ecx, eax... expressions |
|
|
Hi all, this is my first post on this forum thus I hope this is the right place where asking for help.
I've completed Cheat Engine 6.4 Tutorial and I'm trying my first experiment to retrieve static memory address of a value inside a true game running on my PC.
I properly get value address, but it's not green - this means it's not static and it will likely change after game restart; therefore, I'm going to use the technique explained in tutorial which is: get pointers to pointers to pointers... until you find a static address.
Problem is "More information" shows a code like this one:
>>00722C8A - mov [esi+ecx*4+00000FB4],eax
I know which values esi and ecx have, but I don't know how to deal with such an expression when making a pointer: is there any tutorial which explains how to deal with expressions? Could you tell me how to create pointers with expressions and/or if there are better and faster solutions to retrieve static addresses?
Thanks,
|
|
Back to top |
|
 |
Zanzer I post too much
Reputation: 126
Joined: 09 Jun 2013 Posts: 3278
|
Posted: Mon Oct 05, 2015 5:13 pm Post subject: |
|
|
Right-click the address and select Pointer scan for this address. That's probably the simplest way.
http://forum.cheatengine.org/viewtopic.php?t=572465
As for your found instruction, ESI is the base of the structure.
+FB4 is the offset to a fixed-size array of similar types, most likely 4-byte integers.
ECX*4 is pointing to the specific item in that fixed-size array.
So when ECX is 0, it adds +0 to the already +FB4 offset, giving you the first item in the array.
When ECX is 1, it adds +4 (1*4) to +FB4, giving +FB8.
When ECX is 2, it adds +8 (2*4) to +FB4, giving +FBC.
etc.
So for you, you would want to do a value search for the same value held in ESI to find the previous pointer.
|
|
Back to top |
|
 |
Cren How do I cheat?
Reputation: 0
Joined: 05 Oct 2015 Posts: 7
|
Posted: Mon Oct 12, 2015 4:01 am Post subject: |
|
|
As for results obtained via pointer scan, how am I supposed to handle with Base Address retrieved?
As instance, let my pointer scan finds that the address I'm looking for is:
Code: |
Base Address Offset 0 Offset 1 Offset 2 Offset 3 Offset 4 Points to:
"Foo.exe"+006DB754 1C 0 58 3C FB4 2047C074
|
What would that variable static address be?
|
|
Back to top |
|
 |
Zanzer I post too much
Reputation: 126
Joined: 09 Jun 2013 Posts: 3278
|
Posted: Mon Oct 12, 2015 6:20 am Post subject: |
|
|
What are you trying to do with it that you need to handle?
Double click the address and Cheat Engine adds it to your table.
|
|
Back to top |
|
 |
Cren How do I cheat?
Reputation: 0
Joined: 05 Oct 2015 Posts: 7
|
Posted: Mon Oct 12, 2015 8:45 am Post subject: |
|
|
Zanzer wrote: | What are you trying to do with it that you need to handle?
Double click the address and Cheat Engine adds it to your table. |
Added.
But then? I mean: I have the pointer in my table, something like P->20FB5804.
Anyhow I need to retrieve a static address: am I supposed to follow the "classic" procedure to find one? I.e. "Find out what accesses this address", refresh value, take notes of hexadecimal address, find pointer of pointer... and so forth..?
If I do this, I get weird results: debugger gives me in square brackets something like [Foo.exe+6DB754], not an esi/eax/... + offset.
|
|
Back to top |
|
 |
Zanzer I post too much
Reputation: 126
Joined: 09 Jun 2013 Posts: 3278
|
Posted: Mon Oct 12, 2015 10:13 am Post subject: |
|
|
That is the base address. That's how it works.
When the game loads, it loads in a different memory region each time.
However, the static address is always 6DB754 bytes away from the base.
Foo.exe is the base that changes upon each load.
Cheat Engine finds the memory address of the base and then moves 6DB754 bytes to the right.
That's where it finds your base address to use as a pointer.
|
|
Back to top |
|
 |
Cren How do I cheat?
Reputation: 0
Joined: 05 Oct 2015 Posts: 7
|
Posted: Tue Oct 13, 2015 6:52 am Post subject: |
|
|
Zanzer wrote: | That is the base address. That's how it works.
When the game loads, it loads in a different memory region each time.
However, the static address is always 6DB754 bytes away from the base.
Foo.exe is the base that changes upon each load.
Cheat Engine finds the memory address of the base and then moves 6DB754 bytes to the right.
That's where it finds your base address to use as a pointer. |
I still do not understand how to use such an information.
I mean: I have a script which uses a call to .dll with OpenProcess to get an handle ("hwnd") from a process ID, and then it reads a memory address by knowing the hwnd and the address.
If I use this script with any static or non static address found by Cheat Engine 6.4 in its main scan results window, it properly returns the game's variable value.
But I don't know how to deal with "base address"... see attached screenshot to understand what I mean (see attachment now, please).
My script (AutoHotkey, in this case) is something like:
Code: | MemoryOpenFromPID(PID, Privilege=0x1F0FFF)
{
HWND := DllCall("OpenProcess", "Uint", Privilege, "int", 0, "int", PID)
return HWND
} |
and
Code: | MemoryRead(hwnd, address, datatype="int", length=4, offset=0)
{
VarSetCapacity(readvalue,length, 0)
DllCall("ReadProcessMemory","Uint",hwnd,"Uint",address+offset,"Str",readvalue,"Uint",length,"Uint *",0)
finalvalue := NumGet(readvalue,0,datatype)
return finalvalue
} |
I repeat: script works properly with address 20DDDB54 (see image), but I don't know what input to use with the base address ".exe"+006DB754 and its offsets.
Description: |
|
Filesize: |
76 KB |
Viewed: |
20593 Time(s) |

|
|
|
Back to top |
|
 |
Zanzer I post too much
Reputation: 126
Joined: 09 Jun 2013 Posts: 3278
|
|
Back to top |
|
 |
Cren How do I cheat?
Reputation: 0
Joined: 05 Oct 2015 Posts: 7
|
Posted: Tue Oct 13, 2015 7:16 am Post subject: |
|
|
You're pretty chatty, uh?
From your link I see an interesting C++ function; please, let me know if I properly understand its purpose: by passing PID and process' name, it should return a DWORD_PTR (which is just a typedef for unsigned __int3264, right?).
Does that mean that I can compile that function in an executable with its main and use a simple std::cout to print the information I seek in runtime window? And use that address as I've done before with 20DDDB54?
Thanks for your help, anyway!
|
|
Back to top |
|
 |
Zanzer I post too much
Reputation: 126
Joined: 09 Jun 2013 Posts: 3278
|
Posted: Tue Oct 13, 2015 8:52 am Post subject: |
|
|
http://forum.cheatengine.org/viewtopic.php?t=422516
The value of ModuleEntry32.modBaseAddr will be the base address of "game.exe".
Add to that address the offset value of 6DB754.
Now use ReadProcessMemory on the address.
This will return another address value. To this value, add 1C, as shown in your screenshot.
Then ReadProcessMemory at this new address. To that value, add the next offset of 0.
Continue this step until you reach your final offset of FB4.
The final address after you add FB4 will be the 20DDDB54 address in your screenshot.
|
|
Back to top |
|
 |
Cren How do I cheat?
Reputation: 0
Joined: 05 Oct 2015 Posts: 7
|
Posted: Wed Oct 14, 2015 6:09 am Post subject: |
|
|
Zanzer wrote: |
The value of ModuleEntry32.modBaseAddr will be the base address of "game.exe".
Add to that address the offset value of 6DB754.
Now use ReadProcessMemory on the address.
This will return another address value. To this value, add 1C, as shown in your screenshot.
Then ReadProcessMemory at this new address. To that value, add the next offset of 0.
Continue this step until you reach your final offset of FB4.
The final address after you add FB4 will be the 20DDDB54 address in your screenshot. |
Variable's value is 332. Base address and offsets are:
Base Address = 0x400000 + 0x6DB754
Offset 0 = 0x1C
Offset 1 = 0x0
Offset 2 = 0x58
Offset 3 = 0x3C
Offset 4 = 0xFB4
Is it correct to say that the final address should be:
0x400000 + 0x6DB754 + 0x1C + 0x0 + 0x58 + 0x3C + 0xFB4 = 0xADC7B8 ?
If so, why reading 0xADC7B8 does not return 332?
Consider 0x400000 has not been found using the C++ function you've kindly linked but this script:
Code: | ; Return values:
; Null The process's window couldn't be found.
; 0 The GetWindowLong or GetWindowLongPtr call failed.
; Non-Zero The base address of the process (success).
getProcessBaseAddress(WindowTitle, windowMatchMode := "3") ;WindowTitle can be anything ahk_exe ahk_class etc
{
if (windowMatchMode && A_TitleMatchMode != windowMatchMode)
{
mode := A_TitleMatchMode ; This is a string and will not contain the 0x prefix
StringReplace, windowMatchMode, windowMatchMode, 0x ; remove hex prefix as SetTitleMatchMode will throw a run time error. This will occur if integer mode is set to hex and matchmode param is passed as an number not a string.
SetTitleMatchMode, %windowMatchMode% ;mode 3 is an exact match
}
WinGet, hWnd, ID, %WindowTitle%
if mode
SetTitleMatchMode, %mode% ; In case executed in autoexec
if !hWnd
return ; return blank failed to find window
return DllCall(A_PtrSize = 4 ; If DLL call fails, returned value will = 0
? "GetWindowLong"
: "GetWindowLongPtr"
, "Ptr", hWnd, "Int", -6, A_Is64bitOS ? "Int64" : "UInt")
; For the returned value when the OS is 64 bit use Int64 to prevent negative overflow when AHK is 32 bit and target process is 64bit
; however if the OS is 32 bit, must use UInt, otherwise the number will be huge (however it will still work as the lower 4 bytes are correct)
; Note - it's the OS bitness which matters here, not the scripts/AHKs
} |
Hence base address is obtained through a call to .dll "GetWindowLong" or "GetWindowLongPtr", it returns a LONG_PTR.
Cren wrote: |
Consider 0x400000 has not been found using the C++ function you've kindly linked but this script... |
Just for the records: results from that script and your C++ function are the same.
I've compiled and run the C++ function in a very simple main and here's what I get (see attachment, only DWORD is introduced by std::cin, TCHAR* argument is hard-coded).
This means that I am still missing something in pointers algebra
Description: |
|
Filesize: |
13.19 KB |
Viewed: |
20510 Time(s) |

|
|
|
Back to top |
|
 |
Zanzer I post too much
Reputation: 126
Joined: 09 Jun 2013 Posts: 3278
|
Posted: Wed Oct 14, 2015 5:05 pm Post subject: |
|
|
Cren wrote: | Base Address = 0x400000 + 0x6DB754
Offset 0 = 0x1C
Offset 1 = 0x0
Offset 2 = 0x58
Offset 3 = 0x3C
Offset 4 = 0xFB4 |
lpBaseAddress = dwGetModuleBaseAddress(...)
ReadProcessMemory(hProcess, lpBaseAddress + 0x6DB754, &lpBaseAddress, 4)
ReadProcessMemory(hProcess, lpBaseAddress + 0x0, &lpBaseAddress, 4)
ReadProcessMemory(hProcess, lpBaseAddress + 0x58, &lpBaseAddress, 4)
ReadProcessMemory(hProcess, lpBaseAddress + 0x3C, &lpBaseAddress, 4)
ReadProcessMemory(hProcess, lpBaseAddress + 0xFB4, &myvalue, 4)
address = <get the base address>
address = MemoryRead(hwnd, address, "int", 4, 0x6DB754)
address = MemoryRead(hwnd, address, "int", 4, 0x0)
address = MemoryRead(hwnd, address, "int", 4, 0x58)
address = MemoryRead(hwnd, address, "int", 4, 0x3C)
myvalue = MemoryRead(hwnd, address, "int", 4, 0xFB4)
|
|
Back to top |
|
 |
Cren How do I cheat?
Reputation: 0
Joined: 05 Oct 2015 Posts: 7
|
Posted: Thu Oct 15, 2015 1:05 am Post subject: |
|
|
Zanzer wrote: | Cren wrote: | Base Address = 0x400000 + 0x6DB754
Offset 0 = 0x1C
Offset 1 = 0x0
Offset 2 = 0x58
Offset 3 = 0x3C
Offset 4 = 0xFB4 |
lpBaseAddress = dwGetModuleBaseAddress(...)
ReadProcessMemory(hProcess, lpBaseAddress + 0x6DB754, &lpBaseAddress, 4)
ReadProcessMemory(hProcess, lpBaseAddress + 0x0, &lpBaseAddress, 4)
ReadProcessMemory(hProcess, lpBaseAddress + 0x58, &lpBaseAddress, 4)
ReadProcessMemory(hProcess, lpBaseAddress + 0x3C, &lpBaseAddress, 4)
ReadProcessMemory(hProcess, lpBaseAddress + 0xFB4, &myvalue, 4)
address = <get the base address>
address = MemoryRead(hwnd, address, "int", 4, 0x6DB754)
address = MemoryRead(hwnd, address, "int", 4, 0x0)
address = MemoryRead(hwnd, address, "int", 4, 0x58)
address = MemoryRead(hwnd, address, "int", 4, 0x3C)
myvalue = MemoryRead(hwnd, address, "int", 4, 0xFB4) |
Brilliant!
I didn't understand I had to sum offset to content in order to advance along pointers chain.
So many thanks!
|
|
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
|
|