浮点指令之找main函数

发布时间 2023-07-17 22:39:39作者: 不会笑的孩子

环境

vs2019 编译选项x86(32位) debug版本

float指令练习

//c++源码
#include<stdio.h>
int main(int argc,char* argv)
{
	float f = (float)argc;//将int类型转换为float

	printf("%f",f);

	argc = (int)f;//在将float类型转换为int

	printf("%d",argc);

    return 0;
}

编译运行后,在return 0;语句打一个断点,右键可以看到切到汇编代码

对应的汇编代码如下

00183E40 55                   push        ebp  
00183E41 8B EC                mov         ebp,esp  
00183E43 81 EC CC 00 00 00    sub         esp,0CCh  
00183E49 53                   push        ebx  
00183E4A 56                   push        esi  
00183E4B 57                   push        edi  
00183E4C 8D 7D F4             lea         edi,[ebp-0Ch]  
00183E4F B9 03 00 00 00       mov         ecx,3  
00183E54 B8 CC CC CC CC       mov         eax,0CCCCCCCCh  
00183E59 F3 AB                rep stos    dword ptr es:[edi]  
00183E5B B9 03 C0 18 00       mov         ecx,offset _78F0D3D6_helloworld@c (018C003h)  
00183E60 E8 A2 D4 FF FF       call        @__CheckForDebuggerJustMyCode@4 (0181307h)  
     4: 	float f = (float)argc;  
00183E65 F3 0F 2A 45 08       cvtsi2ss    xmm0,dword ptr [argc] //[argc]对应是[ebp+8] cvsi2ss指令:将整数转换为单精度数int强制转为float
00183E6A F3 0F 11 45 F8       movss       dword ptr [f],xmm0//[f] 对应的是[ebp-4] //movss指令:用来传送单精度数,用来转送float 
     5: 	printf("%f",f);
00183E6F F3 0F 5A 45 F8       cvtss2sd    xmm0,dword ptr [f]  
00183E74 83 EC 08             sub         esp,8  
00183E77 F2 0F 11 04 24       movsd       mmword ptr [esp],xmm0//movsd指令:传送双精度数  
00183E7C 68 CC 7B 18 00       push        offset string "%f" (0187BCCh)  
00183E81 E8 17 D5 FF FF       call        _printf (018139Dh)  
00183E86 83 C4 0C             add         esp,0Ch  //外平栈
     6: 	argc = (int)f;
00183E89 F3 0F 2C 45 F8       cvttss2si   eax,dword ptr [f]//cvttss2si将float类型转换为int类型  
00183E8E 89 45 08             mov         dword ptr [argc],eax  
     7: 	printf("%d",argc);
00183E91 8B 45 08             mov         eax,dword ptr [argc]  
00183E94 50                   push        eax  
00183E95 68 D0 7B 18 00       push        offset string "%d" (0187BD0h)  
00183E9A E8 FE D4 FF FF       call        _printf (018139Dh)  
00183E9F 83 C4 08             add         esp,8  
     8:     return 0;
00183EA2 33 C0                xor         eax,eax  
     9: }
00183EA4 5F                   pop         edi  
00183EA5 5E                   pop         esi  
00183EA6 5B                   pop         ebx  
00183EA7 81 C4 CC 00 00 00    add         esp,0CCh  
00183EAD 3B EC                cmp         ebp,esp  
00183EAF E8 7C D3 FF FF       call        __RTC_CheckEsp (0181230h)  
00183EB4 8B E5                mov         esp,ebp  
00183EB6 5D                   pop         ebp  
00183EB7 C3                   ret  

上面的代码:浮点数与整数、整数与浮点数的相互转换,从上面可以看到float类型占4字节,但是使用浮点栈将以8字节方式进行处理(movsd),而使用媒体寄存器则以4字节处理。当浮点数作为参数时,并不能直接入栈,PUSH指令只能传入4字节数据到栈。这样会丢失4字节数据。这就是使用printf函数以整数方式输出浮点数时会产生错误的原因。printf以整数方式输出时,将对应参数作为4字节数据长度,按补码范式解释,而真正压入的参数为浮点类型时,却是8字节长度,需要按浮点编码范式解释。

如何找到main函数

在大学中我们老师都教授我们一个函数的入口函数是main,但是呢今天我们来看看到底是不是。拿出工具x32dbug来进行测试

第一步

第二步进来以后初始的状态

是一个ntdll.dll是重要的Windows NT内核级文件。描述了windows本地NTAPI的接口。当Windows启动时,ntdll.dll就驻留在内存中特定的写保护区域,使别的程序无法占用这个内存区域。

第三步 快捷按F9

我们可以看到是一个._mainCRTStartup>,那么我们在进去(F9)

第三步


.__scrt_common main>,我们再次进去(F9)

第四步


_scrt_common_main_seh>
第五步

其中包含了.main函数,那么我们就算找到了main

00183E4 | 55                      | push ebp                                      | helloworld.c:3
00183E4 | 8BEC                    | mov ebp,esp                                   |
00183E4 | 81EC CC000000           | sub esp,CC                                    |
00183E4 | 53                      | push ebx                                      |
00183E4 | 56                      | push esi                                      | esi:__enc$textbss$end+23
00183E4 | 57                      | push edi                                      | edi:__enc$textbss$end+23
00183E4 | 8D7D F4                 | lea edi,dword ptr ss:[ebp-C]                  | edi:__enc$textbss$end+23
00183E4 | B9 03000000             | mov ecx,3                                     |
00183E5 | B8 CCCCCCCC             | mov eax,CCCCCCCC                              | eax:&"E:\\c++反汇编技术加密与解密\\shujutype\\Debug\\shujutype.exe"
00183E5 | F3:AB                   | rep stosd                                     |
00183E5 | B9 03C01800             | mov ecx,<shujutype._78F0D3D6_helloworld@c>    | helloworld.c:15732480
00183E6 | E8 A2D4FFFF             | call shujutype.181307                         |
00183E6 | F3:0F2A45 08            | cvtsi2ss xmm0,dword ptr ss:[ebp+8]            | helloworld.c:4
00183E6 | F3:0F1145 F8            | movss dword ptr ss:[ebp-8],xmm0               | [ebp-8]:&"E:\\c++反汇编技术加密与解密\\shujutype\\Debug\\shujutype.exe"
00183E6 | F3:0F5A45 F8            | cvtss2sd xmm0,dword ptr ss:[ebp-8]            | helloworld.c:5, [ebp-8]:&"E:\\c++反汇编技术加密与解密\\shujutype\\Debug\\shujutype.exe"
00183E7 | 83EC 08                 | sub esp,8                                     |
00183E7 | F2:0F110424             | movsd qword ptr ss:[esp],xmm0                 |
00183E7 | 68 CC7B1800             | push shujutype.187BCC                         |
00183E8 | E8 17D5FFFF             | call shujutype.18139D                         |
00183E8 | 83C4 0C                 | add esp,C                                     |
00183E8 | F3:0F2C45 F8            | cvttss2si eax,dword ptr ss:[ebp-8]            | helloworld.c:6, [ebp-8]:&"E:\\c++反汇编技术加密与解密\\shujutype\\Debug\\shujutype.exe"
00183E8 | 8945 08                 | mov dword ptr ss:[ebp+8],eax                  |
00183E9 | 8B45 08                 | mov eax,dword ptr ss:[ebp+8]                  | helloworld.c:7
00183E9 | 50                      | push eax                                      | eax:&"E:\\c++反汇编技术加密与解密\\shujutype\\Debug\\shujutype.exe"
00183E9 | 68 D07B1800             | push shujutype.187BD0                         |
00183E9 | E8 FED4FFFF             | call shujutype.18139D                         |
00183E9 | 83C4 08                 | add esp,8                                     |
00183EA | 33C0                    | xor eax,eax                                   | helloworld.c:8, eax:&"E:\\c++反汇编技术加密与解密\\shujutype\\Debug\\shujutype.exe"
00183EA | 5F                      | pop edi                                       | helloworld.c:9, edi:__enc$textbss$end+23
00183EA | 5E                      | pop esi                                       | esi:__enc$textbss$end+23
00183EA | 5B                      | pop ebx                                       |
00183EA | 81C4 CC000000           | add esp,CC                                    |
00183EA | 3BEC                    | cmp ebp,esp                                   |
00183EA | E8 7CD3FFFF             | call shujutype.181230                         |
00183EB | 8BE5                    | mov esp,ebp                                   |
00183EB | 5D                      | pop ebp                                       |
00183EB | C3                      | ret                                           |

与我们编译好的一摸一样,那么我们就可以确定是main函数

总结

main函数是语法规定的用户入口,而真正的入口函数是mainCRTStartup,mainCRTStarup再次调用main函数。