|
Cheat Engine The Official Site of Cheat Engine
|
View previous topic :: View next topic |
Author |
Message |
ichigoned How do I cheat? Reputation: 0
Joined: 09 Aug 2022 Posts: 4
|
Posted: Tue Aug 09, 2022 8:27 pm Post subject: Problem figure out how to use float as integer multiplier. |
|
|
Hi,
I write a heal and damage multiplier in an auto assembly that I learn from youtube video and it works great. For the damage, however, it little bit inconvenient to use IDIV command.
Then I stumbled upon a shared CE table that uses float as a multiplier which more convenience instead use IDIV command.
When I look at CE shared table code it uses FILD, FMUL/FDIV, and FISTP which as far as I know similar to POP and PUSH but convert integer to float, do the arithmetic, then convert back to integer. But the method still does not click for me.
Let's say my game uses a positive value to do healing and a negative value to do the damage. The original instruction when calculating the damage (which is where I injected to) is as follows:
Code: | code:
add ecx,r11d
cmp ecx,edx
jmp return
|
ecx stores the current hero/enemy health
r11d stores the damage/heal value
Now this is my the current multiplier code
Code: | aobscanmodule(...)
alloc(...)
HealMult:
dd #1
registersymbol(...)
newmem:
cmp [r10+280],1 // check whether hero / enemy
jne code
cmp r11d,0 // check whether heal or damage
jl code
imul r11d,[HealMult]
|
Now the question is, how do I write the code so that the r11d register can be multiplied with a float type multiplier?
for reference, I try to copy the code from the shared table (different game) in the codebox below. But seems does not work as intended (either hero/enemy dies in one hit). I suspect that I did something wrong and decide to ask here for more detailed logic behind the shared table code.
Code: | push edx // push edx into the stack
fild dword ptr [rsp] // push and load integer from rsp to the stack?
fmul dword ptr [HealMult] // multiply the value of rsp with the multiplier
fistp dword ptr [rsp] // pop the value of multiply back to rsp?
pop edx // pop edx (that been push previously) value back to edx???, huh?
|
edx I believe it holds the value of heal
Would appreciate it if someone were also able to explain the way reference code work so that I understand the logic behind it.
Thanks in advance.
|
|
Back to top |
|
|
ParkourPenguin I post too much Reputation: 140
Joined: 06 Jul 2014 Posts: 4300
|
Posted: Tue Aug 09, 2022 10:02 pm Post subject: |
|
|
ichigoned wrote: | When I look at CE shared table code it uses FILD, FMUL/FDIV, and FISTP which as far as I know similar to POP and PUSH but convert integer to float, do the arithmetic, then convert back to integer. But the method still does not click for me. | That uses x87, which is pretty much obsolete for 64-bit code. Use SSE instead. (and use doubles, not floats)
Code: | newmem:
cmp [r10+280],1
jne code
cmp r11d,0
jl code
cvtsi2sd xmm0,r11d // convert to double
mulsd xmm0,[HealMult] // multiply
cvttsd2si r11d,xmm0 // convert back to int
code:
add ecx,r11d
cmp ecx,edx
jmp return
HealMult:
dq (double)1.0 |
Points about your code:
- `dd #1` - here 1 is an integer, not a float. Should've been `dd (float)1.0`
- No clue where you got edx from. You clearly say the change in health is stored in r11d.
- There are two stacks at play: the threadstack (rsp) and the x87 stack. The `push` instruction operates on the threadstack. Its purpose is to store the change in health in memory somewhere (`fild` can't read from a general purpose register- only memory).
_________________
I don't know where I'm going, but I'll figure it out when I get there. |
|
Back to top |
|
|
ichigoned How do I cheat? Reputation: 0
Joined: 09 Aug 2022 Posts: 4
|
Posted: Tue Aug 09, 2022 10:54 pm Post subject: |
|
|
ParkourPenguin wrote: | ichigoned wrote: | When I look at CE shared table code it uses FILD, FMUL/FDIV, and FISTP which as far as I know similar to POP and PUSH but convert integer to float, do the arithmetic, then convert back to integer. But the method still does not click for me. | That uses x87, which is pretty much obsolete for 64-bit code. Use SSE instead. (and use doubles, not floats)
Code: | newmem:
cmp [r10+280],1
jne code
cmp r11d,0
jl code
cvtsi2sd xmm0,r11d // convert to double
mulsd xmm0,[HealMult] // multiply
cvttsd2si r11d,xmm0 // convert back to int
code:
add ecx,r11d
cmp ecx,edx
jmp return
HealMult:
dq (double)1.0 |
Points about your code:
- `dd #1` - here 1 is an integer, not a float. Should've been `dd (float)1.0`
- No clue where you got edx from. You clearly say the change in health is stored in r11d.
- There are two stacks at play: the threadstack (rsp) and the x87 stack. The `push` instruction operates on the threadstack. Its purpose is to store the change in health in memory somewhere (`fild` can't read from a general purpose register- only memory).
|
Thanks for the reply.
I have a question.
In this part, I can see that it will borrow xmm0 register to store the value.
Do I need to be concerned xmm0 register being used somewhere else?
Or it is safe to leave it as it is without storing the value of xmm0 before borrowing and then restoring it later?
|
|
Back to top |
|
|
panraven Grandmaster Cheater Reputation: 55
Joined: 01 Oct 2008 Posts: 942
|
Posted: Wed Aug 10, 2022 12:09 am Post subject: |
|
|
Using fpu instruction has benefit to less need to save register (general or xmm), as your concern.
The following code multiply 2 or -2 depend both if it is heal/dmg or enemy/not
Code: |
aobscanmodule(...)
alloc(...)
HealMult:
dd #2, #-1
registersymbol(...)
newmem:
push r11
fild dword ptr[rsp]
cmp [r10+280],1 /// player or enemy?
je short @f
fimul dword ptr[HealMult+4]// negate
@@:
cmp dword ptr[rsp],0 /// negative change?
jge short @f
fimul dword ptr[HealMult+4]// negate
@@:
fimul dword ptr[HealMult] // multiply
fistp dword ptr[rsp] // save r11d -- need qword ptr[rsp]? depend on how r11 use in following code
pop r11
/// jl code
/// imul r11d,[HealMult]
... original code
|
HealMult can use float instead of integer, just change respective instruction to float version.
_________________
- Retarded. |
|
Back to top |
|
|
ichigoned How do I cheat? Reputation: 0
Joined: 09 Aug 2022 Posts: 4
|
Posted: Wed Aug 10, 2022 12:34 am Post subject: |
|
|
panraven wrote: | Using fpu instruction has benefit to less need to save register (general or xmm), as your concern.
The following code multiply 2 or -2 depend both if it is heal/dmg or enemy/not
Code: |
aobscanmodule(...)
alloc(...)
HealMult:
dd #2, #-1
registersymbol(...)
newmem:
push r11
fild dword ptr[rsp]
cmp [r10+280],1 /// player or enemy?
je short @f
fimul dword ptr[HealMult+4]// negate
@@:
cmp dword ptr[rsp],0 /// negative change?
jge short @f
fimul dword ptr[HealMult+4]// negate
@@:
fimul dword ptr[HealMult] // multiply
fistp dword ptr[rsp] // save r11d -- need qword ptr[rsp]? depend on how r11 use in following code
pop r11
/// jl code
/// imul r11d,[HealMult]
... original code
|
HealMult can use float instead of integer, just change respective instruction to float version. |
Now, this is interesting.
Correct me if I'm wrong. But...
Code: | fild dword ptr[rsp] |
What does this line do?
From what I understand, this push whatever value in [rsp] to the top of stack and put it as a float. But I still don't understand the intention of doing this.
Code: | fistp dword ptr[rsp] |
This pop whatever result of multiplication back to [rsp].
But, then how
Will yield the result of multiplication, instead of [rsp]?
|
|
Back to top |
|
|
panraven Grandmaster Cheater Reputation: 55
Joined: 01 Oct 2008 Posts: 942
|
Posted: Wed Aug 10, 2022 12:56 am Post subject: |
|
|
fpu instruction work on an internal stack (limited size), which each is a 10 byte extended double float (EDF).
@"fild dword ptr[rsp]"
it load a 4byte (coz 'dword ptr') integer (i in fild) from the memory [rsp],
convert it to EDF and push into the internal fpu stack.
"This pop whatever result of multiplication back to [rsp]."
Yes, ie.
pop EDF from fpu stack top
convert it to 4byte integer (dword ptr, i in fistp)
then save the 4byte to memory [rsp]
@"pop r11"
It pop pc stack top [rsp] to r11, since we work on [rsp] previously, so ir11 got the multiply result.
_________________
- Retarded. |
|
Back to top |
|
|
ParkourPenguin I post too much Reputation: 140
Joined: 06 Jul 2014 Posts: 4300
|
Posted: Wed Aug 10, 2022 1:17 am Post subject: |
|
|
ichigoned wrote: | Do I need to be concerned xmm0 register being used somewhere else? |
Look around the injection point. If you don't see xmm0 anywhere, it's probably fine.
If you want, use a different one- e.g. xmm6. It's less likely to be used than xmm0.
You could back it up to the stack if you're really concerned, but it's unnecessary.
Code: | sub rsp,20
movups [rsp],xmm0
...
movups xmm0,[rsp]
add rsp,20 |
_________________
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: 458
Joined: 09 May 2003 Posts: 25296 Location: The netherlands
|
Posted: Wed Aug 10, 2022 2:25 am Post subject: |
|
|
or if you don't want to deal with all this and it's not a super highperformance location in the game:
Code: |
HealMult:
dd (float)2.5
...
{$ccode value=r11}
extern float HealMult;
float f=HealMult; //extern float/double has a small bug in libtcc in 7.4 (this works as a bypass)
value=value*f;
{$asm}
//r11 is multiplied by HealMult now
...
|
_________________
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 |
|
|
ichigoned How do I cheat? Reputation: 0
Joined: 09 Aug 2022 Posts: 4
|
Posted: Wed Aug 10, 2022 9:04 am Post subject: |
|
|
Hi,
Very much appreciate all the different approaches to solving the issue.
The cvtsi2sd command is the most preferred as of now. Probably will stick with this until I found other difficulties ahead.
I will try both FPU instruction and Lua scripting once get more grasp of them.
And probably my last question, is the cvtsi2sd command only work for 64bit games?
Thank bunch.
|
|
Back to top |
|
|
ParkourPenguin I post too much Reputation: 140
Joined: 06 Jul 2014 Posts: 4300
|
Posted: Wed Aug 10, 2022 12:11 pm Post subject: |
|
|
The version that takes a 32-bit operand works in 32-bit or 64-bit games. The version that takes a 64-bit operand only works in 64-bit games.
_________________
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
|
|