用VS2015 如何追踪 main之前代码尼?
#include <stdlib.h>
#include <stdio.h>
void main()
{
printf("%d\n", 1);
}
在printf处设置断点,反汇编代码,在ret 设置断点,f5, 再f10单步。便能跳到 编译器插入的代码。
printf("%d\n", 1);
00CE1070 push 1
00CE1072 push 0CE2118h
00CE1077 call printf (0CE1040h)
00CE107C add esp,8
}
00CE107F xor eax,eax
00CE1081 ret //该处设置断点,f5 再单步 f10
00CE1070 push 1
00CE1072 push 0CE2118h
00CE1077 call printf (0CE1040h)
00CE107C add esp,8
}
00CE107F xor eax,eax
00CE1081 ret //该处设置断点,f5 再单步 f10
f10后,将调到下面代码部分,右击,点击转到源码处。
00CE14A3 call ___p___argv (0CE1C30h)
00CE14A8 mov edi,eax
00CE14AA call ___p___argc (0CE1C2Ah)
00CE14AF mov esi,eax
00CE14B1 call __get_initial_narrow_environment (0CE1C06h)
00CE14B6 push eax
00CE14B7 push dword ptr [edi]
00CE14B9 push dword ptr [esi]
00CE14BB call main (0CE1070h)
00CE14C0 mov esi,eax
00CE14A8 mov edi,eax
00CE14AA call ___p___argc (0CE1C2Ah)
00CE14AF mov esi,eax
00CE14B1 call __get_initial_narrow_environment (0CE1C06h)
00CE14B6 push eax
00CE14B7 push dword ptr [edi]
00CE14B9 push dword ptr [esi]
00CE14BB call main (0CE1070h)
00CE14C0 mov esi,eax
//
// main has returned; exit somehow...
//
// main has returned; exit somehow...
//
原型毕露
//exe_common.inl
static __declspec(noinline) int __cdecl __scrt_common_main_seh() throw()
{
if (!__scrt_initialize_crt(__scrt_module_type::exe))
__scrt_fastfail(FAST_FAIL_FATAL_APP_EXIT);
bool has_cctor = false;
__try
{
bool const is_nested = __scrt_acquire_startup_lock();
if (__scrt_current_native_startup_state == __scrt_native_startup_state::initializing)
{
__scrt_fastfail(FAST_FAIL_FATAL_APP_EXIT);
}
else if (__scrt_current_native_startup_state == __scrt_native_startup_state::uninitialized)
{
__scrt_current_native_startup_state = __scrt_native_startup_state::initializing;
if (_initterm_e(__xi_a, __xi_z) != 0)
return 255;
_initterm(__xc_a, __xc_z);
__scrt_current_native_startup_state = __scrt_native_startup_state::initialized;
}
else
{
has_cctor = true;
}
__scrt_release_startup_lock(is_nested);
// If this module has any dynamically initialized __declspec(thread)
// variables, then we invoke their initialization for the primary thread
// used to start the process:
_tls_callback_type const* const tls_init_callback = __scrt_get_dyn_tls_init_callback();
if (*tls_init_callback != nullptr && __scrt_is_nonwritable_in_current_image(tls_init_callback))
{
(*tls_init_callback)(nullptr, DLL_THREAD_ATTACH, nullptr);
}
// If this module has any thread-local destructors, register the
// callback function with the Unified CRT to run on exit.
_tls_callback_type const * const tls_dtor_callback = __scrt_get_dyn_tls_dtor_callback();
if (*tls_dtor_callback != nullptr && __scrt_is_nonwritable_in_current_image(tls_dtor_callback))
{
_register_thread_local_exe_atexit_callback(*tls_dtor_callback);
}
__telemetry_main_invoke_trigger(nullptr);
//
// Initialization is complete; invoke main...
//
int const main_result = invoke_main();
//
// main has returned; exit somehow...
//
__telemetry_main_return_trigger(nullptr);
if (!__scrt_is_managed_app())
exit(main_result);
if (!has_cctor)
_cexit();
// Finally, we terminate the CRT:
__scrt_uninitialize_crt(true, false);
return main_result;
}
__except (_seh_filter_exe(GetExceptionCode(), GetExceptionInformation()))
{
// Note: We should never reach this except clause.
int const main_result = GetExceptionCode();
if (!__scrt_is_managed_app())
_exit(main_result);
if (!has_cctor)
_c_exit();
return main_result;
}
}
再用 od跟踪,谁调用 __scrt_common_main_seh,
发现 是一个 jmp __scrt_common_main_seh的指令,而且刚好位于,__scrt_common_main_seh下面
vs反汇编窗口向下滚动,发现这两条语句,刚好和od吻合。
00CE153D call __security_init_cookie (0CE1A53h)
00CE1542 jmp __scrt_common_main_seh (0CE13C1h)
右击,转到源码处
// exe_main_cpp
extern "C" int mainCRTStartup()
{
return __scrt_common_main();
}
//exe_common.inl
// This is the common main implementation to which all of the CRT main functions
// delegate (for executables; DLLs are handled separately).
static __forceinline int __cdecl __scrt_common_main() throw()
{
// The /GS security cookie must be initialized before any exception handling
// targeting the current image is registered. No function using exception
// handling can be called in the current image until after this call:
__security_init_cookie();
return __scrt_common_main_seh();
}
ok ,这是 vs2015的源码。我们来一步一步来剖解
mainCRTStartup -> __scrt_common_main -> _scrt_common_main_seh
ok,先看 __sexurity_init_cookie(); // gc_support.c
/*** *gs_support.c - initialize the global buffer overrun security cookie * * Copyright (c) Microsoft Corporation. All rights reserved. * *Purpose: * Define __security_init_cookie, which is called at startup to initialize * the global buffer overrun security cookie used by the /GS compile flag. * *******************************************************************************/ #include <windows.h> #if defined (_M_IX86) && defined (_CRTBLD) && defined (_DEBUG) /* * __security_init_cookie must be called before any exception handlers using * the cookie are registered. We do a spot check for this condition in the * debug version of the x86 CRT. */ #define CHECK_FOR_LATE_COOKIE_INIT #define EXCEPTION_CHAIN_END ((struct _EXCEPTION_REGISTRATION_RECORD * POINTER_32)-1) EXCEPTION_DISPOSITION __cdecl _except_handler4( IN struct _EXCEPTION_RECORD *ExceptionRecord, IN PVOID EstablisherFrame, IN OUT struct _CONTEXT *ContextRecord, IN OUT PVOID DispatcherContext ); #endif /* defined (_M_IX86) && defined (_CRTBLD) && defined (_DEBUG) */ /* * Default value used for the global /GS security cookie, defined here and * in gs_cookie.c (since standalone SDK build can't use CRT's internal.h). */ #ifdef _WIN64 #define DEFAULT_SECURITY_COOKIE 0x00002B992DDFA232 #else /* _WIN64 */ #define DEFAULT_SECURITY_COOKIE 0xBB40E64E #endif /* _WIN64 */ /* * The global security cookie. This name is known to the compiler. */ extern UINT_PTR __security_cookie; extern UINT_PTR __security_cookie_complement; /* * Union to facilitate converting from FILETIME to unsigned __int64 */ typedef union { unsigned __int64 ft_scalar; FILETIME ft_struct; } FT; /*** *__security_init_cookie(cookie) - init buffer overrun security cookie. * *Purpose: * Initialize the global buffer overrun security cookie which is used by * the /GS compile switch to detect overwrites to local array variables * the potentially corrupt the return address. This routine is called * at EXE/DLL startup. * *Entry: * *Exit: * *Exceptions: * *******************************************************************************/ void __cdecl __security_init_cookie(void) { UINT_PTR cookie; FT systime={0}; LARGE_INTEGER perfctr; /* * Do nothing if the global cookie has already been initialized. On x86, * reinitialize the cookie if it has been previously initialized to a * value with the high word 0x0000. Some versions of Windows will init * the cookie in the loader, but using an older mechanism which forced the * high word to zero. */
// __security_cooki = 0cc960ca 非调试版本 if (__security_cookie != DEFAULT_SECURITY_COOKIE #if defined (_M_IX86) && (__security_cookie & 0xFFFF0000) != 0 #endif /* defined (_M_IX86) */ ) { __security_cookie_complement = ~__security_cookie; return; //release 版本直接返回。 } /* * Initialize the global cookie with an unpredictable value which is * different for each module in a process. Combine a number of sources * of randomness. */ GetSystemTimeAsFileTime(&systime.ft_struct); #if defined (_WIN64) cookie = systime.ft_scalar; #else /* defined (_WIN64) */ cookie = systime.ft_struct.dwLowDateTime; cookie ^= systime.ft_struct.dwHighDateTime; #endif /* defined (_WIN64) */ cookie ^= GetCurrentThreadId(); cookie ^= GetCurrentProcessId(); #if _CRT_NTDDI_MIN >= NTDDI_VISTA #if defined (_WIN64) cookie ^= (((UINT_PTR)GetTickCount64()) << 56); #endif /* defined (_WIN64) */ cookie ^= (UINT_PTR)GetTickCount64(); #endif /* _CRT_NTDDI_MIN >= NTDDI_VISTA */ QueryPerformanceCounter(&perfctr); #if defined (_WIN64) cookie ^= (((UINT_PTR)perfctr.LowPart << 32) ^ perfctr.QuadPart); #else /* defined (_WIN64) */ cookie ^= perfctr.LowPart; cookie ^= perfctr.HighPart; #endif /* defined (_WIN64) */ /* * Increase entropy using ASLR relocation */ cookie ^= (UINT_PTR)&cookie; #if defined (_WIN64) /* * On Win64, generate a cookie with the most significant word set to zero, * as a defense against buffer overruns involving null-terminated strings. * Don't do so on Win32, as it's more important to keep 32 bits of cookie. */ cookie &= 0x0000FFFFffffFFFFi64; #endif /* defined (_WIN64) */ /* * Make sure the cookie is initialized to a value that will prevent us from * reinitializing it if this routine is ever called twice. */ if (cookie == DEFAULT_SECURITY_COOKIE) { cookie = DEFAULT_SECURITY_COOKIE + 1; } #if defined (_M_IX86) else if ((cookie & 0xFFFF0000) == 0) { cookie |= ( (cookie|0x4711) << 16); } #endif /* defined (_M_IX86) */ __security_cookie = cookie; __security_cookie_complement = ~cookie; }