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 


Why does a 64-bit game use 32-bit addresses on some PCs?

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

Joined: 22 Dec 2024
Posts: 6

PostPosted: Sun Dec 22, 2024 4:28 am    Post subject: Why does a 64-bit game use 32-bit addresses on some PCs? Reply with quote

Hi,

I found that a 64-bit game running on different 64-bit-OS PCs can be different in address organization, and I am writing to ask if anyone knows why.

Particularly, I want to get an immediate value in the "GameManager:Awake" method of the game, which is the base address of the class instance. On most PCs, the opcode would look like the image with the black background. It uses 64-bit addresses and 64-bit registers to store immediate values for addresses (e.g. `mov rax, 000002A139EC2F70`).

On some PCs, however, the opcode would look like the image with the white background, which uses 32-bit registers (e.g. `mov eax, 74323F70`) to store addresses, meanwhile, the addresses are much shorter than normal.

Given that I used lua functions to read immediate values in my cheat table, I need to know when and why the second situation will happen, because I will then have to use different functions (`readQword()`or `readInteger()`) to get the values. In addition, I would like to replicate this situation on my PC, since sometimes the opcode structure is different from the normal one and I need to check the details, but I have no idea how to do this.

FYI: I am sure the Cheat Engine, the game process, and the MS Windows OS are 64-bit.

Appreciating any help or guidance in advance!



PixPin_2024-12-22_16-22-09.png
 Description:
 Filesize:  571.51 KB
 Viewed:  9313 Time(s)

PixPin_2024-12-22_16-22-09.png



PixPin_2024-12-22_18-08-23.png
 Description:
 Filesize:  280.9 KB
 Viewed:  9313 Time(s)

PixPin_2024-12-22_18-08-23.png


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

Joined: 06 Jul 2014
Posts: 4706

PostPosted: Sun Dec 22, 2024 1:38 pm    Post subject: Reply with quote

The game's real code is stored as CIL bytecode. This bytecode gets JIT compiled to machine code (x64 assembly) at runtime by the virtual machine provided by the local dotnet framework. When compiling bytecode, if Windows just so happened to allocate certain memory in the first 4 GiB of the address space, the compiler's assembler can generate more optimal machine code as you see in the images. There are probably some settings that decide where/how windows and/or dotnet allocates memory, but it's easier if you think of it as being random.

It can be worse. If two different computers are using two different versions of the dotnet framework, it might decide to compile the bytecode in a completely different manner.

You can use Lua to disassemble an address and parse the argument string manually. Or read 10 bytes at that address and parse the machine code- if there's a REX prefix (0x48), it's an 8 byte value; otherwise, it's a 4 byte value. Copy the relevant bytes to a new table and use byteTableToDword / byteTableToQword.

_________________
I don't know where I'm going, but I'll figure it out when I get there.
Back to top
View user's profile Send private message
Qiuzy
How do I cheat?
Reputation: 0

Joined: 22 Dec 2024
Posts: 6

PostPosted: Mon Dec 23, 2024 6:47 am    Post subject: Reply with quote

ParkourPenguin wrote:
The game's real code is stored as CIL bytecode. This bytecode gets JIT compiled to machine code (x64 assembly) at runtime by the virtual machine provided by the local dotnet framework. When compiling bytecode, if Windows just so happened to allocate certain memory in the first 4 GiB of the address space, the compiler's assembler can generate more optimal machine code as you see in the images. There are probably some settings that decide where/how windows and/or dotnet allocates memory, but it's easier if you think of it as being random.

It can be worse. If two different computers are using two different versions of the dotnet framework, it might decide to compile the bytecode in a completely different manner.

You can use Lua to disassemble an address and parse the argument string manually. Or read 10 bytes at that address and parse the machine code- if there's a REX prefix (0x48), it's an 8 byte value; otherwise, it's a 4 byte value. Copy the relevant bytes to a new table and use byteTableToDword / byteTableToQword.


I see. Is there a more universal method in Cheat Engine to detect if the game is allocated to the first 4 GB of memory space? There might be a situation where I don't need to read the bytes after the `mov rax/eax` command, but I still need to know whether the game process uses this "more optimal machine code" (since it's different right?). Reading the REX prefix (0x48) from a specific game method or address is also not quite universal because I will then have to find a game method that uses `mov [x64register], [immediate value]`first for every other game I want to make a cheat table with.

I currently "detect" this by checking if the length of the game method address is larger than 9, if not then it is allocated to the first 4GB:
Code:
function IsAddr64Bit()

    return (string.len(string.format("%X", getAddress("GameManager:Awake"))) > 9) and true or false

end


But I'm unsure if this logic can solve the problem 100%.
Back to top
View user's profile Send private message
Dark Byte
Site Admin
Reputation: 470

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

PostPosted: Mon Dec 23, 2024 9:20 am    Post subject: Reply with quote

maybe go with a different method altogether and limit yourself to only entrypoints of functions and capture the given parameters

the value you're after seems to be a static, so maybe you get just get that value by querying the mono functions (look at monoscript.lua)

_________________
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
ParkourPenguin
I post too much
Reputation: 152

Joined: 06 Jul 2014
Posts: 4706

PostPosted: Mon Dec 23, 2024 1:22 pm    Post subject: Reply with quote

Qiuzy wrote:
But I'm unsure if this logic can solve the problem 100%.
You're getting the address of the code and not the address the code is accessing. It'll probably correspond, but it's not guaranteed to.

In general, you could make a "readImmediate" function:
Code:
function readImmediate(addr)
  addr = getAddressSafe(addr)
  if not addr then return nil, 'bad address to readImmediate' end

  assert(inMainThread(), 'cannot get default disassembler from other thread')
  local d = getDefaultDisassembler()
  d.disassemble(addr)
  local numstr = d.LastDisassembleData.parameters:match'%d+$'
  if not numstr then return nil, ('immediate not found at addr %08X'):format(addr) end

  return tonumber(numstr)
end


In this specific case, using CE's mono features is more appropriate. monoscript.lua is in the autorun directory within the main CE directory.

_________________
I don't know where I'm going, but I'll figure it out when I get there.
Back to top
View user's profile Send private message
Qiuzy
How do I cheat?
Reputation: 0

Joined: 22 Dec 2024
Posts: 6

PostPosted: Tue Dec 24, 2024 4:22 am    Post subject: Reply with quote

Dark Byte wrote:
maybe go with a different method altogether and limit yourself to only entrypoints of functions and capture the given parameters

the value you're after seems to be a static, so maybe you get just get that value by querying the mono functions (look at monoscript.lua)

ParkourPenguin wrote:
In this specific case, using CE's mono features is more appropriate.

Actually, I tried the mono functions before switching to manually reading the bytes to get static field addresses. I've so far been trying to figure out a universal solution to cheat a mono game (sort of making my own lua script cheating template) and I knew that `mono_class_getStaticFieldAddress('', mono_findClass(...))` can obtain the immediate values in the previous images I sent.

The problem is: I found it worked great when the game created class instances "directly" (`classname.instance` for example), but there is some other mono games using `SingleTon<someclass>.Instance`pattern. In that case, the disassembly looks like the image below.

And I couldn't find a method in monoscript.lua that can obtain this immediate value (0x2A8D0778) for me (`getStaticFieldAddress` returns nothing). I can get the correct class instance address - that's fine - but only through getting the static field address from the parent of the class (which is the SingleTon), and then reading the pointer of it:
Code:
local test  = mono_findClass('', 'NewSocialMgr')
local test2 = mono_class_getParent(test)
local test3 = mono_class_getStaticFieldAddress('', test2)
print(string.format("%X", readPointer(test3+0x4)))

I'm not satisfied with this because sometimes the game doesn't create the class instance when not loading a save. In that case I would get nothing for running this script. If all relevant entries start with the class instance address, they cannot be used.

But since I know how the `SingleTon.getInstance` works in the opcode, I can set all entries to `((((immediate value0x2A8D0778)+0x24)+0x4)+0x4)` to get the instance, and then + other offsets to get the game attributes. They would all point to the correct addresses when a save is loaded, without me doing anything extra after loading.

`immediate value0x2A8D0778` actually points to the parent SingleTon of the class. But I just don't know how to get it by mono functions (not the `test3` above too).



PixPin_2024-12-24_21-02-04.png
 Description:
 Filesize:  318.32 KB
 Viewed:  9115 Time(s)

PixPin_2024-12-24_21-02-04.png


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 Discussions 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