|
Cheat Engine The Official Site of Cheat Engine
|
View previous topic :: View next topic |
Author |
Message |
Kajih Cheater Reputation: 1
Joined: 08 Feb 2021 Posts: 32
|
Posted: Mon Jan 10, 2022 6:38 pm Post subject: Need help regarding word ptr |
|
|
Hi, I would like to understand what exactly this opcode is doing, I tried goggling some of this but I have a hard time understanding what the difference is between mov and movzx and what exactly is word ptr :
Code: | movzx ecx,word ptr [rdx+r8*2] |
when I look up what addresses this instruction accesses, I can see a new address whenever I move my cursor in the game inventory screen and I can see the value (amount of item). but when I try to save this address to a symbol I created in a script, I am not seeing the same address being returned and the value is incorrect. this is my injected code:
Code: |
push rax
mov rax,[rdx+r8*2]
mov [itemPTR],rax
pop rax
|
In cheatEngine when I add the address manually and put in [itemPTR], but it's not the correct address that appears. Even if I enter itemPTR, the value matches but the address doesn't change when I update the inventory item in the game.
I hope I am making sense. I'd appreciate any help in explaining what I am not understanding. Thank you in advance.
|
|
Back to top |
|
|
TheyCallMeTim13 Wiki Contributor Reputation: 50
Joined: 24 Feb 2017 Posts: 976 Location: Pluto
|
Posted: Mon Jan 10, 2022 7:50 pm Post subject: Re: Need help regarding word ptr |
|
|
Kajih wrote: | Hi, I would like to understand what exactly this opcode is doing, I tried goggling some of this but I have a hard time understanding what the difference is between mov and movzx and what exactly is word ptr :
Code: | movzx ecx,word ptr [rdx+r8*2] |
when I look up what addresses this instruction accesses, I can see a new address whenever I move my cursor in the game inventory screen and I can see the value (amount of item). but when I try to save this address to a symbol I created in a script, I am not seeing the same address being returned and the value is incorrect. this is my injected code:
Code: |
push rax
mov rax,[rdx+r8*2]
mov [itemPTR],rax
pop rax
|
In cheatEngine when I add the address manually and put in [itemPTR], but it's not the correct address that appears. Even if I enter itemPTR, the value matches but the address doesn't change when I update the inventory item in the game.
I hope I am making sense. I'd appreciate any help in explaining what I am not understanding. Thank you in advance. |
MOVZX is move with zero extended, basically it converts a value size of X bits to a value size of Y bits. WORD is a value size (2 bytes), basically you have bit (smallest unit), nibble (4 bits), byte (8 bits), word (2 bytes), dword (4 bytes), qword (8 bytes), and there are others for larger data sizes. You can find more on that here. And since it's using ECX (a 32 bit register or dword) and "word ptr" (word pointer) it's converting a word to a dword with zero extended.
With "mov rax,[rdx+r8*2]" you are moving a qword value at the address of "rdx+r8*2" to RAX. So in the end you are storing a value of the wrong data size and not the address. In this case you want to use LEA (load effective address), i.e. "lea rax,[rdx+r8*2]" will set RAX to the address so you can store it. Then you'll need to set the value type to 2 bytes, if you look in the "see what addresses this instruction accesses" window at the bottom the value type is likely set to 2 bytes.
_________________
|
|
Back to top |
|
|
Kajih Cheater Reputation: 1
Joined: 08 Feb 2021 Posts: 32
|
Posted: Tue Jan 11, 2022 6:28 am Post subject: |
|
|
Oh! now I get it. I still keep getting mixed up between value and address when moving into a register. This was quite a beginner mistake again, since I'm not using assembly every day and just learning as I go, I should really sit down through a more structured learning approach and practice (outside of cheatEngine) to at least get some of these basics ingrained in my head.
Thanks for the explanation, this helped a lot.
|
|
Back to top |
|
|
Kajih Cheater Reputation: 1
Joined: 08 Feb 2021 Posts: 32
|
Posted: Sat Jan 15, 2022 10:56 am Post subject: |
|
|
I have a quick follow up question that is related to MOVZX I believe. I have an injection location that updates a value every frame:
Code: |
newmem:
code:
mov [rsi+4C],di
test r12d,r12d
jmp return
|
This is a shared instruction so I am comparing if it's the player and if so simply retaking the current value and placing it into di:
Code: |
newmem:
cmp [rsi+A4],0
je code
mov di,[rsi+4C]
code:
mov [rsi+4C],di
test r12d,r12d
jmp return
|
However i noticed that the max value for this is located at offset 28, so it's basically [***+4C] / [***+28]. The problem is that the value at +28 is a 2-byte value and the current value is a 4-byte. I figured I would try to use MOVZX here as well to move my 2-byte value into the 4-byte:
Code: |
newmem:
cmp [rsi+A4],0
je code
movzx di,word ptr [rsi+28]
code:
mov [rsi+4C],di
test r12d,r12d
jmp return
|
This doesn't work. I read up a bit on di and si and somewhat understand their purpose but I am having a bit of a hard time wrapping my head around it. I don't believe this is a string manipulation so I am guessing it's used to copy memory from another location. What is why can't I do a movzx with [rsi+28] but I can do a mov with [rsi+4C]. Unless I shouldn't be doing mov di,[rsi+4C] either?
Last and foremost, how can I go about making my injection take the 2-byte value stored at [rsi+28] and store it in the 4-byte location at [rsi+4C]?
Thanks for your time.
EDIT:
I resolved my issue by doing:
Code: | newmem:
cmp [rsi+A4],0
je code
push rax
movzx rax,word ptr [rsi+28] //max mp
mov [rsi+4C],rax
pop rax
jmp return
code:
mov [rsi+4C],di
test r12d,r12d
jmp return
|
but for some reason, this breaks another value somewhere else, it looks like I HAVE to do mov [rsi+4C],di for some reason... but I don't understand why.
|
|
Back to top |
|
|
ParkourPenguin I post too much Reputation: 138
Joined: 06 Jul 2014 Posts: 4275
|
Posted: Sat Jan 15, 2022 1:26 pm Post subject: |
|
|
`cmp [rsi+A4],0` is ambiguous. The size of the value being compared against is unknown. CE defaults to a 32-bit value which is fine if you want that.
Kajih wrote: | The problem is that the value at +28 is a 2-byte value and the current value is a 4-byte. | If the instruction `mov [rsi+4C],di` is the original code writing to your current health, then the game says the current health is a 2-byte value. di is a 2-byte register
`movzx di,word ptr [rsi+28]` doesn't work because movzx zero-extends a smaller value to a larger one. `word ptr` means it should access 2 bytes of memory, and di is a 2-byte register. They're the same size- movzx can't work because there's nothing to extend. Just use mov like the original code does.
`mov [rsi+4C],rax` is bad because you're overwriting unknown data. rax is an 8-byte register, so CE infers it should be writing 8 bytes to the address. The current health is only 2 bytes. You don't know what the other 6 bytes are for. This could crash the game or have other side effects.
_________________
I don't know where I'm going, but I'll figure it out when I get there. |
|
Back to top |
|
|
Kajih Cheater Reputation: 1
Joined: 08 Feb 2021 Posts: 32
|
Posted: Sat Jan 15, 2022 1:56 pm Post subject: |
|
|
ParkourPenguin wrote: | `cmp [rsi+A4],0` is ambiguous. The size of the value being compared against is unknown. CE defaults to a 32-bit value which is fine if you want that. |
I added this check just to differentiate between player and monster, did a quick commonality scan and noticed this offset was always 0 for a monster while the players (in the party was a higher number). Should I go about the check another way? I usually do it this way so please do let me know if there would be a better way.
ParkourPenguin wrote: | If the instruction `mov [rsi+4C],di` is the original code writing to your current health, then the game says the current health is a 2-byte value. di is a 2-byte register
`movzx di,word ptr [rsi+28]` doesn't work because movzx zero-extends a smaller value to a larger one. `word ptr` means it should access 2 bytes of memory, and di is a 2-byte register. They're the same size- movzx can't work because there's nothing to extend. Just use mov like the original code does.
`mov [rsi+4C],rax` is bad because you're overwriting unknown data. rax is an 8-byte register, so CE infers it should be writing 8 bytes to the address. The current health is only 2 bytes. You don't know what the other 6 bytes are for. This could crash the game or have other side effects. |
This makes so much sense now, the game is Final Fantasy 12 and I was tracking MP for party members. The extra 6 bytes are used to keep track of how many Mist Bars (limit breaks) are filled and I can see this now whenever a mist bar was filled, 0x10000 was added to the value. It's clear now that I was not writing to the 2 bytes that was holding my mp but essentially overwriting the information for the bars as well. which messed up the whole game.
Thanks for the help!
|
|
Back to top |
|
|
ParkourPenguin I post too much Reputation: 138
Joined: 06 Jul 2014 Posts: 4275
|
Posted: Sat Jan 15, 2022 10:48 pm Post subject: |
|
|
Kajih wrote: | Should I go about the check another way? I usually do it this way so please do let me know if there would be a better way. | It's fine. I was just asking about the size of the value at [rsi+A4]. If it's a 4-byte value, it's' fine the way it is; if it's something else, you'll need to qualify the memory access. e.g. if it's a 2-byte value, use `cmp word ptr [rsi+A4],0`
_________________
I don't know where I'm going, but I'll figure it out when I get there. |
|
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
|
|