В предыдущих 2-ух частях:
— понимание ошибки Pool Coruption часть 1 (переполнение буфера);
— понимание ошибки Pool Coruption часть 2 (переполнение буфера).
мы рассмотрели различные ошибки, связанные с работой с пулом, которые могут приводить к краху системы. Также мы рассмотрели, что их анализ и нахождение проблемного драйвера не простая задача, поэтому специалистами Microsoft была реализована утилита Driver Verifier.
В этой части мы рассмотрим проблемы в драйверах, которые приводят к синему экрану смерти и которые связаны с освобождением одного и того же участка памяти более одного раза. Если память освобождается дважды то обычно это заканчивается крахом со стоп кодом BSOD 0x000000C2 — BAD_POOL_CALLER а первый аргумент будет равен 7, что означает, что была выполнена попытка освобождения уже освобожденного пула.
Более сложным для анализа будет вариант если пул будет перемещен. Пул структурирован таким образом, что многие драйверы используют одни и те же страницы. То есть возможно ситуация когда драйвер А выполняет вызов ExFreePool и освобождает блок пула, далее этот блок пула предоставляет драйверу Б, после чего происходит повторный вызов ExFreePool в драйвере А. Как следствие, проблем возникает в драйвере Б, который ожидает работать с корректными данными в своем пуле.
Без специального пула решение такого рода проблем затруднительно. Как уже обсуждалось во второй части, каждый пул драйвера находится в отдельной странице. И когда драйвер А пытается повторно освободить память генерируется крах.
Давайте рассмотрим пример подобной ошибки. Для этого воспользуемся уже известной нам утилитой NotMyFault. Не включаем отслеживание за драйверами и выбираем опцию “Double Free”. Вот исходный код драйвера, который будет вызывать крах
VOID DoubleFree( VOID ) { PCHAR buffer = ExAllocatePool( NonPagedPool, ALLOCATION_SIZE ); ExFreePool( buffer ); ExFreePool( buffer ); }
Крэшим систему на виртуалке
Теперь давайте попытаемся выполнить анализ такого дампа.
Microsoft (R) Windows Debugger Version 6.3.9600.17298 AMD64
Copyright (c) Microsoft Corporation. All rights reserved.
Loading Dump File [C:Downloads!Mini080915-06.dmp]
Mini Kernel Dump File: Only registers and stack trace are available
************* Symbol Path validation summary **************Response Time (ms) Location
Deferred srv*C:Symbols*http://msdl.microsoft.com/download/symbols
Symbol search path is: srv*C:Symbols*http://msdl.microsoft.com/download/symbolsExecutable search path is: Windows Server 2008/Windows Vista Kernel Version 6002 (Service Pack 2) UP Free x86 compatibleProduct: WinNt, suite: TerminalServer SingleUserTSBuilt by: 6002.18005.x86fre.lh_sp2rtm.090410-1830Machine Name:Kernel base = 0x81a48000 PsLoadedModuleList = 0x81b5fc70Debug session time: Sun Aug 9 17:03:39.946 2015 (UTC + 3:00)System Uptime: 0 days 0:02:29.986Loading Kernel Symbols
.
Press ctrl-c (cdb, kd, ntsd) or ctrl-break (windbg) to abort symbol loads that take too long.
Run !sym noisy before .reload to track down problems loading symbols.
……………………………………………………..……………………………………………………….…………………….Loading User SymbolsLoading unloaded module list….******************************************************************************** ** Bugcheck Analysis ** *
*******************************************************************************
Use !analyze -v to get detailed debugging information.
BugCheck C2, {7, 110b, 9010000, 837e1008}
*** WARNING: Unable to verify timestamp for myfault.sys*** ERROR: Module load completed but symbols could not be loaded for myfault.sysGetPointerFromAddress: unable to read from 81b7f868Unable to read MiSystemVaType memory at 81b5f420
Probably caused by : myfault.sys ( myfault+6ff )
Followup: MachineOwner
———
kd> !analyze 0v******************************************************************************** ** Bugcheck Analysis ** *
*******************************************************************************
Use !analyze -v to get detailed debugging information.
BugCheck C2, {7, 110b, 9010000, 837e1008}
GetPointerFromAddress: unable to read from 81b7f868Unable to read MiSystemVaType memory at 81b5f420
Probably caused by : myfault.sys ( myfault+6ff )
Followup: MachineOwner
———
kd> !analyze -v******************************************************************************** ** Bugcheck Analysis ** *
*******************************************************************************
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: 00000007, Attempt to free pool which was already freedArg2: 0000110b, (reserved)Arg3: 09010000, Memory contents of the pool block
Arg4: 837e1008, Address of the block of pool being deallocated
Debugging Details:
——————
GetPointerFromAddress: unable to read from 81b7f868
Unable to read MiSystemVaType memory at 81b5f420
POOL_ADDRESS: GetPointerFromAddress: unable to read from 81b7f868Unable to read MiSystemVaType memory at 81b5f420
837e1008
BUGCHECK_STR: 0xc2_7
CUSTOMER_CRASH_COUNT: 6
DEFAULT_BUCKET_ID: COMMON_SYSTEM_FAULT
PROCESS_NAME: NotMyfault.exe
CURRENT_IRQL: 0
ANALYSIS_VERSION: 6.3.9600.17298 (debuggers(dbg).141024-1500) amd64fre
LAST_CONTROL_TRANSFER: from 81b35184 to 81b15b0d
STACK_TEXT: 9d579b5c 81b35184 000000c2 00000007 0000110b nt!KeBugCheckEx+0x1e9d579bd4 99d176ff 837e1008 00000000 00000000 nt!ExFreePoolWithTag+0x17fWARNING: Stack unwind information not available. Following frames may be wrong.9d579bf4 99d17b26 837aa960 00000001 00000000 myfault+0x6ff9d579c2c 81a8c976 971ff040 8588ea40 8588ea40 myfault+0xb269d579c44 81c8e6a1 837aa960 8588ea40 8588eab0 nt!IofCallDriver+0x639d579c64 81c8ee46 971ff040 837aa960 00000000 nt!IopSynchronousServiceTail+0x1d99d579d00 81c8ff10 971ff040 8588ea40 00000000 nt!IopXxxControlFile+0x6b79d579d34 81a92c7a 00000090 00000000 00000000 nt!NtDeviceIoControlFile+0x2a9d579d34 77085e74 00000090 00000000 00000000 nt!KiFastCallEntry+0x12a
000bf758 00000000 00000000 00000000 00000000 0x77085e74
STACK_COMMAND: kb
FOLLOWUP_IP: myfault+6ff
99d176ff ?? ???
SYMBOL_STACK_INDEX: 2
SYMBOL_NAME: myfault+6ff
FOLLOWUP_NAME: MachineOwner
MODULE_NAME: myfault
IMAGE_NAME: myfault.sys
DEBUG_FLR_IMAGE_TIMESTAMP: 4f806ca0
FAILURE_BUCKET_ID: 0xc2_7_myfault+6ff
BUCKET_ID: 0xc2_7_myfault+6ff
ANALYSIS_SOURCE: KM
FAILURE_ID_HASH_STRING: km:0xc2_7_myfault+6ff
FAILURE_ID_HASH: {c8b4976b-dbc5-81a2-e89d-90cb17280354}
Followup: MachineOwner
———
Как видим механизм анализа указывает на myfault.sys, но probably
Теперь включаем “особый пул” с помощью verifier
verifier /flags 1 /driver myfault.sys
Перегружаем компьютер и вновь крешим систему.
Теперь мы получаем стоп код 0x00000CC. Выполняем анализ с помощью Windbg.
Microsoft (R) Windows Debugger Version 6.3.9600.17298 AMD64 Copyright (c) Microsoft Corporation. All rights reserved. Loading Dump File [C:Downloads!Mini080915-07.dmp] Mini Kernel Dump File: Only registers and stack trace are available ************* Symbol Path validation summary ************** Response Time (ms) Location Deferred srv*C:Symbols*http://msdl.microsoft.com/download/symbols Symbol search path is: srv*C:Symbols*http://msdl.microsoft.com/download/symbols Executable search path is: Windows Server 2008/Windows Vista Kernel Version 6002 (Service Pack 2) UP Free x86 compatible Product: WinNt, suite: TerminalServer SingleUserTS Built by: 6002.18005.x86fre.lh_sp2rtm.090410-1830 Machine Name: Kernel base = 0x81a1a000 PsLoadedModuleList = 0x81b31c70 Debug session time: Sun Aug 9 17:17:38.639 2015 (UTC + 3:00) System Uptime: 0 days 0:01:39.296 Loading Kernel Symbols . Press ctrl-c (cdb, kd, ntsd) or ctrl-break (windbg) to abort symbol loads that take too long. Run !sym noisy before .reload to track down problems loading symbols. .............................................................. ................................................................ ......................... Loading User Symbols Loading unloaded module list .... ******************************************************************************* * * * Bugcheck Analysis * * * ******************************************************************************* Use !analyze -v to get detailed debugging information. BugCheck 100000CC, {9f616000, 0, 81aa51bc, 0} *** WARNING: Unable to verify timestamp for myfault.sys *** ERROR: Module load completed but symbols could not be loaded for myfault.sys Could not read faulting driver name Probably caused by : myfault.sys ( myfault+6ff ) Followup: MachineOwner --------- kd> !analyze -v ******************************************************************************* * * * Bugcheck Analysis * * * ******************************************************************************* PAGE_FAULT_IN_FREED_SPECIAL_POOL (cc) Memory was referenced after it was freed. 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: 9f616000, memory referenced Arg2: 00000000, value 0 = read operation, 1 = write operation Arg3: 81aa51bc, if non-zero, the address which referenced memory. Arg4: 00000000, Mm internal code. Debugging Details: ------------------ Could not read faulting driver name READ_ADDRESS: GetPointerFromAddress: unable to read from 81b51868 Unable to read MiSystemVaType memory at 81b31420 9f616000 FAULTING_IP: nt!MmQuerySpecialPoolBlockSize+1a 81aa51bc 8b00 mov eax,dword ptr [eax] MM_INTERNAL_CODE: 0 CUSTOMER_CRASH_COUNT: 7 DEFAULT_BUCKET_ID: COMMON_SYSTEM_FAULT BUGCHECK_STR: 0xCC PROCESS_NAME: NotMyfault.exe CURRENT_IRQL: 0 ANALYSIS_VERSION: 6.3.9600.17298 (debuggers(dbg).141024-1500) amd64fre LAST_CONTROL_TRANSFER: from 81b070e1 to 81aa51bc STACK_TEXT: 9ada9b4c 81b070e1 00000000 9f616800 81cfe195 nt!MmQuerySpecialPoolBlockSize+0x1a 9ada9bb4 9c70a6ff 9f616800 00000000 00000000 nt!ExFreePoolWithTag+0xdc WARNING: Stack unwind information not available. Following frames may be wrong. 9ada9bd4 9c70ab26 8a28e970 00000001 00000000 myfault+0x6ff 9ada9c0c 81cfc6be 8a134040 9f6aaf68 8a28e970 myfault+0xb26 9ada9c30 81a5e92d 9f6aafd8 9f6aaf68 8a134040 nt!IovCallDriver+0x23f 9ada9c44 81c606a1 8a28e970 9f6aaf68 9f6aafd8 nt!IofCallDriver+0x1b 9ada9c64 81c60e46 8a134040 8a28e970 00000000 nt!IopSynchronousServiceTail+0x1d9 9ada9d00 81c61f10 8a134040 9f6aaf68 00000000 nt!IopXxxControlFile+0x6b7 9ada9d34 81a64c7a 00000090 00000000 00000000 nt!NtDeviceIoControlFile+0x2a 9ada9d34 77275e74 00000090 00000000 00000000 nt!KiFastCallEntry+0x12a 0008f5ec 00000000 00000000 00000000 00000000 0x77275e74 STACK_COMMAND: kb FOLLOWUP_IP: myfault+6ff 9c70a6ff ?? ??? SYMBOL_STACK_INDEX: 2 SYMBOL_NAME: myfault+6ff FOLLOWUP_NAME: MachineOwner MODULE_NAME: myfault IMAGE_NAME: myfault.sys DEBUG_FLR_IMAGE_TIMESTAMP: 4f806ca0 FAILURE_BUCKET_ID: 0xCC_myfault+6ff BUCKET_ID: 0xCC_myfault+6ff ANALYSIS_SOURCE: KM FAILURE_ID_HASH_STRING: km:0xcc_myfault+6ff FAILURE_ID_HASH: {65a27173-7222-f0ba-5ad6-d0552d88cd8d} Followup: MachineOwner ---------
Теперь благодаря использованию механизма “Особый пул” мы получаем точное описание стоп кода:
PAGE_FAULT_IN_FREED_SPECIAL_POOL (cc)
Memory was referenced after it was freed.