堆内存破坏检测实战--附完整调试过程
首先解釋一下,什么是堆內(nèi)存?
堆是一種常見的內(nèi)存管理器,應(yīng)用程序通過堆來動態(tài)地分配和釋放內(nèi)存,通常使用堆的情況是無法預(yù)先知道所需要的內(nèi)存大小,或者申請內(nèi)存太大,無法通過棧內(nèi)存來自動分配,下面讓我們再來看一段英文解釋。
A heap is a form of memory manager that an application can use when it needs to allocate?and free memory dynamically. Common situations that call for the use of a heap?are when the size of the memory needed is not known ahead of time and the size of?the memory is too large to neatly fit on the stack (automatic memory).
常見的情況是由于效率或特殊需求一個進程中同時使用幾個堆,如下圖:
?
?
?
下面通過一個完整的demo來帶大家調(diào)試一個對破壞問題,demo代碼如下:
?
#define SZ_MAX_LEN? 10 void?__cdecl?wmain?(int?argc,?WCHAR*?args[]){
????if(argc==2)
????{
????????wprintf(L"Press?any?key?to?start\n");
????????_getch();
????????DupString(args[1]);
????}
????else
????{
????????wprintf(L"Please?enter?a?string");
????}
}
BOOL?DupString(WCHAR*?psz)
{
????BOOL?bRet=FALSE;
????
????if(psz!=NULL)
????{
????????pszCopy=(WCHAR*)?HeapAlloc(GetProcessHeap(),?0,?SZ_MAX_LEN*sizeof(WCHAR));
????????if(pszCopy)
????????{
????????????wcscpy(pszCopy,?psz);
????????????wprintf(L"Copy?of?string:?%s",?pszCopy);
????????????HeapFree(GetProcessHeap(),?0,?pszCopy);
????????????bRet=TRUE;
????????}
????}
????return?bRet;
?
在應(yīng)用程序驗證器下啟用普通頁堆,配置gflags,?運行build出來的代碼,
輸入?yún)?shù)為:SolidmangoSolidmangoSolidmango
得到如下輸出:
?
CommandLine:?C:\WinXP.x86.chk\06overrun.exe?SolidmangoSolidmangoSolidmangoExecutable?search?path?is:?
ModLoad:?01000000?01005000???06overrun.exe
ModLoad:?7c900000?7c9b2000???ntdll.dll
AVRF:?06overrun.exe:?pid?0x120C:?flags?0x8044B026:?application?verifier?enabled
ModLoad:?5ad10000?5ad59000???C:\WINDOWS\System32\verifier.dll
ModLoad:?10000000?10029000???C:\WINDOWS\System32\vrfcore.dll
ModLoad:?003a0000?003dc000???C:\WINDOWS\System32\vfbasics.dll
ModLoad:?7c800000?7c8f6000???C:\WINDOWS\system32\kernel32.dll
AVRF:?verifier.dll?provider?initialized?for?06overrun.exe?with?flags?0x8044B026?
ModLoad:?77c10000?77c68000???C:\WINDOWS\system32\msvcrt.dll
(120c.1700):?Break?instruction?exception?-?code?80000003?(first?chance)
eax=00391ec4?ebx=7ffd8000?ecx=00000004?edx=00000010?esi=00391f98?edi=00391ec4
eip=7c90120e?esp=0006fb20?ebp=0006fc94?iopl=0?????????nv?up?ei?pl?nz?na?po?nc
cs=001b??ss=0023??ds=0023??es=0023??fs=003b??gs=0000?????????????efl=00000202
ntdll!DbgBreakPoint:
7c90120e?cc??????????????int?????3
0:000>?g0:000>?g
?
我們會看到一個訪問違例,?繼續(xù)運行得到如下輸出,說明應(yīng)用程序驗證器驗證成功:
?
=======================================VERIFIER?STOP?00000008:?pid?0x120C:?Corrupted?heap?block.?
????00081000?:?Heap?handle?used?in?the?call.
????001E2B60?:?Heap?block?involved?in?the?operation.
????00000014?:?Size?of?the?heap?block.
????00000000?:?Reserved
=======================================
This?verifier?stop?is?not?continuable.?Process?will?be?terminated?
when?you?use?the?`go'?debugger?command.
=======================================
(120c.1700):?Break?instruction?exception?-?code?80000003?(first?chance)
eax=1000e848?ebx=1000cd44?ecx=00000001?edx=0006f939?esi=00000000?edi=1000e848
eip=7c90120e?esp=0006f9cc?ebp=0006fbd0?iopl=0?????????nv?up?ei?pl?nz?na?po?nc
cs=001b??ss=0023??ds=0023??es=0023??fs=003b??gs=0000?????????????efl=00000202
ntdll!DbgBreakPoint:
7c90120e?cc??????????????int?????3
?
繼續(xù)調(diào)試,此時我們已經(jīng)找到了出問題的堆快,注意觀察上面的輸出中有這樣一條語句:
001E2B60?:?Heap?block?involved?in?the?operation,好的,讓我們看看這個堆塊里面是什么東西,
0:000>?dt?_DPH_BLOCK_INFORMATION?001E2B60-0x20ntdll!_DPH_BLOCK_INFORMATION
???+0x000?StartStamp???????:?0xabcdaaaa
???+0x004?Heap?????????????:?0x80081000?Void
???+0x008?RequestedSize????:?0x14
???+0x00c?ActualSize???????:?0x3c
???+0x010?FreeQueue????????:?_LIST_ENTRY?[?0x1e?-?0x0?]
???+0x010?TraceIndex???????:?0x1e
???+0x018?StackTrace???????:?0x00286c3c?Void
???+0x01c?EndStamp?????????:?0xdcbaaaaa
0:000>?dds?0x00286c3c?//callstack
00286c3c??abcdaaaa
00286c40??00000001
00286c44??00000007
00286c48??00000001
00286c4c??00000014
00286c50??00081000
00286c54??00000000
00286c58??00286c5c
00286c5c??7c94b244?ntdll!RtlAllocateHeapSlowly+0x44
00286c60??7c919c0c?ntdll!RtlAllocateHeap+0xe64
00286c64??003afd2c?vfbasics!AVrfpRtlAllocateHeap+0xb1
00286c68??010012f4?06overrun!DupString+0x24?[c:\awd\chapter6\overrun\overrun.cpp?@?41]
00286c6c??010012ab?06overrun!wmain+0x2b?[c:\awd\chapter6\overrun\overrun.cpp?@?28]
00286c70??010014b8?06overrun!__wmainCRTStartup+0x102?[d:\vistartm\base\crts\crtw32\dllstuff\crtexe.c?@?711]
00286c74??7c817077?kernel32!BaseProcessStart+0x23
00286c78??00000000
我們找到了出問題的callstack:
0:000>?kb
ChildEBP?RetAddr??Args?to?Child??????????????
0006f9c8?10003b68?10062cb0?00000008?001e2b60?ntdll!DbgBreakPoint
0006fbd0?100078c9?1000c540?00000008?00081000?vrfcore!VerifierStopMessageEx+0x4d1
0006fbf4?7c96c06e?00000008?7c96c314?00081000?vrfcore!VfCoreRedirectedStopMessage+0x81
0006fc70?7c96d147?00081000?00000004?001e2b60?ntdll!RtlpDphReportCorruptedBlock+0x17c
0006fc94?7c96d34a?00081000?01000002?00000010?ntdll!RtlpDphNormalHeapFree+0x2e
0006fce4?7c9703eb?00080000?01000002?001e2b60?ntdll!RtlpDebugPageHeapFree+0x79
0006fd58?7c94bafc?00080000?01000002?001e2b60?ntdll!RtlDebugFreeHeap+0x2c
0006fe40?7c91a1ba?00080000?01000002?001e2b60?ntdll!RtlFreeHeapSlowly+0x37
0006ff10?003afe9c?00080000?00000000?001e2b60?ntdll!RtlFreeHeap+0xf9
0006ff58?01001340?00080000?00000000?00000014?vfbasics!AVrfpRtlFreeHeap+0xf8
0006ff70?010012ab?00a64692?0006ffc0?010014b8?06overrun!DupString+0x70?[c:\awd\chapter6\overrun\overrun.cpp?@?47]
0006ff7c?010014b8?00000002?00a64648?00a66e98?06overrun!wmain+0x2b?[c:\awd\chapter6\overrun\overrun.cpp?@?28]
0006ffc0?7c817077?00daf6ee?00daf784?7ffd8000?06overrun!__wmainCRTStartup+0x102?[d:\vistartm\base\crts\crtw32\dllstuff\crtexe.c?@?711]
0006fff0?00000000?010015f6?00000000?78746341?kernel32!BaseProcessStart+0x23
0:000>?du?00a64692?
00a64692??"SolidmangoSolidmangoSolidmango"
?
總結(jié):
原來是我們的參數(shù)破壞了了堆內(nèi)存,終于找到了根源,我們代碼中定義的堆的大小為10,而我們使用的時候,由于堆塊越界,破壞了堆塊的完整性,從而導(dǎo)致了crash的發(fā)生..
?
注:本文的附圖和代碼靈感源自網(wǎng)絡(luò),具體出處不詳,其他內(nèi)容為原創(chuàng)..
總結(jié)
以上是生活随笔為你收集整理的堆内存破坏检测实战--附完整调试过程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Vue实现的滑动切换路由组件
- 下一篇: 女子患异食癖3年吃上百块粉饼:体检身体无