Virtualbox,如何将特定的CPU强制给来宾


14

我在VirtualBox,Windows 8主机中有XP来宾。来宾以透明方式显示与主机相同的处理器(i5 2500k)。但是,大多数安装程序无法识别此处理器,因此无法继续声明不支持的处理器。

有没有办法欺骗客人以为这是旧处理器?如果我记得正确,VMWare具有CPU屏蔽功能,则Virtualbox中是否有类似功能?


您正在安装什么软件来检查CPU型号?
达斯Android

Double Agent控件,Orca和Wix。这是针对我们正在尝试复兴的VB6项目的。
IUnknown

Answers:


19

VirtualBox和CPUID基础

您需要设置VBoxInternal/CPUM/HostCPUID虚拟机的额外数据。这将使VirtualBox 向来宾报告CPUID指令的自定义结果。根据EAX寄存器的值,此指令返回有关处理器的信息-如供应商,类型,系列,步进,品牌,缓存大小,功能(MMX,SSE,SSE2,PAE,HTT)等信息。更多结果捣蛋,欺骗客人的机会就越高。

您可以使用该vboxmanage setextradata命令配置虚拟机。例如,

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

当EAX设置为80000003₍₁₆₎时,将使EBX寄存器中的CPUID返回50202952₍₁₆₎。(从现在开始,十六进制数字将被写为0xNN或NNh。)

设置CPU供应商字符串

如果EAX为0(在AMD上为80000000h),则CPUID将供应商作为ASCII字符串返回给寄存器EBX,EDX,ECX(请注意顺序)。对于AMD CPU,它们如下所示:

| 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" |

(摘自AMD CPUID规范,“ CPUID Fn0000_0000_E”小节)

如果将EBX,EDX和ECX串联,则会得到AuthenticAMD

如果您拥有Bash和传统的Unix实用程序,则可以使用以下命令轻松设置供应商:

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

设置CPU品牌字符串

如果EAX为80000002h,80000003h,80000004h,则CPUID将在寄存器EAX,EBX,ECX,EDX中返回品牌字符串的16个ASCII字符,总计3 * 16 = 48个字符; 字符串以空字符结尾。请注意,此功能是奔腾4处理器引入的。这是品牌字符串在奔腾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"           |
|-----------------|-----------------|------------------|

(摘自《英特尔体系结构指令集扩展程序设计参考》的小节2.9,“ CPUID指令”,表2-30。☠为空字符(数值0)。)

如果将结果汇总在一起,将得到 Intel(R) Pentium(R) 4 CPU 1500MHz☠

如果您拥有Bash和传统的Unix实用程序,则可以使用以下命令轻松设置品牌:

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

如果具有Windows命令提示符,则可以通过运行以下命令将品牌设置为Intel(R) Core(TM)2 CPU 6600 @ 2.40 GHz1

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

计算机:Intel(R)Core(TM)2 CPU 6600 @ 2.40 GHz

1这些HostCPUID值取自VirtualBox错误报告#7865


谢谢。用VERR_CFGM_INVALID_CHILD_PATH破坏了我的VM。
本辛克莱

1
sed必须与G标志一起使用:'s/ //g'
Ben Sinclair

1
真是个好答案!随着Kaby Lake CPU的出现,由于雷德蒙德(Redmond)的某些政策不支持Windows 7上的Windows 7,这突然变得最为有趣。似乎所缺少的只是关于如何设置“ EAX = 1:处理器信息和功能位”,因为它们不是简单的字符串(仅使用CPU品牌,CPU-Z仍将CPU识别为KL);有谁知道?
sxc731

1
根据forums.virtualbox.org/viewtopic.php?f=2&t=77211#p359428,可能存在一种更好(更简洁,更受支持)的设置这些值的方法。
马克·阿默里

@MarkAmery,感谢您的链接。它对品牌来说效果很好,但对供应商来说却不那么理想,因为未在EAX寄存器中设置供应商,并且--cpuid子命令需要EAX寄存器的值。
克里斯蒂安·丘皮图

5

这是一种允许将主机CPU精确地伪装成特定CPU的方法,而不是试图猜测必要的设置。您将需要访问在该主机CPU上运行VirtualBox的计算机,以便转储其cpuid寄存器(最好选择与实际CPU作为模型的体系结构相当的体系结构)。如果您没有人,可以询问一下(例如,我在Reddit上取得了成功)。

  1. 从要模拟的CPU创建一个“模型”文件:

    vboxmanage list hostcpuids > i7_6600U
    
  2. 在目标主机上,确保要修改的虚拟机未运行;您可能需要备份以防万一。
  3. 运行以下脚本以将模型文件(i7_6600U此处)加载到VBox VM的定义中(my_vm_name此处):

    #!/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. 就是这样,您现在可以运行虚拟机并享受伪装的CPU(请注意:您只需运行一次以上脚本)。

如果您需要回滚CPU伪装,则可以vboxmanage modifyvm $vm --cpuidremove $leaf在上面的循环中使用每个叶子(man vboxmanage是您的朋友)。

这对我来说已经完美地工作了几个月,在运行VBox 5.1.22的Ubuntu 17.04主机上伪装了Kaby Lake CPU(i7_7500U)作为Skylake处理器(i7_6600U)。只要您可以为该操作系统创建与上面的little bash脚本等效的方法,该方法就可以在任何主机OS上使用。


关于“设置CPU供应商字符串”部分,我有一条评论:您必须确保将供应商名称在AMD CPU上更改为“ AuthenticAMD”,在Intel CPU上更改为“ GenuineIntel”。如果在AMD CPU上使用“ GenuineIntel”,则虚拟机很可能会损坏。
布尔

非常感谢!在我的Ryzen 7700K上,它像魅力一样工作。我使用旧的AMD Socket SF2主板,通过运行Ubuntu LiveCD,在实时环境中安装VirtualBox并运行vboxmanage命令来获取CPUID。在主机端,我安装了适用于Linux的Windows子系统,因此可以在Windows 10中运行Bash提示并运行您共享的脚本。现在,我可以欺骗Windows 7 VM,使其认为我正在运行A8-5600K。
njbair

很高兴这对您也有用!我应该澄清一下,这些都不需要Linux主机。甚至没有收集“模型”文件,它所需要的只是在该计算机上运行的VirtualBox。bash脚本可能看起来很复杂,但是它所做的只是读取模型文件中的行,跳过0000000b00000017(包括)之间的叶子,并逐个运行它们,vboxmanage modifyvm my_vm_name --cpuidset <line>因此这很容易手动完成,因为它是一次性的。
sxc731

没什么大不了的,我还是在主机上安装了WSL,而Ubuntu LiveCD只是因为它是启动旧AMD主板的最快方法。
njbair
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.