天行健 发表于 昨天 20:07

VT无限硬件中断的代码实现

无限硬件断点的原理 :

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



页: [1]
查看完整版本: VT无限硬件中断的代码实现