| 
			
				|  | Cheat Engine The Official Site of Cheat Engine
 
 
 |  
 
	
		| View previous topic :: View next topic |  
		| Author | Message |  
		| Qiuzy How do I cheat?
 
 ![]() Reputation: 0 
 Joined: 22 Dec 2024
 Posts: 6
 
 
 | 
			
				|  Posted: Sun Dec 22, 2024 4:28 am    Post subject: Why does a 64-bit game use 32-bit addresses on some PCs? |   |  
				| 
 |  
				| 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!
 
 
 
 
	
		
	 
		| Description: |  |  
		| Filesize: | 571.51 KB |  
		| Viewed: | 9313 Time(s) |  
		| 
  
 
 |  
 
 
	
		
	 
		| Description: |  |  
		| Filesize: | 280.9 KB |  
		| Viewed: | 9313 Time(s) |  
		| 
  
 
 |  
 |  |  
		| Back to top |  |  
		|  |  
		| ParkourPenguin I post too much
 
  Reputation: 152 
 Joined: 06 Jul 2014
 Posts: 4706
 
 
 | 
			
				|  Posted: Sun Dec 22, 2024 1:38 pm    Post subject: |   |  
				| 
 |  
				| 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 |  |  
		|  |  
		| Qiuzy How do I cheat?
 
 ![]() Reputation: 0 
 Joined: 22 Dec 2024
 Posts: 6
 
 
 | 
			
				|  Posted: Mon Dec 23, 2024 6:47 am    Post subject: |   |  
				| 
 |  
				|  	  | 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 |  |  
		|  |  
		| Dark Byte Site Admin
 
  Reputation: 470 
 Joined: 09 May 2003
 Posts: 25807
 Location: The netherlands
 
 | 
			
				|  Posted: Mon Dec 23, 2024 9:20 am    Post subject: |   |  
				| 
 |  
				| 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 |  |  
		|  |  
		| ParkourPenguin I post too much
 
  Reputation: 152 
 Joined: 06 Jul 2014
 Posts: 4706
 
 
 | 
			
				|  Posted: Mon Dec 23, 2024 1:22 pm    Post subject: |   |  
				| 
 |  
				| 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. 	  | Qiuzy wrote: |  	  | But I'm unsure if this logic can solve the problem 100%. | 
 
 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 |  |  
		|  |  
		| Qiuzy How do I cheat?
 
 ![]() Reputation: 0 
 Joined: 22 Dec 2024
 Posts: 6
 
 
 | 
			
				|  Posted: Tue Dec 24, 2024 4:22 am    Post subject: |   |  
				| 
 |  
				|  	  | 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).
 
 
 
 
	
		
	 
		| Description: |  |  
		| Filesize: | 318.32 KB |  
		| Viewed: | 9115 Time(s) |  
		| 
  
 
 |  
 |  |  
		| 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
 
 |  |