使用 VMware 调试功能 观察 x86_64 虚拟机 的 特权寄存器

在misty的帮助下完成,方法是使用由VMware提供的自定义gdb命令:monitor来查看特权寄存器,如 monitor r cr3。其实叫特权寄存器并不准确,其主要包括了x86的控制寄存器和系统地址寄存器,但又没有很好的统称,故就按照其属性:只能由运行在ring0级别的特权指令来操控,统称他们为特权寄存器。查看特权寄存器的目的,是为了更彻底的理解操作系统。

查看方法

其实最早知道可以用VMware调试虚拟机的方法是方方告诉我的:

想想也对,VMware fusion / workstation 是我们最常用,最方便,x86平台的虚拟机软件了,软件方法调试x86_64系统真的只能用bochs或者qemu么?

开启调试非常简单:在目标虚拟机的vmx文件中添加开启调试的配置:

debugStub.listen.guest64 = "TRUE"
debugStub.listen.guest64.remote = "TRUE"

remote这行配置就能把端口开在0.0.0.0以便其他环境来调试,配置完成后重新启动目标虚拟机就可以在宿主机的8864端口进行gdb的连接了,不过连接上后查看全部寄存器也只能看到通用的寄存器,这显然不是我们的目标:内核级别的调试。既然都调试了一个完整的系统那肯定是希望看到全部寄存器的。

  gdb -q
(gdb) target remote :8864
Remote debugging using :8864
warning: No executable has been specified and target does not support
determining executable automatically.  Try using the "file" command.
0xffffffff81bfc71e in ?? ()
(gdb) i r
rax            0x4000              16384
rbx            0x1                 1
rcx            0xffff88822fe00000  -131382246375424
rdx            0x1                 1
rsi            0xffffffff8285a6e0  -2105170208
rdi            0xffff88810188a864  -131387318818716
rbp            0xffffffff82603d98  0xffffffff82603d98
rsp            0xffffffff82603d90  0xffffffff82603d90
r8             0xffff88810188a800  -131387318818816
r9             0x0                 0
r10            0xf                 15
r11            0xffff88822fe2af84  -131382246199420
r12            0x1                 1
r13            0xffff88810188a864  -131387318818716
r14            0xffffffff8285a760  -2105170080
r15            0x1                 1
rip            0xffffffff81bfc71e  0xffffffff81bfc71e
eflags         0x246               [ PF ZF IF ]
cs             0x10                16
ss             0x18                24
ds             0x0                 0
es             0x0                 0
fs             0x0                 0
gs             0x0                 0

最后的方法是,在gdb命令行里使用monitor命令即可:

(gdb) monitor r cr3
cr3=0x1060b6002

更多功能

这个monitor功能很强大,通过help可以发现,他不止能看特权寄存器,还能切换使用虚拟地址还是物理地址来访存:

(gdb) monitor help
Supported monitor commands:
   help
   r
   phys
   virt
Please use "monitor help <command>" to get details.
(gdb) monitor help r
Dump hidden register.  Usage: r <register name>
supported registers include:
   cr0
   cr2
   cr3
   cr4
   cs
   ss
   ds
   es
   fs
   gs
   gdtr
   idtr
   ldtr

比如我们尝试用访问bios的第一行代码的地址:0xffff0

(gdb) x /20gx 0xffff0
0xffff0:	Cannot access memory at address 0xffff0
(gdb) monitor phys
(gdb) x /20gx 0xffff0
0xffff0:	0x2f3730f000e05bea	0xa3fc0030322f3232
0x100000:	0x0000000000000000	0x0000000000000000
0x100010:	0x0000000000000000	0x0000000000000000
0x100020:	0x0000000000000000	0x0000000000000000

这句应该是个跳转,但因为gdb连接的时候以及和远程同步了指令集为x86_64,此时就无法使用set architecture i8086,来设置为16位的实模式指令来反汇编这句跳转,不过可以使用IDA动态调试来解决这个问题。

探索过程

如果使用qemu-system来进行调试,在gdb中使用i r查看全部寄存器是可以看到所有特权寄存器的:

所以开始也理所当然的认为vmware的调试也应该给我这个结果,然而是只能看到通用寄存器,但发现了用IDA作为调试器时,使用其命令r cr0的确可以看到:

于是就陷入了困惑,查也查不到,后来还怀疑是gdb没有加载对目标寄存器列表,还用IDA配置文件手动加载了一波:

  gdb -q
(gdb) set tdesc filename /Applications/IDA Pro 7.6python3/ida64.app/Contents/MacOS/cfg/amd64-avx.xml

仍然没用,还换了lldb,也没用。最后发现其实IDA的寄存器窗口也没有正常显示cr系列寄存器,而是在命令行,用IDA的gdb命令行help发现Dump hidden register。开始以为这个功能是IDA的黑魔法,但实际搜索发现,这个东西是vmware实现的:

  pwd
/Applications/VMware Fusion.app
  grep -r "Dump hidden register" ./
Binary file .//Contents/Library/vmware-vmx-debug matches
Binary file .//Contents/Library/vmware-vmx-stats matches
Binary file .//Contents/Library/vmware-vmx matches

这其实是执行gdbserver自定义命令的入口,用法如下:

所以破案了,是VMware没有给我们提供标准的寄存器查看接口。猜测原因,可能的不像QEMU做的那么模块化,每一种CPU就是一个结构体:

VMware fusion / workstation 只针对 x86/x64 平台上的三大操作系统,为了效率,底层做了各种优化:

所以可能不便于给出gdb的统一接口。

能力扩展

有了系统/内核级别的调试能力,就能明白更多,以下小节争取未来有空能单独拎出来说一下:

物理内存

内核漏洞

CTF

底层系统