Page 1 of 1

Assembler question

Posted: Fri Sep 21, 2018 11:26 pm
by beguiler
I was using aobscan to get memory address for a money pointer in a 64bit game and came across this weird issue that doesn't seem to make sense so I was hoping someone here could explain it for me.

Getting the memory location was easy it's a simple 4 byte value but the game is 64bit so the address is a double word and is stored in a 64bit register (RCX). When I looked for what access the memory location I found it really quick and it looked like it would be a simple thing to add one line to the code to get me the address whenever I wanted.

So I tried the following:

Code: Select all

newmem:
mov [_basePtr],rcx  //the code I added. Address I want is in RCX, so a simply copy to my variable

code:
mov eax,[rcx+000000C0]
jmp return
and in cheat engine, the script wouldn't enable. So I did the following to get around it:

Code: Select all

newmem:
push rax  //save what is in rax to stack
mov rax,rcx //copy address I want to rax register
mov [_basePtr],rax  //copy rax value to my variable
pop rax //restore the original content of rax

code:
mov eax,[rcx+000000C0]
jmp return
and this time it works as expected. So my question is why didn't the initial code work? Is there some reason I cannot copy the RCX to my variable? I am not familiar with the inner workings of x86 assembly but it seemed straight forward enough to copy a value of a 64bit register but for some reason it couldn't do it.

Re: Assembler question

Posted: Fri Sep 21, 2018 11:45 pm
by TimFun13
beguiler wrote:
Fri Sep 21, 2018 11:26 pm
I was using aobscan to get memory address for a money pointer in a 64bit game and came across this weird issue that doesn't seem to make sense so I was hoping someone here could explain it for me.

Getting the memory location was easy it's a simple 4 byte value but the game is 64bit so the address is a double word and is stored in a 64bit register (RCX). When I looked for what access the memory location I found it really quick and it looked like it would be a simple thing to add one line to the code to get me the address whenever I wanted.

So I tried the following:

Code: Select all

newmem:
mov [_basePtr],rcx  //the code I added. Address I want is in RCX, so a simply copy to my variable

code:
mov eax,[rcx+000000C0]
jmp return
and in cheat engine, the script wouldn't enable. So I did the following to get around it:

Code: Select all

newmem:
push rax  //save what is in rax to stack
mov rax,rcx //copy address I want to rax register
mov [_basePtr],rax  //copy rax value to my variable
pop rax //restore the original content of rax

code:
mov eax,[rcx+000000C0]
jmp return
and this time it works as expected. So my question is why didn't the initial code work? Is there some reason I cannot copy the RCX to my variable? I am not familiar with the inner workings of x86 assembly but it seemed straight forward enough to copy a value of a 64bit register but for some reason it couldn't do it.
Both are valid, seems like there was an error somewhere else in the script.

EDIT:
Like Kalas pointed out, make sure it's not JITed code (i.e.: you have to spend money for the code to be compiled).

Re: Assembler question

Posted: Fri Sep 21, 2018 11:51 pm
by Kalas
Just a quick question, is this game a unity based engine?
If so make sure the mono features are enabled so you can activate the cheat/script.

If you registered a symbol make sure you unregistered it.

Post full code too so we can gather more information 🙍

Re: Assembler question

Posted: Sat Sep 22, 2018 4:26 am
by beguiler
I think it's unreal engine (Bard's Tale 4). I'll attach the table but there is only one thing in it.

Re: Assembler question

Posted: Sat Sep 22, 2018 5:28 am
by TimFun13
Best I can figure is you fixed whatever it was when you added the move to RAX, try it again without the added push move and pop.

It could have been that you changed the size of the memory allocated with globalAlloc after it was already allocated, this can prevent the script from enabling because it's already allocated so the size can't change.

Re: Assembler question

Posted: Sat Sep 22, 2018 7:15 am
by beguiler
Yeah the table does work as it is now, but it's using 4 lines of code for something that should be one. I have tried commenting out the working code and just doing it with a direct copy of RCX, but it never enables in that condition. I thought that maybe there might be some reason for it I didn't know about because I have limited assembly language experience in general. Oh well not a big deal, I was just curious.

Re: Assembler question

Posted: Sat Sep 22, 2018 12:12 pm
by Kalas
I usually do:

Code: Select all

{ Game   : BardsTale4-Win64-Shipping.exe
  Version: 
  Date   : 2018-09-21


  This script does blah blah blah
}

[ENABLE]

aobscanmodule(GetPtr,BardsTale4-Win64-Shipping.exe,8B 81 C0 00 00 00 41 89) // should be unique
alloc(newmem,$128,"BardsTale4-Win64-Shipping.exe")

label(code)
label(return)

label(MoneyPtr)
registersymbol(MoneyPtr)

newmem:
  mov [MoneyPtr],rcx

code:
  mov eax,[rcx+000000C0]
  jmp return

MoneyPtr:
  dq 0

GetPtr:
  jmp newmem
  nop
return:
registersymbol(GetPtr)

[DISABLE]

GetPtr:
  db 8B 81 C0 00 00 00

unregistersymbol(GetPtr)
unregistersymbol(MoneyPtr)
dealloc(newmem)

{
// ORIGINAL CODE - INJECTION POINT: "BardsTale4-Win64-Shipping.exe"+34F6A5

"BardsTale4-Win64-Shipping.exe"+34F681: 4C 89 4A 20              -  mov [rdx+20],r9
"BardsTale4-Win64-Shipping.exe"+34F685: 48 8B 81 B0 01 00 00     -  mov rax,[rcx+000001B0]
"BardsTale4-Win64-Shipping.exe"+34F68C: 49 89 00                 -  mov [r8],rax
"BardsTale4-Win64-Shipping.exe"+34F68F: C3                       -  ret 
"BardsTale4-Win64-Shipping.exe"+34F690: 48 8B 42 20              -  mov rax,[rdx+20]
"BardsTale4-Win64-Shipping.exe"+34F694: 45 33 C9                 -  xor r9d,r9d
"BardsTale4-Win64-Shipping.exe"+34F697: 48 85 C0                 -  test rax,rax
"BardsTale4-Win64-Shipping.exe"+34F69A: 41 0F 95 C1              -  setne r9l
"BardsTale4-Win64-Shipping.exe"+34F69E: 4C 03 C8                 -  add r9,rax
"BardsTale4-Win64-Shipping.exe"+34F6A1: 4C 89 4A 20              -  mov [rdx+20],r9
// ---------- INJECTING HERE ----------
"BardsTale4-Win64-Shipping.exe"+34F6A5: 8B 81 C0 00 00 00        -  mov eax,[rcx+000000C0]
// ---------- DONE INJECTING  ----------
"BardsTale4-Win64-Shipping.exe"+34F6AB: 41 89 00                 -  mov [r8],eax
"BardsTale4-Win64-Shipping.exe"+34F6AE: C3                       -  ret 
"BardsTale4-Win64-Shipping.exe"+34F6AF: CC                       -  int 3 
"BardsTale4-Win64-Shipping.exe"+34F6B0: 48 8B 42 20              -  mov rax,[rdx+20]
"BardsTale4-Win64-Shipping.exe"+34F6B4: 45 33 C9                 -  xor r9d,r9d
"BardsTale4-Win64-Shipping.exe"+34F6B7: 48 85 C0                 -  test rax,rax
"BardsTale4-Win64-Shipping.exe"+34F6BA: 41 0F 95 C1              -  setne r9l
"BardsTale4-Win64-Shipping.exe"+34F6BE: 4C 03 C8                 -  add r9,rax
"BardsTale4-Win64-Shipping.exe"+34F6C1: 4C 89 4A 20              -  mov [rdx+20],r9
"BardsTale4-Win64-Shipping.exe"+34F6C5: 8B 81 E0 00 00 00        -  mov eax,[rcx+000000E0]
}

Re: Assembler question

Posted: Sat Sep 22, 2018 1:44 pm
by beguiler
Interesting @Kalas, your method works. It looks like it might be related to the globalalloc call.

Re: Assembler question

Posted: Mon Sep 24, 2018 9:51 pm
by JohnFK
You shouldn't use globalalloc on 64bit targets. In worst case it allocates memory in 32bit range where the injection is allocated in 64bit or vice versa making your memory pointer become too far. Perhaps Dark Byte will add a nearby parameter to it same as the alloc command in the future.

I think globalalloc only makes sense actually when dealing with calls because even when a memory pointer is shared between scripts a simple alloc works fine (unless it suffers by the same issue above where allocation and script injection is too far away from each other).

//edit: Also when looking at CE source you see that globalalloc gets overwritten as well when declared twice. Dark Byte might be able to tell cases where this command makes sense, but for me it rather looks like a leftover from older days and only remains for compatiblity reasons.

Re: Assembler question

Posted: Mon Sep 24, 2018 10:43 pm
by beguiler
Well that's good to know. I have always used globalalloc mainly because I learned to use CE from an old tutorial a long time ago that used it so I just kept using it. I never ran into an issue before but I don't think I have ever used it till now with a 64bit program.

Re: Assembler question

Posted: Thu Sep 27, 2018 9:24 pm
by Eric
globalalloc already has support for the prefered memory region parameter

Re: Assembler question

Posted: Fri Sep 28, 2018 8:28 am
by JohnFK
Nice, perhaps you might want to update the wiki sometime as it does no show the prefered parameter option:

[Link]