zoukankan      html  css  js  c++  java
  • 第48章:SEH

    SEH 是 Windows 操作系统提供的异常处理机制,在程序源代码中使用 __try   __catch   __finally 等关键字来具体实现。 

    进程在运行过程中发生异常,OS 会委托进程处理,但如果进程内没有具体实现 SEH ,那么 OS 会启动默认的异常处理机制终止进程运行。如果有调试器,则先交由调试器处理。

    三种异常处理的方法

    (1) 直接修改代码、寄存器、内存

    (2) 将异常抛给被调试者

    (3) 将异常抛给 OS 默认处理机制

     异常

    SEH 

    SEH 是以的形式存在的,第一个异常处理器若未处理相关异常,它就会传递到下一个异常处理器,直到得到处理。SEH 是由 _EXCEPTION_REGISTRATION_RECORD 结构体组成的链表。

    Next 成员指向下一个结构体Handler 则直接指向了异常处理函数的首地址。

    而异常处理函数是由 OS 调用的,即触发异常后,由 OS 提供参数给异常处理函数,并调用它。

    异常处理函数的定义如下:

    1. 异常处理函数的返回值 EXCEPTION_DISPOSITION 是一个枚举类型

    2. 异常处理函数的第一个参数即 EXCEPTION_RECORD 是一个结构体

    ExceptionCode异常类型。比如 80000004 指的是 EXCEPTION_SINGLE_STEP 异常,而 ExceptionAddress 则指出异常发生的地址

    3. 异常处理函数的第三个参数CONTEXT 也是一个结构体

    访问 SEH 链的方法很简单: FS: [ 0 ]

    在实验中继续观察,首先获取 SEH 链,然后将自身的栈指针接入 SEH 链,此时栈底的两个数据分别是 Next 指针和 Handler 函数地址。

    然后运行到触发异常的地方(将数据写入不存在的内存区域):

    触发异常后,按 Shift+ F7,将异常传递给程序自行处理。此时查看栈顶:

    由书作者提供的函数声明可知,第一个参数就是 EXCEPTION_RECORD 的指针:

    红色方框圈起来的两个分别是 ExceptionCode 和 ExceptionAddress ,都由 OS 填入。

    第二个参数的值是 0012FF78

    一看很眼熟,进入栈区查看:

    可以看出,它指向了下一个 SEH 结构体。

    第三个参数指向 CONTEXT 结构体:

    可以看到,框起来的第一个元素是 ContexFlags,第二个元素是 Eip ,前面一个即为 Ebp ,其它大部分都是零。

    继续查看作者编写的异常处理代码:

    首先将第三个参数,即 Contex 结构体放入 esi ,并读取 TEB.NtTilb.BeingDebugged 的值并进行比较,若进程处于被调试阶段,则不跳转,并将地址写入 Contex 结构体中的 Eip .由 Contex 的功能可知,这将改变程序的运行。同时 xor eax,eax 表示函数返回值为0 ,将继续执行异常代码,而不转到下一个 SEH 结构体 。

    接下来是系统代码——> 删除 SEH :

    如果修改了上面 eax 的返回值,使其为1,即 ExceptionContinueSearch ,运行下一个异常处理器:

    和 eax==0 时一样从 ntdll.77018E10 返回后,在 76FF8229 会经历一个跳转:

    并且在一路没有跳转的执行到:

    此函数中存在 call ecx :

    此处就调用了 SEH 链的下一个异常处理函数

    同样,在 OllyDbg 中设置相应的选项,可以避免 SEH 反调试,如果程序出现异常,调试器不会暂停,异常自动被 OS 送给程序。

    经过实验,发现:在没有异常的时候,使用X64dbg 进行调试(没有开启异常忽略)查看 BeingDebugged 的值,可以发现其值是 1。

    而使用 OllyDbg(开启异常忽略),在没有异常发生时,查看 BeingDebugged 的值,其值是 0。

    并且在程序断在系统断点时,查看该元素的值,和上述的值没有变化。在 x64dbg 中,从系统断点处开始对该元素下硬件断点,没有暂停。

    地址:   https://blog.csdn.net/whklhhhh/article/details/79656200

    总结:可以猜测,OD 使用了这种形式。而 X64dbg 没有,只有点击 隐藏调试器 后才会将 BeingDebugged 值设为 0.

  • 相关阅读:
    c基础_笔记_1
    python基础_类型_str
    MySQL的btree索引和hash索引的区别
    最大最小距离算法
    vim代码格式化插件clang-format
    Linux文件检索
    linux下视频转gif
    linux下直接复制文件内容到剪切板
    vim中的分屏操作
    为archlinux终端ls不同类型文件设置不同显示颜色
  • 原文地址:https://www.cnblogs.com/Rev-omi/p/13624497.html
Copyright © 2011-2022 走看看