赞
踩
win32程序分为两种:
1.控制台(/SUBSYSTEM:CONSOLE )
2.GUI(/SUBSYSTEM:WINDOWS)
首先看控制台版本的:
写一段最简单的,或者就直接使用编译器参数的默认main函数,如下:
1.使用/MD选项
F9下断到main函数的标签处,F11后,在Call Stack中回溯到_tmainCRTStartup(),当前文件为crtexe.c。如下:
2.使用/MT选项
F9下断到main函数的标签处,F11后,在Call Stack中回溯到_tmainCRTStartup(),当前文件为crt0.c。如下:
也就是说,不同的运行时链接方式,其实现代码也是不同的。但是其入口点函数的名称是相同的,都是_tmainCRTStartup。这便是Windows下的启动函数(真正的入口函数)。
下面我们分别讨论,这两者在入口函数中都干了些什么。
首先看_security_init_cookie,这个函数在两个实现文件中是一样的,代码如下:
下图是使用了/GS选项后的函数栈帧:
L | ||
ARG2 | 参数2 | |
ARG1 | 参数1 | |
COOKIE VAR | cookie变量 | |
EBP | EBP栈指针 | |
H | RET | 函数返回地址 |
现在继续分析_security_init_cookie的代码,看看其到底做了些什么:
这个security cookie是一个已经预先定义好的全局变量(定义与gs_cookie.c中):
虽然这个值已经预先被定义好,但是在_security_init_cookie函数中会有一次机会继续对其重新赋值。
如果cookie已经初始化过,就不继续处理,但是如果在32位下,其高字节为0x0000,则需要对其进行重新赋值(获得一个高度随机的值),因为这个值在进程初始化后不会再发生变化。
现在看看security cookie是怎么被编译器安排并使用的。编译器会在可能发生栈缓冲区溢出的函数时,定义一个全局cookie,它位于局部变量和返回地址之间,测试代码如下:
在退出函数时在ecx中保存[ebp-4] xor ebp
调用_security_check_cookie函数,代码如下:
通过_security_check_cookie函数便能知道ebp是否发生变化了。这是栈帧被破坏的一个标志。如果ebp发生变化了,则会调用__report_gsfailure显示错误。
现在分别看看在/MD和/MT下CRT入口函数的区别:
1./MT
__tmainCRTStartup代码如下:(crt0.c中)
大致的流程步骤如下:
1.设置应用程序类型,判断是否为托管程序
2.初始化堆
3.初始化多线程环境
4.初始化全局数据和浮点寄存器
5.获取命令行参数和环境变量
6.调用main/WinMain函数
分别深入源码;
1.设置应用程序类型,判断是否为托管程序
主要看判断是否为托管程序,跟进check_managed_app():
原理很简单,通过判断PE节表中的最后一项IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR,它保存了.net的一些高级结构IMAGE_COR20_HEADER.
2.初始化堆
_heap_init这个函数在vs2012之前的版本和之后的版本中实现是不一样的,在讨论这个前可以先推荐一个关于堆的文章(http://msdn.microsoft.com/en-us/library/ms810466.aspx).
先看vs2008版本的代码:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。