int main(int argc, char* argv[])
{
// main(int 1, char * * 0x00380d70) line 7
// mainCRTStartup() line 206 + 25 bytes
// KERNEL32! 7c817067()
// 根据堆栈的先进后出原则可知
// 程序在调用main函数之前,先调用了Kernel32 -> mainCRTStartup -> main 函数
// 也就是说,main函数并不是程序的入口点,而是语法规定的用户入口点
// 由于我的VC++ 6.0并不是完整版,所以查看不了mainCRTStartup的源码,所以打开
// IDA,定位到该函数中
/************************************************************************/
/*
public mainCRTStartup
mainCRTStartup proc near
Code= dword ptr -20h
var_1C= dword ptr -1Ch
ms_exc= CPPEH_RECORD ptr -18h
push ebp
mov ebp, esp
push 0FFFFFFFFh
push offset stru_422138
push offset __except_handler3
mov eax, large fs:0
push eax
mov large fs:0, esp
add esp, 0FFFFFFF0h
push ebx
push esi
push edi
mov [ebp+ms_exc.old_esp], esp
call ds:__imp__GetVersion@0 ; GetVersion()
mov _osver, eax
mov eax, _osver
shr eax, 8
and eax, 0FFh
mov _winminor, eax
mov ecx, _osver
and ecx, 0FFh
mov _winmajor, ecx
mov edx, _winmajor
shl edx, 8
add edx, _winminor
mov _winver, edx
mov eax, _osver
shr eax, 10h
and eax, 0FFFFh
mov _osver, eax
push 0
call _heap_init
add esp, 4
test eax, eax
jnz short loc_4011B4
loc_4011B4:
mov [ebp+ms_exc.registration.TryLevel], 0
call _ioinit
call ds:__imp__GetCommandLineA@0 ; GetCommandLineA()
mov _acmdln, eax
call __crtGetEnvironmentStringsA
mov _aenvptr, eax
call _setargv
call _setenvp
call _cinit
mov ecx, _environ
mov __initenv, ecx
mov edx, _environ
push edx ; envp
mov eax, __argv
push eax ; argv
mov ecx, __argc
push ecx ; argc
call _main
add esp, 0Ch
mov [ebp+var_1C], eax
mov edx, [ebp+var_1C]
push edx
call exit
程序调用了
GetVersion()
_heap_init()
GetCommandLineA()
__crtGetEnvironmentStringsA()
_setargv()
_setenvp()
_cinit()
然后压入堆栈三个参数,分别为:
_environ
__argv
__argc
由C调用约定可知其参数顺序为
(int argc,char *argv[],char **envp[])
然后调用main()函数,因此可以利用main函数有三个参数的特点识别main()函数*/
/************************************************************************/
printf("Hello World!\n");
return 0;
}