Assembler question

Post your topics and discussions here that you can't find a good section for.
Post Reply
beguiler
Expert Cheater
Expert Cheater
Posts: 102
Joined: Sun Mar 19, 2017 1:31 pm
Reputation: 70

Assembler question

Post 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.

TimFun13
Expert Cheater
Expert Cheater
Posts: 1353
Joined: Fri Mar 03, 2017 12:31 am
Reputation: 7

Re: Assembler question

Post 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).

User avatar
Kalas
Expert Cheater
Expert Cheater
Posts: 548
Joined: Fri Mar 03, 2017 9:49 am
Reputation: 134

Re: Assembler question

Post 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 🙍

beguiler
Expert Cheater
Expert Cheater
Posts: 102
Joined: Sun Mar 19, 2017 1:31 pm
Reputation: 70

Re: Assembler question

Post 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.
Attachments
BardsTale4.CT
(3.44 KiB) Downloaded 132 times

TimFun13
Expert Cheater
Expert Cheater
Posts: 1353
Joined: Fri Mar 03, 2017 12:31 am
Reputation: 7

Re: Assembler question

Post 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.

beguiler
Expert Cheater
Expert Cheater
Posts: 102
Joined: Sun Mar 19, 2017 1:31 pm
Reputation: 70

Re: Assembler question

Post 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.

User avatar
Kalas
Expert Cheater
Expert Cheater
Posts: 548
Joined: Fri Mar 03, 2017 9:49 am
Reputation: 134

Re: Assembler question

Post 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]
}

beguiler
Expert Cheater
Expert Cheater
Posts: 102
Joined: Sun Mar 19, 2017 1:31 pm
Reputation: 70

Re: Assembler question

Post by beguiler »

Interesting @Kalas, your method works. It looks like it might be related to the globalalloc call.

JohnFK
Expert Cheater
Expert Cheater
Posts: 59
Joined: Tue Aug 29, 2017 10:50 am
Reputation: 27

Re: Assembler question

Post 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.

beguiler
Expert Cheater
Expert Cheater
Posts: 102
Joined: Sun Mar 19, 2017 1:31 pm
Reputation: 70

Re: Assembler question

Post 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.

Eric
Hall of Famer
Hall of Famer
Posts: 174
Joined: Thu Mar 02, 2017 11:01 pm
Reputation: 90

Re: Assembler question

Post by Eric »

globalalloc already has support for the prefered memory region parameter

JohnFK
Expert Cheater
Expert Cheater
Posts: 59
Joined: Tue Aug 29, 2017 10:50 am
Reputation: 27

Re: Assembler question

Post by JohnFK »

Nice, perhaps you might want to update the wiki sometime as it does no show the prefered parameter option:

[Link]

Post Reply

Who is online

Users browsing this forum: No registered users