[逆向基础] 找到程序真正的入口

一、程序的真正入口

main或WinMain只是“语法规定的程序入口” 并不是“应用程序入口”。

我们使用VC++ 6.0 的栈回溯功能,找到main函数之前的代码。菜单View -> Debug Windows -> Call Stack 打开栈回溯窗口(快捷键 Alt + 7)。
1.png

上图显示程序运行时调用了三个函数,分别为:KERNEL32.DLL、mainCRTStartup和main。 其中KERNEL32! 7C81776F 表示在系统库KERNEL32.dll中的地址7c81776f处调用了mainCRTStartup。
通过双击 mainCRTStartup,我们可以找到这个函数定义在 crt0.c 中,你可以在crt0.c中找到mainCRTStartup的源码。

下面是crt0.c中注释的摘抄:

/***
*crt0.c - C runtime initialization routine
*
*       Copyright (c) Microsoft Corporation. All rights reserved.
*
*Purpose:
*       This is the actual startup routine for apps.  It calls the user's main
*       routine [w]main() or [w]WinMain after performing C Run-Time Library
*       initialization.
*
*       With ifdefs, this source file also provides the source code for:
*       wcrt0.c     the startup routine for console apps with wide chars
*       wincrt0.c   the startup routine for Windows apps
*       wwincrt0.c  the startup routine for Windows apps with wide chars
*
*******************************************************************************/

这里说明了函数真正的入口

/***
*mainCRTStartup(void)
*wmainCRTStartup(void)
*WinMainCRTStartup(void)
*wWinMainCRTStartup(void)
*
*Purpose:
*       These routines do the C runtime initialization, call the appropriate
*       user entry function, and handle termination cleanup.  For a managed
*       app, they then return the exit code back to the calling routine, which
*       is the managed startup code.  For an unmanaged app, they call exit and
*       never return.
*
*       Function:               User entry called:
*       mainCRTStartup          main
*       wmainCRTStartup         wmain
*       WinMainCRTStartup       WinMain
*       wWinMainCRTStartup      wWinMain
*
*Entry:
*
*Exit:
*       Managed app: return value from main() et al, or the exception code if
*                 execution was terminated by the __except guarding the call
*                 to main().
*       Unmanaged app: never return.
*
*******************************************************************************/

由于我安装的的VC++6.0不是完整版,未找到crt0.c。然后,我切换到vs2010下,找到了crt0.c,其中有这样一段定义:

#ifdef _WINMAIN_

    #ifdef WPRFLAG
        #define _tmainCRTStartup    wWinMainCRTStartup
    #else  /* WPRFLAG */
        #define _tmainCRTStartup    WinMainCRTStartup
    #endif  /* WPRFLAG */

#else  /* _WINMAIN_ */

    #ifdef WPRFLAG
        #define _tmainCRTStartup    wmainCRTStartup
    #else  /* WPRFLAG */
        #define _tmainCRTStartup    mainCRTStartup
    #endif  /* WPRFLAG */

#endif  /* _WINMAIN_ */

当然,如果你装了完整版的VC++6.0 应该与此不同。 不过,这些函数的目的总是为了:申请堆空间、初始化堆空间、获取环境变量、获取CommandLine、全局数据初始化、浮点寄存器初始化等。

二、修改程序入口

菜单Project -> Settings -> Link -> Output 在 Entry-point symbol中可以指定程序入口。

2.png

重新指定入口后,没有调用 mainCRTStartup 函数,直接就调用了入口函数MyEntry。 如下图:
3.png

但是,由于没有调用mainCRTStartup函数,堆空间是没有初始化的,当使用堆空间时,程序会报错崩溃,如下图:

4.png

备注: 从Visual Studio 2003(VC7.0)开始,微软加入了防止缓冲区溢出的选项:/GS,编译器会在每个函数的栈内分配一个随机标记,而这个随机标记的种子数由应用程序入口的代码负责初始化。

你可能感兴趣的:([逆向基础] 找到程序真正的入口)