iBinary PC逆向之代码还原技术,第一讲基本数据类型在内存中的表现形式.浮点,指针寻址公式

 目录

最高位是符号位,表示正负
去掉符号位往后数8位 是指数域.
最后的23位则表示尾数.

1.正数浮点转为十六进制表示

2.计算指数位
计算指数位首先移动小数点位置到符号位置除最高位为1的地方.
也就是符号位也好.不是符号位也好.移动到最高位为1的地方. 7.25 转换之后是
0111.01 移动到最高位则是 1.1101.

1100.01 移动 1.10001 总共移动了3位.每次移动一位,指数+1
因为指数为移动了三位.所以 3 + 127(8位) = 130 转为二进制 10000010 这个就是指数位.
也就是上图中所说的符号位后面数8位是指数位. 我们上边计算的就是指数位的值.
为什么 +127.因为可能会出现负数.十进制127可以表示二进制的01111111. IEEE浮点编码规定
当指数域< 0111111的时候,就是一个负数.如果大于01111111的时候就是一个正数. 所以01111111为0. IEEE浮点编码规定的.所以只要记住即可. 127即可. 也可以理解为指数域是8位,表示的数值是128.但IEE规定了.所以-1 指数最大值 - 1即可.

3.计算尾数位
经过上面计算我们符号是1,但是符号位基本不变.因为是正数浮点.所以符号位为0:
指数位为: 130 10000010
现在计算尾数位. 尾数位就是我们移动小数点之后的数值

1.10001 尾数位就是 10001,但是他不组23位.所以我们补0填充.

1000 1000 0000 0000 0000 000 补0之后,我们需要从左到右,按照4个字节分开
100 0100 0000 0000 0000 0000 分开之后.
此时加上我们之前的符号位以及指数位

0100 0001 0100 0100 0000 0000 0000 0000 这是拼接好的.我们转换为16进制进行存储
0x41440000 那么在内存中,我们的浮点数12.25 其实就是16进制 0x41 44 00 00 进行存储的.

2.负数浮点转为十六进制表示.

负数跟上边一样.一样计算指数位.也是分为以下步骤
1.转为科学计数法.
2.移动指数位.
3.计算指数位
4.尾数位补零到23位.
5.拼接进行二进制,并且二进制转为16进制.

1.转为科学计数法
-0.125 = 0.001
2.移动指数位
此时移动指数位是往小数点右边移动,移动到最高位为1的地方.
0.001 =>1.0 移动了三位,计算 -3. 往右边移动就是负数
1.0 则符号位是1代表负数. 指数位是负数.

3.计算指数位.
上面我们计算指数位是往小数点左边移动.所以指数位去相加.现在是往右边移动.所以相减
127-3 = 124 转为二进制 = 01111100
4.尾数位补零
0000 0000 0000 0000 0000 000
5.符号位 指数位 尾数位 进行拼接

1011 1110 0000 0000 0000 0000 0000 0000 (总共32位)
转为16进制
0xBE00 0000
所以-0.125 在内存中的16进制则是 0xBE000000

3.正数浮点16进制转为浮点数解析

我们会转换为16进制那么也要回转换回来
1.16进制拆分为2进制.
2.分出符号位 指数位 尾数位
3.求指数位是负数还是整数
4.移动指数位

比如我们的12.25f. 十六进制是x41440000
1.16进制转为2进制
0100 0001 0100 0100 0000 0000 0000 0000
2.分出符号位 指数位 尾数位
0 10000010 10001000000000000000000
3.求出指数位
指数位位 10000010 > 01111111 所以可以判断我们的小数是正数
10000010 - 01111111 = 130 - 127 = 3;
得出了我们要移动的位数
4.移动指数位
首先计算出的指数转为2进制 3 = 0011;

然后反过来.尾数位右移动三位.如下.
100010 >> 3 = 100.010 尾数的最高位不需要.所以补零

然后加上符号位.
符号位为0.代表是正数.所以+1
1100.010
再举个例子
7.25 在内存的16进制为0x40E8
1.16进制转为二进制
0100 0000 1110 1000 0000 0000 .....
2.计算指数位,尾数需要往右移动纪委
10000001 - 01111111 = 129 - 127 = 2;得出移动2位
3.移动尾数位
因为高位为0,所以代表我们转换的浮点数是正数.最后我们的高位要加上1才可以.
11010 ==>2位 = 11.010
符号位为0.所以高位补1
111.01 这个二进制在转换为10进制得出7.25

小数转为10进制:
.01是是两位. 分别记位 2的-1次方 2-2次方.
第一位计算: 0 * 1/2-1次方.
第二位计算: 1 * 1/2-2次方即可.
最后结果相加.
如果有三位.那么就是 用第三位数值 * 1/2-3次方即可.
01/2 + 1 1/4 = 0.25.所以我们可以推算出是0.25

4.Double类型解析.

double类型转换跟float一样.只不过指数位变成了11位. 剩余的42位表示尾数位.

2~11次方 - 1;就是用于计算的指数.也就是 1023.

三丶浮点汇编

1.浮点栈

因为有了浮点协处理器.所以浮点指令的操作有点不同.它是通过浮点寄存器来实现的.
浮点寄存器是通过栈结构来实现的.也称作浮点栈. 由 st(0) - st(7); 其中写st默认就是st(0)
操作任意浮点栈就需要加上序号 st(7);
值得注意的是浮点栈是循环栈. 也就是说st(0)出栈的数据.会放到st(7)中.这样依次使用.

2.浮点汇编

针对协处理器.也提供的相应的汇编进行操作.
分别是 fld类指令 fst 指令. 以及 fcom fadd等指令
都是大写

3.使用内联浮点汇编实现加法

int main(int argc, char* argv[]) {     float a = 11.25;     float c = 12.35;     float d = 13.25f;     float b = 0.0f;     __asm{         fld dword ptr[ebp - 0x4];         fld dword ptr[ebp - 0x8];         fld dword ptr[ebp - 0xc];         faddp st(1),st(0)         fstp  dword ptr[ebp - 0x10];     }     printf("%f \r\n",b);          return 0;  } 

实现结果:

float GetFloatValue() {        return 12.25f;  } int main(int argc, char* argv[]) {     int value = GetFloatValue();          return 0;  } 

观看汇编,汇编分为两层.一层是调用内.一层是调用外.
调用内: 也就是GetFloatValue()函数内部.

   push        ebp    mov         ebp,esp    sub         esp,40h    push        ebx    push        esi    push        edi    lea         edi,[ebp-40h]    mov         ecx,10h    mov         eax,0CCCCCCCCh    rep stos    dword ptr [edi]    fld         dword ptr [__real@4@4002c400000000000000 (00423fd0)]

50000+
5万行代码练就真实本领
17年
创办于2008年老牌培训机构
1000+
合作企业
98%
就业率

联系我们

电话咨询

0532-85025005

扫码添加微信