 |
Cheat Engine The Official Site of Cheat Engine
|
| View previous topic :: View next topic |
| Author |
Message |
Profound_Darkness Newbie cheater
Reputation: 0
Joined: 21 May 2015 Posts: 23
|
Posted: Fri Aug 20, 2021 3:31 pm Post subject: Strange 1 byte too short address in AA asm... ? |
|
|
So the target process is 64 bit and my intention is to read an address from register into memory to act as a base pointer, pretty bog standard... I'm sure I'm doing something wrong/missing something but I don't quite know what. I don't play with 64 bit targets much. At least things work more or less as expected when I do.
It's acting like AA is writing the address portion 1 byte too short but I'd expect a lot of other cheat tables to be broken if that were generally the case. I haven't played with this for long so I"m hoping someone might be able to point me in an apt direction for further exploration.
This occurs on version 7.1 and 7.3 of CE btw.
What I start with (pre-auto assembler)
| Code: |
movzx eax,byte ptr [rdx+2C]
ret
int 3
int 3
...
int 3
|
relevant AA code:
| Code: |
alloc(memBasePtr, 8)
aobscanmodule(aobBasePtr...)
label(ptrBase)
registersymbol(ptrBase)
aobBasePtr+4:
mov [ptrBase],rdx
ret
memBasePtr:
ptrBase:
dq 0
|
What I get in memory view after activating the item
| Code: |
movzx eax,byte ptr [rdx+2C]
mov [C35A0000],rdx
int 3
...
int 3
|
the newly added code in byte form:
48 89 14 25 00 00 5A C3
a ret being C3 looks interesting.
As a test lets try dropping the ret, obviously nonfunctional code but see what gets assembled.
for mov [ptrBase],rdx I get the bytes: 48 89 14 25 00005ACC
I would expect the address to be 00005A03, in both cases
This strangeness shows up if I do an LEA instruction, ie
lea rax,[ptrBase]
results in the same address being 1 byte shorter than expected, 'eating' a byte from the next instruction. If that's the only change the final byte of the instruction will be CC just like in the MOV instruction.
For now I'm using the following obviously not quite right code to get the address 'proper'
| Code: |
aobBasePtr+4:
mov [ptrBase],rdx
db 03
ret
|
results in:
| Code: |
movzx eax,byte ptr [rdx+2C]
mov [ptrBase],rdx
ret
|
for completion of demonstration...
| Code: |
mov [ptrBase],rdx
nop //byte code 90
ret
|
resulting opcodes:
| Code: |
movzx eax,byte ptr [rdx+2C]
mov [905A0000],rdx
ret
|
lea rax,[ptrBase]
becomes
lea rax,[CC5A0000]
bytes
48 8D 04 25 00 00 5A CC
|
|
| Back to top |
|
 |
ParkourPenguin I post too much
Reputation: 152
Joined: 06 Jul 2014 Posts: 4717
|
Posted: Fri Aug 20, 2021 4:19 pm Post subject: |
|
|
I can't replicate it.
Could you provide a minimal working example with the CE tutorial (Tutorial-x86_64.exe)? If not, at least provide the entire AA script and not just the parts you think are important. (redact the game name- e.g. use "game.exe")
One possible problem I see is that you're not passing the third argument to alloc, which means memBasePtr might not be allocated close enough to the injection point to use RIP-relative addressing.
edit: just noticed your CE is choosing to assemble that with modR/M and SIB bytes 14 25 (Disp32), while mine is assembling it with just 15 (RIP+Disp32). Might be some edge case error in there somewhere. Is that vanilla CE, or did you do something weird (e.g. custom binutils)?
_________________
I don't know where I'm going, but I'll figure it out when I get there. |
|
| Back to top |
|
 |
Profound_Darkness Newbie cheater
Reputation: 0
Joined: 21 May 2015 Posts: 23
|
Posted: Fri Aug 20, 2021 8:46 pm Post subject: |
|
|
Before coming back here I tried ... as it happens what you suggested with tutorial (64 bit) and things were compiled as expected. I've got a lot of blindspots, particularly with 64 bit so didn't consider that 3rd argument to alloc.
I didn't do anything odd, to my fuzzy memory, in 7.1 but I compiled 7.3 rather than from pre-built binaries.
my entire AA script including remarks, most of them are to do alternate assembles to see what happens.
| Code: |
[Enable]
alloc(memBasePtr, 8)
aobscanmodule(aobBasePtr, game.exe, 0F B6 42 2C C3 CC CC CC CC CC CC CC CC CC CC)
//only need first 5 bytes to ID
registersymbol(aobBasePtr)
label(ptrBase)
registersymbol(ptrBase)
aobBasePtr+4:
//lea eax,[ptrBase]
//mov [rax],rdx
//movzx eax,byte ptr[rdx+2C]
mov [ptrBase],rdx
//db 03 // bad fix
ret
//db 0F B6 42 2C C3
memBasePtr:
ptrBase:
dq 0 //64 bit register so pointer might be longer than double
[Disable]
aobBasePtr:
db 0F B6 42 2C C3
db CC CC CC CC CC CC CC CC CC CC
unregistersymbol(aobBasePtr)
unregistersymbol(ptrBase)
dealloc(memBasePtr)
|
result:
| Code: |
aobBasePtr - 0FB6 42 2C - movzx eax,byte ptr [rdx+2C]
game.exe+7DFBB4- 48 89 14 25 00005CC3 - mov [C35C0000],rdx
game.exe+7DFBBC- CC - int 3
|
Now I've tried out the tweak you mentioned, the 3rd argument of alloc. That appears to have helped...
AA
| Code: |
[Enable]
//alloc(memBasePtr, 8)
aobscanmodule(aobBasePtr, game.exe, 0F B6 42 2C C3 CC CC CC CC CC CC CC CC CC CC)
//only need first 5 bytes to ID
alloc(memBasePtr, 8, aobBasePtr)
registersymbol(aobBasePtr)
label(ptrBase)
registersymbol(ptrBase)
aobBasePtr+4:
//lea eax,[ptrBase]
//mov [rax],rdx
//movzx eax,byte ptr[rdx+2C]
mov [ptrBase],rdx
//db 03 // bad fix
ret
//db 0F B6 42 2C C3
memBasePtr:
ptrBase:
dq 0 //64 bit register so pointer might be longer than double
[Disable]
aobBasePtr:
db 0F B6 42 2C C3
db CC CC CC CC CC CC CC CC CC CC
unregistersymbol(aobBasePtr)
unregistersymbol(ptrBase)
dealloc(memBasePtr)
|
result:
| Code: |
aobBasePtr - 0FB6 42 2C - movzx eax,byte ptr [rdx+2C]
game.exe+7DFBB4- 48 89 15 450481FF - mov [ptrBase],rdx
game.exe+7DFBBB- C3 - ret
game.exe+7DFBBC- CC - int 3
|
I'll poke around some in a bit, see if I can force a long distance alloc in the tutorial and see what happens with mov/lea with that.
Thanks.
|
|
| Back to top |
|
 |
ParkourPenguin I post too much
Reputation: 152
Joined: 06 Jul 2014 Posts: 4717
|
Posted: Fri Aug 20, 2021 9:24 pm Post subject: |
|
|
I think there's some buggy edge case behaviour going on with this. What address is the module game.exe loaded at, and what address is ptrBase?
You can execute this in the Lua engine after you enable the script:
| Code: | print(('game.exe: %08X'):format(getAddress('game.exe')))
print(('ptrBase: %08X'):format(getAddress('ptrBase'))) |
Directly addressing a memory location like [ptrBase] is complicated in a 64-bit process because you can't simply use a 64-bit memory displacement (in most cases). Either you can use RIP-relative addressing if the target address is within +-2GB of the next instruction (i.e. modR/M byte 15) or you can use a direct 32-bit displacement from 0 if the address is within the first 4GB of the virtual address space (i.e. modR/M byte 14, SIB byte 25). Maybe there's a scenario where CE thinks it can use RIP-relative addressing but assembles the instruction using a 32-bit displacement anyway (and use 1 more byte than it thought it needed to).
_________________
I don't know where I'm going, but I'll figure it out when I get there. |
|
| Back to top |
|
 |
Profound_Darkness Newbie cheater
Reputation: 0
Joined: 21 May 2015 Posts: 23
|
Posted: Sat Aug 21, 2021 2:04 pm Post subject: |
|
|
game.exe: 13F530000
ptrBase: 03440000
|
|
| Back to top |
|
 |
ParkourPenguin I post too much
Reputation: 152
Joined: 06 Jul 2014 Posts: 4717
|
Posted: Sat Aug 21, 2021 3:23 pm Post subject: |
|
|
I still can't replicate it under similar conditions (CE 7.2). No idea why that's happening for you.
I'm glad using the 3rd parameter to alloc solved this issue.
_________________
I don't know where I'm going, but I'll figure it out when I get there. |
|
| Back to top |
|
 |
Profound_Darkness Newbie cheater
Reputation: 0
Joined: 21 May 2015 Posts: 23
|
Posted: Sat Aug 21, 2021 7:51 pm Post subject: |
|
|
So I managed to sit down and try making something similar to the game but for the tutorial and it broke there too.
So here is my AA script. It's got some extra bits to backup/restore some code but I wanted to keep the core test concept clean so two different allocations.
| Code: |
[Enable]
alloc(memTest, 8, 1000)
label(ptrTest)
registersymbol(ptrTest)
alloc(memBak, 20)
label(bakTest)
registersymbol(bakTest)
define(tutBase, Tutorial-x86_64.exe+2B92)
registersymbol(tutBase)
tutBase:
mov [ptrTest], rdx
nop
memTest:
ptrTest:
dq 0
memBak:
bakTest:
readmem(tutBase, 20)
[Disable]
unregistersymbol(ptrTest)
dealloc(memTest)
tutBase:
readmem(bakTest, 20)
unregistersymbol(bakTest)
unregistersymbol(tutBase)
dealloc(memBak)
|
the resulting bytes/code:
| Code: |
tutBase - 48 89 14 25 00001B90 - mov [901B0000],rdx
|
note the lack of nop in the result... or more accurately that the nop is 'eaten' in the MOV's address.
Tutorial-x86_64.exe: 100000000
ptrTest: 031B0000
Switched to CE 7.2 with the following results:
| Code: |
tutBase - 48 89 14 25 00000C90 - mov [900C0000],rdx
|
Tutorial-x86_64.exe: 100000000
ptrTest: 030C0000
The section of the tutorial code I'm altering is quite arbitrary. it just so happens the offset in tutorial was where memory view opened to after attaching to tutorial the first time.
Unless any other ideas pop up for something I should try/report on I'll likely put further poking at this on the back burner. I mean the particular case we're looking at here mostly only came up because I wasn't doing things quite right anyway.
Thanks again.
|
|
| Back to top |
|
 |
ParkourPenguin I post too much
Reputation: 152
Joined: 06 Jul 2014 Posts: 4717
|
Posted: Sat Aug 21, 2021 9:09 pm Post subject: |
|
|
I can replicate it now with that example.
Directly addressing a memory location that may not have been allocated within 2GB (by not using the 3rd alloc parameter) is pretty much undefined behaviour anyway, so I'm not too concerned about this bug either.
You've done plenty- that minimal working example is all that's needed to identify the bug. All that's left is for someone to sift through CE's source and find it. There may be more important things to do in the meantime though.
Thank you for your help.
_________________
I don't know where I'm going, but I'll figure it out when I get there. |
|
| Back to top |
|
 |
Dark Byte Site Admin
Reputation: 471
Joined: 09 May 2003 Posts: 25830 Location: The netherlands
|
Posted: Sun Aug 22, 2021 12:44 am Post subject: |
|
|
if you put
| Code: |
memTest:
ptrTest:
dq 0
|
before tutbase: it'll work
at the time of assembling it doesn't know what the address will be so it will allocate memory and fill it in when known. But the allocated size is too snall because of this very rare construction that a range above 2gb within the 0 to 2GB range bas a solution thatbis bigger than the others
of course, fixing that may mess up lots if existing scripts, so it's best to go with enforced 3th alloc parameter
_________________
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 |
|
 |
|
|
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
|
|