开始学习VT时最让我糊涂的就是: 在HyperVisor里什么可以做,什么不可以做? 比如,
能否调用Windows的内核函数, 为什么Host代码没法调试? 目前我只看了部分NewBluePill
代码,不涉及开机启动的VMM (DBVM那样的太复杂现在搞不懂呵呵).
用ProgmBoy 提供的串口代码, 其实可以在WinDbg+BOCHS环境下调试Host代码,至少在我
这里可以。这里有个前提,而且网上的一些框架也是这么做的,就是Host直接使用了Guest
的环境,包括:
- Guest的各段寄存器
- Guest的GDT/IDT
- Guest CR3 (如果在DriverEntry里打开VMX,取的就是系统进程的CR3)
这样在Host代码异常的时候(比如CC断点),异常分发过程完全是使用Guest的(前提是Guest CR3
此时可以正常访问到需要的代码和数据,要是被换出去了就完蛋),可以完成与WinDbg的通信,
也就可以调试。我以为这不能算是正常的情况,只能说是“人品”好,Windows的内核调试支持
部分可能比较独立。在Host内本来不应该使用Guest代码。
VMX与一般的保护模式Ring0相比,处于权限更高的层次,Guest执行代码时(无论在Ring0或是
Ring3),因触发某个预先设置的条件陷入VMX,此时Guest处于冻结状态,控制转移到Host。
Host是独立于操作系统之外的,不应依赖Guest代码,这就象驱动出了异常,不能指望应用层
代码来解决。举个例子,如果陷入VMX时,Guest代码所在的函数持有某个锁,然后Host代码
异常,如果用Guest的异常处理又要请求这个锁会怎么样? 所以我的结论是就不要调用Guest函数。
真要解决调试Host的问题,Host应该使用自己的GDT/IDT/CR3...总之就是不借用Guest的任何东西,
自己实现异常分发/与WinDbg通信等等。甚至可以实现自己的SEH机制。当然这是纸上谈兵,这么做
工作量太大。NewBluePill也只是凑合了一下,在自己的IDT Handler里输出调试信息帮助排错而已。
Host用自己的CR3后,若要访问Guest内存,则需要自己解析Guest CR3,映射到Host虚拟地址访问,
NewBluePill里的所谓SparePage就是拿来干这个的。若此时对应的内存被换出去了,我不知道
如何处理,大概只有放弃当前操作(可以注入#PF,但当前代码总不能在Host里等,只有先Resume
让windows去处理)? 这个搞不懂请大牛指点。
另外,使用私有CR3,很多事情得自己做,比如memset,NewBluePill就自己搞了一个:
void vmm_memset(void *s, int c, unsigned int n)
{
unsigned char *p;
unsigned int i;
p = (unsigned char*) s;
for (i=0; i<n; i++) {
p[i] = (unsigned char) c;
}
}
如果Free Build注意对这些函数关闭优化,VC编译器很是智能,居然把对此函数的调用换成了ntoskrnl!_memset。
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!