01 #include "stdio.h"
02
03 void main()
04 {
05 int* p = 0x00000000; // pointer to NULL
06 puts("hello");
07 __try{
08 puts("in try");
09 // try{
10 // puts("in try");
11 // *p = 13; // causes an access violation exception;
12 // }__finally{
13 // puts("in finally");
14 // }
15 }__except(puts("in filter"), 1){
16 puts("in except");
17 }
18 puts("world");
19 }
/// CUT END ///
编译后,生成的结果(偶只调重要的贴上来)
.text:00401000 ; int __cdecl main(int argc,const char **argv,const char *envp)
.text:00401000 _main proc near ; CODE XREF: start+AFp
.text:00401000
.text:00401000 var_1C = dword ptr -1Ch
.text:00401000 var_18 = dword ptr -18h
.text:00401000 var_10 = dword ptr -10h
.text:00401000 var_4 = dword ptr -4
.text:00401000 argc = dword ptr 8
.text:00401000 argv = dword ptr 0Ch
.text:00401000 envp = dword ptr 10h
.text:00401000
.text:00401000 55 push ebp
.text:00401001 8B EC mov ebp, esp
.text:00401003 6A FF push 0FFFFFFFFh
.text:00401005 68 B0 60 40 00 push offset dword_4060B0
.text:0040100A 68 00 12 40 00 push offset unknown_libname_1 ; Microsoft VisualC 2-7/net runtime
.text:0040100F 64 A1 00 00 00 00 mov eax, large fs:0
.text:00401015 50 push eax
.text:00401016 64 89 25 00 00 00+ mov large fs:0, esp
.text:0040101D 83 C4 F4 add esp, 0FFFFFFF4h
.text:00401020 53 push ebx
.text:00401021 56 push esi
.text:00401022 57 push edi
.text:00401023 89 65 E8 mov [ebp+var_18], esp
.text:00401026 C7 45 E4 00 00 00+ mov [ebp+var_1C], 0
.text:0040102D 68 30 70 40 00 push offset aHello ; "hello"
.text:00401032 E8 68 00 00 00 call _puts
.text:00401037 83 C4 04 add esp, 4
.text:0040103A C7 45 FC 00 00 00+ mov [ebp+var_4], 0
.text:00401041 68 38 70 40 00 push offset aInTry ; "in try"
.text:00401046 E8 54 00 00 00 call _puts
.text:0040104B 83 C4 04 add esp, 4
.text:0040104E C7 45 FC FF FF FF+ mov [ebp+var_4], 0FFFFFFFFh
.text:00401055 EB 2A jmp short loc_401081
.text:00401057 ; ?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥
.text:00401057
.text:00401057 __except: ; DATA XREF: .rdata:004060B4o
.text:00401057 68 40 70 40 00 push offset aInFilter ; "in filter"
.text:0040105C E8 3E 00 00 00 call _puts
.text:00401061 83 C4 04 add esp, 4
.text:00401064 B8 01 00 00 00 mov eax, 1
.text:00401069 C3 retn
.text:0040106A ; ?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥
.text:0040106A
.text:0040106A __except_body:
.text:0040106A 8B 65 E8 mov esp, [ebp-18h]
.text:0040106D 68 4C 70 40 00 push offset aInExcept ; "in except"
.text:00401072 E8 28 00 00 00 call _puts
.text:00401077 83 C4 04 add esp, 4
.text:0040107A C7 45 FC FF FF FF+ mov [ebp+var_4], 0FFFFFFFFh
.text:00401081
.text:00401081 loc_401081: ; CODE XREF: _main+55j
.text:00401081 68 58 70 40 00 push offset aWorld ; "world"
.text:00401086 E8 14 00 00 00 call _puts
.text:0040108B 83 C4 04 add esp, 4
.text:0040108E 8B 4D F0 mov ecx, [ebp+var_10]
.text:00401091 64 89 0D 00 00 00+ mov large fs:0, ecx
.text:00401098 5F pop edi
.text:00401099 5E pop esi
.text:0040109A 5B pop ebx
.text:0040109B 8B E5 mov esp, ebp
.text:0040109D 5D pop ebp
.text:0040109E C3 retn
.text:0040109E _main endp
注意,是怎么处理异常的!
开始几句
.text:00401005 68 B0 60 40 00 push offset dword_4060B0
.text:0040100A 68 00 12 40 00 push offset unknown_libname_1 ; Microsoft VisualC 2-7/net runtime
.text:0040100F 64 A1 00 00 00 00 mov eax, large fs:0
.text:00401015 50 push eax
.text:00401016 64 89 25 00 00 00+ mov large fs:0, esp
是设置异常的,奇怪的是,似乎每个__try{...} __except(...){...} 结构,都是push offset unknown_libname_1的。。。不管了,起码偶分析的两个是如此出来,改天分析正常的cpp异常结构再说。
看到 push offset dword_4060B0 跟进去瞧瞧
.rdata:004060B0 FF FF FF FF dword_4060B0 dd 0FFFFFFFFh ; DATA XREF: _main+5o
.rdata:004060B4 57 10 40 00 dd offset __except
shit!敲明白否? 那个__except是偶注释的,敲机器码,可见实际抵制是401057h
也就是,在_main函数内,明白否?
偶这实际注释的,就是
__except,是处理捕捉的函数的,也就是__except(...)括号中的
__except_body,才是,实际处理异常的程序,也就是__excpet(...){...},大括号中的。
有了此基础,分析程序CRT0.C文件
/ CUT HERE ///
001 /***
002 *crt0.c - C runtime initialization routine
003 *
004 * Copyright (c) 1989-1997, Microsoft Corporation. All rights reserved.
005 *
006 *Purpose:
007 * This the actual startup routine for apps. It calls the user's main
008 * routine [w]main() or [w]WinMain after performing C Run-Time Library
009 * initialization.
010 *
011 * (With ifdef's, this source file also provides the source code for
012 * wcrt0.c, the startup routine for console apps with wide characters,
013 * wincrt0.c, the startup routine for Windows apps, and wwincrt0.c,
014 * the startup routine for Windows apps with wide characters.)
015 *
016 *******************************************************************************/
017
018 #ifdef _WIN32
019
020 #ifndef CRTDLL
021
022 #include <cruntime.h>
023 #include <dos.h>
024 #include <internal.h>
025 #include <stdlib.h>
026 #include <string.h>
027 #include <rterr.h>
028 #include <windows.h>
029 #include <awint.h>
030 #include <tchar.h>
031 #include <dbgint.h>
032
033 /*
034 * wWinMain is not yet defined in winbase.h. When it is, this should be
035 * removed.
036 */
037
038 int
039 WINAPI
040 wWinMain(
041 HINSTANCE hInstance,
042 HINSTANCE hPrevInstance,
043 LPWSTR lpCmdLine,
044 int nShowCmd
045 );
046
047 #ifdef WPRFLAG
048 _TUCHAR * __cdecl _wwincmdln(void);
049 #else /* WPRFLAG */
050 _TUCHAR * __cdecl _wincmdln(void);
051 #endif /* WPRFLAG */
052
053 /*
054 * command line, environment, and a few other globals
055 */
056
057 #ifdef WPRFLAG
058 wchar_t *_wcmdln; /* points to wide command line */
059 #else /* WPRFLAG */
060 char *_acmdln; /* points to command line */
061 #endif /* WPRFLAG */
062
063 char *_aenvptr = NULL; /* points to environment block */
064 wchar_t *_wenvptr = NULL; /* points to wide environment block */
065
066
067 void (__cdecl * _aexit_rtn)(int) = _exit; /* RT message return procedure */
068
069 static void __cdecl fast_error_exit(int); /* Error exit via ExitProcess */
070
071 /*
072 * _error_mode and _apptype, together, determine how error messages are
073 * written out.
074 */
075 int __error_mode = _OUT_TO_DEFAULT;
076 #ifdef _WINMAIN_
077 int __app_type = _GUI_APP;
078 #else /* _WINMAIN_ */
079 int __app_type = _CONSOLE_APP;
080 #endif /* _WINMAIN_ */
081
082
083 /***
084 *BaseProcessStartup(PVOID Peb)
085 *
086 *Purpose:
087 * This routine does the C runtime initialization, calls main(), and
088 * then exits. It never returns.
089 *
090 *Entry:
091 * PVOID Peb - pointer to Win32 Process Environment Block (not used)
092 *
093 *Exit:
094 * This function never returns.
095 *
096 *******************************************************************************/
097
098 #ifdef _WINMAIN_
099
100 #ifdef WPRFLAG
101 void wWinMainCRTStartup(
102 #else /* WPRFLAG */
103 void WinMainCRTStartup(
104 #endif /* WPRFLAG */
105
106 #else /* _WINMAIN_ */
107
108 #ifdef WPRFLAG
109 void wmainCRTStartup(
110 #else /* WPRFLAG */
111 void mainCRTStartup(
112 #endif /* WPRFLAG */
113
114 #endif /* _WINMAIN_ */
115 void
116 )
117 // 根据编译器的设置,选择出实际使用的
118 // void wWinMainCRTStartup(void)
119 // void WinMainCRTStartup(void)
120 // wmainCRTStartup(void)
121 // mainCRTStartup(void)
122 {
123 int mainret;
124
125 #ifdef _WINMAIN_
126 _TUCHAR *lpszCommandLine;
127 STARTUPINFO StartupInfo;
128 #endif /* _WINMAIN_ */
129
130 /*
131 * Get the full Win32 version
132 */
133 // 获得版本信息
134 _osver = GetVersion();
135
136 _winminor = (_osver >> 8) & 0x00FF ;
137 _winmajor = _osver & 0x00FF ;
138 _winver = (_winmajor << 8) + _winminor;
139 _osver = (_osver >> 16) & 0x00FFFF ;
140
141 // 静态库版本:
142 // /ML Single-Threaded 使用静态库LIBC.LIB
143 // /MLd Debug Single-Threaded 使用静态库LIBCD.LIB
144 // /MT Multithreaded 使用静态库LIBCMT.LIB
145 // /MTd Debug Multithreaded 使用静态库LIBCMTD.LIB
146 #ifdef _MT
147 if ( !_heap_init(1) ) /* initialize heap */ // 多线程用此方式初始化堆
148 #else /* _MT */
149 if ( !_heap_init(0) ) /* initialize heap */ // 单线程用此方式初始化堆
150 #endif /* _MT */
151 fast_error_exit(_RT_HEAPINIT); /* write message and die */
152
153 #ifdef _MT
154 if( !_mtinit() ) /* initialize multi-thread */
155 fast_error_exit(_RT_THREAD); /* write message and die */
156 #endif /* _MT */
157
158 /*
159 * Guard the remainder of the initialization code and the call
160 * to user's main, or WinMain, function in a __try/__except
161 * statement.
162 */
163
164 __try {
165
166 _ioinit(); /* initialize lowio */
167
168 #ifdef WPRFLAG
169 /* get wide cmd line info */
170 _wcmdln = (wchar_t *)__crtGetCommandLineW();
171
172 /* get wide environ info */
173 _wenvptr = (wchar_t *)__crtGetEnvironmentStringsW();
174
175 _wsetargv();
176 _wsetenvp();
177 #else /* WPRFLAG */
178 /* get cmd line info */
179 _acmdln = (char *)GetCommandLineA();
180
181 /* get environ info */
182 _aenvptr = (char *)__crtGetEnvironmentStringsA();
183
184 _setargv();
185 _setenvp();
186 #endif /* WPRFLAG */
187
188 _cinit(); /* do C data initialize */
189
190 #ifdef _WINMAIN_
191
192 StartupInfo.dwFlags = 0;
193 GetStartupInfo( &StartupInfo );
194
195 #ifdef WPRFLAG
196 lpszCommandLine = _wwincmdln();
197 mainret = wWinMain(
198 #else /* WPRFLAG */
199 lpszCommandLine = _wincmdln();
200 mainret = WinMain(
201 #endif /* WPRFLAG */
202 GetModuleHandleA(NULL),
203 NULL,
204 lpszCommandLine,
205 StartupInfo.dwFlags & STARTF_USESHOWWINDOW
206 ? StartupInfo.wShowWindow
207 : SW_SHOWDEFAULT
208 );
209 #else /* _WINMAIN_ */
210
211 #ifdef WPRFLAG
212 __winitenv = _wenviron;
213 mainret = wmain(__argc, __wargv, _wenviron);
214 #else /* WPRFLAG */
215 __initenv = _environ;
216 mainret = main(__argc, __argv, _environ);
217 #endif /* WPRFLAG */
218
219 #endif /* _WINMAIN_ */
220 exit(mainret);
221 }
222 __except ( _XcptFilter(GetExceptionCode(), GetExceptionInformation()) )
223 {
224 /*
225 * Should never reach here
226 */
227 _exit( GetExceptionCode() );
228
229 } /* end of try - except */
230
231 }
232
233
234
235 /***
236 *_amsg_exit(rterrnum) - Fast exit fatal errors
237 *
238 *Purpose:
239 * Exit the program with error code of 255 and appropriate error
240 * message.
241 *
242 *Entry:
243 * int rterrnum - error message number (amsg_exit only).
244 *
245 *Exit:
246 * Calls exit() (for integer divide-by-0) or _exit() indirectly
247 * through _aexit_rtn [amsg_exit].
248 * For multi-thread: calls _exit() function
249 *
250 *Exceptions:
251 *
252 *******************************************************************************/
253
254 void __cdecl _amsg_exit (
255 int rterrnum
256 )
257 {
258 #ifdef _WINMAIN_
259 if ( __error_mode == _OUT_TO_STDERR )
260 #else /* _WINMAIN_ */
261 if ( __error_mode != _OUT_TO_MSGBOX )
262 #endif /* _WINMAIN_ */
263 _FF_MSGBANNER(); /* write run-time error banner */
264
265 _NMSG_WRITE(rterrnum); /* write message */
266 _aexit_rtn(255); /* normally _exit(255) */
267 }
268
269 /***
270 *fast_error_exit(rterrnum) - Faster exit fatal errors
271 *
272 *Purpose:
273 * Exit the process with error code of 255 and appropriate error
274 * message.
275 *
276 *Entry:
277 * int rterrnum - error message number (amsg_exit only).
278 *
279 *Exit:
280 * Calls ExitProcess.
281 *
282 *Exceptions:
283 *
284 *******************************************************************************/
285
286 static void __cdecl fast_error_exit (
287 int rterrnum
288 )
289 {
290 #ifdef _WINMAIN_
291 if ( __error_mode == _OUT_TO_STDERR )
292 #else /* _WINMAIN_ */
293 if ( __error_mode != _OUT_TO_MSGBOX )
294 #endif /* _WINMAIN_ */
295 _FF_MSGBANNER(); /* write run-time error banner */
296
297 _NMSG_WRITE(rterrnum); /* write message */
298 ExitProcess(255); /* normally _exit(255) */
299 }
300
301 #ifndef WPRFLAG
302
303
304 #endif /* WPRFLAG */
305
306 #endif /* CRTDLL */
307
308 #else /* _WIN32 */
309
/ CUT END //
知道了__try{...} __except(...){...} j结果,在分析这个程序,就比较简单了
瞧瞧欲分析的例子程序
01 /// CUT HERE ///
02 // a.cpp //
03 #include <stdio.h>
04
05 int main()
06 {
07 return 0;
08 }
09 // CUT END //
很简单,看看分析结果
.text:00401007 public start
.text:00401007 start proc near
.text:00401007
.text:00401007 var_20 = dword ptr -20h
.text:00401007 var_1C = dword ptr -1Ch
.text:00401007 var_18 = dword ptr -18h
.text:00401007 ExceptionInfo = dword ptr -14h
.text:00401007 var_4 = dword ptr -4
.text:00401007
.text:00401007 55 push ebp
.text:00401008 8B EC mov ebp, esp
.text:0040100A 6A FF push 0FFFFFFFFh
.text:0040100C 68 A0 50 40 00 push offset dword_4050A0
.text:00401011 68 64 1C 40 00 push offset unknown_libname_1 ; Microsoft VisualC 2-7/net runtime
.text:00401016 64 A1 00 00 00 00 mov eax, large fs:0
.text:0040101C 50 push eax
.text:0040101D 64 89 25 00 00 00+ mov large fs:0, esp
.text:00401024 83 EC 10 sub esp, 10h
.text:00401027 53 push ebx
.text:00401028 56 push esi
.text:00401029 57 push edi
.text:0040102A 89 65 E8 mov [ebp+var_18], esp
.text:0040102D FF 15 04 50 40 00 call ds:GetVersion ; Get current version number of Windows
.text:0040102D ; and information about the operating system platform
.text:00401033 33 D2 xor edx, edx
.text:00401035 8A D4 mov dl, ah
.text:00401037 89 15 E4 84 40 00 mov dword_4084E4, edx
.text:0040103D 8B C8 mov ecx, eax
.text:0040103F 81 E1 FF 00 00 00 and ecx, 0FFh
.text:00401045 89 0D E0 84 40 00 mov dword_4084E0, ecx
.text:0040104B C1 E1 08 shl ecx, 8
.text:0040104E 03 CA add ecx, edx
.text:00401050 89 0D DC 84 40 00 mov dword_4084DC, ecx
.text:00401056 C1 E8 10 shr eax, 10h
.text:00401059 A3 D8 84 40 00 mov dword_4084D8, eax
.text:0040105E 6A 00 push 0
.text:00401060 E8 A8 0A 00 00 call _heap_init
.text:00401065 59 pop ecx
.text:00401066 85 C0 test eax, eax
.text:00401068 75 08 jnz short loc_401072
.text:0040106A 6A 1C push 1Ch ; NumberOfBytesWritten
.text:0040106C E8 9A 00 00 00 call _fast_error_exit
.text:00401071 59 pop ecx
.text:00401072
.text:00401072 loc_401072: ; CODE XREF: start+61j
.text:00401072 83 65 FC 00 and [ebp+var_4], 0
.text:00401076 E8 72 07 00 00 call __ioinit
.text:0040107B FF 15 00 50 40 00 call ds:GetCommandLineA
.text:00401081 A3 D8 89 40 00 mov dword_4089D8, eax
.text:00401086 E8 30 06 00 00 call ___crtGetEnvironmentStringsA
.text:0040108B A3 C0 84 40 00 mov dword_4084C0, eax
.text:00401090 E8 D9 03 00 00 call __setargv
.text:00401095 E8 1B 03 00 00 call __setenvp
.text:0040109A E8 90 00 00 00 call __cinit
.text:0040109F A1 F4 84 40 00 mov eax, envp
.text:004010A4 A3 F8 84 40 00 mov dword_4084F8, eax
.text:004010A9 50 push eax ; envp
.text:004010AA FF 35 EC 84 40 00 push argv ; argv
.text:004010B0 FF 35 E8 84 40 00 push argc ; argc
.text:004010B6 E8 45 FF FF FF call _main
.text:004010BB 83 C4 0C add esp, 0Ch
.text:004010BE 89 45 E4 mov [ebp+var_1C], eax
.text:004010C1 50 push eax ; int
.text:004010C2 E8 95 00 00 00 call _exit
.text:004010C7 ; ?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥
.text:004010C7
.text:004010C7 __except: ; DATA XREF: .rdata:004050A4o
.text:004010C7 8B 45 EC mov eax, [ebp+ExceptionInfo]
.text:004010CA 8B 08 mov ecx, [eax]
.text:004010CC 8B 09 mov ecx, [ecx]
.text:004010CE 89 4D E0 mov [ebp+var_20], ecx
.text:004010D1 50 push eax ; ExceptionInfo
.text:004010D2 51 push ecx ; int
.text:004010D3 E8 59 01 00 00 call __XcptFilter
.text:004010D8 59 pop ecx
.text:004010D9 59 pop ecx
.text:004010DA C3 retn
.text:004010DB ; ?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥?¥
.text:004010DB
.text:004010DB __except_body:
.text:004010DB 8B 65 E8 mov esp, [ebp+var_18]
.text:004010DE FF 75 E0 push [ebp+var_20] ; int
.text:004010E1 E8 87 00 00 00 call __exit
.text:004010E1 start endp
这就是启动的整体部分,嘿嘿,很明显了吧,对这CRT0.C文件看~~
注意,IDA分析的有点问题,主要是针对start这个函数的结尾分析有问题