Validating Pool Block Information
Kernel pool management appears to be slightly different from
usermode heap management. However, if one assumes that the only concern is dealing with
pool memory allocations which are less than PAGE_SIZE,
it is fairly similar. Each call to ExAllocatePoolWithTag()
returns a pre-buffer header as follows:
0: kd> dt _POOL_HEADER
+0x000 PreviousSize : Pos 0, 9 Bits
+0x000 PoolIndex : Pos 9, 7 Bits
+0x002 BlockSize : Pos 0, 9 Bits
+0x002 PoolType : Pos 9, 7 Bits
+0x000 Ulong1 : Uint4B
+0x004 ProcessBilled : Ptr32 _EPROCESS
+0x004 PoolTag : Uint4B
+0x004 AllocatorBackTraceIndex : Uint2B
+0x006 PoolTagHash : Uint2B
For the purposes of locating objects, the following is a
breakdown of what could be useful. Again, static refers to fields
common between similar executive objects and not all allocated
POOL_HEADER structures.
The POOL_HEADER contains several fields that appear to be common to
similar objects which could be used to further verify the likelihood of
locating an object of a specific type such as BlockSize,
PoolType, and PoolTag.
In addition to the mentioned static fields, two other fields,
PreviousSize and BlockSize, can be used to
validate that the currently assumed POOL_HEADER appears to
be a valid, allocated pool block and is in one of the pool managers
maintained link lists. PreviousSize and BlockSize
are multiples of the minimum pool alignment which is 8 bytes on a
32bit system and 16 bytes on a 64bit system. These two elements supply byte
offsets to the neighboring pool blocks.
If PreviousSize equals 0, the current POOL_HEADER
should be the first pool block in the pool's contiguous allocations.
If it is not, it should be the same as the previous
POOL_HEADERs BlockSize. The BlockSize
should never equal 0 and should always be the same as the proceeding
POOL_HEADERs PreviousSize.
The following code validates a POOL_HEADER of an allocated
pool block.
//
// Assumes BlockOffset < PAGE_SIZE
// ASSERTS Flink == Flink->Blink && Blink == Blink->Flink
//
BOOLEAN ValidatePoolBlock (
IN PPOOL_HEADER pPoolHdr,
IN VALIDATE_ADDR pValidator
) {
BOOLEAN bReturn = FALSE;
PPOOL_HEADER pPrev;
PPOOL_HEADER pNext;
pPrev = (PPOOL_HEADER)((PUCHAR)pPoolHdr
- (pPoolHdr->PreviousSize * sizeof(POOL_HEADER)));
pNext = (PPOOL_HEADER)((PUCHAR)pPoolHdr
+ (pPoolHdr->BlockSize * sizeof(POOL_HEADER)));
if
((
( pPoolHdr == pNext )
||( pValidator( pNext + sizeof(POOL_HEADER) - 1 )
&& pPoolHdr->BlockSize == pNext->PreviousSize )
)
&&
(
( pPoolHdr != pPrev )
||( pValidator( pPrev )
&& pPoolHdr->PreviousSize == pPrev->BlockSize )
))
{
bReturn = TRUE;
}
return bReturn;
}
|