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

14

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

Existe-t-il un moyen de tromper l'invité en lui faisant croire qu'il s'agit d'un ancien processeur? Si je me souviens bien, VMWare avait une fonction de masquage CPU, y a-t-il quelque chose de similaire dans virtualbox?

IUnknown
la source
Quel logiciel installez-vous qui vérifie le modèle de processeur?
Dark Android
Contrôles Double Agent, Orca et Wix. Il s'agit d'un projet VB6 que nous essayons de relancer.
IUnknown

Réponses:

19

Bases de VirtualBox et CPUID

Vous devez définir les VBoxInternal/CPUM/HostCPUIDextradata de la machine virtuelle. Cela fera que VirtualBox rapportera les résultats personnalisés de l' instruction CPUID à l'invité. En fonction de la valeur du registre EAX, cette instruction renvoie des informations sur le processeur - des choses comme le fournisseur, le type, la famille, la progression, la marque, la taille du cache, les fonctionnalités (MMX, SSE, SSE2, PAE, HTT), etc. vous mangle, plus les chances de tromper l'invité sont élevées.

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

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

fera CPUID retourner 50202952₍₁₆₎ dans le registre EBX, quand appelé avec EAX réglé à 80000003₍₁₆₎. (Désormais, les nombres hexadécimaux seront écrits comme 0xNN ou NNh.)

Définition de la chaîne du fournisseur de CPU

Si EAX est 0 (ou 80000000h sur AMD), CPUID renvoie le vendeur sous forme de chaîne ASCII dans les registres EBX, EDX, ECX (notez la commande). Pour un processeur AMD, ils ressemblent à ceci:

| Register | Value      | Description                    |
|----------|------------|--------------------------------|
| EBX      | 6874_7541h | The ASCII characters "h t u A" |
| ECX      | 444D_4163h | The ASCII characters "D M A c" |
| EDX      | 6974_6E65h | The ASCII characters "i t n e" |

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

Si vous concaténez EBX, EDX et ECX, vous obtiendrez AuthenticAMD.

Si vous avez Bash et les utilitaires Unix traditionnels, vous pouvez facilement définir 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, i.e.
    # 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 marque du processeur

Si EAX est 80000002h, 80000003h, 80000004h, CPUID renvoie 16 caractères ASCII de la chaîne de marque dans les registres EAX, EBX, ECX, EDX, totalisant 3 * 16 = 48 caractères; la chaîne se termine par un caractère nul . Notez que cette fonctionnalité a été introduite avec les processeurs Pentium 4. Voici à quoi peut ressembler la chaîne de marque 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 de jeu 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 définir 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, i.e.
    # value=""
    vboxmanage setextradata "$vm" $key $value
done

Si vous disposez d'une invite de commande Windows, vous pouvez définir la marque sur Intel(R) Core(TM)2 CPU 6600 @ 2.40 GHz1 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: processeur Intel (R) Core (TM) 2 6600 @ 2,40 GHz

1 Les HostCPUIDvaleurs sont extraites du rapport de bogue VirtualBox # 7865 .

Cristian Ciupitu
la source
Merci. J'ai eu ma machine virtuelle cassée avec VERR_CFGM_INVALID_CHILD_PATH.
Ben Sinclair
1
sed doit être utilisé avec le drapeau G:'s/ //g'
Ben Sinclair
1
Quelle bonne réponse! Et avec l'avènement des processeurs Kaby Lake, cela est soudainement devenu plus intéressant en raison d'une certaine politique de Redmond pour ne pas prendre en charge Windows 7 sur ceux-ci ... Il semble que tout ce qui manque soit les instructions sur la façon de définir "EAX = 1: Processor Info and Feature Bits "car ce ne sont pas de simples chaînes (avec juste la marque du CPU, CPU-Z reconnaît toujours le CPU comme KL); quelqu'un sait?
sxc731
1
Par forums.virtualbox.org/viewtopic.php?f=2&t=77211#p359428 , il peut y avoir un meilleur moyen (plus succinct, plus pris en charge) de définir ces valeurs.
Mark Amery
@MarkAmery, merci pour le lien. Cela fonctionne bien pour la marque, mais pas si bien pour le fournisseur car le fournisseur n'est pas défini dans le registre EAX et la --cpuidsous - commande nécessite une valeur pour le registre EAX.
Cristian Ciupitu
5

Voici une approche qui permet de masquer le CPU hôte avec précision en tant que 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 ce CPU hôte afin de pouvoir vider ses cpuidregistres (il est probablement préférable de choisir une architecture raisonnablement similaire à celle de votre CPU réel en tant que modèle). Si vous n'en avez pas sous la main, vous pouvez demander autour (j'ai eu du succès sur Reddit par exemple).

  1. Créez un fichier "modèle" à partir du CPU que vous souhaitez émuler:

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

    #!/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. Voilà, vous pouvez maintenant exécuter votre machine virtuelle et profiter du processeur masqué (remarque: vous n'avez besoin d'exécuter le script ci-dessus qu'une seule fois).

Si jamais vous avez besoin de restaurer la mascarade du processeur, vous pouvez l'utiliser vboxmanage modifyvm $vm --cpuidremove $leafpour chacune des feuilles de la boucle ci-dessus ( man vboxmanagec'est votre ami).

Cela fonctionne parfaitement depuis quelques mois pour moi, masquant un processeur Kaby Lake (i7_7500U) comme un Skylake (i7_6600U) sur un hôte Ubuntu 17.04 exécutant la VBox 5.1.22. L'approche devrait fonctionner sur n'importe quel système d'exploitation hôte, à condition que vous puissiez créer un équivalent du petit script bash ci-dessus pour ce système d'exploitation.

sxc731
la source
En ce qui concerne la partie "Définition de la chaîne du fournisseur de CPU", j'ai un commentaire: vous devez vous assurer de changer le nom du vendeur en "AuthenticAMD" sur le processeur AMD et "GenuineIntel" sur le processeur Intel. Si vous utilisez "GenuineIntel" sur un processeur AMD, la machine virtuelle se cassera très probablement.
abulhol
Merci beaucoup pour cela! Cela a fonctionné comme un charme sur mon Ryzen 7700K. J'ai utilisé une ancienne carte mère AMD Socket SF2 pour obtenir le CPUID en exécutant un LiveCD Ubuntu, en installant VirtualBox dans l'environnement en direct et en exécutant la commande vboxmanage. Côté hôte, j'ai installé le sous-système Windows pour Linux afin de pouvoir exécuter une invite Bash dans Windows 10 et exécuter le script que vous avez partagé. Maintenant, je peux tromper ma machine virtuelle Windows 7 en lui faisant croire que j'utilise un A8-5600K.
njbair
Heureux que cela fonctionne aussi pour vous! J'aurais dû préciser que rien de tout cela ne nécessite un hôte Linux; même pas collecter le fichier "modèle", il suffit de VirtualBox s'exécutant sur cette machine. Le script bash peut sembler compliqué, mais il ne fait que lire les lignes du fichier modèle, ignorer les feuilles entre 0000000bet 00000017(inclus) et les exécuter un par un vboxmanage modifyvm my_vm_name --cpuidset <line>afin que cela puisse facilement être fait à la main car il s'agit d'une opération unique.
sxc731
Pas de problème, j'ai quand même installé WSL sur l'ordinateur hôte, et l'Ubuntu LiveCD était simplement parce que c'était le moyen le plus rapide de faire tourner l'ancienne carte mère AMD.
njbair