Virtualbox, comment forcer une CPU spécifique à l'invité

J'ai un invité XP dans VirtualBox, hôte Windows 8. L'invité affiche le processeur de manière transparente comme l'hôte (i5 2500k). Cependant, la plupart des installateurs ne reconnaissent pas ces processeurs et ne permettent pas de continuer à indiquer le processeur non supporté.

Existe-t-il un moyen de tromper l'invité en pensant que c'est un ancien processeur? Si je me souviens bien, VMWare avait une fonction de masquage CPU, y at-il quelque chose de similaire dans la boîte virtuelle?

Principes de base de VirtualBox et de CPUID

Vous devez définir les VBoxInternal/CPUM/HostCPUID HostCPUID de la machine virtuelle. Cela fera que VirtualBox affiche des résultats personnalisés pour l'instruction CPUID auprès de l'invité. Selon la valeur du registre EAX, cette instruction renvoie des informations sur le processeur – choses comme le fournisseur, le type, la famille, le démarrage, la marque, la taille du cache, les fonctionnalités (MMX, SSE, SSE2, PAE, HTT), etc. Plus de résultats Tu mangle, plus les chances de tromper l'invité sont élevées.

Vous pouvez utiliser la commande vboxmanage setextradata pour configurer la machine virtuelle. Par exemple,

 vboxmanage setextradata WinXP VBoxInternal/CPUM/HostCPUID/80000003/ebx 0x50202952 

Rendra le retour CPUID 50202952₍₁₆₎ dans le registre EBX, lorsqu'il sera appelé avec EAX réglé sur 80000003₍₁₆₎. (A partir de maintenant, les nombres hexadécimaux seront écrits comme 0xNN ou NNh.)

Réglage de la chaîne du fournisseur de processeur

Si EAX est 0 (ou 80000000h sur AMD), CPUID retourne le fournisseur en tant que chaîne ASCII dans les registres EBX, EDX, ECX (notez l'ordre). Pour un processeur AMD, ils ressemblent à ceci:

 | Register | Value | Description | |----------|------------|--------------------------------| | EBX | 6874_7541h | The ASCII characters "htu A" | | ECX | 444D_4163h | The ASCII characters "DMA c" | | EDX | 6974_6E65h | The ASCII characters "itne" | 

(Tiré de la spécification AMD CPUID , sous-section "CPUID Fn0000_0000_E")

Si vous concatuez EBX, EDX et ECX, vous obtiendrez AuthenticAMD .

Si vous avez Bash et les utilitaires Unix traditionnels, vous pouvez facilement configurer le fournisseur avec les commandes suivantes:

 vm='WinXP' # UUID works as well # The vendor string needs to have 12 characters! vendor='AuthenticAMD' if [ ${#vendor} -ne 12 ]; then exit 1 fi ascii2hex() { echo -n 0x; od -A n --endian little -t x4 | sed 's/ //g'; } registers=(ebx edx ecx) for (( i=0; i<${#vendor}; i+=4 )); do register=${registers[$(($i/4))]} value=`echo -n "${vendor:$i:4}" | ascii2hex` # set value to an empty string to reset the CPUID, ie # value="" for eax in 00000000 80000000; do key=VBoxInternal/CPUM/HostCPUID/${eax}/${register} vboxmanage setextradata "$vm" $key $value done done 

Définition de la chaîne de la marque CPU

Si EAX est 80000002h, 80000003h, 80000004h, CPUID renvoie 16 caractères ASCII de la chaîne de la marque dans les registres EAX, EBX, ECX, EDX, totalisant 3 * 16 = 48 caractères; La chaîne est terminée avec un caractère nul . Notez que cette fonctionnalité a été introduite avec les processeurs Pentium 4. C'est ainsi que la chaîne de la marque peut se lancer sur un processeur Pentium 4:

 | EAX Input Value | Return Values | ASCII Equivalent | |-----------------|-----------------|------------------| | 80000002h | EAX = 20202020h | " " | | | EBX = 20202020h | " " | | | ECX = 20202020h | " " | | | EDX = 6E492020h | "nI " | |-----------------|-----------------|------------------| | 80000003h | EAX = 286C6574h | "(let" | | | EBX = 50202952h | "P )R" | | | ECX = 69746E65h | "itne" | | | EDX = 52286D75h | "R(mu" | |-----------------|-----------------|------------------| | 80000004h | EAX = 20342029h | " 4 )" | | | EBX = 20555043h | " UPC" | | | ECX = 30303531h | "0051" | | | EDX = 007A484Dh | "☠zHM" | |-----------------|-----------------|------------------| 

(Tiré de la Référence de programmation des extensions d'ensemble d'instructions d'architecture Intel , sous-section 2.9, «Instruction CPUID», tableau 2-30. ☠ est le caractère nul (valeur numérique 0).)

Si vous mettez les résultats ensemble, vous obtiendrez Intel(R) Pentium(R) 4 CPU 1500MHz☠ .

Si vous avez Bash et les utilitaires Unix traditionnels, vous pouvez facilement configurer la marque avec les commandes suivantes:

 vm='WinXP' # UUID works as well # The brand string needs to have 47 characters! # The null terminator is added automatically brand=' Intel(R) Pentium(R) 4 CPU 1500MHz' if [ ${#brand} -ne 47 ]; then exit 1 fi ascii2hex() { echo -n 0x; od -A n --endian little -t x4 | sed 's/ //g'; } eax_values=(80000002 80000003 80000004) registers=(edx ecx ebx eax) for (( i=0; i<${#brand}; i+=4 )); do eax=${eax_values[$((${i} / 4 / 4))]} register=${registers[$((${i} / 4 % 4 ))]} key=VBoxInternal/CPUM/HostCPUID/${eax}/${register} value=`echo -n "${brand:$i:4}" | ascii2hex` # set value to an empty string to reset the CPUID, ie # value="" vboxmanage setextradata "$vm" $key $value done 

Si vous avez une invite de commande Windows, vous pouvez définir la marque sur Intel(R) Core(TM)2 CPU 6600 @ 2.40 GHz 1 en exécutant:

 set vm=your-vm-name-or-uuid vboxmanage setextradata %vm% VBoxInternal/CPUM/HostCPUID/80000002/eax 0x65746e49 vboxmanage setextradata %vm% VBoxInternal/CPUM/HostCPUID/80000002/ebx 0x2952286c vboxmanage setextradata %vm% VBoxInternal/CPUM/HostCPUID/80000002/ecx 0x726f4320 vboxmanage setextradata %vm% VBoxInternal/CPUM/HostCPUID/80000002/edx 0x4d542865 vboxmanage setextradata %vm% VBoxInternal/CPUM/HostCPUID/80000003/eax 0x43203229 vboxmanage setextradata %vm% VBoxInternal/CPUM/HostCPUID/80000003/ebx 0x20205550 vboxmanage setextradata %vm% VBoxInternal/CPUM/HostCPUID/80000003/ecx 0x20202020 vboxmanage setextradata %vm% VBoxInternal/CPUM/HostCPUID/80000003/edx 0x20202020 vboxmanage setextradata %vm% VBoxInternal/CPUM/HostCPUID/80000004/eax 0x30303636 vboxmanage setextradata %vm% VBoxInternal/CPUM/HostCPUID/80000004/ebx 0x20402020 vboxmanage setextradata %vm% VBoxInternal/CPUM/HostCPUID/80000004/ecx 0x30342e32 vboxmanage setextradata %vm% VBoxInternal/CPUM/HostCPUID/80000004/edx 0x007a4847 

Ordinateur: Intel (R) Core (TM) 2 CPU 6600 @ 2,40 GHz

1 Les valeurs HostCPUID ont été prises à partir du rapport de bug VirtualBox n ° 7865 .

Les instructions de Christian sont très utiles, mais il y a un problème mineur dans le script de bash "brand string". L'ordre doit être:

 registers=(eax ebx ecx edx) 

Sinon, la chaîne sera complètement désordonnée.

En ce qui concerne la partie «Réglage de la chaîne du fournisseur de processeur», j'ai un commentaire: vous devez vous assurer de changer le nom du fournisseur en «AuthenticAMD» sur AMD CPU et «GenuineIntel» sur la CPU Intel. Si vous utilisez "GenuineIntel" sur une CPU AMD, la machine virtuelle va très probablement perdre.

Voici une approche qui permet de masquer la CPU hôte précisément comme une CPU spécifique plutôt que d'essayer de deviner les paramètres nécessaires. Vous aurez besoin d'accéder à une machine exécutant VirtualBox sur cette CPU hôte afin que vous puissiez décharger ses registres de cpuid . Si vous n'en avez pas un à la main, vous pouvez demander (par exemple, j'ai eu des succès sur Reddit).

  1. Créez un fichier "modèle" à partir de la CPU que vous souhaitez imiter:

     vboxmanage list hostcpuids > i7_6600U 
  2. Sur l'hôte cible, assurez-vous que la machine virtuelle que vous souhaitez modifier ne fonctionne pas; Vous voudrez peut-être faire une sauvegarde au cas où.
  3. Exécutez le script suivant pour charger le fichier modèle ( i7_6600U ici) dans la définition de votre VBox VM ( my_vm_name ici):

     #!/bin/bash vm=my_vm_name model_file=i7_6600U egrep -e '^[[:digit:]abcdef]{8} ' $model_file | while read -r line; do leaf="0x`echo $line | cut -f1 -d' '`" # VBox doesn't like applying leaves between the below boundaries so skip those: if [[ $leaf -lt 0x0b || $leaf -gt 0x17 ]]; then echo "Applying: $line" vboxmanage modifyvm $vm --cpuidset $line fi done 
  4. C'est ça, vous pouvez maintenant exécuter votre machine virtuelle et profiter de la CPU masquée (notez: il suffit d'exécuter le script ci-dessus une fois).

Si vous avez besoin d'annuler la mascarade de l'UC, vous pouvez utiliser vboxmanage modifyvm $vm --cpuidremove $leaf pour chacune des feuilles dans la boucle ci-dessus ( man vboxmanage est votre ami).

Cela fonctionne parfaitement pendant quelques mois pour moi, masquant un Kaby Lake CPU (i7_7500U) en tant que Skylake (i7_6600U) sur un hôte Ubuntu 17.04 exécutant VBox 5.1.22. L'approche devrait fonctionner sur tout système d'exploitation hôte, pourvu que vous puissiez créer un équivalent du petit script bash ci-dessus pour ce système d'exploitation.