天天看點

示範Heap Spray(堆噴射)的原理

#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;
  base* baseObj = new base;
  char buff[8] = {0};
  char* spray = new char[bufLen];

  memset(spray,0x0c,sizeof(char)*bufLen);
  memset(spray+bufLen-0x10,0xcc,0x10);

  strcpy(buff,"12345678\x0c\x0c\x0c\x0c");
  baseObj->baseInit1();

  return 0;
}      
0:000> dd baseObj L1
0012ff6c  004300A0
0:000> dd 4300a0 L1
004300A0 0042202c
0:000> dt _PEB 7ffdf000 ;檢視程序堆分布
ntdll!_PEB
+0x088 NumberOfHeaps    : 4
+0x090 ProcessHeaps     : 0x773a8500  -> 0x001c0000 Void
;程序有4個堆 堆句柄記錄在0x773a8500開始的數組中

0:000> dd 0x773a8500   L8
773a8500  001c0000 00010000 00020000 003c0000

;crt堆一般是程式堆數組元素中最後一個 是以調用new char[bufLen];後挂入從0x3c0000開始處的堆虛拟配置設定的HEAP!VirtualAllocdBlocks隊列
0:000> dt _HEAP 003c0000
ntdll!_HEAP
+0x0a0 VirtualAllocdBlocks : _LIST_ENTRY [ 0x630000 - 0x630000 ] 

0:000> dd 0x530000 
00630000  003c00a0 003c00a0 ;<----00630000處的8B是_LIST_ENTRY結構,指向HEAP!VirtualAllocdBlocks隊列頭
00630030  0c800000 ;<----00530030處的16進制0c800000正好是請求配置設定的記憶體
00630040  cdcdcdcd cdcdcdcd cdcdcdcd cdcdcdcd ;

0:000> dd 0x0c0c0c0c
0c0c0c0c  0c0c0c0c 0c0c0c0c 0c0c0c0c 0c0c0c0c
0c0c0c1c  0c0c0c0c 0c0c0c0c 0c0c0c0c 0c0c0c0c

strcpy(buff,"12345678\x0c\x0c\x0c\x0c");

0:000> dd buff L1
0012ff64  00000000 ;buff位于棧位址0x12ff64
0:000> dd baseObj L1
0012ff6c  004300a0 ;baseObj位于棧位址0x12ff6c,覆寫後baseObj的虛函數表vftable指針值被設定為0x0c0c0c0c