Intel VT学习笔记(五)—— 调试技巧

Intel VT学习笔记(五)—— 调试技巧

要点回顾

上一篇中,我们主要学习了如何填写Guest state fields的各项字段,以及如何对错误码进行排查,并最终成功执行了Guest代码。

在GuestEntry中,我们通过执行VMCALL指令触发VM-Exit,而没有用INT 3指令直接中断,其中是有原因的。

在本篇,我们将解释为什么没有在GuestEntry中使用INT 3中断,以及相关的调试技巧。

INT 3失效

将GuestEntry修改为以下代码:

void __declspec(naked) GuestEntry()
{
    __asm {
        mov ax, es
        mov es, ax

        mov ax, ds
        mov ds, ax

        mov ax, fs
        mov fs, ax

        mov ax, gs
        mov gs, ax

        mov ax, ss
        mov ss, ax

        int 3
    }
}

执行结果:
在这里插入图片描述
不难发现,CPU并没有在Guest断下来,而是直接来到了Host,说明Guest在执行某行代码时抛出了VM-Exit信号。
在这里插入图片描述
此时,错误码为0x1C,查Intel手册卷3附录C能够得知含义是「Control-register accesses」,即控制寄存器访问。

那么在什么地方访问了控制寄存器呢?我们看下EIP所处的位置:
在这里插入图片描述
可以看到,是在执行INT 3中断处理程序的途中访问了Cr3寄存器,导致Guest抛出了VM-Exit信号,因此先触发了Host中的INT 3断点。

值得注意的是,当从Guest切换到Host时,权限也由VMX non-root切换到了VMX root,因此在Host中是能够正常执行INT 3的。

调试技巧

那么,如果想要在Guest中触发INT 3中断,应该怎么做呢?

本篇先记录一种最简单的方法。

步骤

  1. Guest执行INT 3指令,触发VM-Exit,进入Host
  2. 立刻保存Guest的各项状态信息。
  3. 收集错误码等重要参数
  4. 将CPU还原成Guest触发VM-Exit时的状态,继续执行INT 3后半部分
  5. 由于此时只是改变了EIP,权限不变,因此继续执行INT 3时能够成功。

当然,本篇这种方法只是饮鸩止渴,并不是一劳永逸的,但其中的思想值得参考,更加成熟的方法将在后续给出。

代码实现:

static void  VMMEntryPointEbd(void)
{
	ULONG ExitReason;

	ExitReason = Vmx_VmRead(VM_EXIT_REASON);
	Log("ExitReason", ExitReason);

	g_GuestRegs.esp = Vmx_VmRead(GUEST_RSP);
	g_GuestRegs.eip = Vmx_VmRead(GUEST_RIP);

	Log("g_GuestRegs.esp", g_GuestRegs.esp);
	Log("g_GuestRegs.eip", g_GuestRegs.eip);

	__asm
	{
		// 还原Guest状态,继续执行INT 3后半部分
		mov  eax, g_GuestRegs.eax
		mov  ecx, g_GuestRegs.ecx
		mov  edx, g_GuestRegs.edx
		mov  ebx, g_GuestRegs.ebx
		mov  esp, g_GuestRegs.esp
		mov  ebp, g_GuestRegs.ebp
		mov  esi, g_GuestRegs.esi
		mov  edi, g_GuestRegs.edi

		push g_GuestRegs.eflags
		popfd

		//此时处于VMX root权限,因此不会再次触发VM-Exit
		jmp g_GuestRegs.eip
	}
}

void __declspec(naked) VMMEntryPoint(void)
{
	__asm
	{
		//通过INT 3进来后,立刻保存Guest的状态
		mov g_GuestRegs.eax, eax
		mov g_GuestRegs.ecx, ecx
		mov g_GuestRegs.edx, edx
		mov g_GuestRegs.ebx, ebx
		mov g_GuestRegs.esp, esp
		mov g_GuestRegs.ebp, ebp
		mov g_GuestRegs.esi, esi
		mov g_GuestRegs.edi, edi

		pushfd
		pop eax
		mov g_GuestRegs.eflags, eax

		//需要设置fs和gs,否则无法正常运行
		mov ax, fs
		mov fs, ax
		mov ax, gs
		mov gs, ax
	}

	Log("VM Exit", 0);

	//尽量不要在裸函数中定义局部变量,或实现太多功能,最好封装成函数
	VMMEntryPointEbd();
}

执行结果:
在这里插入图片描述可以看到,此时,已经成功在Guest中执行INT 3并中断。
在这里插入图片描述

参考资料

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值