[翻譯]內核池基礎知識(池損壞)

做者:huity
出處:http://www.javashuo.com/article/p-swxwfauk-e.html
版權:本文版權歸做者全部。文章在博客園、看雪、我的博客同時發佈。
轉載:歡迎轉載,但未經做者贊成,必須保留此段聲明;必須在文章中給出原文鏈接;不然必究法律責任。html

 

Part1  Buffer Overflows

 池是內核模式內存,用做驅動程序的存儲空間。
池的組織方式與在從演講或書中記筆記時使用記事本的方式相似。 有些筆記多是1行,其餘筆記多是多行。 許多不一樣的註釋都在同一頁面上。內存也被組織成頁,一般一頁內存爲4KB。 Windows內存管理器將這個4KB的頁面分紅更小的塊。 一個塊可能小到8個字節或可能更大。 這些塊中的每個與其餘塊並排存在。
!pool命令可用於查看存儲在頁面中的池塊。
kd> !pool fffffa8003f42000
Pool page fffffa8003f42000 region is Nonpaged pool
*fffffa8003f42000 size:  410 previous size:    0  (Free)      *Irp
            Pooltag Irp  : Io, IRP packets
fffffa8003f42410 size:   40 previous size:  410  (Allocated)  MmSe
fffffa8003f42450 size:  150 previous size:   40  (Allocated)  File
fffffa8003f425a0 size:   80 previous size:  150  (Allocated)  Even
fffffa8003f42620 size:   c0 previous size:   80  (Allocated)  EtwR
fffffa8003f426e0 size:   d0 previous size:   c0  (Allocated)  CcBc
fffffa8003f427b0 size:   d0 previous size:   d0  (Allocated)  CcBc
fffffa8003f42880 size:   20 previous size:   d0  (Free)       Free
fffffa8003f428a0 size:   d0 previous size:   20  (Allocated)  Wait
fffffa8003f42970 size:   80 previous size:   d0  (Allocated)  CM44
fffffa8003f429f0 size:   80 previous size:   80  (Allocated)  Even
fffffa8003f42a70 size:   80 previous size:   80  (Allocated)  Even
fffffa8003f42af0 size:   d0 previous size:   80  (Allocated)  Wait
fffffa8003f42bc0 size:   80 previous size:   d0  (Allocated)  CM44
fffffa8003f42c40 size:   d0 previous size:   80  (Allocated)  Wait
fffffa8003f42d10 size:  230 previous size:   d0  (Allocated)  ALPC
fffffa8003f42f40 size:   c0 previous size:  230  (Allocated)  EtwR

因爲許多池分配存儲在同一頁面中,所以每一個驅動程序僅使用已分配的空間相當重要。若是DriverA使用的空間比分配的空間多,則會寫入下一個驅動程序的空間(DriverB)並損壞DriverB的數據。將這種覆蓋到下一個驅動程序的空間的狀況稱爲緩衝區溢出。接着,內存管理器或DriverB將嘗試使用此損壞的內存,並將遇到意外的信息。這種意外信息一般會致使藍屏(BSOD)。數據庫

 

一般,池損壞顯示爲終止碼 0x19 BAD_POOL_HEADER或終止碼 0xC2 BAD_POOL_CALLER。 這些終止碼能夠輕鬆肯定崩潰中涉及池損壞。 可是,訪問意外內存的結果可能會有很大差別,所以池損壞會致使許多不一樣類型的錯誤檢查。
與任何藍屏轉儲分析同樣,最好的起點是!analyze -v。 此命令將顯示終止碼和參數,並對崩潰進行一些基本解釋。
kd> !analyze -v
*******************************************************************************
*                                                                             *
*                        Bugcheck Analysis                                    *
*                                                                             *
*******************************************************************************
SYSTEM_SERVICE_EXCEPTION (3b)
An exception happened while executing a system service routine.
Arguments:
Arg1: 00000000c0000005, Exception code that caused the bugcheck
Arg2: fffff8009267244a, Address of the instruction which caused the bugcheck
Arg3: fffff88004763560, Address of the context record for the exception that caused the bugcheck
Arg4: 0000000000000000, zero.

 

在上述例子中,錯誤檢查是一個終止碼 0x3B SYSTEM_SERVICE_EXCEPTION。 此終止碼的第一個參數是c0000005,它是訪問衝突的狀態代碼。 訪問衝突是嘗試訪問無效內存(此錯誤與權限無關)。 能夠在WDK頭ntstatus.h中查找狀態代碼。
!analyze -v命令還提供了一個有用的捷徑來進入失敗的上下文。
CONTEXT:  fffff88004763560 -- (.cxr 0xfffff88004763560;r)

 

運行此命令會向咱們顯示崩潰時的寄存器值。
kd> .cxr 0xfffff88004763560
rax=4f4f4f4f4f4f4f4f rbx=fffff80092690460 rcx=fffff800926fbc60
rdx=0000000000000000 rsi=0000000000001000 rdi=0000000000000000
rip=fffff8009267244a rsp=fffff88004763f60 rbp=fffff8009268fb40
r8=fffffa8001a1b820  r9=0000000000000001 r10=fffff800926fbc60
r11=0000000000000011 r12=0000000000000000 r13=fffff8009268fb48
r14=0000000000000012 r15=000000006374504d
iopl=0         nv up ei pl nz na po nc
cs=0010  ss=0018  ds=002b  es=002b  fs=0053  gs=002b             efl=00010206
nt!ExAllocatePoolWithTag+0x442:
fffff800`9267244a 4c8b4808        mov     r9,qword ptr [rax+8] ds:002b:4f4f4f4f`4f4f4f57=????????????????

 

從上面的輸出咱們能夠看到崩潰發生在ExAllocatePoolWithTag中,這很好地代表崩潰是因爲池損壞形成的。 一般狀況下,看着dump的工程師會在此時中止並得出結論認爲崩潰是由池損壞引發的,但咱們能夠更進一步。
執行失敗的指令是解引用rax + 8。 rax寄存器包含4f4f4f4f4f4f4f4f,它不具備x64系統上指針所需的規範形式。 這說明由於rax中的數據應該是一個指針,但很明顯他不是,致使系統崩潰了。
要肯定rax不包含預期數據的緣由,咱們必須在失敗以前檢查指令。
kd> ub .
nt!KzAcquireQueuedSpinLock [inlined in nt!ExAllocatePoolWithTag+0x421]:
fffff800`92672429 488d542440      lea     rdx,[rsp+40h]
fffff800`9267242e 49875500        xchg    rdx,qword ptr [r13]
fffff800`92672432 4885d2          test    rdx,rdx
fffff800`92672435 0f85c3030000    jne     nt!ExAllocatePoolWithTag+0x7ec (fffff800`926727fe)
fffff800`9267243b 48391b          cmp     qword ptr [rbx],rbx
fffff800`9267243e 0f8464060000    je      nt!ExAllocatePoolWithTag+0xa94 (fffff800`92672aa8)
fffff800`92672444 4c8b03          mov     r8,qword ptr [rbx]
fffff800`92672447 498b00          mov     rax,qword ptr [r8]

 

彙編代碼中顯示rax來自r8所指向數據。查找前面寄存器的值,看到r8值爲fffffa8001a1b820,查看內存,能夠看到與rax中數據一致,由此能夠判定,是此處內存出現問題。
kd> dq fffffa8001a1b820 l1
fffffa80`01a1b820  4f4f4f4f`4f4f4f4f

 

要肯定此意外數據是不是由池損壞引發的,咱們可使用!pool命令。
kd> !pool fffffa8001a1b820
Pool page fffffa8001a1b820 region is Nonpaged pool
 fffffa8001a1b000 size:  810 previous size:    0  (Allocated)  None

 

fffffa8001a1b810看起來不像是一個有效的小池分配,檢查整個頁面是否其實是大頁面分配的一部分......
kd> !pool fffffa8001a1b820
Pool page fffffa8001a1b820 region is Nonpaged pool
fffffa8001a1b000 size:  810 previous size:    0  (Allocated)  None
fffffa8001a1b810 doesn't look like a valid small pool allocation, checking to see
if the entire page is actually part of a large page allocation...
fffffa8001a1b810 is not a valid large pool allocation, checking large session pool...
fffffa8001a1b810 is freed (or corrupt) pool
Bad previous allocation size @fffffa8001a1b810, last size was 81
***
*** An error (or corruption) in the pool was detected;
*** Attempting to diagnose the problem.
***
*** Use !poolval fffffa8001a1b000 for more details.
Pool page [ fffffa8001a1b000 ] is __inVALID.
Analyzing linked list...
[ fffffa8001a1b000 --> fffffa8001a1b010 (size = 0x10 bytes)]: Corrupt region

Scanning for single bit errors...

None found
 
上面的輸出看起來不像咱們以前使用的!pool命令。 此輸出顯示池標頭的損壞,這會阻止命令走分配鏈。
上面的輸出顯示在大小爲810的fffffa8001a1b000上有一處分配。若是咱們查看這個內存,咱們應該看到一個池頭。 可是,咱們看到的是4f4f4f4f`4f4f4f4f的樣子。
kd> dq fffffa8001a1b000 + 810
fffffa80`01a1b810  4f4f4f4f`4f4f4f4f 4f4f4f4f`4f4f4f4f
fffffa80`01a1b820  4f4f4f4f`4f4f4f4f 4f4f4f4f`4f4f4f4f
fffffa80`01a1b830  4f4f4f4f`4f4f4f4f 00574f4c`46524556
fffffa80`01a1b840  00000000`00000000 00000000`00000000
fffffa80`01a1b850  00000000`00000000 00000000`00000000
fffffa80`01a1b860  00000000`00000000 00000000`00000000
fffffa80`01a1b870  00000000`00000000 00000000`00000000
fffffa80`01a1b880  00000000`00000000 00000000`00000000
此時,咱們能夠肯定系統因池損壞而崩潰。
由於損壞發生在以前,而且轉儲是系統當前狀態的快照,因此沒有具體證據代表內存是如何被破壞的。 在損壞以前當即分配池塊的驅動程序多是寫入錯誤位置並致使此損壞的驅動程序。 此池塊標有「None」標記,咱們能夠在內存中搜索此標記以肯定哪些驅動程序使用它。
kd> !for_each_module s -a @#Base @#End "None"
fffff800`92411bc2  4e 6f 6e 65 e9 45 04 26-00 90 90 90 90 90 90 90  None.E.&........
kd> u fffff800`92411bc2-1
nt!ExAllocatePool+0x1:
fffff800`92411bc1 b84e6f6e65      mov     eax,656E6F4Eh
fffff800`92411bc6 e945042600      jmp     nt!ExAllocatePoolWithTag (fffff800`92672010)
fffff800`92411bcb 90              nop

 

文件Pooltag.txt列出了由Windows提供的內核模式組件和驅動程序,相關文件或組件(若是已知)以及組件名稱用於池分配的池標記。 Pooltag.txt隨Windows調試工具(在triage文件夾中)和Windows WDK(在\ tools \ other \ platform \ poolmon中)一塊兒安裝。 Pooltag.txt顯示如下標記:

 
None - <unknown>    - call to ExAllocatePool

 

不幸的是,咱們發現當驅動程序調用ExAllocatePool(未指定標記)時會使用此標記。 這不容許咱們肯定在損壞以前分配塊的驅動程序。 即便咱們能夠將標記綁定回驅動程序,也可能不足以判定使用此標記的驅動程序是破壞內存的驅動程序。
下一步應該是啓用特殊池並但願在行爲中捕獲損壞者。
 

Part2  Special Pool for Buffer Overruns

在本節中,咱們將討論特殊池如何幫助識別向緩衝區寫入太多數據的驅動程序。
池一般被組織爲容許多個驅動程序將數據存儲在同一內存頁中,如圖1所示。

圖1 未損壞池
 
經過容許多個驅動程序共享同一頁面,池能夠有效地使用可用的內核內存空間。 可是,這種共享要求每一個驅動程序都要當心使用池,使用池的任何錯誤均可能破壞其餘驅動程序池並致使崩潰。
圖二 損壞池
 
如圖2所示池,若是DriverA分配100個字節但寫入120個字節,它將覆蓋由DriverB存儲的池頭和數據。 在第1部分中,咱們演示了這種類型的緩衝區溢出,但咱們沒法識別哪些代碼致使損壞池。
 
爲了捕獲損壞池的驅動程序,咱們可使用特殊池。 特殊池更改池的組織方式,使得每一個驅動程序的分配位於單獨的內存頁中。 這有助於防止驅動程序意外寫入另外一個驅動程序的內存。 特殊池也在頁末尾進行驅動程序的分配,經過將下一個虛擬頁面標記爲無效將其設置爲保護頁面。寫入超過度配的結尾,會致使保護頁面進行當即錯誤檢查。
 
特殊池還用重複模式填充頁面的未使用部分,稱爲「slop bytes」。 若是在模式中發現任何錯誤,在釋放頁面時將檢查這些slop字節,生成錯誤檢查以指示內存已損壞。 這種類型的損壞不是緩衝區溢出,它多是下溢或其餘形式的損壞。
圖3 特殊池
因爲特殊池將每一個池分配存儲在其本身的4KB頁面中,所以會致使內存使用量增長。啓用特殊池時,內存管理器將配置可在系統上分配特殊池的限制,當達到此限制時,將使用常規池。對於比64位系統具備更少內核空間的32位系統,這種限制尤爲明顯。
 
解釋了特殊池的工做原理,如今來用它。
 
有兩種方法能夠啓用特殊池。驅動驗證程序容許在特定驅動程序上啓用特殊池。 KB188831中描述的PoolTag註冊表值容許爲特定池標記啓用特殊池。從Windows Vista和Windows Server 2008開始,驅動驗證程序捕獲特殊池分配的其餘信息,所以這一般是推薦的方法。
 
要使用驅動程序驗證程序啓用特殊池,請使用如下命令行,或從驗證程序GUI中選擇該選項。使用/ driver標誌指定要驗證的驅動程序,這是列出您懷疑是問題緣由的驅動程序的位置。您可能須要驗證已編寫並但願測試的驅動程序或最近在系統上更新的驅動程序。在下面的命令行中,我只驗證myfault.sys。須要從新啓動才能啓用特殊池。
verifier /flags 1 /driver myfault.sys
啓用驗證程序並從新啓動系統後,重複致使崩潰的活動。 對於某些問題,活動可能只是等待一段時間。 對於咱們的演示,咱們運行NotMyFault(有關詳細信息,請參閱第1部分)。
 
特殊池中緩衝區溢出致使的崩潰將是一個終止碼0xD6,DRIVER_PAGE_FAULT_BEYOND_END_OF_ALLOCATION。
kd> !analyze -v
*******************************************************************************
*                                                                             *
*                        Bugcheck Analysis                                    *
*                                                                             *
*******************************************************************************
 
DRIVER_PAGE_FAULT_BEYOND_END_OF_ALLOCATION (d6)
N bytes of memory was allocated and more than N bytes are being referenced.
This cannot be protected by try-except.
When possible, the guilty driver's name (Unicode string) is printed on
the bugcheck screen and saved in KiBugCheckDriver.
Arguments:
Arg1: fffff9800b5ff000, memory referenced
Arg2: 0000000000000001, value 0 = read operation, 1 = write operation
Arg3: fffff88004f834eb, if non-zero, the address which referenced memory.
Arg4: 0000000000000000, (reserved)
咱們能夠調試此崩潰並肯定notmyfault.sys寫入池緩衝區以外。
調用堆棧顯示myfault.sys訪問了無效內存,這會生成頁面錯誤。
kd> k
Child-SP          RetAddr           Call Site
fffff880`04822658 fffff803`721333f1 nt!KeBugCheckEx
fffff880`04822660 fffff803`720acacb nt! ?? ::FNODOBFM::`string'+0x33c2b
fffff880`04822700 fffff803`7206feee nt!MmAccessFault+0x55b
fffff880`04822840 fffff880`04f834eb nt!KiPageFault+0x16e
fffff880`048229d0 fffff880`04f83727 myfault+0x14eb
fffff880`04822b20 fffff803`72658a4a myfault+0x1727
fffff880`04822b80 fffff803`724476c7 nt!IovCallDriver+0xba
fffff880`04822bd0 fffff803`7245c8a6 nt!IopXxxControlFile+0x7e5
fffff880`04822d60 fffff803`72071453 nt!NtDeviceIoControlFile+0x56
fffff880`04822dd0 000007fc`4fe22c5a nt!KiSystemServiceCopyEnd+0x13
00000000`004debb8 00000000`00000000 0x000007fc`4fe22c5a

 

!pool命令顯示myfault.sys引用的地址是特殊池。
kd> !pool fffff9800b5ff000
Pool page fffff9800b5ff000 region is Special pool
fffff9800b5ff000: Unable to get contents of special pool block

 

頁表條目顯示該地址無效。 這是特殊池用於捕獲溢出的防禦頁面。
kd> !pte fffff9800b5ff000
                                           VA fffff9800b5ff000
PXE at FFFFF6FB7DBEDF98    PPE at FFFFF6FB7DBF3000    PDE at FFFFF6FB7E6002D0    PTE at FFFFF6FCC005AFF8
contains 0000000001B8F863  contains 000000000138E863  contains 000000001A6A1863  contains 0000000000000000
pfn 1b8f      ---DA--KWEV  pfn 138e      ---DA--KWEV  pfn 1a6a1     ---DA--KWEV  not valid
此內存以前的分配是一個800字節的非分頁池標記爲「Wrap」。 「Wrap」是驗證程序在沒有標記的狀況下分配池時使用的標記,它至關於咱們在第1部分中看到的「None」標記。
kd> !pool fffff9800b5ff000-1000
Pool page fffff9800b5fe000 region is Special pool
*fffff9800b5fe000 size:  800 data: fffff9800b5fe800 (NonPaged) *Wrap
            Owning component : Unknown (update pooltag.txt)
特殊池是跟蹤緩衝區溢出池損壞的有效機制。 它還能夠用於捕獲其餘類型的池損壞,咱們將在之後的文章中討論。
 

Part3 Special Pool for Double Frees

在本系列的第1部分和第2部分中,咱們討論了池損壞以及如何使用特殊池來肯定此類損壞的緣由。 在這一部分中,咱們將使用特殊池來捕獲一個雙重釋放池內存。
雙重釋放池將致使系統顯示藍屏,可是由此致使的崩潰可能會有所不一樣。 在最明顯的狀況下,兩次釋放池分配的驅動程序將致使系統當即崩潰,終止碼爲C2 BAD_POOL_CALLER,第一個參數將爲7,表示「嘗試釋放已釋放的池」。 若是您遇到此類崩潰,則應在故障排除步驟列表中啓用特殊池。
BAD_POOL_CALLER (c2)
The current thread is making a bad pool request.  Typically this is at a bad IRQL level or double freeing the same allocation, etc.
Arguments:
Arg1: 0000000000000007, Attempt to free pool which was already freed
Arg2: 00000000000011c1, (reserved)
Arg3: 0000000004810007, Memory contents of the pool block
Arg4: fffffa8001b10800, Address of the block of pool being deallocated
一個不太明顯的崩潰是池已被從新申請。正如第二部分所示,池的結構使得多個驅動程序共享一個頁面。當DriverA調用ExFreePool釋放其池塊時,該塊可供其餘驅動程序使用。 若是內存管理器將此內存提供給DriverF,而後DriverA再次釋放它,則當池分配再也不包含預期數據時,DriverF中可能會發生崩潰。 對於沒有特殊池的DriverF的開發者來講,這樣的問題多是困難的。

 

特殊池將每一個驅動程序的分配放在一個單獨的內存頁中(如第2部分所述)。 當驅動程序釋放特殊池中的池塊時,將釋放整個頁面,而且對任意頁面的任何訪問都將致使當即錯誤檢查。 此外,特殊池將此頁面放在要再次使用的頁面列表的尾部。 這增長了頁面在第二次釋放時仍然可用的可能性,下降了上面顯示的DriverA / DriverF場景的可能性。
爲了驗證這種失敗,咱們將再次使用Sysinternals工具NotMyFault。 選擇「Double free」選項,而後單擊「Crash」。 極可能你會獲得上面提到的中止C2錯誤檢查。 啓用特殊池並從新啓動以得到更多信息錯誤。
verifier /flags 1 /driver myfault.sys
 
選擇啓用特殊池的「雙重免費」選項會致使如下崩潰。 錯誤檢查代碼PAGE_FAULT_IN_NONPAGED_AREA表示某些驅動程序試圖訪問無效的內存。 此無效內存是已釋放的特殊池頁面。
PAGE_FAULT_IN_NONPAGED_AREA (50)
Invalid system memory was referenced.  This cannot be protected by try-except,
it must be protected by a Probe.  Typically the address is just plain bad or it
is pointing at freed memory.
Arguments:
Arg1: fffff9800a7fe7f0, memory referenced.
Arg2: 0000000000000000, value 0 = read operation, 1 = write operation.
Arg3: fffff80060263888, If non-zero, the instruction address which referenced the bad memory address.
Arg4: 0000000000000002, (reserved)
查看調用堆棧,咱們能夠看到myfault.sys正在釋放池,ExFreePoolSanityChecks發生了致使崩潰的頁面錯誤。
kd> kn
# Child-SP          RetAddr           Call Site
00 fffff880`0419fe28 fffff800`5fd7e28a nt!DbgBreakPointWithStatus
01 fffff880`0419fe30 fffff800`5fd7d8de nt!KiBugCheckDebugBreak+0x12
02 fffff880`0419fe90 fffff800`5fc5b544 nt!KeBugCheck2+0x79f
03 fffff880`041a05b0 fffff800`5fd1c5bc nt!KeBugCheckEx+0x104
04 fffff880`041a05f0 fffff800`5fc95acb nt! ?? ::FNODOBFM::`string'+0x33e2a
05 fffff880`041a0690 fffff800`5fc58eee nt!MmAccessFault+0x55b
06 fffff880`041a07d0 fffff800`60263888 nt!KiPageFault+0x16e
07 fffff880`041a0960 fffff800`6024258c nt!ExFreePoolSanityChecks+0xe8
08 fffff880`041a09a0 fffff880`04c9b5d9 nt!VerifierExFreePoolWithTag+0x3c
09 fffff880`041a09d0 fffff880`04c9b727 myfault!MyfaultDeviceControl+0x2fd
0a fffff880`041a0b20 fffff800`60241a4a myfault!MyfaultDispatch+0xb7
0b fffff880`041a0b80 fffff800`600306c7 nt!IovCallDriver+0xba
0c fffff880`041a0bd0 fffff800`600458a6 nt!IopXxxControlFile+0x7e5
0d fffff880`041a0d60 fffff800`5fc5a453 nt!NtDeviceIoControlFile+0x56
0e fffff880`041a0dd0 000007fd`ea212c5a nt!KiSystemServiceCopyEnd+0x13
使用錯誤檢查代碼中的地址,咱們能夠看到內存其實是無效的:
kd> dd fffff9800a7fe7f0
fffff980`0a7fe7f0  ???????? ???????? ???????? ????????
fffff980`0a7fe800  ???????? ???????? ???????? ????????
fffff980`0a7fe810  ???????? ???????? ???????? ????????
fffff980`0a7fe820  ???????? ???????? ???????? ????????
fffff980`0a7fe830  ???????? ???????? ???????? ????????
fffff980`0a7fe840  ???????? ???????? ???????? ????????
fffff980`0a7fe850  ???????? ???????? ???????? ????????
fffff980`0a7fe860  ???????? ???????? ???????? ????????
    
kd> !pte fffff9800a7fe7f0
                                           VA fffff9800a7fe7f0
PXE at FFFFF6FB7DBEDF98    PPE at FFFFF6FB7DBF3000    PDE at FFFFF6FB7E600298    PTE at FFFFF6FCC0053FF0
contains 0000000002A91863  contains 0000000002A10863  contains 0000000000000000
pfn 2a91      ---DA--KWEV  pfn 2a10      ---DA--KWEV  not valid

 

到目前爲止,咱們有足夠的證據證實myfault.sys釋放了無效的內存,可是咱們怎麼知道這個內存被釋放了兩次呢? 若是有雙重釋放,咱們須要肯定對ExFreePool的第一次或第二次調用是否不正確。 爲此咱們須要肯定哪些代碼首先釋放了內存。
Driver Verifier特殊池跟蹤最後的0x10000調用以分配和釋放池。 您可使用!verifier 80命令轉儲此數據庫。 要限制數據輸出,您還能夠將此命令傳遞給您懷疑被雙重釋放的內存地址。
不要假設錯誤檢查代碼中的地址是被釋放的地址,請從調用VerifierExFreePoolWithTag的函數中獲取地址。
在上面的調用堆棧中,VerifierExFreePoolWithTag下面的調用是第9幀(從0開始計數,或者使用kn)。
kd> .frame /r 9
09 fffff880`041a09d0 fffff880`04c9b727 myfault+0x15d9
rax=0000000000000000 rbx=fffff9800a7fe800 rcx=fffff9800a7fe800
rdx=fffffa8001a37fa0 rsi=fffffa80035975e0 rdi=fffffa8003597610
rip=fffff88004c9b5d9 rsp=fffff880041a09d0 rbp=fffffa80034568d0
r8=fffff9800a7fe801  r9=fffff9800a7fe7f0 r10=fffff9800a7fe800
r11=0000000000000000 r12=0000000000000000 r13=0000000000000000
r14=fffff800600306c7 r15=fffffa8004381b80
iopl=0         nv up ei ng nz na po nc
cs=0010  ss=0018  ds=002b  es=002b  fs=0053  gs=002b             efl=00000286
myfault+0x15d9:
fffff880`04c9b5d9 eb7a            jmp     myfault+0x1655 (fffff880`04c9b655)

 

在x64系統上,第一個參數在rcx中傳遞。 下面的程序集顯示rcx源自rbx。
kd> ub fffff880`04c9b5d9
myfault+0x15ba:
fffff880`04c9b5ba ff15a80a0000    call    qword ptr [myfault+0x2068 (fffff880`04c9c068)]
fffff880`04c9b5c0 33d2            xor     edx,edx
fffff880`04c9b5c2 488bc8          mov     rcx,rax
fffff880`04c9b5c5 488bd8          mov     rbx,rax
fffff880`04c9b5c8 ff154a0a0000    call    qword ptr [myfault+0x2018 (fffff880`04c9c018)]
fffff880`04c9b5ce 33d2            xor     edx,edx
fffff880`04c9b5d0 488bcb          mov    rcx,rbx
fffff880`04c9b5d3 ff153f0a0000    call    qword ptr [myfault+0x2018 (fffff880`04c9c018)]
運行!verifier 80:rbx中的地址
kd> !verifier 80 fffff9800a7fe800
最近內核池分配和自由操做的日誌:
日誌中最多有0x10000個條目。
解析0x0000000000010000個日誌條目,搜索地址0xfffff9800a7fe800。
======================================================================
Pool block fffff9800a7fe800, Size 0000000000000800, Thread fffffa80046ce4c0
fffff80060251a32 nt!VfFreePoolNotification+0x4a
fffff8005fe736c9 nt!ExFreePool+0x595
fffff80060242597 nt!VerifierExFreePoolWithTag+0x47
fffff88004c9b5ce myfault!MyfaultDeviceControl+0x2f2
fffff88004c9b727 myfault!MyfaultDispatch+0xb7
fffff80060241a4a nt!IovCallDriver+0xba
fffff800600306c7 nt!IopXxxControlFile+0x7e5
fffff800600458a6 nt!NtDeviceIoControlFile+0x56
fffff8005fc5a453 nt!KiSystemServiceCopyEnd+0x13
======================================================================
Pool block fffff9800a7fe800, Size 0000000000000800, Thread fffffa80046ce4c0
fffff80060242a5d nt!VeAllocatePoolWithTagPriority+0x2d1
fffff8006024b20e nt!XdvExAllocatePoolInternal+0x12
fffff80060242f69 nt!VerifierExAllocatePool+0x61
fffff88004c9b5c0 myfault!MyfaultDeviceControl+0x2e4
fffff88004c9b727 myfault!MyfaultDispatch+0xb7
fffff80060241a4a nt!IovCallDriver+0xba
fffff800600306c7 nt!IopXxxControlFile+0x7e5
fffff800600458a6 nt!NtDeviceIoControlFile+0x56
fffff8005fc5a453 nt!KiSystemServiceCopyEnd+0x13

 

上面的輸出顯示由myfault.sys分配的池塊,而後由myfault.sys釋放。 若是咱們將這些信息與調用堆棧結合起來致使咱們的錯誤檢查,咱們能夠得出結論,池在MyfaultDeviceControl中在偏移量0x2f2處被釋放一次,而後在偏移量爲0x2fd的MyfaultDeviceControl中再次釋放。
如今咱們知道哪一個驅動程序致使了問題,若是這是咱們的驅動程序,咱們就知道要調查的代碼區域。
 
原文連接:
相關文章
相關標籤/搜索