Im zweiten Teil dieser mehrteiligen Serie definierten wir den Begriff Ausführbare Datei und zeigten, was hinter Anti-Debugging steckt. Die Analyse der Malware war dynamisch, das heisst, der bösartige Code wurde effektiv ausgeführt – und das Analysesystem mit grosser Wahrscheinlichkeit infiziert. Wäre es daher nicht praktisch, die Analyse in einer virtuellen Umgebung durchzuführen? Mit einem Knopfdruck ist der saubere Zustand wieder hergestellt. Eine Idee, die auf der Hand liegt. Entsprechend haben sich die Autoren bösartiger Software dazu Gedanken gemacht und eine Technik entwickelt, diesen Umstand auszunutzen – Anti-VM: Läuft die Malware in einer virtuellen Maschine, so gehe davon aus, dass es sich um einen Malware-Analysten handelt und mache nichts böses.
Bevor wir darauf eingehen – lohnt es sich überhaupt das anzuschauen? Werden nicht bald alle Maschinen virtuell laufen? Schön möglich, aber im Moment nicht und die Anti-VM-Technik wird erstaunlich oft angewandt. Gemäss einer Untersuchung von Qualys [1] (im Jahr 2012) implementieren 90% der untersuchten Malwaresamples (4 Millionen Stück) mindestens eine Anti-Malware-Technik – mit über 80% bei weitem am häufigsten Anti-VM.

Notabene: 2.9 der 4 Millionen untersuchten Malwaresamples greifen auf eine Anti-VM-Methode namens IN zurück – weshalb wir uns in diesem Artikel hauptsächlich damit beschäftigen.
Virtuelle Maschinen unterscheiden sich von physikalischen Maschinen. Diese Unterschiede können offensichtlich sein: Installierte Software (VMware-Tools), Laufende Prozesse (vmtoolsd.exe), Herstellerkennung der (virtuellen) Netzwerkkarte (00:0c:29:xx:xx:xx), Harddisk-Bezeichnungen etc. Aber einige Unterschiede sind erst in den Tiefen des Betriebssystems zu finden. Die erste Detektion einer virtuellen Umgebung auf nicht-triviale Art wird Joanna Rutkowska von Invisible Things Lab attributiert. Ihr Code aus dem Jahr 2004 wird häufig wie folgt zitiert[2]:
int swallow_redpill () { unsigned char m[2+4], rpill[] = "\x0f\x01\x0d\x00\x00\x00\x00\xc3"; *((unsigned*)&rpill[3]) = (unsigned)m; ((void(*)())&rpill)(); return (m[5]>0xd0) ? 1 : 0; }
…auch bekannt als “Red Pill”.
Auf die Funktionsweise dieser Red Pill gehen wir hier nicht ein, weil sie ein wenig veraltet ist. Wir untersuchen dafür die oben erwähnte IN-Methode im Detail.
Computer können mit der Aussenwelt in beide Richtungen interagieren: Mausbewegungen, Mikrofone, Lautsprecher, Bildschirme etc. Diese Geräte werden an einem Anschluss (Port) angeschlossen. Die CPU hat die Möglichkeit, über den Assemblerbefehl IN Daten aus einem Port auszulesen bzw. über den Assemblerbefehl OUT Daten in einen Port zu schreiben. VMware nutzt solche Ports, um die Kommunikation zwischen dem Hostsystem und dem virtuellen System zu gewährleisten. Diesen Umstand nutzt diese Detektionsmethode aus.
Die Adresse des entsprechenden VMware-Ports ist 0x5658h. 56h 58h steht für ‘VX’ gemäss der ASCII-Tabelle und gehört in das Register EDX. Wird nun das Register EAX auf den magischen Wert 564D5868h (‘VMXh’) und das Register EBX auf einen beliebigen Wert (ausser 564D5868h) gesetzt, haben wir schon fast alles nötige vorbereitet, um unsere VM zu detektieren. Wir müssen in das Register ECX nur noch ein Backdoor-Command [3] schreiben und dann den Port auslesen. Wir wählen, wie alle anderen auch, das Backdoor-Command 0Ah, welches besagt “Gib mir den VMware Versionstyp zurück!” und bitten dann das Betriebssystem höflich, mit der Aussenwelt (sprich dem Hostsystem) Kontakt aufzunehmen.
mov EAX,564D5868h ;// EAX: Magische Zahl 564D5868h mov EBX,0h ;// EBX: Beliebiger Wert mov ECX,0Ah ;// ECX: Backdoor-Command mov EDX,5658h ;// EDX: Portadresse 5658h ('VX') IN EAX,DX ;// Aufruf des Ports und Resultat ins Register EAX cmp EBX,564D5868h ;// Ist EBX == Magische Zahl 564D5868h?
Detektion: Obwohl wir spezifiziert haben, dass das Resultat im Register EAX abgelegt werden soll, wird auch das Register EBX verändert – es wird magischerweise auf die magische Zahl gesetzt! Wenn das Register EBX der magischen Zahl entspricht, dann sind wir in einer virtuellen Maschine, ansonsten nicht. Der vollständige Code befindet sich am Ende dieses Artikels.

Können wir den Umstand, dass Anti-VM-Techniken oft eingesetzt werden, ausnutzen? Ja, warum nicht? Naiv könnte man die MAC-Adresse des eigenen PCs so ändern, dass die Herstellerkennung der von VMware entspricht (00:0c:29)? Prüft eine Malware, naiverweise, auch nur die MAC-Adresse, so wird der bösartige Code nicht ausgeführt. Natürlich kann man das besser machen – und möglicherweise wird diese Art der Immunisierung sogar von einigen Sicherheitspaketen implementiert.
In der nächsten Folge befassen wir uns mit einer Technik, welche sich Anti-Automation nennt und der automatisierten Analyse (der Massenanalyse von Malware Samples) ein Schnippchen schlägt bzw. zu schlagen versucht.
[1] http://research.dissect.pe/docs/blackhat2012-presentation.pdf
[2] http://charette.no-ip.com:81/programming/2009-12-30_Virtualization/index.html
[3] https://sites.google.com/site/chitchatvmback/backdoor
Der vollständige Code (in MASM):
.386 .model flat,stdcall option casemap:none includelib c:\masm32\lib\user32.lib includelib c:\masm32\lib\kernel32.lib MessageBoxA PROTO :DWord, :DWord, :DWord, :DWord ExitProcess PROTO :DWord ASSUME fs:nothing .data Caption db "VM Detection: IN",0 VMDetected db "Running inside a VM...",0 VMNotDetected db "Not running inside a VM...",0 ExceptionDetected db "Exception: Not running inside a VM...",0 .code start: ;// Wenn nicht VM: Exception möglich, daher Handler einrichten push exception_handler push fs:[0h] mov fs:[0h],esp ;// Die Register gemäss Dokumentation setzen und Port aufrufen mov EAX,564D5868h ;// EAX: Magische Zahl 564D5868h mov EBX,0h ;// EBX: Beliebiger Wert mov ECX,0Ah ;// ECX: Backdoor-Command mov EDX,5658h ;// EDX: Portadresse 5658h ('VX') IN EAX,DX ;// Aufruf des Ports und Resultat ins Register EAX cmp EBX,564D5868h ;// Ist EBX == Magische Zahl 564D5868h? ;// Auswertung: Wenn nein, keine virtuelle Maschine jne vm_not_detected invoke MessageBoxA,0,addr VMDetected, addr Caption,64 invoke ExitProcess, 0 vm_not_detected: invoke MessageBoxA,0,addr VMNotDetected, addr Caption,64 invoke ExitProcess, 0 exception_handler: invoke MessageBoxA,0,addr ExceptionDetected, addr Caption,64 invoke ExitProcess, 0 END start