欢迎来到 黑吧安全网 聚焦网络安全前沿资讯,精华内容,交流技术心得!

Windows调试艺术——从0开始的异常处理(下)

来源:本站整理 作者:佚名 时间:2019-04-02 TAG: 我要投稿

windows调试艺术主要是记录我自己学习的windows知识,并希望尽可能将这些东西在某些实际方面体现出来。
要阅读本文章的小伙伴建议先看看《windows调试艺术》的前两篇文章来了解一下前置知识
Windows调试艺术——从0开始的异常处理(上)
Windows调试艺术——利用LDR寻找dll基址
上一篇我们详细的了解了windows对于硬件和软件异常的不同处理过程以及相似的分发机制,但windows的异常管理远没有那么简单,还包括了SEH、VEH、安全措施等的重要知识,这次就来进行一下补充。要特别说明一下,作为windows最核心的部分之一,异常的大部分内容微软并没有公布,在加之笔者水平有限,所以在一些地方的了解还有很多欠缺,希望有能力的朋友能提出和我共同将windows异常这部分的内容总结完善。
 
SEH
SEH(structure exception handle)即结构化异常处理,往大了说它是整个Windows异常处理体系的一种称呼,往小了说它是维护异常体系的一个具体结构。在之前的文中提到了FS寄存器的0偏移直接指向了TEB,TEB的第一个结构是TIB,而TIB的0也就是ExceptionList,也就是异常处理链表的头节点,其结构如下。
typedef struct _EXCEPTION_REGISTRATION_RECORD
{
  struct _EXCEPTION_REGISTRATION_RECORD *Next;
  PEXCEPTION_ROUTINE Handler;
}EXCEPTION_REGISTRATION_RECORD
Next指向了下一个SEH节点,而Handler实际上就是我们具体的来处理该异常的函数了,我们也把它叫做异常处理回调函数。如果大家还记得数据结构的知识的话很显然这就是个简单的链表,而该链表只允许在头节点来进行删除和增添操作,且FS的0一直指向头节点,这就说明,越新的函数越接近头节点,系统会维护链表最后的next指向0xFFFFFFFF,回调函数的模版如下:
__cdecl _except_handler( struct _EXCEPTION_RECORD *ExceptionRecord,
                        void * EstablisherFrame,
                        struct _CONTEXT *ContextRecord,
                        void * DispatcherContext);
SEH安装
通过之前的讲解我们可以知道SEH是基于线程的一种处理机制,而它又依赖于栈进行存储和查找,所以也被称作是基于栈帧的异常处理机制。在windows操作系统下的基础栈布局如下所示

通过这样的布局我们也可以推断出来,SEH的装载甚至还在函数的序言之前,具体的装载代码如下:
push offset SEHandler
push fs:[0]
mov fs:[0],esp
先向栈中压入了Handler和当前的节点,他们就又构成了一个EXCEPTION_REGISTRATION_RECORD结构,而esp指向栈顶,正好就是新的EXCEPTION_REGISTRATION_RECORD,将它付给fs:[0]也就是让SEH的头节点变成了刚刚加入的新节点。
卸载过程其实就是恢复栈平衡,代码如下
mov esp,dword ptr fs:[0]
pop dword ptr fs:[0]
要注意,SEH异常的安装实际上从main函数之前就开始了,当我们在启动一个进程时,实际的启动位置也就是kernel!32BaseProcessStartThunk,而在这个函数内就已经开始有try、catch结构了,线程的启动函数kernel!32BaseThreadStart也是如此
VOID BaseThreadStart(PTHREAD_START_ROUTINE pfnStartAddr, PVOID pvParam) {
    __try{
        ExitThread((pfnStartAddr)(pvParam));
    }
    __except (UnhandledExceptionFilter(GetExceptionInformation())){
        ExitProcess(GetExceptionCode());
    }
}
实际上这里的try catch结构构成的异常回调函数就是常说的top level,即顶层异常处理,它们也是SEH链的最后一部分,并且可以看到,它们的except还存在一个叫做UnhandledFilter函数,和字面上的意思相似,这是用来实现异常过滤的函数,这是非常重要的一个函数,我们后面会细讲。
RltDispatchExeption
当我们的异常分发到了RtlDispatchException函数时,就会根据线程注册的SEH来处理该异常,之前的处理实际上都是简单的”打包”和”描述”的过程,到了这一步才开始真正的异常处理。为了个更好的理解这个过程,这里笔者给出了简化版的RltDispatchExeption伪代码,简单描绘一下该函数的执行过程,伪代码由笔者根据逆向和资料自行编写,有错误之处还望大家指出
if VEH异常处理例程 != Exception_continue_search
    goto end_func
else
    limit = 栈的limit
    seh = 借助FS寄存器获取SEH的头节点
    while(seh!=-1):
        if SEH节点不在栈中 || SEH节点位置没有按ULONG对齐 || Handler在栈中
            goto end_func
        else
            seh = 当前seh指向的下一个seh
    seh = 借助FS寄存器获取SEH的头节点
    while(seh!=-1):
        if(检查safeseh)
            goto end_func

[1] [2] [3] [4] [5]  下一页

【声明】:黑吧安全网(http://www.myhack58.com)登载此文出于传递更多信息之目的,并不代表本站赞同其观点和对其真实性负责,仅适于网络安全技术爱好者学习研究使用,学习中请遵循国家相关法律法规。如有问题请联系我们,联系邮箱admin@myhack58.com,我们会在最短的时间内进行处理。
  • 最新更新
    • 相关阅读
      • 本类热门
        • 最近下载