Hypervisor Abyss, part 1

avril 29th, 2008 at 10:33 admin

J’ai décidé de me réveiller après avoir passé une soirée à me faire défoncer par Jean-Marie à propos d’un exploit quelque peu … défaillant. Je me rachète en commençant une série de post sur la virtualisation, sujet à la mode en ce moment. Je vous propose de découvrir comment coder votre propre petit hyperviseur, le but étant de comprendre comment fonctionne le support hardware au niveau de la virtualisation, de voir ses capacités et de les utiliser à plus ou moins bon escient. Je vais juste vous montrer comment réaliser un BluePill like sous architecture Intel en utilisant la feature VT sous 32 bits. Abyss has virtualized you !

Le concept de BluePill est simple, il consiste à utiliser le support VMX (Virtual Machine eXtensions) sous Intel ou bien SVM (Secure Virtual Machine) pour AMD pour virtualiser le système d’exploitation et ainsi ajouter une couche entre votre hardware et votre OS. Dans le cadre d’une virtualisation assistée par le processeur on parle d’une HVM (Hardware-assisted Virtual Machine), les constructeurs ont fournit ces jeux d’instructions afin de simplifier la vie des développeurs tout en améliorant les performances des produits de virtualisation.

D’abord quelques définitions, j’essaye de respecter les notations provenant des white-papers de VMWare : Un hyperviseur est un programme utilisant le support hardware pour gérer plusieurs VM (Virtual Machine) représentés par des VMM (Virtual Machine Monitor). Une VM s’exécute en mode non-root, un VMM en mode root, le HVM est, quant à lui, aussi en mode root. On peut parler aussi d’Host et de Guest, l’Host étant la machine hébergeant plusieurs Guest virtualisés.

Dans le cas présent nous avons affaire à une exception, en effet, l’Host et le Guest sont confondus. Cela veut dire que notre OS s’exécutera en mode non-root la majeure partie du temps, un passage en mode root sera requis pour gérer des cas précis, c’est à ce moment que nous pouvons contrôler son comportement. Ici l’HVM est confondu avec un VMM du fait qu’il n’existe qu’une seule VM qui est notre OS, un bel endomorphisme en tout cas :]

Le passage de l’hyperviseur à la VM s’appel VM Entry, l’inverse est nommé VM Exit. Le principe d’une machine virtuelle est là, la VM fonctionne de manière autonome sauf pour certaines opérations sensibles ou elle doit faire un VM exit pour laisser l’hyperviseur gérer la chose. L’HVM fait son boulot et rend la main à la VM avec un VM Entry, cela continue tant que l’hyperviseur décide de faire tourner la VM, s’il n’a pas crashé entre temps !

Pour commencer, il faut lire la doc, je dirais même plus, bouffer la doc ! C’est un travail assez long et fastidieux car le man Intel est super détaillé à ce sujet. On retrouve la documentation décrivant le VMX au chapitre 19 du « Intel 64 and IA-32 Architectures Software Developer’s Manual Volume 3B: System Programming Guide, Part 2« .

Dans ce premier post je vais vous montrer comment détecter si votre processeur supporte le VMX, voir si il est disponible, puis je vous montrerais comment l’initialiser.

Première étape donc : vérifier que le proco gère bien le VMX, chose simple, il suffit d’appeler l’instruction CPUID avec le registre EAX mit à 1. CPUID retourne dans ECX une structure du type :

//
// Used by the cpuid instruction when eax=1
//
typedef struct _VMX_FEATURES
{
unsigned SSE3        :1;        // SSE3 Extensions
unsigned RES1        :2;
unsigned MONITOR     :1;        // MONITOR/WAIT
unsigned DS_CPL      :1;        // CPL qualified Debug Store
unsigned VMX         :1;        // Virtual Machine Technology
unsigned RES2        :1;
unsigned EST         :1;        // Enhanced Intel© Speedstep Technology
unsigned TM2         :1;        // Thermal monitor 2
unsigned SSSE3       :1;        // SSSE3 extensions
unsigned CID         :1;        // L1 context ID
unsigned RES3        :2;
unsigned CX16        :1;        // CMPXCHG16B
unsigned xTPR        :1;        // Update control
unsigned PDCM        :1;        // Performance/Debug capability MSR
unsigned RES4        :2;
unsigned DCA         :1;
unsigned RES5        :13;
} VMX_FEATURES;

Le champ VMX (bit 5) nous indique donc si oui ou non notre CPU supporte le VMX.

Après, il se peut que le support VMX soit désactiver par votre BIOS pour le savoir il faut contrôler le MSR IA32_FEATURE_CONTROL (indice 0x3A) définit par :

typedef struct _IA32_FEATURE_CONTROL_MSR
{
unsigned Lock            :1;        // Bit 0 is the lock bit - cannot be modified once lock is set, controled by BIOS
unsigned VmxonInSmx      :1;
unsigned VmxonOutSmx     :1;
unsigned Reserved2       :29;
unsigned Reserved3       :32;
} IA32_FEATURE_CONTROL_MSR;

Le bit 0 (Lock Bit) est celui contrôler par le BIOS, le bit 1 définit si l’instruction VMXON est autorisée en mode non SMX tandis que le bit 2 définit si VMXON peut être lancée en mode SMX. Le SMX (Safer Mode eXtension) est apparu sur les processeurs Intel 64 bits et fournit un ensemble de fonctionnalité permettant d’établir un environnement protégé conçu par l’utilisateur basé sur le support VMX, il faudrait que je lise la doc pour comprendre de quoi il s’agit en détail.

VMXON est une instruction provenant du VMX, elle permet de mettre le CPU en mode « VMX Operation », l’instruction VMXON demande à ce qu’on lui fournisse un espace mémoire respectant certaines propriétés. Pour connaitre les besoins de VMXON il faut lire le MSR IA32_VMX_BASIC (0×480):

typedef struct _IA32_VMX_BASIC_MSR
{
unsigned RevId           :32;    // Bits 31..0 contain the VMCS and VMXON revision identifier
unsigned VMRegionSize    :12;    // Bits 43..32 report # of bytes for VMXON and VMCS regions
unsigned RegionClear     :1;        // Bit 44 set only if bits 32-43 are clear
unsigned Reserved1       :3;        // Undefined
unsigned PhyAddrWidth    :1;        // Physical address width for referencing VMXON, VMCS, etc.
unsigned DualMon         :1;        // Reports whether the processor supports dual-monitor
                                    // treatment of SMI and SMM
unsigned MemType         :4;        // Memory type that the processor uses to access the VMCS
unsigned VmExitReport    :1;        // Reports weather the procesor reports info in the VM-exit
                                    // instruction information field on VM exits due to execution
                                    // of the INS and OUTS instructions
unsigned Reserved2       :9;        // Undefined
} IA32_VMX_BASIC_MSR;

Des champs PhyAddrWidth et MemType de ce MSR on déduit le type et la taille de la mémoire à allouer pour VMXON. En général il suffit d’une page allouée en mémoire non caché. Heureusement le noyau nous fournit l’API MmAllocateNonCachedMemory pour allouer de la mémoire sans passer par les caches L1 ou L2.

A noter qu’il faut mettre dans les 4 premiers bytes de la VMXONRegion la valeur du RevID obtenu dans le MSR IA32_VMX_BASIC.

Avant de lancer VXMON il faut s’assurer que le bit 13 (VMXE) du registre de contrôle CR4 soit positionné à 1 sinon on aura un #UD (invalid-opcode exception, handlé par la routine KiTrap06) lorsque VMXON sera lancé. Une fois que le CPU est en mode VMX Operation il n’est plus possible de modifier ce bit. Je rappel que le rôle du CR4 est d’indiquer et de contrôler certaines extensions du CPU, il est définit par :

typedef struct _CR4_REG
{
unsigned VME        :1;            // Virtual Mode Extensions
unsigned PVI        :1;            // Protected-Mode Virtual Interrupts
unsigned TSD        :1;            // Time Stamp Disable
unsigned DE         :1;            // Debugging Extensions
unsigned PSE        :1;            // Page Size Extensions
unsigned PAE        :1;            // Physical Address Extension
unsigned MCE        :1;            // Machine-Check Enable
unsigned PGE        :1;            // Page Global Enable
unsigned PCE        :1;            // Performance-Monitoring Counter Enable
unsigned OSFXSR     :1;            // OS Support for FXSAVE/FXRSTOR
unsigned OSXMMEXCPT :1;            // OS Support for Unmasked SIMD Floating-Point Exceptions
unsigned Reserved1  :2;            //
unsigned VMXE       :1;            // Virtual Machine Extensions Enabled
unsigned Reserved2  :18;           //
} CR4_REG;

De plus, les bits 0 (PE) pour le mode protégé et 31 (PG) pour la pagination du CR0 doivent être à 1, c’est généralement déjà le cas à cause de notre OS, heureusement :=). Le PAE ne change rien dans l’activation de l’hyperviseur.

Enfin, pour lancer VMXON il faut lui donner un pointeur sur une zone de mémoire de 64 bits contenant l’adresse physique de la VMXONRegion. On fait simple en obtenant la PHYSICAL_ADDRESS de notre VMXONRegion avec MmGetPhysicalAddress puis on push sur la stack les 32 bits de poids fort d’abord puis les 32 bits de poid faible. On exécute un VMXON qword ptr [esp], on n’oublie pas de réaligner la stack et de checker le CF (bit 0) de l’EFLAGS, si il est à 1 c’est que VMXON a foiré. Hop nous avons initialisé le VMX sur le core ! \o/

La prochaine partie sera consacrée à l’initialisation de la VMCS, cette structure sert à définir l’état de l’Host et du Guest, la manière de gérer les interruptions et exceptions et plein d’autres choses.

Je fournirais le code entier de l’hyperviseur à la fin de cette série, je vous promet qu’il y aura des surprises dedans !
Get the Windows XP SP3 here !

ref :
http://ivanlef0u.fr/repo/index.php?path=./windoz/hvm

Entry Filed under: RE

7 Comments

  • 1. texane  |  avril 30th, 2008 at 12:29

    en voila une bonne initiative… on attend la suite :)
    je me permet: https://blog.kaneton.org/bin/view/Blog/Articles


  • 2. texane  |  avril 30th, 2008 at 12:32

    En passant, c’est bien le champ VMRegionSize et non PhyAddrWidth qui defini la taille de la VMCS. Width est utilise pour les acces a certains champs de la VMCS


  • 3. admin  |  avril 30th, 2008 at 12:44

    Oui pardon, erreur de ma part que je n’ai pas fait dans mon code :) Bien vu !


  • 4. nofade  |  mai 9th, 2008 at 14:02

    http://bluepillproject.org/


  • 5. Ivanlef0u’s Blog &r&hellip  |  mai 11th, 2008 at 19:56

    [...] de notre voyage dans le monde des hyperviseurs, dans la 1ère partie j’ai montré comment initialiser le support VMX sur le CPU, cette fois-ci, on passe aux [...]


  • 6. Malware :: Hiding Virtual&hellip  |  novembre 27th, 2012 at 00:19

    [...] Blog – Hypervisor Abyss (in French) :: Part 1 :: Part 2 :: Part [...]


  • 7. Monitor everything you wa&hellip  |  juin 24th, 2013 at 14:52

    [...] Abyss by @Ivanlef0u : part1, part2, [...]


Trackback this post


Calendar

novembre 2018
L Ma Me J V S D
« fév    
 1234
567891011
12131415161718
19202122232425
2627282930  

Most Recent Posts