0

I was reverse engineering a game using cheat engine and trying to trace where my health gets reduced.

Basically the health gets stored in the stack and then pops out for displaying on the screen. After it pops out I tried to modify the memory address but that didn't work. Which means we need to modify it before it gets placed into the stack. After lots of diligent scrolling back, I came across the following code.

fld qword ptr[ebp-38]

This code basically pushes my health onto the stack. However, there are a whole bunch of really odd things in this code:

  1. This code pushes a value into the float register. It pushes my health float value (71.70) onto the Float registers. However, it is not clear from where its getting this value from. From [EBP-38]? It can't be that because that stores the value "-2.0".
  2. Once the value is pushed onto the Float registers, I notice that a value has been pushed onto the first register and all other values seem to be shifted. Both of these changes happen from just 1 instruction. Please take a look at the screenshot to see what I'm talking about.

(If screenshot doesn't show big then right-click and "open in new tab" for a bigger size). cheat engine showing the line that adds our data

  1. Here's the really odd part. If I select this code in cheat engine then it shows the details of the operation on the right pane. There it shows that the value being moved is "double". However, this is supposed to be a floating point instruction. So shouldn't a float value get moved?
  2. Another odd thing is that after the value is moved, the float register shows that all 0s have been moved. The existing value is shifted down.

after the fld instruction has executed the float registers have changed

So my question is:

1) What does this instruction do exactly?

2) To change this value to a custom value, can I change the source address? (wherever that is?). Assuming that that is [EBP-38] If yes, then can I use a simple move instruction for this?

Something like mov [ebp-38], (hex value for 99 float)?

1

Qword is 8 bytes not 4 bytes so what you show in your first screen shot as 32 bit value is not correct representation

ebp-38 is an address it can point to x y z where x,y,z can be char , int , float , double , "your fancy new secret type"

Qword qualifies the address with the type here it says it is a 64 bit numeric

float operations opearate on float (32) / double (64) / and ? long double ?? 80

cdb -c ".formats 4051eccc`c0000000;q" cdb | grep -iE "Double|Float"
  Float:   low -2 high 3.28008
  Double:  71.7

you can see how float operations work on botb 32 bit as well as 64 bit based on bit size type qualifiers assembling some instructions in-place

0:000> a .
771f05a6 push 4051eccc
771f05ab push 0xc0000000
771f05b0 fld qword ptr [esp]
771f05b3 fld dword ptr [esp]

disassembling to confirm

771f05b6
0:000> u . l4
ntdll!LdrpDoDebuggerBreak+0x2c:
771f05a6 68ccec5140      push    4051ECCCh
771f05ab 68000000c0      push    0C0000000h
771f05b0 dd0424          fld     qword ptr [esp]
771f05b3 d90424          fld     dword ptr [esp]

stepping through to see the results

0:000> 
771f05a6 68ccec5140      push    4051ECCCh
0:000> t
771f05ab 68000000c0      push    0C0000000h
0:000> t
771f05b0 dd0424          fld     qword ptr [esp] ss:0023:000af874=4051ecccc0000000
0:000> t
771f05b3 d90424          fld     dword ptr [esp]      ss:0023:000af874=c0000000

querying registers

0:000> r st0
st0=-2.0000000000000e+0000 (1:4000:8000000000000000)
0:000> r st1
st1= 7.16999969482421875000000000000e+0001 (0:4005:8f66660000000000)
0:000> dd esp l2
000af874  c0000000 4051eccc

0:000> ?? *(float *) @@masm(@esp)
float -2

0:000> ?? *(double *) @@masm(@esp)
double 71.6999969482421875

you should better read this to learn how fpu works why the top slot is copied etc At Simply FPU by Raymond Filiatreault read chapter 1 internals where he explains how st registers are loaded and copied and trashed an unloaded

  • I've tried to read this answer multiple times but it goes over my head. Each time I quit somewhere in the middle. I guess I'll have to catch someone to put this in simple words. Thanks for replying. – Mugen Feb 10 at 12:47
  • it is simple qword (quad word) is 64bit number fld uses Qword in that instruction you posted so it means it is operating on DOUBLE (8 bytes ) not 32 Bit Float (4 bytes) – blabb Feb 10 at 22:02
  • Could you please explain what is "0:000> a ." just before the code? I don't think I've seen that anywhere. – Mugen Feb 11 at 7:53
  • open windbg and try that . is alias for current instruction pointer (eip / rip) a is assemble command it assembles in place a . is assemble at eip u . is disassemble at eip – blabb Feb 11 at 8:04

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.