SEH不能捕获异常

异常处理真的是个好复杂的东西,网上有不少牛文,大家参考,这里只说其中的一点,关于SHE不工作的问题及如何解决的一点思路。
        这个故事是发生在内核,驱动A开始工作的很好,后来老大说改成由驱动B模拟系统加载驱动B吧。也就是自己完成PE文件映射,重定位处理,导入表处理等等。改完后唯一的问题就是,SHE不工作了。


__try
{
    Xor eax,eax
    Mov [eax],ebx
}

__except (EXCEPTION_EXECUTE_HANDLER)
{
}

上面的代码稳蓝。

    疑惑了N久,WINDBG了下,发现了一个叫做RtlIsValidHandler的函数,顾名思义是一个判断异常处理过程是否合法的函数。原型应该是

BOOLEAN RtlIsValidHandler(PVOID Handler);

如果返回0那么这个异常处理过程就不会被调用,就是我们看到的失效状况。查了下这个函数据说是xp sp2 2003 sp1 才出现的一个新的安全检测函数。防止数据运行,溢出攻击等等。在2000下尝试被加载的驱动,果然工作良好。

    于是最简单的解决方法诞生了,想办法找到RtlIsValidHandler的地址,hook了直接返回1OK。这样相当于屏蔽了系统的安全检测机制,商业产品的话被同行说成给病毒木马开后门就不好了。还是着手分析下RtlIsValidHandler的流程构造一个符合规则的异常处理函数是正道。

    还好RtlIsValidHandler不大,开始就是对一个叫做RtlLookupFunctionTable函数的调用,这次不是太容易顾名思义了。单从返回参数来看也很诡异。RtlLookupFunctionTable也非常不大^_^,而且提示明显,有一个对_PsLoadedModuleList的遍历动作,有点安全方面经验的朋友基本可以很快推测个八九不离十。这个函数的原型跟伪代码如下:




返回值1 RtlLookupFunctionTable(异常处理程序地址,返回值2,返回值3 )
{
               if 当前irql不为DISPATCH_LEVEL
                  KeRaiseIrqlToDpcLevel()

               遍历_PsLoadedModuleList
               
{
                         if 异常处理程序地址 
>=
 当前模块基址 
                            and 异常处理程序地址 
<=
 当前模块基址+当前模块大小
                    
{
                         返回值1=当前模块
->InMemoryOrderLinks->
Flink
                         返回值3=当前模块
-> InMemoryOrderLinks->
Blink
                         返回值2=当前模块
->
DllBase
                         降低irql
                          Return ;
                         }

                    }


               遍历完成没有找到
               返回值1=传入的异常处理地址
               返回值3=传入的异常处理地址
               返回值2=遍历到的最后一个模块的基址
    
              降低irql
              Return;
}

    大致如此,随后RtlIsValidHandler对返回值做了相关检测没有仔细分析。已知的如下。




if 返回值1 ==0 或者 返回值3 == 0直接确定这个异常处理是合法的。
if 返回值2 <=0(也就是大于0x80000000没错吧?)确定这个异常处理是非法的。
           回到SHE不能捕获异常的问题,原因是因为在驱动加载时为了隐蔽没有把模块插入到PsLoadedModuleList链表中,上面RtlLookupFunctionTable会发现异常处理过程没有落在任何Module之内,之后的返回值肯定导致RtlIsValidHandler返回0,于是异常处理过程就不被调用了。尝试把驱动加入LoadedModuleList后,问题已经解决。其他的检测也就不仔细研究了。

    补充:PsLoadedModuleList是一个内核变量,指向一个加载模块的链表,具体结构是



lkd> dt nt!_LDR_DATA_TABLE_ENTRY
   
+0x000
 InLoadOrderLinks : _LIST_ENTRY
   
+0x008
 InMemoryOrderLinks : _LIST_ENTRY
   
+0x010
 InInitializationOrderLinks : _LIST_ENTRY
   
+0x018
 DllBase          : Ptr32 Void
   
+0x01c
 EntryPoint       : Ptr32 Void
   
+0x020
 SizeOfImage      : Uint4B
   
+0x024
 FullDllName      : _UNICODE_STRING
   
+0x02c
 BaseDllName      : _UNICODE_STRING
   
+0x034
 Flags            : Uint4B
   
+0x038
 LoadCount        : Uint2B
   
+0x03a
 TlsIndex         : Uint2B
   
+0x03c
 HashLinks        : _LIST_ENTRY
   
+0x03c
 SectionPointer   : Ptr32 Void
   
+0x040
 CheckSum         : Uint4B
   
+0x044
 TimeDateStamp    : Uint4B
   
+0x044
 LoadedImports    : Ptr32 Void
   
+0x048
 EntryPointActivationContext : Ptr32 Void
   
+0x04c
 PatchInformation : Ptr32 Void

    实际发现InMemoryOrderLinks InInitializationOrderLinks这两个链表貌似在做一些跟它的名称很不相符的工作。其内容经常为0或者未知内容,总之不像一个双向链表。从前面的比较也可以看出不应该是链表,自己太笨不能理解。希望有明白的牛人可以指教。

       SEH用起来简单,理解起来相当复杂,Ring3Ring0的检测貌似不完全相同。总之有一天你发现异常捕获也异常了^_^,就考虑下新加入的这个RtlIsValidHandler

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值