看学加密与解密二版学习笔记(2) - SEH 结构化异常处理

[ 工 具 ] flyod1.10

[ 目 的 ] 学习SEH的手法,另书中是用SoftICE调试的,看起来不习惯.根据原文内容重新整理一下,便于和我一样的菜鸟们一起学习.
          今天下决心,好好学习,这是就算是个开始吧!感觉学明白的确很不容易!

[ 注 释 ] ?--为不能理解的地方,请大侠们指点一下.学习过程中,有理解错误的地方,肯请大侠们多多指教.

[练习对象] 加密与加密二版第10章,光盘配套的练习软件:seh.exe seh2.exe

[ writer ]  ytcswb  2005.2.1  感谢看学及论坛的大侠们为我们提供这么好的学习资料。

1.例子seh.exe学习:
00401000 > $  8D4424 F8     lea eax,dword ptr ss:[esp-8] //程序入口!根据下面的代码分析,这里显然可以
                                                         //理解为开辟8字节的空间,并把栈顶指针保存到eax
                                                         //相当于sub esp,8 ; lea eax,dword ptr ss:[esp]
00401004   .  64:8705 00000>xchg dword ptr fs:[0],eax    //记住fs[0]永远是指向当前err结构的指针,
                                                         //执行完成后,fs[0]指向栈顶,准备在堆栈中构造1个err结构
                                                         //eax等于原fs[0],即指向原来的err结构的指针,即那个err结构的地址
0040100B   .  BB 2E104000   mov ebx,Seh.0040102E         //地址40102e-->ebx,建议在此地址上设断点,才能正常跟踪入seh代码中
00401010   .  53            push ebx                     //压入堆栈,即当前err结构的handler成员,当前异常处理代码的入口地址
00401011   .  50            push eax                     //压入原fs[0],即当前err结构的prev成员,即下一个err结构的地址
此时堆栈:
0012FFBC   0012FFE0  指针到下一个 SEH 记录 //0012FFE0是个指针,看看就知道指向下一个err结构,数值上等于下一个err结构的地址
0012FFC0   0040102E  SE 句柄               //建立了1个当前的err结构
0012FFE0   FFFFFFFF  SEH 链尾部 
0012FFE4   77E74809  SE 句柄

err结构的定义[在Essup.INC源文件中定义的---VC++ CRT(CRT含义:C++RunTime library)]:
_EXCEPTION _REGISTERATION stru
   prev    dd ? //指向下一个err结构的指针,数值上等于下一个err结构的首地址(在堆栈中)
   handler dd ? //指向异常处理代码的指针,数值上等于异常处理代码的入口地址即首地址
_EXCEPTION _REGISTERATION ends

00401012   .  BE 00000000   mov esi,0                    //简单的赋值语句
00401017   .  8B06          mov eax,dword ptr ds:[esi]   //读取线性地址0,产生异常
                                                         //执行后,windows检查到异常,执行线程马上被中段,从用户模式转到内核模式
                                                         //控制权交到操作系统的异常调试程序(exception dispatcher),由它负责找到
                                                         //处理这个异常的方法,即所有应用程序的异常最终都是由windwos来处理的,
                                                         //同一个版本的windows有固定的异常处理代码.
//如果你把这句nop掉了,也就等于去除了异常.会接着执行到下面的代码,并显示"SEH Fail"!
             
00401019   .  6A 00         push 0                                   ; /Style = MB_OK|MB_APPLMODAL
0040101B   .  68 00304000   push Seh.00403000                        ; |Title = "OK"
00401020   .  68 10304000   push Seh.00403010                        ; |Text = "SEH Fail"
00401025   .  6A 00         push 0                                   ; |hOwner = NULL
00401027   .  E8 1C000000   call <jmp.&USER32.MessageBoxA>           ; \MessageBoxA
0040102C   .  EB 13         jmp short Seh.00401041
0040102E   .  6A 00         push 0                                   ; /Style = MB_OK|MB_APPLMODAL
00401030   .  68 00304000   push Seh.00403000                        ; |Title = "OK"
00401035   .  68 03304000   push Seh.00403003                        ; |Text = "SEH Succeed "
0040103A   .  6A 00         push 0                                   ; |hOwner = NULL
0040103C   .  E8 07000000   call <jmp.&USER32.MessageBoxA>           ; \MessageBoxA
00401041   >  6A 00         push 0                                   ; /ExitCode = 0
00401043   .  E8 06000000   call <jmp.&KERNEL32.ExitProcess>         ; \ExitProcess
00401048   $- FF25 08204000 jmp dword ptr ds:[<&USER32.MessageBoxA>] ;  USER32.MessageBoxA
0040104E   .- FF25 00204000 jmp dword ptr ds:[<&KERNEL32.ExitProcess>;  kernel32.ExitProcess
00401054      00            db 00
00401055      00            db 00
---------------------------------------------------------------------------------------------------
00401017   .  8B06          mov eax,dword ptr ds:[esi]   
//读取线性地址0,产生异常
//执行完这1条指令,od的状态行可以看到,产生了什么异常.状态行的内容如下:
//访问违反:读取[00000000],使用shift+F7/F8/F9键跳过异常以继续执行程序.
//windows检测到了这个异常,就会向堆栈压入3个结构.压入顺序为 EXCEPTION_RECORD,EXCEPTION_CONTEXT,EXCEPTION_POINTERS
//EXCEPTION_POINTERS结构就在栈顶,其定义如下:

typedef strut_EXCEPTION_POINTERS{ 
+0 pEXCEPTION_RECORD ExceptionRecord DWORD ? //指针,指向EXCEPTION_RECORD结构,即EXCEPTION_RECORD的首地址
+4 pCONTEXT ContextRecord            DWORD ? //指针,指向EXCEPTION_CONTEXT结构,即EXCEPTION_CONTEXT的首地址
}_EXCEPTION_POINTERS ends

在看看EXCEPTION_RECORD结构:
EXCEPTION_RECORD struct{      //共6个成员
+0  DWORD ExceptionCode       //异常代码,定义了产生异常的原因
+4  DWORD ExceptionFlags      //异常标志 ?
+8  struct EXCEPTION_RECORD   //指针,指向另一个EXCEPTION_RECORD结构
+C  DVOID ExceptionAddress    //异常发生的地址
+10 DWORD NumberParameters    //与异常联系的参数个数(0~15)一般=0 ?
+14 ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]   //异常信息 ?
}EXCEPTION_RECORD ends

//执行完401017指令后,我们在od的代码窗口的看到代码如下:

77FB4DAF >  8B4C24 04       mov ecx,dword ptr ss:[esp+4]
77FB4DB3    8B1C24          mov ebx,dword ptr ss:[esp] //来到了ntdll领空,即系统领空
  {
  //马上看看堆栈:
  0012FCCC   0012FCD4 -| //指针,指向EXCEPTION_RECORD结构,即EXCEPTION_RECORD的首地址-----\这就是EXCEPTION_POINTERS
  0012FCD0   0012FCF0 -| //指针,指向EXCEPTION_CONTEXT结构,即EXCEPTION_CONTEXT的首地址---\
  0012FCD4   C0000005---------------\1--异常代码.这里开始就是EXCEPTION_RECORD结构
  0012FCD8   00000000               \2--异常标志=0
  0012FCDC   00000000               \3--指针,指向另一个EXCEPTION_RECORD结构,这里=0 
                                               没有另一个EXCEPTION_RECORD结构,为NULL指针.
  0012FCE0   00401017  Seh.00401017 \4--异常发生的地址,这就是发生异常的那条指令的地址.
  0012FCE4   00000002               \5--与异常联系的参数个数=2 ?
  0012FCE8   00000000               \6--异常信息 ?
  0012FCEC   00000000---------------\
  0012FCF0   0001003F---------------\这里开始就是EXCEPTION_CONTEXT结构,ContextFlags
  0012FCF4   00000000               \Dr0  
  0012FCF8   00000000               \Dr1 
  0012FCFC   00000000               \Dr2
  0012FD00   00000000               \Dr3 
  0012FD04   0000A000               \Dr6
  0012FD08   00000000               \Dr7
  
  我们重点看看0012FCF0 +B8=12FDA8
  0012FDA4   0012FFF0
  0012FDA8   00401017  Seh.00401017 \异常发生的地址,这就是发生异常的那条指令的地址.
  0012FDAC   0000001B
  }
继续跟踪:
77FB4DB6    51              push ecx //指针,指向EXCEPTION_CONTEXT结构
77FB4DB7    53              push ebx //指针,指向EXCEPTION_RECORD结构
77FB4DB8    E8 ACBDFAFF     call ntdll.77F60B69 //如果f8过,会出现SEH succeed 提示窗口,即执行了程序自己的异常代码,
                                                //为了看系统是如何处理的,我们f7进入
77FB4DBD    0AC0            or al,al
77FB4DBF    74 0C           je short ntdll.77FB4DCD
77FB4DC1    5B              pop ebx
77FB4DC2    59              pop ecx
77FB4DC3    6A 00           push 0
77FB4DC5    51              push ecx
77FB4DC6    E8 480BFCFF     call ntdll.ZwContinue
77FB4DCB    EB 0B           jmp short ntdll.77FB4DD8
77FB4DCD    5B              pop ebx
77FB4DCE    59              pop ecx
77FB4DCF    6A 00           push 0
77FB4DD1    51              push ecx
77FB4DD2    53              push ebx
77FB4DD3    E8 F213FCFF     call ntdll.ZwRaiseException
77FB4DD8    83C4 EC         add esp,-14
77FB4DDB    890424          mov dword ptr ss:[esp],eax
77FB4DDE    C74424 04 01000>mov dword ptr ss:[esp+4],1
77FB4DE6    895C24 08       mov dword ptr ss:[esp+8],ebx
77FB4DEA    C74424 10 00000>mov dword ptr ss:[esp+10],0
77FB4DF2    54              push esp
77FB4DF3    E8 AFC2F9FF     call ntdll.RtlRaiseException
77FB4DF8    C2 0800         retn 8

继续跟到这段代码里:
77F79B7E    55              push ebp
77F79B7F    8BEC            mov ebp,esp
77F79B81    FF75 0C         push dword ptr ss:[ebp+C]
77F79B84    52              push edx
77F79B85    64:FF35 0000000>push dword ptr fs:[0]
77F79B8C    64:8925 0000000>mov dword ptr fs:[0],esp
  {
  //堆栈建立了1个err结构
  0012FC04   0012FFBC  指针到下一个 SEH 记录 //enter键看看
  0012FC08   77F79BB8  SE 句柄
  0012FFBC   0012FFE0  指针到下一个 SEH 记录
  0012FFC0   0040102E  SE 句柄 // 熟悉这个地址吧
  0012FFE0   FFFFFFFF  SEH 链尾部
  0012FFE4   77E74809  SE 句柄
  }
77F79B93    FF75 14         push dword ptr ss:[ebp+14]
77F79B96    FF75 10         push dword ptr ss:[ebp+10]
77F79B99    FF75 0C         push dword ptr ss:[ebp+C]
77F79B9C    FF75 08         push dword ptr ss:[ebp+8]
77F79B9F    8B4D 18         mov ecx,dword ptr ss:[ebp+18]
  {
  //此时我们马上看看堆栈:
  0012FBF4   0012FCD4 //指针,指向EXCEPTION_RECORD结构,即EXCEPTION_RECORD的首地址  -----回调函数的参数1
  0012FBF8   0012FFBC //指向err结构.可以看看上面我们截取的SEH链表                 -----回调函数的参数2
  0012FBFC   0012FCF0 //指针,指向EXCEPTION_CONTEXT结构,即EXCEPTION_CONTEXT的首地址-----回调函数的参数3
  0012FC00   0012FCAC //参数4  _lpDispatchrContext ? 最先被压入堆栈.
  0012FC04   0012FFBC  指针到下一个 SEH 记录
  0012FC08   77F79BB8  SE 句柄
  0012FC0C   0012FFBC
  }
77F79BA2    FFD1            call ecx                      //Seh.0040102E到这里执行,就是程序的自己的异常处理代码,f7
                                                          //这就是异常处理回调函数,其参数含义请往下看.
  {
  0040102C   . /EB 13         jmp short Seh.00401041
  0040102E   . |6A 00         push 0                                   ; /Style = MB_OK|MB_APPLMODAL
  00401030   . |68 00304000   push Seh.00403000                        ; |Title = "OK"
  00401035   . |68 03304000   push Seh.00403003                        ; |Text = "SEH Succeed "
  0040103A   . |6A 00         push 0                                   ; |hOwner = NULL
  0040103C   . |E8 07000000   call <jmp.&USER32.MessageBoxA>           ; \MessageBoxA
  00401041   > \6A 00         push 0                                   ; /ExitCode = 0
  00401043   .  E8 06000000   call <jmp.&KERNEL32.ExitProcess>         ; \ExitProcess
  00401048   $- FF25 08204000 jmp dword ptr ds:[<&USER32.MessageBoxA>] ;  USER32.MessageBoxA
  0040104E   .- FF25 00204000 jmp dword ptr ds:[<&KERNEL32.ExitProcess>;  kernel32.ExitProcess
  }
77F79BA4    64:8B25 0000000>mov esp,dword ptr fs:[0]
77F79BAB    64:8F05 0000000>pop dword ptr fs:[0]
77F79BB2    8BE5            mov esp,ebp
77F79BB4    5D              pop ebp
77F79BB5    C2 1400         retn 14

[总结]

//读取线性地址0,产生异常
//执行后,windows检查到异常,执行线程马上被中段,从用户模式转到内核模式
//控制权交到操作系统的异常调试程序(exception dispatcher),由它负责找到
//处理这个异常的方法,即所有应用程序的异常最终都是由windwos来处理的,
//那么同一个版本的windows就有固定的异常处理代码.跟踪seh保护的程序时,以此为切入点,可以轻而一举地找到关键!

2.例子seh2.exe学习:

00401000 >/$  68 51104000   push seh2.00401051                       ;  SE handler installation发生异常后到这里执行
                                                                     //看学强调:提前在这个handler设个断点,否则程序容易跑飞!
                                                                     //只有这样才能正常跟进seh处理代码!
00401005  |.  64:FF35 00000>push dword ptr fs:[0]
0040100C  |.  64:8925 00000>mov dword ptr fs:[0],esp                 //构造1个err结构

0012FFBC   0012FFE0  指针到下一个 SEH 记录 //fs:[0]=esp=0x0012FFBC
0012FFC0   00401051  SE 句柄
0012FFE0   FFFFFFFF  SEH 链尾部
0012FFE4   77E74809  SE 句柄

00401013  |.  BE 00000000   mov esi,0
00401018  |.  8B06          mov eax,dword ptr ds:[esi] //产生异常
//这里实际是故意引发一个异常,为的就是通过修改CONTEXT,来实现反跟踪及改变程序流程(设置暗桩吗?)
0040101A  |.  6A 00         push 0                                   ; /Style = MB_OK|MB_APPLMODAL
0040101C  |.  68 00304000   push seh2.00403000                       ; |Title = "SEH"
00401021  |.  68 0F304000   push seh2.0040300F                       ; |Text = "SEH程序没有运行"
00401026  |.  6A 00         push 0                                   ; |hOwner = NULL
00401028  |.  E8 57000000   call <jmp.&USER32.MessageBoxA>           ; \MessageBoxA
0040102D  |.  6A 00         push 0                                   ; /Style = MB_OK|MB_APPLMODAL
0040102F  |.  68 00304000   push seh2.00403000                       ; |Title = "SEH"
00401034  |.  68 04304000   push seh2.00403004                       ; |Text = "Hello,SEH!"
00401039  |.  6A 00         push 0                                   ; |hOwner = NULL
0040103B  |.  E8 44000000   call <jmp.&USER32.MessageBoxA>           ; \MessageBoxA
00401040  |.  64:8F05 00000>pop dword ptr fs:[0]
00401047  |.  83C4 04       add esp,4
0040104A  |.  6A 00         push 0                                   ; /ExitCode = 0
0040104C  \.  E8 39000000   call <jmp.&KERNEL32.ExitProcess>         ; \ExitProcess
00401051  /$  55            push ebp                                 ;  Structured exception handler
00401052  |.  8BEC          mov ebp,esp
00401054  |.  53            push ebx
00401055  |.  8B45 10       mov eax,dword ptr ss:[ebp+10]
00401058  |.  8D1D 2D104000 lea ebx,dword ptr ds:[40102D]
0040105E  |.  8998 B8000000 mov dword ptr ds:[eax+B8],ebx
00401064  |.  33DB          xor ebx,ebx
00401066  |.  8958 04       mov dword ptr ds:[eax+4],ebx
00401069  |.  8958 08       mov dword ptr ds:[eax+8],ebx
0040106C  |.  8958 0C       mov dword ptr ds:[eax+C],ebx
0040106F  |.  8958 10       mov dword ptr ds:[eax+10],ebx
00401072  |.  C740 18 55010>mov dword ptr ds:[eax+18],155
00401079  |.  B8 00000000   mov eax,0
0040107E  |.  5B            pop ebx
0040107F  |.  C9            leave
00401080  \.  C2 1000       retn 10
00401083      CC            int3
发生异常,就来到这里:
看堆栈:
0012FCCC   0012FCD4  //指针,指向EXCEPTION_RECORD结构,即EXCEPTION_RECORD的首地址-----\这就是EXCEPTION_POINTERS
0012FCD0   0012FCF0  //指针,指向EXCEPTION_CONTEXT结构,即EXCEPTION_CONTEXT的首地址---\
0012FCD4   C0000005  ---------------\1--异常代码.这里开始就是EXCEPTION_RECORD结构
0012FCD8   00000000
0012FCDC   00000000
0012FCE0   00401018  seh2.00401018  \4--异常发生的地址,这就是发生异常的那条指令的地址.
0012FCE4   00000002
0012FCE8   00000000
0012FCEC   00000000
0012FCF0   0001003F  ---------------\这里开始就是EXCEPTION_CONTEXT结构,ContextFlags
0012FCF4   00000000 //dr0
0012FCF8   00000000 //dr1
0012FCFC   00000000 //dr2
0012FD00   00000000 //dr3
0012FD04   0000A000 //dr6
0012FD08   00000000 //dr7
0012FD0C   FFFF027F

77FB4DB3    8B1C24          mov ebx,dword ptr ss:[esp]
77FB4DB6    51              push ecx
77FB4DB7    53              push ebx
77FB4DB8    E8 ACBDFAFF     call ntdll.77F60B69 //f7
77FB4DBD    0AC0            or al,al
77FB4DBF    74 0C           je short ntdll.77FB4DCD
77FB4DC1    5B              pop ebx
77FB4DC2    59              pop ecx
77FB4DC3    6A 00           push 0
77FB4DC5    51              push ecx
77FB4DC6    E8 480BFCFF     call ntdll.ZwContinue
77FB4DCB    EB 0B           jmp short ntdll.77FB4DD8
77FB4DCD    5B              pop ebx
77FB4DCE    59              pop ecx
77FB4DCF    6A 00           push 0
77FB4DD1    51              push ecx
77FB4DD2    53              push ebx
77FB4DD3    E8 F213FCFF     call ntdll.ZwRaiseException
77FB4DD8    83C4 EC         add esp,-14
77FB4DDB    890424          mov dword ptr ss:[esp],eax
77FB4DDE    C74424 04 01000>mov dword ptr ss:[esp+4],1
77FB4DE6    895C24 08       mov dword ptr ss:[esp+8],ebx
77FB4DEA    C74424 10 00000>mov dword ptr ss:[esp+10],0
77FB4DF2    54              push esp
77FB4DF3    E8 AFC2F9FF     call ntdll.RtlRaiseException
77FB4DF8    C2 0800         retn 8
77FB4DFB >^ E9 7DBCFAFF     jmp ntdll.77F60A7D

77F79B7E    55              push ebp
77F79B7F    8BEC            mov ebp,esp
77F79B81    FF75 0C         push dword ptr ss:[ebp+C]
77F79B84    52              push edx
77F79B85    64:FF35 0000000>push dword ptr fs:[0]
77F79B8C    64:8925 0000000>mov dword ptr fs:[0],esp
77F79B93    FF75 14         push dword ptr ss:[ebp+14] //参数4  _lpDispatchrContext ?
77F79B96    FF75 10         push dword ptr ss:[ebp+10] //参数3  _lpDContext,指向Context结构
77F79B99    FF75 0C         push dword ptr ss:[ebp+C]  //参数2  _lpSEH ,指向ERR结构
77F79B9C    FF75 08         push dword ptr ss:[ebp+8]  //参数1  _lpExceptionRecord ,指向ExceptionRecord结构
77F79B9F    8B4D 18         mov ecx,dword ptr ss:[ebp+18]
77F79BA2    FFD1            call ecx         ; seh2.00401051 转到这里了 f7
                                             //这就是异常处理回调函数,执行当前异常处理代码即401051处
                                             //注:回调函数都是由windows调用的!
                                             //看学强调: 在此回调函数上设断点,可以轻易地对付一些加壳的反跟踪代码!!!!!
77F79BA4    64:8B25 0000000>mov esp,dword ptr fs:[0] //恢复原来的SEH链表
77F79BAB    64:8F05 0000000>pop dword ptr fs:[0]
77F79BB2    8BE5            mov esp,ebp
77F79BB4    5D              pop ebp
77F79BB5    C2 1400         retn 14

00401051  /$  55            push ebp                                 ;  Structured exception handler
00401052  |.  8BEC          mov ebp,esp
00401054  |.  53            push ebx
00401055  |.  8B45 10       mov eax,dword ptr ss:[ebp+10] // eax是CONTEXT结构的指针
00401058  |.  8D1D 2D104000 lea ebx,dword ptr ds:[40102D] //通过修改CONTEXT.EIP,希望到这里执行!
0040105E  |.  8998 B8000000 mov dword ptr ds:[eax+B8],ebx //修改CONTEXT.EIP,改变程序执行线路,这大概就是利用seh的常用手法!
                                                          //没改时,是401018即发生异常的指令地址,经过1轮处理又会到这里执行
                                                          //又产生异常
00401064  |.  33DB          xor ebx,ebx
00401066  |.  8958 04       mov dword ptr ds:[eax+4],ebx //DR0 清零,使断点失效,这大概也是利用seh的常用手法,实现反跟踪!
00401069  |.  8958 08       mov dword ptr ds:[eax+8],ebx //DR1
0040106C  |.  8958 0C       mov dword ptr ds:[eax+C],ebx //DR2
0040106F  |.  8958 10       mov dword ptr ds:[eax+10],ebx//DR3
00401072  |.  C740 18 55010>mov dword ptr ds:[eax+18],155 //DR7
00401079  |.  B8 00000000   mov eax,0 //回调处理函数的返回值ExceptionContinueExcetion-->eax
//ExceptionContinueExcetion=0  回调函数返回后,系统将线程环境恢复到_lpContext参数指定的CONTEXT结构并继续执行.
                               即,表示已经修复,从异常处继续执行,如果前面没有修改CONTEXT.EIP的值,就会到401018即异常发生处
                               继续执行,由于前面修改了CONTEXT.EIP=40102D,所以就转到40102D处继续执行了.
//ExceptionContinueExcetion=1  回调函数拒绝处理这个异常,系统将通过err结构的prev指针得到前一个回掉函数的地址并继续执行它
                               也就是转到前一个err结构的异常处理代码处继续执行.
//ExceptionContinueExcetion=2  回调函数在执行中又发生了异常,即嵌套异常
//ExceptionContinueExcetion=3  发生嵌套的展开操作 ?
0040107E  |.  5B            pop ebx
0040107F  |.  C9            leave
00401080  \.  C2 1000       retn 10

[总结] 
//看学强调: 在此回调函数上设断点,可以轻易地对付一些加壳的反跟踪代码!!!!!
//看学强调: 要提前在err结构的handler地址上设断点,否则代码就可能跑飞跟踪seh的关键断点!!!!
//看学提示: 可修改CONTEXT结构成员,来实现反跟踪及改变程序流程(设置暗桩吗?)                                                                  

**************************************************************************************************************


[附录] 跟踪到异常处理回调函数的过程:
注: windows xp-sp1平台.只要是同样平台,就可以按下面步骤,来到系统的异常处理回调函数.
    熟悉一下这段代码,应该有好处,当发生异常时,可以快速找到那个call ecx异常处理回调函数,从而找到程序自己的异常处理代码。
00401000 >/$  68 51104000   push seh2.00401051 //  SE handler installation
                                               //只有在这个401051上设断点,才能跟到异常处理代码(SEH代码)处.
                                               //即要提前在err结构的handler地址上设断点,否则代码就可能跑飞!
                                               //跟踪seh的关键断点!!!!
00401005  |.  64:FF35 00000>push dword ptr fs:[0]
0040100C  |.  64:8925 00000>mov dword ptr fs:[0],esp
00401013  |.  BE 00000000   mov esi,0
00401018  |.  8B06          mov eax,dword ptr ds:[esi]  //产生异常,来到 代码[1]
0040101A  |.  6A 00         push 0                                            ; /Style = MB_OK|MB_APPLMODAL
0040101C  |.  68 00304000   push seh2.00403000                                ; |Title = "SEH"
00401021  |.  68 0F304000   push seh2.0040300F                                ; |Text = "SEH程序没有运行"
00401026  |.  6A 00         push 0                                            ; |hOwner = NULL
00401028  |.  E8 57000000   call <jmp.&USER32.MessageBoxA>                    ; \MessageBoxA
0040102D  |.  6A 00         push 0                                            ; /Style = MB_OK|MB_APPLMODAL
0040102F  |.  68 00304000   push seh2.00403000                                ; |Title = "SEH"
00401034  |.  68 04304000   push seh2.00403004                                ; |Text = "Hello,SEH!"
00401039  |.  6A 00         push 0                                            ; |hOwner = NULL
0040103B  |.  E8 44000000   call <jmp.&USER32.MessageBoxA>                    ; \MessageBoxA
00401040  |.  64:8F05 00000>pop dword ptr fs:[0]
00401047  |.  83C4 04       add esp,4
0040104A  |.  6A 00         push 0                                            ; /ExitCode = 0
0040104C  \.  E8 39000000   call <jmp.&KERNEL32.ExitProcess>                  ; \ExitProcess
00401051  /$  55            push ebp                                          ;  Structured exception handler
00401052  |.  8BEC          mov ebp,esp
00401054  |.  53            push ebx
00401055  |.  8B45 10       mov eax,dword ptr ss:[ebp+10]
00401058  |.  8D1D 2D104000 lea ebx,dword ptr ds:[40102D]
0040105E      8998 B8000000 mov dword ptr ds:[eax+B8],ebx
00401064  |.  33DB          xor ebx,ebx
00401066  |.  8958 04       mov dword ptr ds:[eax+4],ebx
00401069  |.  8958 08       mov dword ptr ds:[eax+8],ebx
0040106C  |.  8958 0C       mov dword ptr ds:[eax+C],ebx
0040106F  |.  8958 10       mov dword ptr ds:[eax+10],ebx
00401072  |.  C740 18 55010>mov dword ptr ds:[eax+18],155
00401079  |.  B8 00000000   mov eax,0
0040107E  |.  5B            pop ebx
0040107F  |.  C9            leave
00401080  \.  C2 1000       retn 10

代码[1]
77FB4DB3    8B1C24          mov ebx,dword ptr ss:[esp]
77FB4DB6    51              push ecx
77FB4DB7    53              push ebx
77FB4DB8    E8 ACBDFAFF     call ntdll.77F60B69 //F7 进入,来到代码 [2]
77FB4DBD    0AC0            or al,al
77FB4DBF    74 0C           je short ntdll.77FB4DCD
77FB4DC1    5B              pop ebx
77FB4DC2    59              pop ecx
77FB4DC3    6A 00           push 0
77FB4DC5    51              push ecx
77FB4DC6    E8 480BFCFF     call ntdll.ZwContinue //代码[5],F7进入,回到代码[6]
77FB4DCB    EB 0B           jmp short ntdll.77FB4DD8
77FB4DCD    5B              pop ebx
77FB4DCE    59              pop ecx
77FB4DCF    6A 00           push 0
77FB4DD1    51              push ecx
77FB4DD2    53              push ebx
77FB4DD3    E8 F213FCFF     call ntdll.ZwRaiseException
77FB4DD8    83C4 EC         add esp,-14
77FB4DDB    890424          mov dword ptr ss:[esp],eax
77FB4DDE    C74424 04 01000>mov dword ptr ss:[esp+4],1
77FB4DE6    895C24 08       mov dword ptr ss:[esp+8],ebx
77FB4DEA    C74424 10 00000>mov dword ptr ss:[esp+10],0
77FB4DF2    54              push esp
77FB4DF3    E8 AFC2F9FF     call ntdll.RtlRaiseException
77FB4DF8    C2 0800         retn 8
77FB4DFB >^ E9 7DBCFAFF     jmp ntdll.77F60A7D

代码 [2]
77F60B69    55              push ebp
77F60B6A    8BEC            mov ebp,esp
77F60B6C    83EC 60         sub esp,60
77F60B6F    56              push esi
77F60B70    FF75 0C         push dword ptr ss:[ebp+C]
77F60B73    8B75 08         mov esi,dword ptr ss:[ebp+8]
77F60B76    56              push esi
77F60B77    E8 AA000000     call ntdll.77F60C26
77F60B7C    84C0            test al,al
77F60B7E    0F85 EB6F0200   jnz ntdll.77F87B6F
77F60B84    53              push ebx
77F60B85    57              push edi
77F60B86    8D45 F8         lea eax,dword ptr ss:[ebp-8]
77F60B89    50              push eax
77F60B8A    8D45 FC         lea eax,dword ptr ss:[ebp-4]
77F60B8D    50              push eax
77F60B8E    E8 3C910100     call ntdll.77F79CCF
77F60B93    E8 52910100     call ntdll.77F79CEA
77F60B98    8365 08 00      and dword ptr ss:[ebp+8],0
77F60B9C    8BD8            mov ebx,eax
77F60B9E    83FB FF         cmp ebx,-1
77F60BA1    0F84 4A1C0100   je ntdll.77F727F1
77F60BA7    3B5D FC         cmp ebx,dword ptr ss:[ebp-4]
77F60BAA    0F82 481C0100   jb ntdll.77F727F8
77F60BB0    8D43 08         lea eax,dword ptr ds:[ebx+8]
77F60BB3    3B45 F8         cmp eax,dword ptr ss:[ebp-8]
77F60BB6    0F87 3C1C0100   ja ntdll.77F727F8
77F60BBC    F6C3 03         test bl,3
77F60BBF    0F85 331C0100   jnz ntdll.77F727F8
77F60BC5    8B43 04         mov eax,dword ptr ds:[ebx+4]
77F60BC8    3B45 FC         cmp eax,dword ptr ss:[ebp-4]
77F60BCB    72 09           jb short ntdll.77F60BD6
77F60BCD    3B45 F8         cmp eax,dword ptr ss:[ebp-8]
77F60BD0    0F82 221C0100   jb ntdll.77F727F8
77F60BD6    F605 4A32FC77 8>test byte ptr ds:[77FC324A],80
77F60BDD    0F85 936F0200   jnz ntdll.77F87B76
77F60BE3    FF73 04         push dword ptr ds:[ebx+4]
77F60BE6    8D45 F0         lea eax,dword ptr ss:[ebp-10]
77F60BE9    50              push eax
77F60BEA    FF75 0C         push dword ptr ss:[ebp+C]
77F60BED    53              push ebx
77F60BEE    56              push esi
77F60BEF    E8 528F0100     call ntdll.77F79B46           // F4下,F7进入,来到代码[3]
77F60BF4    F605 4A32FC77 8>test byte ptr ds:[77FC324A],80
77F60BFB    8BF8            mov edi,eax
77F60BFD    0F85 896F0200   jnz ntdll.77F87B8C
77F60C03    395D 08         cmp dword ptr ss:[ebp+8],ebx
77F60C06    0F84 8E6F0200   je ntdll.77F87B9A
77F60C0C    8BC7            mov eax,edi
77F60C0E    33C9            xor ecx,ecx
77F60C10    2BC1            sub eax,ecx
77F60C12    0F84 3E340100   je ntdll.77F74056
77F60C18    48              dec eax
77F60C19    0F85 886F0200   jnz ntdll.77F87BA7
77F60C1F    8B1B            mov ebx,dword ptr ds:[ebx]
77F60C21  ^ E9 78FFFFFF     jmp ntdll.77F60B9E
77F60C26    55              push ebp
77F60C27    8BEC            mov ebp,esp
77F60C29    51              push ecx
77F60C2A    51              push ecx
77F60C2B    57              push edi
77F60C2C    BF 1032FC77     mov edi,ntdll.77FC3210
77F60C31    393D 1032FC77   cmp dword ptr ds:[77FC3210],edi
77F60C37    0F85 48E80100   jnz ntdll.77F7F485
77F60C3D    32C0            xor al,al
77F60C3F    5F              pop edi
77F60C40    C9              leave
77F60C41    C2 0800         retn 8
77F60C44 >  55              push ebp

代码[3]
77F79B46    BA B89BF777     mov edx,ntdll.77F79BB8
77F79B4B    EB 07           jmp short ntdll.77F79B54
77F79B4D    BA DF9BF777     mov edx,ntdll.77F79BDF
77F79B52    8D09            lea ecx,dword ptr ds:[ecx]
77F79B54    53              push ebx
77F79B55    56              push esi
77F79B56    57              push edi
77F79B57    33C0            xor eax,eax
77F79B59    33DB            xor ebx,ebx
77F79B5B    33F6            xor esi,esi
77F79B5D    33FF            xor edi,edi
77F79B5F    FF7424 20       push dword ptr ss:[esp+20]
77F79B63    FF7424 20       push dword ptr ss:[esp+20]
77F79B67    FF7424 20       push dword ptr ss:[esp+20]
77F79B6B    FF7424 20       push dword ptr ss:[esp+20]
77F79B6F    FF7424 20       push dword ptr ss:[esp+20]
77F79B73    E8 06000000     call ntdll.77F79B7E //// F4下,F7进入,来到代码[4]
77F79B78    5F              pop edi
77F79B79    5E              pop esi
77F79B7A    5B              pop ebx
77F79B7B    C2 1400         retn 14

代码[4]
77F79B7E    55              push ebp
77F79B7F    8BEC            mov ebp,esp
77F79B81    FF75 0C         push dword ptr ss:[ebp+C]
77F79B84    52              push edx
77F79B85    64:FF35 0000000>push dword ptr fs:[0]
77F79B8C    64:8925 0000000>mov dword ptr fs:[0],esp
77F79B93    FF75 14         push dword ptr ss:[ebp+14]
77F79B96    FF75 10         push dword ptr ss:[ebp+10]
77F79B99    FF75 0C         push dword ptr ss:[ebp+C]
77F79B9C    FF75 08         push dword ptr ss:[ebp+8]
77F79B9F    8B4D 18         mov ecx,dword ptr ss:[ebp+18]
77F79BA2    FFD1            call ecx   //这就是异常处理回调函数!
77F79BA4    64:8B25 0000000>mov esp,dword ptr fs:[0]
77F79BAB    64:8F05 0000000>pop dword ptr fs:[0]
77F79BB2    8BE5            mov esp,ebp
77F79BB4    5D              pop ebp
77F79BB5    C2 1400         retn 14 //返回后继续跟,回到代码[5]处
代码[6]
77F75913 >  B8 20000000     mov eax,20
77F75918    BA 0003FE7F     mov edx,7FFE0300
77F7591D    FFD2            call edx //f7,到代码[8]
77F7591F    C2 0800         retn 8

代码[8]
7FFE0300    8BD4            mov edx,esp
7FFE0302    0F34            sysenter
7FFE0304    C3              retn //返回到 代码[9]

代码[9]
0040102F  |.  68 00304000   push seh2.00403000                                ; |Title = "SEH"
00401034  |.  68 04304000   push seh2.00403004                                ; |Text = "Hello,SEH!"
00401039  |.  6A 00         push 0                                            ; |hOwner = NULL
0040103B  |.  E8 44000000   call <jmp.&USER32.MessageBoxA>                    ; \MessageBoxA
00401040  |.  64:8F05 00000>pop dword ptr fs:[0]
00401047  |.  83C4 04       add esp,4
0040104A  |.  6A 00         push 0                                            ; /ExitCode = 0
0040104C  \.  E8 39000000   call <jmp.&KERNEL32.ExitProcess>                  ; \ExitProcess //f7,进入,到代码[10]

代码[10]-----这段代码,任何程序只要执行了exitprocess都会看到!留个印象吧!
77E598FD >  55              push ebp
77E598FE    8BEC            mov ebp,esp
77E59900    6A FF           push -1
77E59902    68 B0F3E877     push kernel32.77E8F3B0
77E59907    FF75 08         push dword ptr ss:[ebp+8]
77E5990A    E8 86FFFFFF     call kernel32.77E59895 // 结束了应用程序的生命!
77E5990F  ^ E9 A47DFEFF     jmp kernel32.TerminateProcess
77E59914  - FF25 F413E477   jmp dword ptr ds:[<&ntdll.LdrShutdownProcess>]    ; ntdll.LdrShutdownProcess
77E5991A    391D A470EB77   cmp dword ptr ds:[77EB70A4],ebx
77E59920    0F84 99150000   je kernel32.77E5AEBF
77E59926    53              push ebx
77E59927    53              push ebx
77E59928    53              push ebx
77E59929    E8 D2F4FEFF     call kernel32.WriteProfileStringW
77E5992E    E9 8C150000     jmp kernel32.77E5AEBF
77E59933 >  837C24 04 00    cmp dword ptr ss:[esp+4],0
77E59938    0F84 C4730200   je kernel32.77E80D02
77E5993E    FF7424 08       push dword ptr ss:[esp+8]
77E59942    FF7424 08       push dword ptr ss:[esp+8]
77E59946    FF15 6814E477   call dword ptr ds:[<&ntdll.NtTerminateThread>]    ; ntdll.ZwTerminateThread
77E5994C    85C0            test eax,eax
77E5994E    0F8C B7730200   jl kernel32.77E80D0B
77E59954    33C0            xor eax,eax
77E59956    40              inc eax
77E59957    C2 0800         retn 8
**************************************************************************************************************

附件:SEH.rar