Virtuelle Maschinen erkennen
Dieses Wochenende habe ich endlich mal was anderes gemacht als für DEI-Toe-Na zu entwickeln. Mein erstes selbstbestimmtes Wochenende seit Anfang Mai sozusagen. Aber obwohl, wer weiß? Vielleicht leckt der DEI ja Blut und baut das noch in DEI-Toe-Na für sein Basic Inventory ein, dann wär's ja doch wieder für DEI-Toe-Na gewesen....
Ich wollte schon länger mal Code schreiben, der halbwegs brauchbar erkennt, ob eine Maschine in einer virtualisierten Umgebung läuft. Speziell will ich erkennen, ob eine Maschine unter VMWare oder Virtual PC läuft. Auf Codeproject gibt es dazu ein schönes Sample von lallous. Es testet ob eine Maschine unter VMWare oder VPC läuft mit Hilfe einer Sequenz von Assemblerinstruktionen, die die Anwesenheit des Kommunikationskanals zwischen der Virtual Machine und ihrem Host untersucht. Bei dem Test auf VMWare wird dazu etwas an einen nichtexistierenden Port geschickt (den es aber unter VMWare gibt, zwecks Kommunikation zwischen Host und Guest) und bei dem Test auf VPC wird eine illegale Instruktion erzeugt (die es aber unter VPC gibt). In beiden Fällen wird der Code in einem SEH Frame ausgeführt und wird dabei eine Exception ausgelöst, dann läuft der Code nicht auf der jeweiligen Virtualisierungsplattform, ansonsten läuft er dort.
Das schöne an diesen Lösungen ist, daß sie nicht auf Heuristiken angewiesen sind (wie etwa Testen ob gewisse Services oder Prozesse auf der Maschine laufen, oder ob bestimmte Hardware vorhanden ist, wie etwa die VMWare NICs). Was diese Lösungen natürlich mit irgendwelchen Bastellösungen gemein hat, ist der Umstand, daß alles undokumentiert ist. Aber warum sollte beispielsweise VMWare in einer neuen Version ihrer Software das Interface zu alten VMWare-Maschinen willentlich kaputtmachen? Außerdem ganz nützlich ist, daß beide oben beschriebenen Verfahren zur Erkennung auch dann funktionieren, wenn auf den jeweiligen Systemen die spezifischen Add-Ons noch nicht installiert sind, also die "VMWare Tools" bzw. die "Virtual Machine Additions"
Zurück zu dem Beispielcode von lallous. Er ist eigentlich wirklich ganz brauchbar, zumindest funktioniert er mit VMWare Workstation 5.5.2 und mit Virtual PC2004. Die Informationen über das Backdoor-Interface von VMWare sind von Ken Kato, man findet sie hier, wo man auch sieht, daß alle Funktionen schon einige Versionen lang im Einsatz sind, ein weiterer Hinweis darauf, daß sich daran so schnell nichts ändern wird. Insbesondere interessant ist, daß man mit der Erkennung, ob VMWare läuft, auch erkennen kann, auf welchem Produkt die Maschine läuft, also ob sie auf VMWare Workstation, GSX, ESX oder was auch immer läuft. Diese Erkennung hat lallous nicht in seinem Code, also habe ich sie flugs in meinem Code nachgezogen. Außerdem läuft der Code von lallous nur auf x86, also habe ich zum ersten Mal wieder seit 15 Jahren heute etwas länger in Assembler programmiert und herausgekommen ist eine Variante in x64-Assemblercode, die auch in native x64 Code zweifelsfrei erkennt, ob die Maschine unter VMWare läuft oder nicht.
Keine Ahnung ob der Code so wirklich das Nonplusultra in x64 Assembler ist, aber er ist ja nicht wirklich allzu lang und das Exception Handling, das dem Vernehmen nach nicht ganz so trivial unter x64 ist, habe ich dem C-Compiler überlassen. Als Scratch-Register benutze ich r8, das müßte eigentlich auch OK sein, denn r8 wird normalerweise für den zweiten Parameter einer Funktion benutzt - meine hat nur einen Parameter. Ansonsten sieht der x64 Assemblercode der Variante für x86 verflucht ähnlich. Bis halt auf den Umstand, daß für x64 nicht der Stack für die Parameterübergabe an Funktionen verwendet wird, sondern ausnahmslos Register.
Übersetzt wird das Ganze mit VS6, für die native x64-Übersetzung braucht man das Windows 2003 Server SP1 PlatSDK. Sicherlich läßt sich das Ganze auch in VS2005 für x64 übersetzen, man muß eben den Pfad für den ml64.exe anpassen, der das ASM file für x64 übersetzt. Und hier kann man den ganzen Mist runterladen.
Was bleibt ist der Test von dem Ganzen unter den Serverprodukten von VMWare und dem VMWare Player und natürlich unter VPC 2007 Beta. Und wer weiss, vielleicht finde ich noch jemanden, der für mich Tests unter VPC für den Mac macht.