修改 CPU 型号信息

CPUID(CPU Identification)函数是一种在 x86 架构处理器上运行的指令,用于获取处理器的详细信息。它是一种特殊指令,通过它可以查询 CPU 的制造商、型号、功能特性和支持的指令集等信息。因此,如果我们需要修改虚拟机的 CPU 相关信息,我们可以通过更改 CPUID 指令的返回值来实现。

CPUID 指令主要有标准 CPUID 功能扩展 CPUID 功能。标准 CPUID 功能使用输入值 0x000000000x000000FF(通常是 0x000000000x00000010 左右),这些功能用于获取 CPU 的基本信息。而扩展 CPUID 功能使用输入值 0x800000000x8000000FF,这些功能主要用于获取 CPU 的高级特性或特定于制造商的信息。

一、CPUID 指令

1 标准 CPUID 指令

1.1 0h:Vendor-ID(制造商 ID) 和最大标准函数数量

该函数除了返回最大标准函数数量并存储在 eax 寄存器中之外,同时还会返回制造商识别字符串并存储在 ebxedxecx 中,这三个寄存器包含的 ASCll 字符串为:GenuineIntel。

该指令返回的信息格式如下图所示:

我们可以通过下面代码来获取该信息:

#include <stdio.h>
#include <string.h>
#include <intrin.h>  // 包含对 CPUID 指令的支持

// 声明一个函数,用于调用 CPUID 指令并返回制造商名称
void GetCPUInfo(char* manufacturer, int* eax, int* ebx, int* ecx, int* edx);

int main() {
    char manufacturer[13] = { 0 }; // CPU制造商名称(最多12个字符 + 1个结束符)
    int eax, ebx, ecx, edx;

    // 调用函数获取 CPU 信息
    GetCPUInfo(manufacturer, &eax, &ebx, &ecx, &edx);

    // 打印 CPU 信息
    printf("CPUID Function 0x00000000:\n");
    printf("最大支持的函数数量 EAX: 0x%08X\n\n", eax);

    printf("CPU 制造商名称: %s\n", manufacturer);
    printf("EBX: 0x%08X\n", ebx);
    printf("ECX: 0x%08X\n", ecx);
    printf("EDX: 0x%08X\n", edx);

    return 0;
}

void GetCPUInfo(char* manufacturer, int* eax, int* ebx, int* ecx, int* edx) {
    int info[4];  // 用于存储 CPUID 返回的寄存器值

    // 调用 CPUID 指令获取最大支持的函数数量 和 CPU 制造商名称
    __cpuid(info, 0x00000000);

    // 返回最大支持的函数数量
    *eax = info[0];  

    // 将制造商名称存储到字符串中
    memcpy(manufacturer, &info[1], 4); // EBX
    memcpy(manufacturer + 4, &info[3], 4); // EDX
    memcpy(manufacturer + 8, &info[2], 4); // ECX
    manufacturer[12] = '\0'; // 添加字符串结束符

    // 调用CPUID指令获取CPU功能标志
    __cpuid(info, 0x00000001);
    *ebx = info[1];
    *ecx = info[2];
    *edx = info[3];
}

输出信息如下:

1.2 1h:特征信息

eax 被初始化为 1h 时,执行该函数会返回处理器识别信息并存储在 eaxebx 中,返回特征标志存储在 ecxedx 中,其中 eaxebx 存储 CPUID 序列号低 8 位,而 ecxedx 存储 CPUID 序列号高 8 位。

1.3 2h:缓存描述符

1.4 3h:处理器序列号

处理器序列号(PSN)只存在于 Pentium Ⅲ 处理器中。该值在 Pentium 4 和之后的处理器中是保留的。

1.5 4h:确定性缓存参数

1.6 5h:MONITOR / MWAIT 参数

1.7 6h:数字热传感器和电源管理参数

eax 被初始化为 6h 时,调用 CPUID 指令会返回数字热传感器和电源管理参数并存储在 eaxebxecxedx 寄存器中。

eax 寄存器含义如下图:

1.8 7h:结构化扩展特征标志枚举

1.9 8h:该函数保留

1.10 9h:直接缓存访问(DCA)参数

1.11 Ah:架构性能监视器特性

1.12 Bh:x2APIC 特性/处理器拓扑C

1.13 Ch:该函数保留

1.14 Dh:XSAVE 特性

2 扩展 CPUID 指令

2.1 80000000h:最大扩展函数数量

eax 被初始化为 80000000h 时,CPUID 指令将返回处理器支持的最大扩展函数号,并将其存储在 eax 中。

2.2 80000001h:扩展特征位

eax 被初始化为 80000001h 时,CPUID 指令会将扩展特征位加载到 edx 寄存器中,这个特征位表示处理器支持哪些扩展特征。

2.3 80000002h、80000003h、80000004h:处理器品牌字符串

每个函数都会返回处理器名称的 16 个 ASCll 字节并存储在 eaxebxecxedx 寄存器中,处理器名称可以通过拼接这三个函数总共返回 ASCll 字节得到,其以小端序格式返回并以 NULL 结尾,最多 48 个字符,用前导空格右对齐。除了返回处理器名称外,这三个函数还以 ASCll 字节形式返回处理器支持的最大速度。

2.4 80000005h:该函数保留

2.5 80000006h:扩展的 L2 缓存特性

该函数会返回 L2 缓存的详细信息并存储在 ecx 寄存器中,包括 L2 Cache Line Size in bytesL2 Cache AssociativityL2 Cache size described in 1-KB units

2.6 80000007h:高级电源管理

2.7 80000008h:虚拟和物理地址大小

Core SoloCore DuoCore2 Duo 处理器系列中,当 eax 被初始化为 80000008h 时,CPUID 指令将会返回支持的虚拟和物理地址大小并存储在 eax 中,其他通用寄存器中的值是保留的。这个信息对 BIOS 决定是否支持 Intel(R) 64 指令集架构是非常有用的。

二、修改 CPU 信息

通过更改虚拟机 .vmx 中的配置项,我们可以更改 CPUID 指令返回的信息,我们通过软件查看虚拟机的 CPU 型号如下图所示:

1 修改 CPU 型号

1.1 通过 vmx 文件修改 CPU 型号

通过调用 CPUID 函数的 80000002h80000003h80000004h,通过拼接其返回信息,我们可以得到 CPU 的型号信息,因此我们可以设置这三个 CPUID 函数的返回来修改虚拟机的型号。

Intel 旗下有如下 CPU 型号:
赛扬(Celeron):桌面低端
奔腾(Pentium):桌面中端(移动 + 笔记本)
酷睿 (Core):桌面高端
至强(Xeon):服务器中端
安腾(Itanium):服务器高端
凌动(Atom):移动平台

注:查看 CPU 全名:https://www.cpu7.com/cpu_list/cpu.html

以将 CPU 型号修改为 Intel(R) Core(R) I9-9900X 4.5GHz 为例,首先我们将 CPU 型号信息按四个字节拆开并转换成对应二进制:

Inte:01001001 01101110 01110100 01100101
l(R):01101100 00101000 01010010 00101001
 Cor:00100000 01000011 01101111 01110010
e(R):01100101 00101000 01010010 00101001
 I9-:00100000 01001001 00111001 00101101
9900:00111001 00111001 00110000 00110000
X 4.:01011000 00100000 00110100 00101110
5GHz:00110101 01000111 01001000 01111010

注:每个空格也算一个字符,文本到二进制的转换:http://ascii-to-binary.bchrt.com/

三个功能函数各有 eaxebxecxedx 四个寄存器,一共十六个寄存器,可以存储 48 个字节(包括结束符 NULL),每个寄存器按照小端序存储四个字节,剩余没有填充的寄存器中的字节全用 0010:000(代表空格)填充:

cpuid.80000002.eax = "0110:0101:0111:0100:0110:1110:0100:1001"
cpuid.80000002.ebx = "0010:1001:0101:0010:0010:1000:0110:1100"
cpuid.80000002.ecx = "0111:0010:0110:1111:0100:0011:0010:0000"
cpuid.80000002.edx = "0010:1001:0101:0010:0010:1000:0110:0101"
cpuid.80000003.eax = "0010:1101:0011:1001:0100:1001:0010:0000"
cpuid.80000003.ebx = "0011:0000:0011:0000:0011:1001:0011:1001"
cpuid.80000003.ecx = "0010:1110:0011:0100:0010:0000:0101:1000"
cpuid.80000003.edx = "0111:1010:0100:1000:0100:0111:0011:0101"
cpuid.80000004.eax = "0010:0000:0010:0000:0010:0000:0010:0000"
cpuid.80000004.ebx = "0010:0000:0010:0000:0010:0000:0010:0000"
cpuid.80000004.ecx = "0010:0000:0010:0000:0010:0000:0010:0000"
cpuid.80000004.edx = "0010:0000:0010:0000:0010:0000:0010:0000"

1.2 通过动态内存修改 CPU 型号

2 修改 CPU 的 CPUID

我们可以通过下面命令获取 CPUID:

注:获取 CPUID:wmic cpu get ProcessorId

Intel CPU 的前 8 个字节都为 BFEBFBFF,后 8 个字节才是 CPUID,我们可以通过修改 CPUID.1 指令的返回来修改虚拟机的 CPUID 值,其返回值中 eaxebx 代表后 8 个字节的 CPUID,ecxedx 代表 前 8 个字节,我们对其进行修改:

cpuid.1.eax = "00000000000000110000011010100001"
cpuid.1.ecx = "0--------------0----------------"
cpuid.1.ebx = "0--------------0----------------"
cpuid.1.edx = "10111111111010111111101111111111"

注:修改 eaxedxwmic cpu get ProcessorId 命令的显示就会改变,但是其实还有一组 CPUID 序列号,是隐藏在 ebxecx 中的,也需要修改。此外,开启 CPU 虚拟化后 ebx 必须设置为上面值。此处 eax 值为 000306A1edx 值为 BFEBFBFF

3 其他 CPU 信息修改

cpuid.80000000.0.ebx="0111:0101:0110:1110:0110:0101:0100:0111"
cpuid.80000000.0.ecx="0110:1100:0110:0101:0111:0100:0110:1110"
cpuid.80000000.0.edx="0100:1001:0110:0101:0110:1110:0110:1001"

cpuid.80000001.0.eax="0000:0000:0000:0000:0000:0000:0000:0000"

cpuid.6.eax = "00000000000000000000000000000000"
cpuid.6.ecx = "00000000000000000000000000000000"
posted @ 2025-07-04 16:23  lostin9772  阅读(53)  评论(0)    收藏  举报