c00*_*0fd 3 virtualization vmware assembly kernel windows-kernel
当我在VMWare Workstation虚拟机中运行的Windows 7 x64的内核模式下运行以下汇编序列时:
xor eax, eax
mov ax, gs
mov gs, ax ; this instruction
Run Code Online (Sandbox Code Playgroud)
最后一条mov gs, ax指令会立即导致该VM崩溃(或可能是错误检查),并显示以下弹出消息:
发生故障导致虚拟CPU进入关闭状态.如果此故障发生在虚拟机之外,则会导致物理计算机重新启动.通过错误配置虚拟机,客户机操作系统中的错误或VMWare Workstation中的问题可以达到关闭状态.
重新加载gs寄存器会导致内核中的问题,还是虚拟化问题?
我没有看到mov英特尔手册中有关该指令的任何异常.
PS.顺便说一句,更换gs寄存器fs不会导致此错误.
编辑:回答有关GDT中段描述符状态的问题.这里是:
0: kd> r gs
gs=002b
0: kd> dg 28
P Si Gr Pr Lo
Sel Base Limit Type l ze an es ng Flags
---- ----------------- ----------------- ---------- - -- -- -- -- --------
0028 00000000`00000000 00000000`ffffffff Data RW Ac 3 Bg Pg P Nl 00000cf3
Run Code Online (Sandbox Code Playgroud)
我不确定为什么这一举动mov gs,ax会导致Windows立即出现三重故障,但很快就会导致它崩溃.在64位Windows内核中,GS段用作访问当前CPU的处理器控制区域(PCR)的指针.每个CPU具有指向不同PCR的不同GS基值.您的mov ax,gs mov gs,ax序列实际上打破了这个,因为它将GS基址的不正确值加载到描述符缓存中.
GDT实际上并不包含GS寄存器的正确基础.由于GDT只能保存32位地址,因此实际上并不用于加载GS基址.相反,IA32_GS_BASE和IA32_KERNEL_GS_BASE MSR(后者与SWAPGS指令组合)用于为GS段设置64位基址.存储在GS寄存器中的选择器值只是一个虚拟值.
因此,您的mov gs,ax指令会加载存储在GDT中的虚拟32位基值,而不是存储在IA32_GS_BASE中的64位值.这意味着GS段的基地址设置为0,而不是当前CPU的PCR地址.在加载这个不正确的GS库之后,Windows内核尝试使用GS寄存器访问PCR(使用类似指令mov rax, gs:[10])只是时间问题,并最终读取可能未映射的内存导致意外的内核页面错误和崩溃.