启动函数

在编写Win32应用程序时,都必须在源码里实现一个WinMain函数。但Windows程序执行并不是从WinMain函数开始的,首先被执行的是启动函数相关代码,这段代码是编译器生成的。启动代码完成初始化进程,再调用WinMain。标准编译器通常包含启动代码在内的库文件源码,例如Visual C++中,启动代码存放在CRT/SRC/crt0.c文件中。
所有的C/C++运行时启动函数的作用基本都是相同的:检索指向新进程的命令行指针,检索指向新进程的环境变量指针,全局变量初始化,内存堆栈初始化等。当所有的初始化操作完毕后,启动函数就调用应用程序的进入点函数。
调用WinMain如下所示:
GetStartupInfo (&StartupInfo);
Int nMainRetVal = WinMain(GetModuleHandle(NULL),NULL,pszCommandLineAnsi,( StartupInfo.dwFlags&STARTF_USESHOWWINDOW)?StartupInfo.wShowWindow:SW__SHOWDEFAULT);
当进入点返回时,启动函数便调用C运行库期的exit函数,将返回值(nMainRetVal)传递给它,进行一些必要处理,最后调用系统函数ExitProcess退出。 其他一些编译器,如Delphi、BorLand C++开发包中都有相应的启动代码。
在绝大数情况下,我们对启动代码并不需要关心。 对于逆向分析人员来说,首要的任务是找到Winmain函数。

WinMain函数原型如下:
int WINAPI WinMain(
HINSTANCE hInstance, // 当前实例的句柄
HINSTANCE hPrevInstance, // 前一个实例的句柄
LPSTR lpCmdLine, // 命令行的指针
int nCmdShow // 窗口的显示状态
);
其中参数hInstance一般通过GetModuleHandleA函数进行获取的,这对识别WinMain函数有些帮助。另外,对WinMain的调用通常放在启动函数代码结尾部分,后面通常跟着诸如exit或XcptFilter之内的两、三个函数。例如下面这段代码:
.text:004010DC push eax ; nShowCmd
.text:004010DD push [ebp+lpCmdLine] ; lpCmdLine
.text:004010E0 push esi ; hPrevInstance
.text:004010E1 push esi ; lpModuleName
.text:004010E2 call ds:GetModuleHandleA
.text:004010E8 push eax ; hInstance
.text:004010E9 call WinMain(x,x,x,x)
.text:004010EE mov [ebp+var_60], eax
.text:004010F1 push eax ; int
.text:004010F2 call _exit

许多开发人员可以得到启动源代码的情况下对启动代码进行修改,这样,程序的执行可能不是从WinMain开始,而是从任何其他的函数开始。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值