Yes, keep going with the article I mentioned in the previous post, I come up with a new thing: "mainCRTStartup" or other function depending on the switch we choose when start a new project (/SUBSYSTEM:WINDOWS or /SUBSYSTEM:CONSOLE). Let's go >:)
The first guy I met is crtexe.c and the code of that function is here:
- #ifdef _WINMAIN_
- #ifdef WPRFLAG
- int wWinMainCRTStartup(
- #else /* WPRFLAG */
- int WinMainCRTStartup(
- #endif /* WPRFLAG */
- #else /* _WINMAIN_ */
- #ifdef WPRFLAG
- int wmainCRTStartup(
- #else /* WPRFLAG */
- int mainCRTStartup(
- #endif /* WPRFLAG */
- #endif /* _WINMAIN_ */
- void
- )
- {
- /*
- * 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 __tmainCRTStartup();
- }
Let's begin with the __security_init_cookie( ) function. "Cookie", "security", huhm, something relating to web application? Of course not, I have investigated and found some helpful information from here. Thanks Brandon Bray (MSFT) for your useful article.
Now I'll summary everything in my view for easily understanding later.
- winMain
The base address where an executable file's image loads is determined by the linker. Different linkers can use different default base addresses. The Visual C++ linker uses a default base address of 0x00400000 because this is the lowest address an executable file image can load to when you run Windows 98. You can change the base address that your application loads to by using the /BASE: address linker switch for Microsoft's linker.
- Buffer Overflow
Function parameters(The Exception Handler frame is optional. It just exists in the case that the function which is called includes try/catch.)
Function return address
Frame pointer
Exception Handler frame
Locally declared variables and buffers
Callee save registers
The BO is caused coz the return address is overwriten. And Visual Studio comes up with an option for checking this problem - /GS (Buffer Security Check). So, the new stack layout will become like this with new field - cookie.
Function parametersIn this way, when a function is called, instead that ESP register's value is subtracted with the total size of local variable, it's actually subtracted with more extra 4 bytes. Means that
Function return address
Frame pointer
Cookie
Exception Handler frame
Locally declared variables and buffers
Callee save registers
sub esp 24hinstead of
sub esp 20hThe reason is coz of cookie. Let's see the detail:
sub esp,24h
mov eax,dword ptr [___security_cookie (408040h)]
xor eax,dword ptr [esp+24h]
mov dword ptr [esp+20h],eax
I'll explain more detail about the value at ___security_cookie (408040h) (I call it X) later. Now it's more important to be clear that code. Value at [esp+24h] is the function return address is "xor"ed with the X and then is put right below the return address. Huh, what's for? Keep going with the end code (epilog):mov ecx,dword ptr [esp+20h] xor ecx,dword ptr [esp+24h] add esp,24h jmp __security_check_cookie (4010B2h)
Oops! It's not simple as common:
ECX now is the "xor"ed value got from the prolog, and one more time is "xor"ed with the return address. So strange, no any ret instruction but jump ... instead :| I think now it's time to take a loot atadd esp,20h ret
__security_check_cookie function. Open seccheck.c in VC/crt/src/intel of visual studio 9 (maybe the filename changes with other version - in this case, just search with the function name :-) )
- void __declspec(naked) __fastcall __security_check_cookie(UINT_PTR cookie)
- {
- /* x86 version written in asm to preserve all regs */
- __asm {
- cmp ecx, __security_cookie
- jne failure
- rep ret /* REP to avoid AMD branch prediction penalty */
- failure:
- jmp __report_gsfailure
- }
- }
Ref: Jeffrey Richter, Programming Applications for Microsoft Windows, Fourth Edition.