堆内存破坏检测实战--附完整调试过程
首先解釋一下,什么是堆內存?
堆是一種常見的內存管理器,應用程序通過堆來動態地分配和釋放內存,通常使用堆的情況是無法預先知道所需要的內存大小,或者申請內存太大,無法通過棧內存來自動分配,下面讓我們再來看一段英文解釋。
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來帶大家調試一個對破壞問題,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;
?
在應用程序驗證器下啟用普通頁堆,配置gflags,?運行build出來的代碼,
輸入參數為: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
?
我們會看到一個訪問違例,?繼續運行得到如下輸出,說明應用程序驗證器驗證成功:
?
=======================================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
?
繼續調試,此時我們已經找到了出問題的堆快,注意觀察上面的輸出中有這樣一條語句:
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"
?
總結:
原來是我們的參數破壞了了堆內存,終于找到了根源,我們代碼中定義的堆的大小為10,而我們使用的時候,由于堆塊越界,破壞了堆塊的完整性,從而導致了crash的發生..
?
注:本文的附圖和代碼靈感源自網絡,具體出處不詳,其他內容為原創..
總結
以上是生活随笔為你收集整理的堆内存破坏检测实战--附完整调试过程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Vue实现的滑动切换路由组件
- 下一篇: 区块链不适用的若干场景