 |
Cheat Engine The Official Site of Cheat Engine
|
View previous topic :: View next topic |
Author |
Message |
Hugo_the_Dwarf Newbie cheater
Reputation: 0
Joined: 17 Apr 2019 Posts: 13
|
Posted: Mon Apr 22, 2019 1:53 am Post subject: Need Help with Code Injection Logic |
|
|
So I've been messing around with adding "newer" features into an older game (Turok 2: Seeds of Evil) I've implemented a low level health regen portion, that I just need to balance out now. But the problem I'm facing now is some crashing and comparing logic that isn't working right. The code is below:
EDIT: I'll update this with the final code once all the issues are resolved, or after a few weeks have passed with what was solved.
EDIT2: I figured out my crash, and have updated the below code with the final product, To assembly experts uncommented parts that Bloodybone hadn't touched are probably dying on the inside but this is the best I could do at my level, and it works
Code: | aobscanmodule(DamageUpdate,horus_x64.exe,F3 0F 11 43 70 48 8B) // should be unique
alloc(NEWDamageUpdate,$1000,"horus_x64.exe"+54A23)
registersymbol(DamageUpdate)
registersymbol(NEWDamageUpdate)
label(code)
label(return)
label(p_string)
label(stringcmp)
label(stringcmp_loop)
NEWDamageUpdate:
code:
push rax
mov rax,[rbx+78]
//mov rax,[rax+60]
push rax
push rcx
push rdx
lea rcx,[rax+60] // The difference between lea and mov is that mov, copies the value from the address in this case [rax+60] and lea gets the address of [rax+60]
lea rdx,[p_string]
call short stringcmp // The short prefix means that the call will be a "short call" which means that it only takes to bytes but can only jump a short distance instead of the normal five for a long or even 14 or 15 bytes for the far call
test al,al // This checks if al is 0 and if it is the Zero-Flag is set
pop rdx
pop rcx
pop rax
jne short Final // This jumps if the Zero-Flag is not set meaning that al had to be anything but 0 before
movd eax,xmm0 //I changed the movq to a moved because a float is only 4 bytes long and a movq moves 8 bytes
cmp eax,(float)0
jge short Final
mov rax,[1407F2EA8]
lea rax,[rax+70]
add [rax],10000
Final:
pop rax
movss [rbx+70],xmm0
jmp return
stringcmp: // This function returns 1 if the both strings passed are 1:1 and 0 if they're not
/*
This function takes 2 pointers where each points to the start of the string
and then both of them are compared to each other
*/
// Save Registers
push rsi
push rdi
// Move the pointers to the start of the strings in to the saved registers
mov rsi,rcx
mov rdi,rdx
// Set rax to 0
xor rax,rax
stringcmp_loop:
lodsb // This instruction moves the byte at [rsi] into al and increments rsi
/* You could also write it like this:
mov byte ptr al,[rsi]
inc rsi
Which means that it moves the Char of the first string into al and makes rsi point to the next char in the first string
*/
cmp byte ptr [rdi],al // And then Compares it to the Char of the other String
je short @f // This then jumps to the next @@ if the Chars are the same
pop rdi
pop rsi
xor al,al // Sets al to zero
ret
@@:
inc rdi // rdi now points to the next Char in the second string
test al,al // Check if the CHar is 0 meaning the string has ended
jne short stringcmp_loop // If the string has not ended, loop
pop rdi
pop rsi
mov al,1
ret
p_string:
db 50,'layer',0 // This equals the String 'Player' and the 0 at the end means that the String is zero-teminated
DamageUpdate:
jmp NEWDamageUpdate
return:
[DISABLE]
DamageUpdate:
db F3 0F 11 43 70
dealloc(NEWDamageUpdate)
unregistersymbol(DamageUpdate)
unregistersymbol(NEWDamageUpdate) |
Explanation on the Data used in the code:
RBX is the register holding the Actor that has taken damage (RBX+70 points to the HP value 'float')
XMM0 is the new calculated HP 'float' (RBX+70 is 100.00, XMM0 is 70.00 as the Actor took 30 dmg)
I'm using RAX to hold a 'pointer' that contains the actor's base definition ( RBX+78 ) offset inside of that pointer by 60 is the actor's classname 'string'
so using
mov rax,[rbx+78]
mov rax,[rax+60]
to get the actor's classname
Now where I'm struggling but I'll explain what I'm trying to do. I'm trying to make new logic that when something is killed, the player is healed by a small amount.
The struggle is:
1) FIXED BY "Bloodybone" not able to compare the classname properly (this is due to my own lack of experience/knowledge) the player Actor classname is "Player" (magical huh) however when injected the memory view has in the "comment" header ("Play") so the string is too long for the cmp operations memory bytes. Any tips on how to compare large strings (or how I'd compare each char in the RAX register holding the String (that is if I even loaded the string correctly to begin with, not sure how to debug that right in CE)
2) Compare is not working with XMM0 as I'm not sure how I can properly work with that Register compared to the other registers, the compare is not working (with my implementation) as even if the number is 0 or below, it's not triggering (well going through with the code I want to run, it just jumps to the end all the time)
3) Application Crash if inner most code is run. What I'm using is a static pointer, then getting the offset for the Player's HP.
I may have to regather what static address I'm using, but what I have in the cheat table to see my HP is a pointer 1407F2EA8[Offset '+70'] I got this pointer from looking at the HUD's graphical update logic (and yes the one I posted is the player's real HP, not the graphical display value)
Any tips or guidance would be appreciated as I'm enjoying injecting new types of code other than the standard "don't subtract value, or unlimited x" just this lifesteal stuff isn't working out as I'd hope. Passive HP regen works fine tho.
Last edited by Hugo_the_Dwarf on Mon Apr 22, 2019 3:47 pm; edited 2 times in total |
|
Back to top |
|
 |
Bloodybone Newbie cheater
Reputation: 0
Joined: 07 Dec 2016 Posts: 21 Location: Germany
|
Posted: Mon Apr 22, 2019 5:48 am Post subject: |
|
|
Let me know if this code works:
Code: | label(code)
label(return)
label(p_string)
label(stringcmp)
label(stringcmp_loop)
NEWDamageUpdate:
code:
push rax
mov rax,[rbx+78]
//mov rax,[rax+60]
push rax
push rcx
push rdx
lea rcx,[rax+60]
lea rdx,[p_string]
call short stringcmp
test al,al
pop rdx
pop rcx
pop rax
jne Final
movd eax, xmm0
cmp eax,0
jge Final
mov rax,1407F2EA8
mov rax,[rax+70]
add rax,1000
push rdi
mov rdi,1407f2ea8
mov [rdi+70],rax
pop rdi
Final:
pop rax
movss [rbx+70],xmm0
jmp return
stringcmp:
push rsi
push rdi
mov rsi,rcx
mov rdi,rdx
xor rax,rax
stringcmp_loop:
lodsb
cmp byte ptr [rdi],al
je short @f
pop rdi
pop rsi
xor al,al
ret
@@:
inc rdi
test al,al
jne short stringcmp_loop
pop rdi
pop rsi
mov al,1
ret
p_string:
db 50,'layer',0
DamageUpdate:
jmp NEWDamageUpdate
return: |
|
|
Back to top |
|
 |
Hugo_the_Dwarf Newbie cheater
Reputation: 0
Joined: 17 Apr 2019 Posts: 13
|
Posted: Mon Apr 22, 2019 10:35 am Post subject: |
|
|
Hey Bloodybone,
I tried out the String Compare logic and it works I'm just trying to follow your changes, and understand it more (the assembly commands, etc)
I'm super new to assembly (not programming, so stuff can go over my head on what it does)
Mainly the prefix/verb "short" in the call and jumps in your new code (does having it or not having that have different effects, as seen with my jumps)
I also noticed you used lea instead of the mov I had (I'm watching a YT vid on MOV vs LEA so maybe I'll understand soon)
Either way that solves my issue number 1). Would you be able to add some comments to your code so I can have an idea on what the steps are (I'm still trying to dig through, if you don't want to that's fine, just figure I'd learn faster if I had a rough idea of the steps and actions)
So Thanks again for this String Compare logic. I hope I can understand it enough to recreate it for other projects.
|
|
Back to top |
|
 |
Bloodybone Newbie cheater
Reputation: 0
Joined: 07 Dec 2016 Posts: 21 Location: Germany
|
Posted: Mon Apr 22, 2019 11:00 am Post subject: |
|
|
I'm gonna add some comments to the code I originally posted
Edit:
Here is the Code with the Comments, I hope they'll help
Code: | label(code)
label(return)
label(p_string)
label(stringcmp)
label(stringcmp_loop)
NEWDamageUpdate:
code:
push rax
mov rax,[rbx+78]
//mov rax,[rax+60]
push rax
push rcx
push rdx
lea rcx,[rax+60] // The difference between lea and mov is that mov, copies the value from the address in this case [rax+60] and lea gets the address of [rax+60]
lea rdx,[p_string]
call short stringcmp // The short prefix means that the call will be a "short call" which means that it only takes to bytes but can only jump a short distance instead of the normal five for a long or even 14 or 15 bytes for the far call
test al,al // This checks if al is 0 and if it is the Zero-Flag is set
pop rdx
pop rcx
pop rax
jne Final // This jumps if the Zero-Flag is not set meaning that al had to be anything but 0 before
movd eax,xmm0 I changed the movq to a moved because a float is only 4 bytes long and a movq moves 8 bytes
cmp eax,0
jge Final
mov rax,1407F2EA8
mov rax,[rax+70]
add rax,1000
push rdi
mov rdi,1407f2ea8
mov [rdi+70],rax
pop rdi
Final:
pop rax
movss [rbx+70],xmm0
jmp return
stringcmp: // This function returns 1 if the both strings passed are 1:1 and 0 if they're not
/*
This function takes 2 pointers where each points to the start of the string
and then both of them are compared to each other
*/
// Save Registers
push rsi
push rdi
// Move the pointers to the start of the strings in to the saved registers
mov rsi,rcx
mov rdi,rdx
// Set rax to 0
xor rax,rax
stringcmp_loop:
lodsb // This instruction moves the byte at [rsi] into al and increments rsi
/* You could also write it like this:
mov byte ptr al,[rsi]
inc rsi
Which means that it moves the Char of the first string into al and makes rsi point to the next char in the first string
*/
cmp byte ptr [rdi],al // And then Compares it to the Char of the other String
je short @f // This then jumps to the next @@ if the Chars are the same
pop rdi
pop rsi
xor al,al // Sets al to zero
ret
@@:
inc rdi // rdi now points to the next Char in the second string
test al,al // Check if the CHar is 0 meaning the string has ended
jne short stringcmp_loop // If the string has not ended, loop
pop rdi
pop rsi
mov al,1
ret
p_string:
db 50,'layer',0 // This equals the String 'Player' and the 0 at the end means that the String is zero-teminated
DamageUpdate:
jmp NEWDamageUpdate
return: |
|
|
Back to top |
|
 |
Hugo_the_Dwarf Newbie cheater
Reputation: 0
Joined: 17 Apr 2019 Posts: 13
|
Posted: Mon Apr 22, 2019 1:29 pm Post subject: |
|
|
Thank you for your comments, this is helping me greatly understand what's going on.
I'm still fuzzy with the stuff going on in the stringcmp function but I think I can piece things together from your comments and some Google-Fu.
now I need to Google about what registers do what since there is AL, AC, etc? and the RAX. I know XMM# are mostly for floats/scalar values?
Still much I need to study up on, I wouldn't figure a simple feature would be so troublesome for a beginner for me to do so thank you for your insight.
Also the explaination on the short, long, and far was very helpful
EDIT:
I figured out the crash and it was with this section:
Code: | mov rax 1407F2EA8
mov rax,[rax+70]
mov rax,[rax]
add rax, 1000 |
The fixed logic is:
Code: | mov rax,[1407F2EA8]
lea rax,[rax+70]
add [rax],10000 |
any other combo or lack of '[]'s causes a hard crash (I finally found the "watchlist" in the view section of memory view, it's a godsend for debugging)
I'm going to update the OP with the final code, and paste the broken code below for future ref for whoever wanted to see my failure.
Code: | aobscanmodule(DamageUpdate,horus_x64.exe,F3 0F 11 43 70 48 8B) // should be unique
alloc(NEWDamageUpdate,$1000,"horus_x64.exe"+54A23)
registersymbol(DamageUpdate)
registersymbol(NEWDamageUpdate)
label(code)
label(return)
NEWDamageUpdate:
code:
push rax
mov rax,[rbx+78]
mov rax,[rax+60]
cmp rax,'Play'
je Final
movq rax, xmm0
cmp rax,0
jnle Final
mov rax 1407F2EA8
mov rax,[rax+70]
mov rax,[rax]
add rax, 1000
Final:
pop rax
movss [rbx+70],xmm0
jmp return
DamageUpdate:
jmp NEWDamageUpdate
return:
[DISABLE]
DamageUpdate:
db F3 0F 11 43 70
dealloc(NEWDamageUpdate)
unregistersymbol(DamageUpdate)
unregistersymbol(NEWDamageUpdate) |
|
|
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
|
|