当从 FPU 弹出到 CPU 堆栈时,无法理解数字的变化

逆向工程 堆栈变量
2021-07-10 19:53:12

所以我正在开发一款破解版,并遇到了一些让我感到困惑的 FPU 负载和爆裂声。

地址 main 0040169E 从 FPU 堆栈(ST0=4275451536.0000000000)弹出 00000000_FED63690h 的 80 位值到 CPU 堆栈

但是当放在 CPU 堆栈上时,它的值更改为

CPU Stack
Locked    Value      ASCII Comments
0028FB38  |D2000000     Ò
0028FB3C  |41EFDAC6  ÆÚïA

为什么?

这是带有一些注释的代码:

main    00401696    PUSH EAX                                EAX=FED63690
main    00401697    FILD QWORD PTR SS:[LOCAL.268]           Loads the FED63690 as a 64 bit value so -> 00000000_FED63690
main    0040169A    LEA ESP,[LOCAL.266]                     ESP=0028FB20 (loads address of string on stack), ST0=4275451536.0000000000 (which euals above number)
main    0040169E    FSTP QWORD PTR SS:[LOCAL.260]           POPS 80 bit value of ST0 onto program stack as 64 bit   

        LOCAL.260 is address 0028FB38

        Stack now looks like:

        CPU Stack
        Locked    Value      ASCII Comments
        0028FB38  |D2000000     Ò
        0028FB3C  |41EFDAC6  ÆÚïA


main    004016A4    FLD QWORD PTR SS:[LOCAL.260]            Loads value onto FPU Stack so -> ST0=4275451536.0000000000 (Same as before)
main    004016AA    FSTP QWORD PTR SS:[LOCAL.264]           <%i> = -771751936.       POPS 80 bit value of ST0 onto program stack as 64 bit

        LOCAL.260 is address 0028FB28

        Stack now looks like:

        CPU Stack
        Locked    Value      ASCII Comments
        0028FB28  |D2000000     Ò
        0028FB2C  |41EFDAC6  ÆÚïA


main    004016AE    MOV DWORD PTR SS:[LOCAL.265],00401469   Format => "%i"
main    004016B6    LEA EAX,[LOCAL.194]             
main    004016BC    MOV DWORD PTR SS:[LOCAL.266],EAX        s => OFFSET LOCAL.194
main    004016BF    CALL <JMP.&msvcrt.sprintf>          

        Result is:

        s="-771751936"
1个回答

4275451536大于2^31 (2147483648)小于但小于2 ^32 (4294967296)
从而它被表示为2^31 + ( 2 ^31 * ((4275451536 - 2 ^31 ) / 2^31)
2^31 * 1.990912266075611114501953125

指数总是写有偏差(64 位精度为 1023),所以1054 = 0x41e

小数部分可以写成 1/2 + 1/4 + 1/8 + 1/16 + 1/32 + 1/64 ..... 1/2 ^n

0.984375     < 0.990912266075611114501953125 < 0.9921875

(1/2+...+1/64) <   -------                     < (1/2+....+ 1/128)
 111111

尾数显式近似为 52 位,隐式添加 1 或 0

显示特定十进制转换的 ac src 如下所示

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BIAS 1023
int main(void) {
    char binform[100] = {0};
    unsigned long a = 4275451536;
    _ultoa_s(a%2,&binform[0],4,10);
    a = a/2;
    int i = 1;
    while (a>2) {
        a = a/2;
        _ultoa_s(a%2,&binform[i++],4,10);
    }
    char paddedstr[100] = {0};
    sprintf_s(paddedstr,100,"%s0000000000000000000000",_strrev(binform));
    printf("%x-%I64x\n",i+BIAS,_strtoui64(&paddedstr[1],0,2));
}

执行结果是

>F2H.exe
41e-fdac6d2000000