Archive for avril, 2008

Hypervisor Abyss, part 1

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

7 comments avril 29th, 2008

Phrack 65 is out !

Le dernier Phrack vient de sortir et c’est un petit rêve pour moi qui se réalise, car oui ! Je suis dedans ! J’ai coécrit un article avec le grand mxatone. J’espère que notre travaille vous plaira et cela vous donnera un paquet d’idées pour la suite. En tout cas, personnellement, je suis assez content du paper que nous avons release, on a essayé d’innover le plus possible en plongeant au fond du système en étudiant des mécanismes peu documentés voir pas du tout en ayant pour objectif de proposer une vision nouvelle dans un discipline qui, il faut le dire, commence un peu à tourner en rond, la furtivité des rootkits en se basant sur les composants systèmes déjà disponibles et ne venez pas me parler des rootkit HVM comme BlueBill qui virtualise l’OS, ils profitent d’une feature hardware pour s’installer entre le matériel et le système pour pouvoir le contrôler.

Notre article « Stealth Hooking: another way to subvert the Windows kernel » décrit des techniques de hook extrêmement furtives dans le noyau se basant sur des éléments volatiles, donc difficilement détectable par des Anti-rootkit et autres HIPS. La première partie est basé sur la gestion des interruptions hardware par Windows, depuis l’IDT jusqu’aux DPC chargés de gérés l’I/O entre le périphérique et la mémoire. La deuxième partie décrit le fonctionnement de la kernel NonPaged pool, comprenez la gestion par l’OS de la mémoire qui ne peu être swappée, puis montre comment, en corrompant les structures de gestion de cette mémoire, contrôler différents mécanismes clés de l’OS. Pour résumer d’un coté l’article décrit un moyen de contrôle des I/O sur l’OS, de l’autre une méthode permettant de hooker des fonctions clés comme l’allocation des IRP ou bien de gérer des trigger permettant à un rk d’effectuer des opérations à un moment précis.

J’ajouterais aussi que écrire en anglais est loin d’être simple, nous remercions tout ceux qui nous ont relu et nous on aidé à rendre notre paper plus propre et plus clair :]

Nous vous souhaitons, mxatone et moi, une bonne lecture et un bon Phrack !

17 comments avril 12th, 2008


Calendar

avril 2008
L Ma Me J V S D
« mar   mai »
 123456
78910111213
14151617181920
21222324252627
282930  

Posts by Month

Posts by Category