(vt) 无限硬件中断的代码实现

简介

在学习vt时了解到无限硬件断点技术,即不依赖于dr寄存器实现硬件断点。
由于硬件断点依赖于调试寄存器 dr0-dr3,这就意味着只能设置4个硬件断点。

无限硬件断点的原理

  1. 根据目标地址计算出其PTE地址,设置PTE的 nx/xd 属性,即不可执行属性。
    (由于PTE控制着4KB物理页的属性,因此目标代码所属的整个物理页都被设置为不可执行。)
  2. 当执行流执行至目标物理页时,由于代码的不可执行属性而触发 #PF 缺页中断。
  3. 此时根据触发缺页中断的线性地址判断是否为目标地址?若是,则修改PTE的执行属性并进行事件注入至 #DB,内核异常处理函数将会将该异常派发给调试器。若不是,则仍需要修复PTE的可执行属性,置位rflags.TF以便于下条指令触发 #DB 异常被vmm接管,修复cr2并进行事件注入 #PF。
  4. 当vmm接管 #DB 异常时,判断是否为目标进程的目标线性地址,并根据情况进行分类处理。

源码实现

关键函数的源码如下:

void HandleOfInterruption()
{
    Rflags rflags = { 0 };
    VmExitInterruptInformation exit_interrupt_info = { 0 };
    ExitQualification exit_qualification = { 0 };
    IA32_DEBUGCTL_STRUCRION ia32_debugctl = { 0 };

    rflags.all = g_pGuestRegs->rflags;
    asm_vmread32(&g_vmm_handle_config.exit_instruction_length, VM_EXIT_INSTRUCTION_LEN);
    asm_vmread(&exit_qualification, EXIT_QUALIFICATION);
    asm_vmread32(&exit_interrupt_info, VM_EXIT_INTR_INFO);
    asm_vmread32(&ia32_debugctl, IA32_DEBUGCTL);

    if (exit_interrupt_info.Bits.valid)
    {
        /*
        *   中断类型: 0.外部中断, 2.nmi, 3.硬件中断, 6.软中断
        */
        switch (exit_interrupt_info.Bits.vector)
        {

        case 1:  // debug 硬件中断
        {
            // signel-step      exit_qualification.Bits.bs=true
            if (rflags.Bits.tf && !ia32_debugctl.Bits.btf)
            {
                DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[+] #DB signel-step ==> GuestRIP: 0x%p, GuestRSP: 0x%p\n", g_pGuestRegs->rip, g_pGuestRegs->rsp);

                /*
                *   是否开启无线硬件中断? 若开启则重新设置页属性nx
                */
                if (g_vmx_config.enable_unlimit_hardware_breakpoint)
                {
                    unsigned __int64 guest_cr3;
                    asm_vmread(&guest_cr3, GUEST_CR3);

                    if (directory_table_base.user_cr3 == guest_cr3 ||
                        directory_table_base.kernel_cr3 == guest_cr3)
                    {
                        SetupPteNx(g_pGuestRegs->rip, TRUE);

                        rflags.Bits.tf = FALSE;
                        asm_vmwrite(GUEST_RFLAGS, rflags.all);
                        break;
                    }
                }

                g_vmm_handle_config.Config.Bits.event_inject = TRUE;
                break;
            }

            // haredWare breakpointer
            if (!rflags.Bits.tf && (exit_qualification.all & 0xf))
            {
                DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[+] #DB hard-ware ==> GuestRIP: 0x%p, GuestRSP: 0x%p\n", g_pGuestRegs->rip, g_pGuestRegs->rsp);
                g_vmm_handle_config.Config.Bits.event_inject = TRUE;
                break;
            }

            break;
        }

        case 3:  // int3 软中断
        {
            DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[+] #BP ==> GuestRIP: 0x%p, GuestRSP: 0x%p\n", g_pGuestRegs->rip, g_pGuestRegs->rsp);
            g_vmm_handle_config.Config.Bits.event_inject = TRUE;
            break;
        }

        case 0xe:   // page_fault   软中断
        {
            unsigned __int64 guest_cr3;
            asm_vmread(&guest_cr3, GUEST_CR3);

            if (g_vmx_config .enable_unlimit_hardware_breakpoint && (
                directory_table_base.user_cr3 == guest_cr3 ||
                directory_table_base.kernel_cr3 == guest_cr3))
            {
                DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[+] #PF ==> GuestRIP: 0x%p, GuestRSP: 0x%p, fault_address: 0x%p\n", g_pGuestRegs->rip, g_pGuestRegs->rsp, exit_qualification.all);
                
                /*
                *   目标地址: 1.取消nx; 2.将异常注入给#DB;
                */
                if (exit_qualification.all == targetAddress)
                {
                    exit_interrupt_info.Bits.type = 3;
                    exit_interrupt_info.Bits.vector = 1;
                    exit_interrupt_info.Bits.error_code_valid = FALSE;
                    g_vmm_handle_config.Config.Bits.event_inject = TRUE;

                    SetupPteNx(exit_qualification.all, FALSE);
                }
                else
                {   /* 程序正常返回执行 signel-step */
                    SetupPteNx(exit_qualification.all, FALSE);
                    g_vmm_handle_config.Config.Bits.event_inject = FALSE;

                    rflags.Bits.tf = TRUE;
                    asm_vmwrite(GUEST_RFLAGS, rflags.all);
                }                
            }
            else 
            {
                asm_WriteCr2(exit_qualification.all);
                g_vmm_handle_config.Config.Bits.event_inject = TRUE;
            }

            break;
        }

        default:
            DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[+] 未处理中断 ==> type: %d, index: %d\n", exit_interrupt_info.Bits.type, exit_interrupt_info.Bits.vector);
        }

        /*
        *   事件注入
        */
        if (g_vmm_handle_config.Config.Bits.event_inject)
        {
            VmEntryInterruptionInformationField interruption_information_field = { 0 };
            interruption_information_field.Bits.valid = TRUE;
            interruption_information_field.Bits.type = exit_interrupt_info.Bits.type;
            interruption_information_field.Bits.vector = exit_interrupt_info.Bits.vector;

            if (exit_interrupt_info.Bits.error_code_valid)
            {
                UINT64 ExitInterruptErrorCode = 0;
                interruption_information_field.Bits.deliver_error_code = TRUE;
                asm_vmread(&ExitInterruptErrorCode, VM_EXIT_INTR_ERROR_CODE);
                asm_vmwrite(VM_ENTRY_EXCEPTION_ERROR_CODE, ExitInterruptErrorCode);
            }

            asm_vmwrite(VM_ENTRY_INSTRUCTION_LEN, g_vmm_handle_config.exit_instruction_length);
            asm_vmwrite(VM_ENTRY_INTR_INFO_FIELD, interruption_information_field.all);

            /*VmxProcessorBasedControls process_base;
            asm_vmread(&process_base.all, CPU_BASED_VM_EXEC_CONTROL);
            process_base.Bits.monitor_trap_flag = TRUE;
            asm_vmwrite(CPU_BASED_VM_EXEC_CONTROL, process_base.all);*/
        }
        
    }
    else
        DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[!] 无效ExitInterruptInfo.\n");

tag_ret:
    return;
}

__int64 pte_base;    // 用于线性地址与pte的转换
DirectoryTableBase directory_table_base = { 0 };
__int64* targetAddress = 0x0000000140001130;
_PsLookupProcessByProcessId WkPsLookUpProcessByProcessId;

void SetupPteNx(__int64* address, BOOLEAN setup)
{
	PHYSICAL_ADDRESS pa;
	pa.QuadPart = 0xffffffffffffffff;
	PAttachProcessStruct attach_procee = (PAttachProcessStruct)MmAllocateContiguousMemory(sizeof(AttachProcessStruct), pa);
	
	attach_procee->target_cr3 = directory_table_base.kernel_cr3;
	attach_procee->pte = (((__int64)address >> 9) & 0x7ffffffff8) + pte_base;
	attach_procee->setup = setup;

	/*
	*	切换Cr3并修改pte
	*/
	AttachProcess(attach_procee->target_cr3, &attach_procee->currect_cr3);
	memcpy(&attach_procee->pte_t, (void*)attach_procee->pte, 8);
	attach_procee->pte_t.Bits.xd = attach_procee->setup;
	memcpy((void*)attach_procee->pte, &attach_procee->pte_t, 8);
	AttachProcess(attach_procee->currect_cr3, &attach_procee->currect_cr3);

	MmFreeContiguousMemory(attach_procee);
}

void InitDirectoryTableBaseByPid(__int64 pid)
{
	PEPROCESS pEProcess;

	WkPsLookUpProcessByProcessId(pid, &pEProcess);
	directory_table_base.kernel_cr3 = *(__int64*)((__int64)pEProcess + 0x28);
	directory_table_base.user_cr3 = *(__int64*)((__int64)pEProcess + 0x280);
	ObDereferenceObject(pEProcess);
}

void UnlimitHareWareBreakpoint(int index) 
{
	UNICODE_STRING unicode_PsLookUpProcessByProcessId;
	UNICODE_STRING unicode_MiSystemFault;

	idt_hook_config.Bits.set_pte_nx = TRUE;

	// 初始化PsLookupProcessByProcessId
	RtlInitUnicodeString(&unicode_PsLookUpProcessByProcessId, L"PsLookupProcessByProcessId");
	WkPsLookUpProcessByProcessId = (_PsLookupProcessByProcessId)MmGetSystemRoutineAddress(&unicode_PsLookUpProcessByProcessId);

	pte_base = *(__int64*)((__int64)MmProtectMdlSystemAddress + 0xc9);

	InitDirectoryTableBaseByPid(3724);
	SetupPteNx(targetAddress, TRUE);
}

asm_AttachProcess	proc
	mov		rax, cr3
	mov		[rdx], rax
	mov		cr3, rcx
	ret
asm_AttachProcess	endp

效果图:
在这里插入图片描述

在这里插入图片描述


需要注意的是,我的测试环境为Windows10,单核。


参考:https://bbs.kanxue.com/thread-111149.htm

自己踩过的坑:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值