`

(00XX系列)摸摸Windows的SEH

阅读更多
节一:终止处理(Termination Handlers)
节二:异常处理(Exception Handling)
节三:其他参考函数和总结

(不喜欢节前代码的直接往下拉)
节一:终止处理(Termination Handlers)

__try
{
	//如果是return,会先保存当前返回值,不受__finally影响
}
__finally
{
	//除了exit,terminateProcess, terminateThread,这里必执行
}

int fun_1()
{
004114E0  push        ebp  
004114E1  mov         ebp,esp 
004114E3  push        0FFFFFFFEh 
004114E5  push        offset ___rtc_tzz+108h (418BC8h) 
004114EA  push        offset @ILT+145(__except_handler4) (411096h)  //压入异常的函数地址
004114EF  mov         eax,dword ptr fs:[00000000h] 
004114F5  push        eax  
004114F6  add         esp,0FFFFFF2Ch 
004114FC  push        ebx  
004114FD  push        esi  
004114FE  push        edi  
004114FF  lea         edi,[ebp-0E4h] 
00411505  mov         ecx,33h 
0041150A  mov         eax,0CCCCCCCCh 
0041150F  rep stos    dword ptr es:[edi] 
00411511  mov         eax,dword ptr [___security_cookie (419010h)] 
00411516  xor         dword ptr [ebp-8],eax 
00411519  xor         eax,ebp 
0041151B  push        eax  
0041151C  lea         eax,[ebp-10h] 
0041151F  mov         dword ptr fs:[00000000h],eax 
   int dwTemp = 0;
00411525  mov         dword ptr [ebp-20h],0 

   while (dwTemp < 10) {
0041152C  cmp         dword ptr [ebp-20h],0Ah 
00411530  jge         $LN12+0Bh (411592h) 

      __try {
00411532  mov         dword ptr [ebp-4],0 
         if (dwTemp == 2)
00411539  cmp         dword ptr [ebp-20h],2 
0041153D  jne         fun_1+74h (411554h) 
            continue;
0041153F  push        0FFFFFFFEh 
00411541  lea         eax,[ebp-10h] 
00411544  push        eax  
00411545  push        offset ___security_cookie (419010h) 
0041154A  call        @ILT+165(__local_unwind4) (4110AAh) //很复杂的异常调用,最后跳到finally 
0041154F  add         esp,0Ch                             //还原异常调用堆栈
00411552  jmp         fun_1+4Ch (41152Ch) 

         if (dwTemp == 3)
00411554  cmp         dword ptr [ebp-20h],3 
00411558  jne         fun_1+8Fh (41156Fh) 
            break;
0041155A  push        0FFFFFFFEh 
0041155C  lea         eax,[ebp-10h] 
0041155F  push        eax  
00411560  push        offset ___security_cookie (419010h) 
00411565  call        @ILT+165(__local_unwind4) (4110AAh) //很复杂的异常调用,最后跳到finally  
0041156A  add         esp,0Ch 
0041156D  jmp         $LN12+0Bh (411592h) 
      }
      __finally {
0041156F  mov         dword ptr [ebp-4],0FFFFFFFEh 
00411576  call        $LN9 (41157Dh)    //执行__finally里的代码               
0041157B  jmp         $LN12 (411587h)   //跳到正常的while结尾
         dwTemp++;
0041157D  mov         eax,dword ptr [ebp-20h] 
00411580  add         eax,1 
00411583  mov         dword ptr [ebp-20h],eax 
$LN10:
00411586  ret              
      }

      dwTemp++;
00411587  mov         eax,dword ptr [ebp-20h] 
0041158A  add         eax,1 
0041158D  mov         dword ptr [ebp-20h],eax 
   }
00411590  jmp         fun_1+4Ch (41152Ch) 

   dwTemp += 10;
00411592  mov         eax,dword ptr [ebp-20h] 
00411595  add         eax,0Ah 
00411598  mov         dword ptr [ebp-20h],eax 
   return(dwTemp);
0041159B  mov         eax,dword ptr [ebp-20h] 


}

try块中的return;
return i;
004117F3  mov         eax,dword ptr [ebp-20h] 
004117F6  mov         dword ptr [ebp-0ECh],eax 
004117FC  push        0FFFFFFFEh 
004117FE  lea         ecx,[ebp-10h] 
00411801  push        ecx  
00411802  push        offset ___security_cookie (41F040h) 
00411807  call        @ILT+240(__local_unwind4) (4110F5h) //执行__finally中函数


       
        可以看出SHE在一切企图退出try块但是不退出函数体,之前插入jmp到__finally中的汇编然后清空自己堆栈,再返回下文的处理;
        对于退出函数体的代码(return),拆了两部分,执行到mov eax 返回值,然后把行为交给__finally;
        对于exit之类的结束函数,直接返回。
        而__finally中的处理是把__finally中的代码当成一个函数调用,返回后(直接一个ret指令,非常的简洁),其中的行为全部按正常行为执行。(比如这里如果有return 就直接返回)。 然后跳回到try的上下文中。

        In fact, it is always best to remove all returns, continues, breaks, gotos, and so on from inside both the try and finally blocks of a termination handler and to put these statements outside the handler.

        以上就是__try的一些大致的原理.进行汇编跟调的话,很容易的发现call @ILT+240(__local_unwind4) (4110F5h)总是执行了许多繁杂的代码。这又钩了C/C++程序员效率问题唧唧喳喳的老毛病。微软提供了配套的__leave关键字:

__leave;
0041152F  jmp         fun_1+76h (411556h) 


节二:Exception Handling(异常处理)

__try
{	
}
__except( EXCEPTION_EXECUTE_HANDLER )
{
}


=========代码段一==========
int fun_finally()
{
	__try
	{
		int i=0;
		i/=i;
		cout<<"fun_finally:try"<<endl;
	}
	__finally
	{
		cout<<"fun_finally::finally"<<endl;
	}

	return 0;
}

int fun_exception()
{
	int i;
	__try
	{
		fun_finally();
	}
	__except( EXCEPTION_EXECUTE_HANDLER )
	{
		cout<<"fun_exception:except"<<endl;
	}

	return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
	fun_exception();
	return 0;
}


=========代码段二==========
void fun_exception_2();
void fun_exception_1()
{
	__try
	{
		fun_exception_2();
	}
	__except( EXCEPTION_EXECUTE_HANDLER )
	{
		cout<<"fun_exception_1"<<endl;
	}
}

void fun_exception_2()
{
	__try
	{
		int i=0;
		i/=i;
	}
	__except( EXCEPTION_EXECUTE_HANDLER )
	{
		cout<<"fun_exception_2"<<endl;	
	}	
}

int _tmain(int argc, _TCHAR* argv[])
{
	
	fun_exception_1();
	return 0;
}



1、如何跳转
       except跳转有点奇怪,不像__finally有个典型的call或者__leave的jmp式。在VC里调试,而是直接从你出现异常的语句上跳到except中。

2、except后语句从哪儿开始执行?
       一般来说,我们在except都会放一些保护的措施。但如果说try里的代码块越多,产生的错误性就越未知,except的保护措施就越没有针对性。对于有把握的可以参考 EXCEPTION_CONTINUE_HANDLER返回值。EXCEPTION_CONTINUE_HANDLER恰是认为你有把握处理出现的异常,并且重新执行产生异常的语句。
       无把握的,或许觉得直接返回或者干脆直接跳到except后更保险,可以参考EXCEPTION_EXECUTE_HANDLER 关键字。

3、except的等级规划
       具体的图在windows核心编程里非常清楚。这里稍微综述下:当异常发生的原则是,先寻找离它最近的_except块。确定返回的是EXCEPTION_EXECUTE_HANDLER,才会到原来的地方继续执行其他的一些保护函数(俗称展开)。比如except和finally一起用,并且finally是except的一个子类,则finally先调用,然后再回到except里(看代码一)。这也是应该的,finally的规则就是只要不是exit之类的函数,就必须先执行爷的,况且你调用爷,爷没执行完你敢抛弃爷?
       如果是except里有个except,比如代码二,执行完子类的except后就回不到调用函数了。


节三:其他参考函数
       前面的一些函数功能已经足已我的使用。也不用为没掌握剩余的而自我烦恼。如果你能将整本windows核心编程的内容都在一个应用程序里表示出来,除了要写一个完整的OS,我实在想不出来还有什么得需要如此的应用。
       其余的关键字有EXCEPTION_CONTINUE_HANDLER,EXCEPTION_CONTINUE_SEARCH.获取异常的信息函GetExceptionCode,GetExceptionInformation.
另注:GetExceptionInformation可以帮你打印出程序崩溃时的调用堆栈信息(附件中特意包含,不过下载处已经忘记了,向原作者表示抱歉)。比如著名的内存溢出检测库VLD等。
       在网上查找SEH的资料时,发现非常深也非常浅,深包括整个异常链表的串联等(我看了下原文是97年微软的连接),但我觉得一些机制地方如果能理解汇编的方式就算是足够了;浅包括除了搜索结果很少,一些程序员论坛提问的方式也仅仅是异常怎么用。从表现形式来说,复杂的SEH机制还不如返回值的判断来得直接。而此番学习,是因为游戏服务器的一些架构复杂的逻辑因素太多,经常会有空指针等操作。当然,这些问题都要暴露出来才能解决,但是不能以服务器当掉做为代价。况且一些复杂的多个依赖对象创建,一些异常情况的判断,用一些SEH结构可以表示得更简洁和高效。
       这里感谢《windows 核心编程 5th》一书,讲得非常全面和细致。我最喜欢的是下面这段话:
However, keep in mind that the process might be unstable because an exception was raised. So it is advisable to keep the code inside the filter relatively simple
[/size]
1
1
分享到:
评论

相关推荐

    Windows_SEH.zip_SEH

    本文将深入探讨SEH的工作原理、其在Windows程序设计中的应用,以及如何有效地利用SEH来提高程序的健壮性。 ### 1. 结构化异常处理基础 #### 1.1 异常的概念 异常是程序执行过程中遇到的非正常情况,它可以是硬件...

    SEH系列:代码文件3

    SEH系列:代码文件3

    SEH系列:代码文件2

    SEH系列:代码文件2

    SEH系列:代码文件1

    SEH系列:代码文件1

    libcc-s-seh-1.dll(附安装教程)

    在Windows平台上,SEH(Structured Exception Handling)是一种用于处理程序异常的技术,而libcc_s_seh-1.dll就是实现这一功能的关键组件。 当您尝试运行某个应用程序时,如果系统提示“找不到libcc_s_seh-1.dll”...

    SEH分析笔记(x86篇)

    然而,SEH引入了一个异常链表(Exception Handler Chain),这个链表包含了程序预先定义的一系列异常处理函数,按照优先级顺序排列。当异常发生时,系统会沿着这个链表寻找合适的处理程序来恢复或处理异常,而不是...

    C++异常和SEH的区别

    对于C++开发者来说,理解两种主要的异常处理方式——C++标准异常处理机制(`try-catch`)与特定于Windows平台的结构化异常处理(Structured Exception Handling, SEH)——之间的区别尤为重要。本文将深入探讨这两种...

    seh结构化处理易语言模块源码

    在Windows操作系统中,SEH是一种处理程序运行时异常的标准机制。这个"seh结构化处理易语言模块源码"提供的是用易语言编写的模块,用于理解和实现SEH机制。 易语言是一款中国本土开发的、以中文编程为特色的编程语言...

    ASM-SEH-GAME-call.rar_64 汇编seh_SEH_hook game_汇编call_远程call

    描述中提到的"win32汇编 SEH实现的远程调用call"指出,此技术应用于32位Windows系统,尽管标题提及的是64位环境,但描述中的"win32汇编"可能是指在32位上下文中讨论的SEH技术。远程调用call是指在一个进程中执行的...

    SEH异常处理.rar

    SEH,全称为Structured Exception Handling(结构化异常处理),是微软在Windows操作系统中引入的一种异常处理机制。在编程过程中,异常处理是必不可少的部分,它帮助我们处理程序运行时可能出现的各种错误或异常...

    易语言SEH异常处理源码.rar

    结构化异常处理是Windows操作系统中的一种机制,用于处理程序运行时可能出现的各种异常情况,如除零错误、访问非法内存等。在C++和汇编语言中,SEH是非常重要的异常处理方式。在易语言中,虽然其语法与传统编程语言...

    x86-64-13.2.0-release-posix-seh-rev1.7z

    综合上述信息,"x86-64-13.2.0-release-posix-seh-rev1.7z" 这个压缩包提供的工具集允许开发者在Windows 64位环境下使用GCC和G++进行跨平台编程,尤其是对于那些希望在Windows系统上开发与Unix/Linux系统兼容的C++...

    x86-64-posix-seh和MinGW-W64-install.exe

    总结来说,x86-64-posix-seh是Windows 64位平台上的异常处理机制,而MinGW-W64是用于在Windows上构建64位程序的工具集,两者结合使用,可以帮助开发者在Windows环境中编写、编译和调试与POSIX兼容的64位程序。...

    windows异常处理SEH教程.zip

    win异常处理SEH教程.zip 先天型SEH 后天型SEH VEH C++ EH

    C++ SEH HOOK拦截任意API 1G视频教程.zip

    SEH(Structured Exception Handling)是Windows操作系统中用于处理异常的一种机制,它为程序员提供了控制异常处理流程的能力。本教程“C++ SEH HOOK拦截任意API 1G视频教程”显然专注于利用C++中的SEH技术来实现API...

    mingw_x86_64-posix-seh

    MingW_x86_64-Posix-SEH是一个针对Windows操作系统的开发工具集,主要为64位架构设计,用于编译C和C++程序。MingW(Minimalist GNU for Windows)是一个开源项目,它将GNU编译器集合(GCC)和其他GNU工具移植到...

    用SEH技术实现APIHook钩子

    在Windows环境中,有多种方法来实现API Hook,其中一种是使用结构化异常处理(Structured Exception Handling, 简称SEH)。本篇文章将深入探讨如何利用SEH技术来实现API Hook。 首先,我们需要理解SEH的基本概念。...

    SEH反调试.rar

    SEH反调试.rar

    易语言SEH异常处理

    SEH是微软Windows操作系统中的一种异常处理框架,它提供了一种有序的方式来捕获和处理程序执行过程中的异常。在易语言中,我们可以通过设置异常处理来确保程序在遇到错误时不会立即崩溃,而是能够优雅地处理异常并...

    西门子 SEH62.1时控开关设置说明

    西门子 SEH62.1 时控开关设置说明 西门子 SEH62.1 时控开关是一种微处理器控制的时控开关装置,具有自动存储编程时间的功能。该装置可以根据时间程序自动动作,并具有手动开关、手动关、可调倒计时定时开四种模式。...

Global site tag (gtag.js) - Google Analytics