POOL_HEADER

Dieser Beitrag führt eine kleine, aber dennoch wichtige Struktur des Microsoft Windows NT Kernel ein, den POOL_HEADER. Mit Sicherheit werde ich in der nächsten Zeit noch häufiger auf diese Struktur zurückgreifen. Auch mein Vortrag auf der IMF 2006 ist ganz dieser Struktur gewidmet.

Die kleinste Zuordnungseinheit für Arbeistspeicher auf Hardware-Ebene ist die Seite. Gewöhnlich besteht eine Seite aus 4096 Bytes. Der Kernel und Gerätetreiber benötigen in der Regel jedoch nur weitaus kleinere Speicherblöcke. Offensichtlich würde hier sehr viel Speicher verschwendet werden.

Es gibt jedoch eine einfache Lösung für dieses problem: Der Kernel belegt einige Speicherseiten und fasst sie zu einem so genannten pool zusammen. Wann immer nun eine Routine weniger als eine Seite an Speicher anfordert, bedient der Kernel diese Anforderung aus seinem Pool. Die Granularität liegt dabei bei 32 Bytes für Windows 2000 und sogar nur 8 Bytes von XP an aufwärts.

Jeder dieser Allokationen steht ein kurzer Header voran, der über ihre Größe und den vorgeblichen Inhaber informiert. Dieser Header heißt POOL_HEADER. In Windows 2000 ist er folgendermaßen deklariert:

kd> dt _POOL_HEADER
   +0x000 PreviousSize     : UChar
   +0x001 PoolIndex        : UChar
   +0x002 PoolType         : UChar
   +0x003 BlockSize        : UChar
   +0x000 Ulong1           : Uint4B
   +0x004 ProcessBilled    : Ptr32 _EPROCESS
   +0x004 PoolTag          : Uint4B
   +0x004 AllocatorBackTraceIndex : Uint2B
   +0x006 PoolTagHash      : Uint2B

Und nun die Deklaration in Windows XP:

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

BlockSize bezeichnet die Größe der Allokation zuzüglich des Headers von 8 Bytes. Gemessen wird sie in Einheiten entsprechend der Granularität, also 8 beziehungsweise 32 Bytes. In ähnlicher Weise verweist PreviousSize auf den Anfang der davor liegenden Allokation.

Wann immer eine Routine Speicher über die Funktion ExAllocatePoolWithTag oder eine ähnliche Funktion anfordert, muss sie eine kurze kennzeichnung ("Tag") aus bis zu vier druckbaren Zeichen angeben. Diese Kennzeichnung wird im Feld PoolTag gespeichert. So nützlich dies auf den ersten Blick erscheinen mag, bedenken Sie jedoch bitte, dass hierbei keinerlei Autorisationsprüfung erfolgt. Jede Routine kann versehentlich oder um gezielt zu täuschen beliebige Kennzeichnungen angeben, auch solche, die bereits von anderen Treibern oder dem Kernel verwendet werden.

Bequem betrachten lässt sich der Inhalt eines Pools mit Microsoft Kernel-Debugger.

kd> !pool e1000000
Pool page e1000000 region is Paged pool
*e1000000 size:   48 previous size:    0  (Allocated) *MmDT
		Pooltag MmDT : Mm debug, Binary : nt!mm
 e1000048 size:   10 previous size:   48  (Free)        ...
 e1000058 size:   60 previous size:   10  (Allocated)  Dacl
 e10000b8 size:   10 previous size:   60  (Allocated)  ObNm
 e10000c8 size:   10 previous size:   10  (Free)       SeSc
 e10000d8 size:   10 previous size:   10  (Allocated)  ObDi
 e10000e8 size:   10 previous size:   10  (Allocated)  ObDi
 e10000f8 size:   10 previous size:   10  (Allocated)  ObDi
 e1000108 size:   10 previous size:   10  (Allocated)  ObDi
 e1000118 size:    8 previous size:   10  (Free)       ObNm
 e1000120 size:   10 previous size:    8  (Allocated)  ObDi
 e1000130 size:   10 previous size:   10  (Allocated)  ObDi
 e1000140 size:   20 previous size:   10  (Allocated)  ObNm
 e1000160 size:   10 previous size:   20  (Allocated)  SePa
 e1000170 size:   50 previous size:   10  (Allocated)  Obtb

Vergleichen Sie diese Auflistung bitte mit der Ansicht in einem Hex-Editor:

Pool tags sind auch im Hex-Editor deutlich zu erkennen.

Die Pool Tags sind deutlich zu erkennen, ebenso einige Strings die in den Allokationen gespeichert sind. Wenn Sie gut mit Windows' Datenstrukturen vertraut sind, dann finden Sie vielleicht auch einige Security IDs (SIDs) in dem Block mit der Kennzeichnung "Dacl".

Archiv

Impressum

Dieses Blog ist ein Projekt von:
Andreas Schuster
Im Äuelchen 45
D-53177 Bonn
impressum@forensikblog.de

Copyright © 2005-2012 by
Andreas Schuster
Alle Rechte vorbehalten.
Powered by Movable Type 5.12