Suche nach Prozessen und Threads

| 3 Kommentare

Die Suche nach variierenden Strukturen wie Prozessen und Threads ist keine einfache Aufgabe. Die Kriterien müssen sorgfältig gewählt werden. Auf der einen Seite soll der Kriteriensatz zu möglichst wenigen Fehlern erster Art führen, auf der anderen Seite dürfen aber auch keine gültigen Datenstrukturen fälschlicherweise übergangen werden. In diesem Beitrag beschreibe ich die Kriterien, die ich in PTfinder v0.2.00 implementiert habe.

Das erste Kriterium ist die Ausrichtung, oder Alignment. EPROCESS und ETHREAD Strukturen liegen in Memory Pools. Gemäß der Dokumentation zur Funktion ExAllocatePoolWithTag im Microsoft Developer Network werden Speicheranforderungen von weniger als PAGE_SIZE bytes an 8-Byte Grenzen ausgerichtet. Bei der Auswertung eines Abbildes des physischen Speichers reicht es deswegen aus, mit der Überprüfung bei jedem achten Byte aufzusetzen.

Tatsächlich gilt das sogar für gespeicherte VMware SItzungen (VMSS), mit Microsofts Debuggern erstellten vollständige Speicherabbilder und Windows Crashdumps. Die Header dieser Dateien sind selbst ein Vielfaches von 8 Byte lang, so dass sie die Suche nicht nachteilig beeinflussen. Sollte es jedoch notwendig werden, so lässt sich PTfinder mit der Option --skip auch an andere Header anpassen.

An der zu überprüfenden Dateipositon muss sich nun entweder der DISPATCHER_HEADER eines Prozesses oder eines Threads befinden. Wie bereits in dem Artikel zum Dispatcher Header gesagt, werden nur zwei Felder, nämlich Type und Size ausgewertet. Die Werte für Type haben sich dabei von Windows 2000 bis einschließlich Windows Vista nicht geändert. Size ist für einen gegebenen Type zumindest innerhalb einer Windows Version konstant. Zwei weitere Felder, Absolute und Inserted scheinen nur Nullen zu enthalten. Da ich für dieses Verhalten allerdings keine Dokumentation finden konnte, habe ich mich entschlossen, diese beiden Felder nicht in das Suchmuster einzubeziehen. Einen Anstieg von Fehlern erster Art konnte ich hierdurch nicht feststellen.

Im nächsten Schritt erfolgen noch einige weitere formale Überprüfungen. Sie basieren ebenfalls auf der DISPATCHER_HEADER Struktur, wenn auch auf anderen Typen. Wiederum erfolgt der Vergleich nur mittels der Felder Type und Size.

Für Prozesse ist ein SYNCHRONIZATION_EVENT an den Offsets 0x70, 0x13c und 0x164 erforderlich. Der erste ist nicht notwendig, sofern UniqueProcessId == 0 (das ist der Idle-Prozess). Die in diesem Artikel angegebenen Offsets beziehen sich übrigens auf Microsoft Windows 2000 Service Pack 4. Offsets für andere Versionen werde ich demnächst veröffentlichen. Einstweilen bitte ich darum, auf die zahlreichen bereits in diesem Blog veröffentlichten Beschreibungen von EPROCESS und ETHREAD Strukturen zurückzugreifen.

Bei Threads sind ein NOTIFICATION_TIMER am Offset 0x0e8 und zwei SEMAPHOREn an den Offsets 0x190 und 0x1e8 erforderlich. Letztere ist nicht erforderlich, wenn Cid.UniqueProcess == 0 (wiederum der Idle-Prozess).

Schließlich gibt es auch noch einige inhaltliche Kriterien:

Das Feld PageDirectoryBase der EPROCESS Struktur verweist auf eine Tabelle zur Umrechnung der virtuellen in physische Adressen. Wenn dieses Feld keinen gültigen Wert enthält, dann wird wahrscheinlich die gesamte EPROCESS Struktur ungültig sein. Deshalb darf PageDirectoryBase nicht Null sein. Außerdem muss das Feld genau auf den Beginn einer Speicherseite zeigen, die 4096 Bytes (0x1000 in hexadezimaler Notation) groß ist. Die zweite Bedingung lautet also PageDirectoryBase mod 0x1000 == 0.

ThreadListEntry enthält zwei Zeiger auf EPROCESS Strukturen, Flink und Blink.
Diese Zeiger enthalten virtuelle Adressen. Da die Kontrollstrukturen im Kernelspeicher liegen, muss ihre virtuelle Adresse größer als die Grenze zwischen Benutzer- und Kernelspeicher, also 0x80000000 sein (entsprechend 0xc0000000 für Systeme, die mit dem /3GB Schalter gestartet wurden).

In einer ähnlichen Weise verweist das Feld ThreadsProcess zurück auf eine EPROCESS Struktur. Auch diese Adresse muss hinter der "Grenze" im Kernelspeicher liegen. Schließlich darf die StartAddress eines Threads nicht Null sein. Beide Regeln gelten nicht für den Idle-Thread (Cid.UniqueProcess == 0).

3 Kommentare

> Wie bereits in dem Artikel zum Dispatcher Header gesagt, werden nur zwei Felder, nämlich
Type und Size ausgewertet.> Wie bereits in dem Artikel zum Dispatcher Header gesagt, werden nur zwei Felder, nämlich
Type und Size ausgewertet.

Es scheint mir gewiß daß diese zwei Felder unverändert bleiben sollen indem sie buchstäblich im Maschienencode enthält sind. Aber es ist mir nicht klar wenn sie unverändert bleiben müssen. Haben Sie irgendwo gefunden wo diese Felder angewendet sind? Was is ihre Funktion? Sind sie nur informatorisch?

Rossetoecioccolato.

Hallo RossetoeCioccolato,

vielen Dank für Ihre Frage.

In der Tat wäre die häufige Nutzung dieser Felder durch den Kernel hilfreich, zum Beispiel wie in der Routine "KeDispatcherObjectWake" in http://koders.com/c/fid617B37619EA5A2F540D239E12584A57FA2701E8B.aspx (ab Zeile 325). Aber leider zeigt der Code nicht Windows, sondern ReactOS. Im Longhorn-Kernel habe ich derartigen Code bislang noch nicht gefunden.

Ich denke, dass Windows den Typ eines Objektes auf eine andere Weise prüft (nämlich anhand eines Zeigers im _OBJECT_HEADER). Derzeit untersuche ich, ob sich hieraus ein manipulationssicherer Suchausdruck ableiten lässt. Meine Ergebnisse werde ich sobald möglich hier im Blog zur Diskussion stellen.

Viele Grüße,
Andreas Schuster

Andreas,

Der ObjektTyp-Zeiger verändert sich von Bootsitzung zur Bootsitzung. Aber binnen einer Sitzung bleibt dieser Zeiger derselbe für alle Objekte eines Types. Wenn Sie können einen Prozess und ein Thread der Bootsitzung anders finden, Sie können doch die Werte der ObjektTyp-Zeigern nützen um alle Prozessen und Threads der Bootsitzung zu finden.

Rossetoecioccolato.

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