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 


Pointers and offsets with esi, ecx, eax... expressions

 
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine
View previous topic :: View next topic  
Author Message
Cren
How do I cheat?
Reputation: 0

Joined: 05 Oct 2015
Posts: 7

PostPosted: Mon Oct 05, 2015 6:50 am    Post subject: Pointers and offsets with esi, ecx, eax... expressions Reply with quote

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
View user's profile Send private message
Zanzer
I post too much
Reputation: 126

Joined: 09 Jun 2013
Posts: 3278

PostPosted: Mon Oct 05, 2015 5:13 pm    Post subject: Reply with quote

Right-click the address and select Pointer scan for this address. That's probably the simplest way. Smile
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
View user's profile Send private message
Cren
How do I cheat?
Reputation: 0

Joined: 05 Oct 2015
Posts: 7

PostPosted: Mon Oct 12, 2015 4:01 am    Post subject: Reply with quote

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
View user's profile Send private message
Zanzer
I post too much
Reputation: 126

Joined: 09 Jun 2013
Posts: 3278

PostPosted: Mon Oct 12, 2015 6:20 am    Post subject: Reply with quote

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
View user's profile Send private message
Cren
How do I cheat?
Reputation: 0

Joined: 05 Oct 2015
Posts: 7

PostPosted: Mon Oct 12, 2015 8:45 am    Post subject: Reply with quote

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
View user's profile Send private message
Zanzer
I post too much
Reputation: 126

Joined: 09 Jun 2013
Posts: 3278

PostPosted: Mon Oct 12, 2015 10:13 am    Post subject: Reply with quote

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
View user's profile Send private message
Cren
How do I cheat?
Reputation: 0

Joined: 05 Oct 2015
Posts: 7

PostPosted: Tue Oct 13, 2015 6:52 am    Post subject: Reply with quote

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.



img.png
 Description:
 Filesize:  76 KB
 Viewed:  20593 Time(s)

img.png


Back to top
View user's profile Send private message
Zanzer
I post too much
Reputation: 126

Joined: 09 Jun 2013
Posts: 3278

PostPosted: Tue Oct 13, 2015 7:00 am    Post subject: Reply with quote

http://forum.cheatengine.org/viewtopic.php?p=5240405#5240405
Back to top
View user's profile Send private message
Cren
How do I cheat?
Reputation: 0

Joined: 05 Oct 2015
Posts: 7

PostPosted: Tue Oct 13, 2015 7:16 am    Post subject: Reply with quote

You're pretty chatty, uh? Very Happy

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
View user's profile Send private message
Zanzer
I post too much
Reputation: 126

Joined: 09 Jun 2013
Posts: 3278

PostPosted: Tue Oct 13, 2015 8:52 am    Post subject: Reply with quote

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
View user's profile Send private message
Cren
How do I cheat?
Reputation: 0

Joined: 05 Oct 2015
Posts: 7

PostPosted: Wed Oct 14, 2015 6:09 am    Post subject: Reply with quote

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 Sad



Untitled1.png
 Description:
 Filesize:  13.19 KB
 Viewed:  20510 Time(s)

Untitled1.png


Back to top
View user's profile Send private message
Zanzer
I post too much
Reputation: 126

Joined: 09 Jun 2013
Posts: 3278

PostPosted: Wed Oct 14, 2015 5:05 pm    Post subject: Reply with quote

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
View user's profile Send private message
Cren
How do I cheat?
Reputation: 0

Joined: 05 Oct 2015
Posts: 7

PostPosted: Thu Oct 15, 2015 1:05 am    Post subject: Reply with quote

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! Very Happy
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 All times are GMT - 6 Hours
Page 1 of 1

 
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