XPAJ. Untersuchung eines Bootkits unter x64

Inhalt

Einleitung

Die Zahl der Bootkits steigt stetig an. Es erscheinen ganz unterschiedliche neue Bootkits – komplexe sowie simple, die ganz verschiedene Ziele verfolgen (dabei kann es sich sowohl um Rootkits als auch um Erpresser-Trojaner handeln). Die Virenschreiber schrecken auch nicht davor zurück, den Schadcode der Konkurrenz zu analysieren.

Heute lässt sich kaum ein Experte mehr von einem neuen Bootkit hinter dem Ofen hervorlocken — das Thema „Infizierung des Bootsektors“ ist ausreichend erforscht und im Internet gibt es dazu reichlich Informationen. Allerdings geriet uns nun ein überaus interessantes Exemplar in die Hände: Der Datei-Infektor Xpaj, der über die Funktionalität eines Bootkits verfügt, und der sowohl unter Windows x86 als auch unter Windows x64 funktioniert. Interessant macht ihn vor allem die Tatsache, dass er unter Windows x64 bei aktivem Schutzmechanismus Patch Guard funktioniert, indem er durch einen Kernel Hook den infizierten MBR vor Lese- und Schreibzugriffen schützt.

Im vorliegenden Artikel untersuche ich die Arbeit des Rootkits ausschließlich unter Windows 7 x64; eine Untersuchung des Rootkits unter Windows x86 wäre wenig sinnvoll, da der Funktionsalgorithmus des Rootkits in beiden Betriebssystemen nahezu identisch ist.

¿Carga de prueba?

Aus den Ergebnissen der Analyse derselben Xpaj-Modifikation durch unsere Kollegen von der Firma Symantec lassen sich folgende Schlüsse ziehen:

  • Der Datei-Infektor Xpaj infiziert keine ausführbaren 64-Bit-Module, Kernelmodus-Treiber eingeschlossen, d.h. der Virus infiziert lediglich ausführbare 32-Bit-Dateien (.exe und .dll);
  • die infizierten Dateien enthalten keinen Mechanismus zur Selbstreplikation;
  • der aus dem Kernelmodus in die 64-Bit-Anwendung eingeschleuste Code gibt nur eine Debug-Mitteilung aus und tätigt keine weitere Aktionen.

Auf der Grundlage der oben aufgezählten Fakten und der Infektionsstatistik (siehe unten) lässt sich vermuten, dass es sich bei diesem Viren-Exemplar lediglich um eine Testversion handelt. Möglicherweise wird die nächste Modifikation des Schadprogramms eine vollwertige Version sein, und vielleicht wird von den Autoren ein Mechanismus zur Infektion von ausführbaren 64-Bit-Dateien umgesetzt, darunter auch Kernelmodus-Treiber (selbstverständlich mit Deaktivierung des Mechanismus zur Prüfung von Signaturen).

Download

Wie üblich beginnt alles mit dem infizierten MBR. Die Hauptaufgabe des befallenen Master Boot Records liegt – wie in praktisch allen früheren Fällen auch – im Lesen zusätzlicher Sektoren und die Übergabe der Steuerung an diese.

In den zusätzlichen Sektoren am Ende der Festplatte sind Module enthalten, die das Bootkit je nach Bedarf lädt. Alle Module, bis auf das erste, sind mit APLib komprimiert.

Der Funktionsalgorithmus des ersten Moduls sieht folgendermaßen aus:

  • Einlesen des Original-MBR vor der Infizierung und Schreiben in den Speicher an der Stelle des infizierten MBRs;
  • Abfangen des Interrupt 13h, der für das Lesen und Schreiben der Festplattensektoren verantwortlich ist;
  • Übergabe der Steuerung an den Original-MBR.

Als Ergebnis der Übergabe der Steuerung an den Original-MBR erfolgt die weitere Initialisierung des Betriebssystems. Während der Initialisierung des Betriebssystems findet das Lesen der Kerneldatei von der Festplatte und notwendiger Komponenten statt. Während des Interrupt Hooks wartet das Bootkit auf das Einlesen der Kerneldatei, berechnet eine Kontrollsumme vom Anfang der Datei und überprüft die Inhalte einiger Header-Felder.

Für die Fortsetzung der Initialisierung des Bootkits wurde eine Methode gewählt, die der in TDL4 verwendeten sehr ähnlich ist, nur dass in diesem Fall die Kerneldatei das Ziel ist, und nicht KDCOM.DLL. Wird ein Lesevorgang der Kerneldatei entdeckt, speichert das Bootkit die ersten 0x120 Byte vom Anfang der Datei und überschreibt den Header mit seinem eigenen Code.


Abb. 1: Modifizierter Header der Kerneldatei

Daraufhin macht das Bootkit die zu exportierende Funktion MmMapIoSpace ausfindig und fängt sie mit Hilfe eines Hooks ab. Der Hook zeigt auf den Code im Dateiheader des Kernel.


Abb. 2: Abfangen der Funktion MmMapIoSpace

Der Prototyp der Funktion sieht folgendermaßen aus:

PVOID MmMapIoSpace(
IN PHYSICAL_ADDRESS PhysicalAddress,
IN SIZE_T NumberOfBytes,
IN MEMORY_CACHING_TYPE CacheType
);

Diese Funktion bildet die physikalische Adresse in den virtuellen Speicher ab. Man darf dabei nicht vergessen, dass sich das erste Modul des Bootkits zum Zeitpunkt des ersten Aufrufs dieser Funktion noch immer im physikalischen Speicher befindet.

Die weitere Initialisierung des Bootkits erfolgt nach dem Aufruf der Hook Funktion.


Abb. 3: Stapelspeicher der Aufrufe von MmMapIoSpace

Beim ersten Aufruf stellt der Code, der sich im Header der Kerneldatei befindet, die manipulierten Bytes der Funktion MmMapIoSpace wieder her und ruft die Originalfunktion auf, die die physikalische Adresse des ersten Moduls des Bootkits in den virtuellen Speicher abbildet (siehe Abb. 1 und Abb. 5) und übergibt daraufhin die Steuerung dem abgebildeten Code.


Abb. 4: Header der Kerneldatei


Abb. 5: Aufruf der Originalfunktion MmMapIoSpace und Inhalt des physischen Speichers

Die Initialisierung des Bootkits wird durch die Übergabe der Steuerung an den abgebildeten physikalischen Speicher fortgesetzt.


Abb. 6: Widergespiegelter Code

Der weitere Funktionsalgorithmus sieht folgendermaßen aus:

  • Wiederherstellung der manipulierten 0x120 Byte am Anfang der Kerneldatei;
  • Hook des Interrupts INT 0x01 (KiDebugTrapOrFault) für jeden Prozess;
  • Auffinden der exportierten Funktion ZwLoadDriver nach Hash-Summe;
  • Hook von ZwLoadDriver;
  • Auffinden der exportierten Funktion NtReadFile nach Hash-Summe;
  • Hook von NtReadFile Auffinden der exportierten Funktion NtWriteFile nach Hash-Summe;
  • Hook von NtWriteFile;
  • Beenden des Interrupt Hooks INT 0x01 (KiDebugTrapOrFault) für jeden Prozess;
  • Aufrufen von MmMapIoSpace mit den Originalparametern, d.h. Übergabe der Steuerung an den Kernel zur weiteren Initialisierung des Betriebssystems.


Abb. 7: Hook von KiDebugTrapOrFault


Abb. 8: Erstes Stadium des Abfangens von ZwLoadDriver, NtReadFile und NtWriteFile

Die weitere Initialisierung des Bootkits wird vom Hook der Funktion ZwLoadDriver übernommen, da die NtReadFile/NtWriteFile Hooks im ersten Stadium der Bootkit Aktivitäten von NtReadFile/NtWriteFile Attrappen sind, die die Steuerung an die Originalfunktionen übergeben und keine andere Funktion ausführen.


Abb. 9: Attrappe der Funktion NtReadFile

Es ist offensichtlich, dass es sich hier um einen Platzhalter handelt, in welchen später der funktionierende Code für den NtReadFile/NtWriteFile Hook geschrieben wird.

Beim ersten Aufruf der Funktion ZwLoadDriver erfolgt die weitere Initialisierung des Bootkits.

Der Funktionsalgorithmus des ZwLoadDriver Hooks sieht folgendermaßen aus:

  • Öffnen des Links «??physicaldrive0»;
  • Lesen der Sektoren des dritten Moduls von der Festplatte;
  • Entpacken von APLib;
  • Übergabe der Steuerung auf den Entry Point des dritten Moduls;
  • Aufrufen der Originalfunktion ZwLoadDriver.
Interessantes Detail: Beim Aufruf des ZwLoadDriver Hooks wird ein Flag gesetzt, welches anzeigt, dass die Funktion bereits aufgerufen wurde – noch bevor der symbolische Link «??physicaldrive0» geöffnet wird. Im Falle eines wiederholten Aufrufs des Hooks wird die Steuerung umgehend an die Originalfunktion übergeben. Dieser Link wird nur in einem bestimmten Stadium der Initialisierung des Betriebssystems angezeigt. Auf diese Weise kann man eine weitere Initialisierung des Bootkits verhindern, wenn der Aufruf von ZwLoadDriver von einem willkürlichen Treiber in einer frühen Phase des Betriebssystem-Boots gestartet wird, solange der Link im System noch nicht erstellt wurde.

Damit endet die Arbeit des ersten Moduls und die Steuerung wird an das dritte Modul übergeben, das die Initialisierung des Bootkits vollendet.


Abb. 10: Hauptfunktion des dritten Moduls

Das dritte Modul führt die folgenden Aktionen durch:

  • Laden verschiedener Einstellungen;
  • Erstellung einer Callback Funktion, welche bei einer Prozesserstellung aufgerufen wird;
  • Erstellung einer Callback Funktion, welche aufgerufen wird, wenn ein Modul in den Speicher geladen wird;Ersetzen der Attrappen von NtReadFile/NtWriteFile Hooks durch vollwertige Versionen.


Abb. 11: Vollwertiger Abfänger von NtReadFile

Vergleichen Sie den Hook der Funktion von NtReadFile auf Abbildung 11 mit dem Hook auf Abbildung 9.

Es ist offensichtlich, dass die Hooks von NtReadFile/NtWriteFile notwendig sind, um die kritischen Stellen des Bootkits vor Lese- und Schreibzugriffen zu schützen.

Callback Funktionen

Während der Initialisierung installiert das Bootkit zwei Callback Funktionen.

Die erste Funktion beendet die Prozesse von Antiviren-Produkten. Beim Aufruf der Funktion während der Erstellung eines beliebigen Prozesses im System berechnet das Bootkit die Kontrollsumme aus dem Namen des Prozesses und vergleicht sie mit seiner internen Liste von Kontrollsummen.


Abb 12: Kontrollsummen im Namen der Prozesse

Entspricht die Kontrollsumme eines Prozessnamens einer Kontrollsumme aus der Liste des Bootkits, fügt das Bootkit die Instruktion RET in den Entry Point des Prozesses ein und der Prozess wird beendet.


Abb. 13: Funktion zur Beendigung des Prozesses

Die zweite Callback Funktion wird von dem Bootkit zum Laden des Moduls ausgeführt. Sie wird dazu benutzt, den Code in verschiedene Prozesse einzuschleusen, unter anderem auch in populäre Browser. Analog nutzen die Funktionen zum Beenden eines Prozesses in dieser Funktion den Algorithmus zum Berechnen der Kontrollsumme eines Prozessnamens und zum Vergleichen mit der integrierten Kontrollsummen-Liste.


Abb. 14: Funktion zum Einschleusen des Codes

Und was ist mit Patch Guard?

Ich habe eingangs auf den Schutzmechanismus verwiesen, der in den Kernel des Betriebssystems Windows 64-Bit integriert ist. Das Ziel von Patch Guard besteht darin, eine Veränderung des Kernels des Betriebssystems und dessen kritischer Strukturen zu verhindern, wie etwa verschiedene Service Tables (SSDT, IDT, GDT), Kernelobjekte und anderer. Der Schutzmechanismus wird in einem frühen Stadium der Kernelinitialisierung aktiviert und er kontrolliert in gewissen Zeiträumen die oben beschriebenen Strukturen auf eventuelle Modifikationen. Werden Modifikationen gefunden, kommt es zu einem absichtlichen Systemabsturz. In erster Linie wurde dieser Mechanismus zu dem Zweck entwickelt, um vor Kernel-Rootkits zu schützen. Doch es gibt noch eine zweite Seite der Medaille: Viele Antiviren-Produkte und Schutzlösungen verwenden Methoden zur Kernelüberwachung für verschiedene Zwecke, unter anderem für das proaktive Schutzmodul.

Die Auseinandersetzungen zwischen Antiviren-Unternehmen und der Firma Microsoft zu diesem Thema halten bis zum heutigen Tage an. Einige sind der Meinung, dass Antiviren-Unternehmen keine undokumentierten Hooks innerhalb des System-Kernels benutzen dürfen, und man das Einschleusen von schädlichem Code in den Kernel mit anderen Methoden verhindern sollte. Andere meinen, dass Microsoft nicht den notwendigen Schutzlevel gewährleistet, und die Hooks für eine verbesserte Sicherheit des Betriebssystems notwendig sind. Wieder andere sind der Ansicht, dass das System, wenn einmal Schadcode in den Kernel gelangt ist, nicht mehr als vertrauenswürdig gilt und es sinnlos ist, solche Systeme zu desinfizieren. Alle haben auf ihre Weise Recht, doch dieses Thema möchte ich an dieser Stelle nicht weiter vertiefen.

Jeder Schutzmechanismus kann durchbrochen oder auf die eine oder andere Weise umgangen werden. Und auch Patch Guard bildet dabei keine Ausnahme. Dieser Mechanismus wurde sowohl von Drittanalysten als auch von Cyberkriminellen ausreichend unter die Lupe genommen, wobei mehrere Wege aufgedeckt wurden, diesen Schutz zu umgehen. So verwendet TDL-4 beispielsweise eine konzeptionelle Methode, die darauf hinausläuft, dass die Hook Destination dieses Rootkits schlichtweg nicht durch den Schutzmechanismus überprüft wird. Andere bekannte Mechanismen fußen auf der Modifikation des Lademechanismus und der Kerneldatei des Betriebssystems; alle bewirken, dass die Initialisierung von Patch Guard deaktiviert wird. Eine andere Methode basiert auf einer Modifikation des bereits initialisierten Kernels, die den Start des Kontrollmechanismus verhindert. Außerdem wird Patch Guard nicht initialisiert, wenn der Kernel-Debugger während des Bootens des Betriebssystems aktiviert ist (dieses Feature existiert, damit Entwickler Haltepunkte für das Debugging und das Testen ihrer Treiber nutzen können).

Xpaj ist gerade deshalb so interessant, weil dieser Schädling einen anderen konzeptionellen Ansatz zur Umgehung von Patch Guard verwendet. Eine Besonderheit von Patch Guard ist, dass es relativ spät im Bootvorgang des Betriebssystems initialisiert wird. Da Xpaj ein Bootkit ist, ist es in der Lage, jede Etappe beim Booten des Betriebssystems zu kontrollieren und den Kernel noch vor der Initialisierung des Schutzmechanismus zu modifizieren. Zum Zeitpunkt der Initialisierung enthält der Kernel bereits alle Modifikationen und Hooks von Xpaj, und anstatt diese Veränderungen zu erkennen, beginnt Patch Guard nun, sie zu schützen!

Ich habe ein kleines Experiment durchgeführt, um mich davon zu überzeugen, dass Patch Guard die Hooks von ZwLoadDriver/NtReadFile/NtWriteFile tatsächlich schützt. Zu diesem Zweck startete ich das infizierte System im Debugging-Modus, wartete den Systemboot ab, schaltete den Kernel-Debugger hinzu und stellte die modifizierten Bytes einer der gehookten Funktionen wieder her. Nach einiger Zeit stürzte das System ab. Das bedeutet, dass Patch Guard die Veränderungen des Kernel im Speicher erkannt und den Blue Screen verursacht hat.


Abb 15: Systemabsturz nach Wiederherstellung der modifzierten Funktion

Wie heißt es so schön – kein Kommentar!

Statistik

Mit Hilfe unseres Cloud-Services KSN habe ich eine Statistik zu den nachweislich mit Xpaj infizierten Master Boot Records nach Anzahl der detektierten Installer dieses Schadprogramms zusammengestellt. Am interessantesten sind dabei die Verbreitung des Bootkits nach Ländern sowie die Versionen der infizierten Betriebssysteme.


Abb. 16: Verbreitung der Installer nach Ländern


Abb. 17: Geografische Verbreitung des infizierten MBR


Abb. 18: Statistik nach infizierten Betriebssystemen

Fazit

Im Jahr 2008 erlebten wir die Renaissance einer alten Technologie – die Infektion des MBR. Seither ist recht viel Zeit vergangen. Heute sind Bootkits ein moderner Trend in der „Rootkitfabrikation“ und in näherer Zukunft wird dieser Mechanismus im Arsenal der Cyberkriminellen einen festen Platz einnehmen.

Die Infektion des Bootrecords ist eine äußerst bequeme Methode, Schadcode so früh wie möglich zu initialisieren – zudem eröffnen sich dadurch unermessliche Möglichkeiten, das Booten des Betriebssystems zu kontrollieren.

Die Betriebssysteme der Familie Windows x64 sind ein fester Bestandteil in der Betriebssystemlandschaft und daher sind Virenschreiber selbstverständlich bemüht, ihre Machwerke universell zu gestalten, um das zahlenmäßig hohe Niveau von Infektionen aufrecht zu erhalten.

Um Rootkits abzuwehren, hat Microsoft eine Reihe von Beschränkungen und neuen Technologien für Windows x64 eingeführt. Doch die Praxis zeigt, dass weder die Forderung nach gültigen Signaturen bei Kernelmodus-Treibern noch der Schutzmechanismus Patch Guard die Situation insgesamt zu verbessern vermögen. Rootkits unter 64-Bit-Betriebssystemen gab es immer, gibt es heute und wird es immer geben – und es werden immer mehr.

Ähnliche Beiträge

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.