本人系統是win7 64位,待調試程序是32位。這里使用的方法是真機配合虛擬機同時調試的方法來找出句柄泄露的源碼位置。
如果真機直接使用X64版本的windbg偵測句柄泄露時顯示:
0:000:x86> !htrace -diff Handle tracing information snapshot successfully taken. 0x1 new stack traces since the previous snapshot. Ignoring handles that were already closed... Outstanding handles opened since the previous snapshot: -------------------------------------- Handle = 0x0000000000000030 - OPEN Thread ID = 0x0000000000001240, Process ID = 0x0000000000001048 0x0000000076fcfc0a: ntdll!ZwCreateFile+0x000000000000000a 0x000000007480bfe3: wow64!whNtCreateFile+0x000000000000010f 0x00000000747fcf87: wow64!Wow64SystemServiceEx+0x00000000000000d7 0x000000007478276d: wow64cpu!ServiceNoTurbo+0x0000000000000024 0x00000000747fd07e: wow64!RunCpuSimulation+0x000000000000000a 0x00000000747fc549: wow64!Wow64LdrpInitialize+0x0000000000000429 0x0000000076fcae27: ntdll!LdrpInitializeProcess+0x0000000000001780 0x0000000076fc72f8: ntdll! ?? ::FNODOBFM::`string'+0x000000000002af20 0x0000000076fb2ace: ntdll!LdrInitializeThunk+0x000000000000000e 0x0000000077180056: ntdll32!ZwCreateFile+0x0000000000000012 0x000000007610bb7f: KERNELBASE!CreateFileW+0x000000000000035e 0x0000000076892345: kernel32!CreateFileWImplementation+0x0000000000000069 0x000000007689caa4: kernel32!CreateFileA+0x0000000000000037 -------------------------------------- Displayed 0x1 stack traces for outstanding handles opened since the previous snapshot.
如果真機直接使用X86版本的windbg偵測句柄泄露時顯示:
0:000> !htrace -diff Handle tracing information snapshot successfully taken. 0x1 new stack traces since the previous snapshot. Ignoring handles that were already closed... Outstanding handles opened since the previous snapshot: -------------------------------------- Handle = 0x00000030 - OPEN Thread ID = 0x00001058, Process ID = 0x00001378 0x047cf647: +0x047cf647 0x047d9398: +0x047d9398 0x044cc813: +0x044cc813 0x76fcfc0a: +0x76fcfc0a 0x7480bfe3: +0x7480bfe3 0x747fcf87: +0x747fcf87 0x7478276d: +0x7478276d 0x747fd07e: +0x747fd07e 0x747fc549: +0x747fc549 0x76fcae27: +0x76fcae27 0x76fc72f8: +0x76fc72f8 0x76fb2ace: +0x76fb2ace 0x77180056: ntdll!ZwCreateFile+0x00000012 0x7610bb7f: KERNELBASE!CreateFileW+0x0000035e 0x76892345: kernel32!CreateFileWImplementation+0x00000069 0x7689caa4: kernel32!CreateFileA+0x00000037 -------------------------------------- Displayed 0x1 stack traces for outstanding handles opened since the previous snapshot.
總之兩個版本都不能有效的顯示正確的堆棧,下面講解一種方法:虛擬機XP SP3系統下偵測句柄泄露,真機下配合定位源碼位置。
准備工作:
1.下載windbg,現在的windbg沒有單獨的下載地址了,而是和SDK一起打包發行的,Download and Install Debugging Tools for Windows 。
根據需要選擇下載,下載或在線安裝的時候選擇“Debugging Tools for Windows”即可,下載的比較慢。
下載安裝成功后配置符號路徑:srv*c:\symbols*http://msdl.microsoft.com/download/symbols
2.在虛擬機里(本人虛擬機系統XP SP3)里進行句柄泄露的偵測。
首先用windbg載入目標程序,!htrace -enable開啟句柄跟蹤開關。
某個時刻創建一次句柄快照:!htrace -snapshot
繼續運行后進行一次句柄快照對比:!htrace -diff
兩次的句柄快照對比出期間打開或者關閉的句柄:
0:002> !htrace -diff Handle tracing information snapshot successfully taken. 0x4 new stack traces since the previous snapshot. Ignoring handles that were already closed... Outstanding handles opened since the previous snapshot: -------------------------------------- Handle = 0x000005a0 - OPEN Thread ID = 0x000001e4, Process ID = 0x000004e4 -------------------------------------- Displayed 0x1 stack traces for outstanding handles opened since the previous snapshot.
可以看到中間有句柄0x000005a0被打開了,可能是一次句柄泄露但是也不一定,需要繼續分析,使用!htrace 0x000005a0命令顯示創建該句柄的堆棧:
0:002> !htrace 0x000005a0 -------------------------------------- Handle = 0x000005a0 - OPEN Thread ID = 0x00000290, Process ID = 0x000004e4 0x7606a0ee: SETUPAPI!EnablePnPPrivileges+0x0000008b 0x76069ffd: SETUPAPI!PnPGetGlobalHandles+0x0000001d 0x7606bcd6: SETUPAPI!CM_Locate_DevNode_ExW+0x00000078 0x7606befe: SETUPAPI!pSetupOpenAndAddNewDevInfoElem+0x00000045 0x7606b594: SETUPAPI!SetupDiGetClassDevsExW+0x00000459 0x7606d641: SETUPAPI!SetupDiGetClassDevsA+0x0000003d 0x006fcf86: test!cclass1::func1+0x00000056 0x005e617f: test!cclass3::func2+0x0000018f 0x005df7c6: test!cclass2::func3+0x00000056 0x005de4b9: test!Func+0x00000039 --------------------------------------
句柄是在用戶代碼:test!cclass1::func1+0x00000056處創建的,使用lsa命令顯示源碼位置。
由於是在虛擬機中調試的沒有源碼,這個時候在真機中用X86版本的windbg載入目標程序,並使用lsa命令即可顯示源碼位置。
0:000> lsa test!cclass1::func1+0x00000056 64: 65: hDevInfo = SetupDiGetClassDevs(NULL, 66: 0, 67: 0, > 68: DIGCF_PRESENT|DIGCF_ALLCLASSES); 69: 70: if(hDevInfo == INVALID_HANDLE_VALUE) 71: { 72: return FALSE; 73: }
然后檢查下這塊代碼有無釋放句柄即可,經檢查后面代碼沒有調用SetupDiDestroyDeviceInfoList釋放句柄,故而造成句柄泄露。