VS下EXE可执行文件启动代码剖析(5)使用动态运行库的EXE

来源:互联网 发布:电子取证软件 编辑:程序博客网 时间:2024/05/22 05:24

前面看到在使用静态运行库的EXE的启动代码做了很多的工作,下面再来看看使用动态库的EXE的启动代码


使用/mtd选项生产一个EXE,在我们的main函数开头下断,查看调用堆栈可以看到程序在被系统加载完成之后,我们程序的入口由Crtexe.c文件中的__tmainCRTStartup开始

下面是代码


staticint__tmainCRTStartup(         void         );#ifdef _WINMAIN_#ifdef WPRFLAGint wWinMainCRTStartup(#else  /* WPRFLAG */int WinMainCRTStartup(#endif  /* WPRFLAG */#else  /* _WINMAIN_ */#ifdef WPRFLAGint wmainCRTStartup(#else  /* WPRFLAG */int mainCRTStartup(#endif  /* WPRFLAG */#endif  /* _WINMAIN_ */        void        ){        __security_init_cookie();        return __tmainCRTStartup();}
跟使用静态运行库时一样的   同样先是创建了一个cookier然后 四种情况下调用的是同一个函数__tmainCRTStartup



直接上代码  在代码中注释,相比使用静态库,使用动态库的启动代码只完成了很有限的工作。


__declspec(noinline)int__tmainCRTStartup(        void        ){#ifdef _WINMAIN_        _TUCHAR *lpszCommandLine;        STARTUPINFOW StartupInfo;        BOOL inDoubleQuote=FALSE;        GetStartupInfoW( &StartupInfo );#endif  /* _WINMAIN_ */#ifdef _M_IX86        /*         * Enable app termination when heap corruption is detected on         * Windows Vista and above. This is a no-op on down-level OS's         * and enabled by default for 64-bit processes.         */                           //在XPSP3 VISTA 及之后的版本中增加了一个Heap管理特性,当Heap管理器发现进程中有任何使用中的Heap出现错误的时候,系统终止进程        if (!_NoHeapEnableTerminationOnCorruption) //如果该全局标准为0表示 需要开启该特性        {            HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);   //设置开启        }#endif  /* _M_IX86 */        /*        __try   //        {              void *lock_free=0;            void *fiberid=((PNT_TIB)NtCurrentTeb())->StackBase;  获取栈基址            int nested=FALSE;            while((lock_free=InterlockedCompareExchangePointer((volatile PVOID *)&__native_startup_lock, fiberid, 0))!=0)            {                                                     //如果__native_startup_lock为0 把fiberid的值给它                if(lock_free==fiberid)                {                    nested=TRUE;                    break;                }                Sleep(1000);            }            if (__native_startup_state == __initializing)  //在混合模式的情况下如果其他本地地方在初始化本地代码,那么出错,不能同时初始化            {                _amsg_exit( _RT_CRT_INIT_CONFLICT);            }            else if (__native_startup_state == __uninitialized)            {                __native_startup_state = __initializing;#ifndef _SYSCRT                if (_initterm_e( __xi_a, __xi_z ) != 0)                {                    return 255;                                         //初始化C全局对象                }#else  /* _SYSCRT */                _initterm((_PVFV *)(void *)__xi_a, (_PVFV *)(void *)__xi_z);  #endif  /* _SYSCRT */             }            else            {                has_cctor = 1;            }            /*            * do C++ constructors (initializers) specific to this EXE            */            if (__native_startup_state == __initializing)             {                _initterm( __xc_a, __xc_z );                       //初始化C++全局对象                __native_startup_state = __initialized;            }            _ASSERTE(__native_startup_state == __initialized);            if(!nested)            {                /* For X86, the definition of InterlockedExchangePointer wrongly causes warning C4312 */#pragma warning(push)#pragma warning(disable:4312)                InterlockedExchangePointer((volatile PVOID *)&__native_startup_lock, 0);#pragma warning(pop)            }             */            if (__dyn_tls_init_callback != NULL &&                _IsNonwritableInCurrentImage((PBYTE)&__dyn_tls_init_callback))            {                __dyn_tls_init_callback(NULL, DLL_THREAD_ATTACH, NULL);            //初始化TLS相关的            }            /* Enable buffer count checking if linking against static lib */            _CrtSetCheckCount(TRUE);#ifdef _WINMAIN_            /*             * Skip past program name (first token in command line).             * Check for and handle quoted program name.             */#ifdef WPRFLAG            lpszCommandLine = (wchar_t *)_wcmdln;#else  /* WPRFLAG */            lpszCommandLine = (unsigned char *)_acmdln;#endif  /* WPRFLAG */            while (*lpszCommandLine > SPACECHAR ||                   (*lpszCommandLine&&inDoubleQuote)) {                /*                 * Flip the count from 1 to 0 or 0 to 1 if current character                 * is DOUBLEQUOTE                 */                if (*lpszCommandLine==DQUOTECHAR) inDoubleQuote=!inDoubleQuote;#ifdef _MBCS                if (_ismbblead(*lpszCommandLine)) {                    if (lpszCommandLine) {                        lpszCommandLine++;                    }                }#endif  /* _MBCS */                ++lpszCommandLine;            }            /*             * Skip past any white space preceeding the second token.             */            while (*lpszCommandLine && (*lpszCommandLine <= SPACECHAR)) {                lpszCommandLine++;            }                                                //去掉命令行参数中程序自身路径的部分#ifdef WPRFLAG            mainret = wWinMain(#else  /* WPRFLAG */            mainret = WinMain(#endif  /* WPRFLAG */                       (HINSTANCE)&__ImageBase,                       NULL,                       lpszCommandLine,                       StartupInfo.dwFlags & STARTF_USESHOWWINDOW                        ? StartupInfo.wShowWindow                        : SW_SHOWDEFAULT                               //调用我们的main函数                      );#else  /* _WINMAIN_ */#ifdef WPRFLAG            __winitenv = envp;            mainret = wmain(argc, argv, envp);#else  /* WPRFLAG */            __initenv = envp;            mainret = main(argc, argv, envp);#endif  /* WPRFLAG */#endif  /* _WINMAIN_ */            /*             * Note that if the exe is managed app, we don't really need to             * call exit or _c_exit. .cctor should be able to take care of             * this.             */            if ( !managedapp )                exit(mainret);            if (has_cctor == 0)                _cexit();         //退出代码,        }        __except ( _XcptFilter(GetExceptionCode(), GetExceptionInformation()) )        {            /*                                                    //发生异常调用退出函数 终止进程             * Should never reach here             */            mainret = GetExceptionCode();            /*             * Note that if the exe is managed app, we don't really need to             * call exit or _c_exit. .cctor should be able to take care of             * this.             */            if ( !managedapp )                _exit(mainret);            if (has_cctor == 0)                _cexit();        } /* end of try - except */        return mainret;}


使用动态库的EXE的启动代码  除了 初始化全局对象外,并没有做其他实质性的初始化工作,然后就调用了main函数 将执行权限交给了我们

因此可以推断对CRT的初始化工作,运行库的DLL文件中,当Msvcrtxx.DLL被加载到后,DLL的启动代码完成了之前我们分析的,使用静态库的exe的启动代码所做的工作。


于是我在VC\crt\src  下搜索包含_ioinit的文件,发现crtlib.c文件中的_CRTDLL_INIT 函数调用了这个初始化io的函数

__CRTDLL_INIT 开始地方下断  果然在这里


代码

BOOL WINAPI_CRTDLL_INIT(        HANDLE  hDllHandle,        DWORD   dwReason,        LPVOID  lpreserved        ){    if (dwReason == DLL_PROCESS_ATTACH)    {        /*         * The /GS security cookie must be initialized before any exception         * handling targetting the current image is registered.  No function         * using exception handling can be called in the current image until         * after __security_init_cookie has been called.         */        __security_init_cookie();    }    return __CRTDLL_INIT(hDllHandle, dwReason, lpreserved);

很明显就是这个运行库DLL的启动代码了   跟EXE的如出一辙

__declspec(noinline)BOOL __cdecl__CRTDLL_INIT(        HANDLE  hDllHandle,        DWORD   dwReason,        LPVOID  lpreserved        ){        if ( dwReason == DLL_PROCESS_ATTACH ) {            if ( !_heap_init() )    /* initialize heap */   //分配堆                return FALSE;            if(!_mtinit())          /* initialize multi-thread */  多线程支持            {                _heap_term();       /* heap is now invalid! */                return FALSE;       /* fail DLL load on failure */            }            if (_ioinit() < 0) {    /* inherit file info */  初始IO                _mtterm();                _heap_term();       /* heap is now invalid! */                return FALSE;       /* fail DLL load on failure */            }            _aenvptr = (char *)__crtGetEnvironmentStringsA();   获取环境变量            _acmdln = GetCommandLineA();            _wcmdln = GetCommandLineW();#ifdef _MBCS            __initmbctable();#endif  /* _MBCS */            if (_setenvp() < 0 ||   /* get environ info */                _cinit(FALSE) != 0)  /* do C data initialize */            {                _ioterm();          /* shut down lowio */                _mtterm();          /* free TLS index, call _mtdeletelocks() */                _heap_term();       /* heap is now invalid! */                return FALSE;       /* fail DLL load on failure */            }            proc_attached++;        }        else if ( dwReason == DLL_PROCESS_DETACH ) {           ..................................   清理工作省略        }        else if ( dwReason == DLL_THREAD_ATTACH )        {...........................................清理工作省略          }        return TRUE;}


一切都是那么的熟悉有木有,所有的初始化工作这个DLL都给做了,EXE安心的调用它提供的库函数就OK了



0 0