使用 VMware 调试功能 观察 x86_64 虚拟机 的 特权寄存器
参考:https://xuanxuanblingbling.github.io/ctf/tools/2021/10/22/vmware/
在misty的帮助下完成,方法是使用由VMware提供的自定义gdb命令:monitor来查看特权寄存器,如 monitor r cr3。其实叫特权寄存器并不准确,其主要包括了x86的控制寄存器和系统地址寄存器,但又没有很好的统称,故就按照其属性:只能由运行在ring0级别的特权指令来操控,统称他们为特权寄存器。查看特权寄存器的目的,是为了更彻底的理解操作系统。
查看方法
其实最早知道可以用VMware调试虚拟机的方法是方方告诉我的:
想想也对,VMware fusion / workstation 是我们最常用,最方便,x86平台的虚拟机软件了,软件方法调试x86_64系统真的只能用bochs或者qemu么?
- Setup - VMM debugging using VMware’s GDB stub and IDA Pro - Part 1
- VMware上进行Linux Kernel调试
- 汇编学习笔记(8)-IDA+VMware调试MBR
- 源码级调试的XNU内核
- 内核探析 之 <固件(UEFI)逆向到内核(XNU)启动高级调试>
开启调试非常简单:在目标虚拟机的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
查看全部寄存器是可以看到所有特权寄存器的:
- How to show all x86 control registers when debugging the Linux kernel in GDB through QEMU?
- Debugging with gdbserver and qemu, how to set watchpoint on a control register, cr3
所以开始也理所当然的认为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的统一接口。
能力扩展
有了系统/内核级别的调试能力,就能明白更多,以下小节争取未来有空能单独拎出来说一下:
物理内存
内核漏洞
- Linux内存管理与KSMA攻击
- 内核空间镜像攻击揭秘:ARM 硬件特性,竟能开启安卓8终端的上帝模式?
- 神秘的Linux页表隔离(PTI)补丁
- KEPLER Facilitating Control-flow Hijacking Primitive Evaluation for Linux Kernel Vulnerabilities
- Project Zero 对近几年 iOS 内核漏洞利用技术的总结
- Rootkits and Bootkits
CTF
- Linux 内核漏洞利用
- Linux Kernel Pwn 入门笔记
- CTF中的VM题目入门
- CTF中的VM题目入门(二)
- ctf 强网杯出题思路-solid_core-HijackPrctl
- Confidence2020 CTF KVM
- 【linux内核userfaultfd使用】Balsn CTF 2019 - KrazyNote