我爱代码 - 专业游戏安全与逆向论坛

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 2308|回复: 0

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

[复制链接]

2382

主题

53

回帖

9151

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
9151
QQ
发表于 2025-2-3 18:56:46 | 显示全部楼层 |阅读模式

想要查看内容赶紧注册登陆吧!

您需要 登录 才可以下载或查看,没有账号?立即注册

x
简介

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

无限硬件断点的原理 :

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

关键函数的源码如下:

  1. void HandleOfInterruption()
  2. {
  3.     Rflags rflags = { 0 };
  4.     VmExitInterruptInformation exit_interrupt_info = { 0 };
  5.     ExitQualification exit_qualification = { 0 };
  6.     IA32_DEBUGCTL_STRUCRION ia32_debugctl = { 0 };

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

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

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

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

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

  36.                         rflags.Bits.tf = FALSE;
  37.                         asm_vmwrite(GUEST_RFLAGS, rflags.all);
  38.                         break;
  39.                     }
  40.                 }

  41.                 g_vmm_handle_config.Config.Bits.event_inject = TRUE;
  42.                 break;
  43.             }

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

  51.             break;
  52.         }

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

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

  63.             if (g_vmx_config .enable_unlimit_hardware_breakpoint && (
  64.                 directory_table_base.user_cr3 == guest_cr3 ||
  65.                 directory_table_base.kernel_cr3 == guest_cr3))
  66.             {
  67.                 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);
  68.                
  69.                 /*
  70.                 *   目标地址: 1.取消nx; 2.将异常注入给#DB;
  71.                 */
  72.                 if (exit_qualification.all == targetAddress)
  73.                 {
  74.                     exit_interrupt_info.Bits.type = 3;
  75.                     exit_interrupt_info.Bits.vector = 1;
  76.                     exit_interrupt_info.Bits.error_code_valid = FALSE;
  77.                     g_vmm_handle_config.Config.Bits.event_inject = TRUE;

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

  84.                     rflags.Bits.tf = TRUE;
  85.                     asm_vmwrite(GUEST_RFLAGS, rflags.all);
  86.                 }               
  87.             }
  88.             else
  89.             {
  90.                 asm_WriteCr2(exit_qualification.all);
  91.                 g_vmm_handle_config.Config.Bits.event_inject = TRUE;
  92.             }

  93.             break;
  94.         }

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

  98.         /*
  99.         *   事件注入
  100.         */
  101.         if (g_vmm_handle_config.Config.Bits.event_inject)
  102.         {
  103.             VmEntryInterruptionInformationField interruption_information_field = { 0 };
  104.             interruption_information_field.Bits.valid = TRUE;
  105.             interruption_information_field.Bits.type = exit_interrupt_info.Bits.type;
  106.             interruption_information_field.Bits.vector = exit_interrupt_info.Bits.vector;

  107.             if (exit_interrupt_info.Bits.error_code_valid)
  108.             {
  109.                 UINT64 ExitInterruptErrorCode = 0;
  110.                 interruption_information_field.Bits.deliver_error_code = TRUE;
  111.                 asm_vmread(&ExitInterruptErrorCode, VM_EXIT_INTR_ERROR_CODE);
  112.                 asm_vmwrite(VM_ENTRY_EXCEPTION_ERROR_CODE, ExitInterruptErrorCode);
  113.             }

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

  116.             /*VmxProcessorBasedControls process_base;
  117.             asm_vmread(&process_base.all, CPU_BASED_VM_EXEC_CONTROL);
  118.             process_base.Bits.monitor_trap_flag = TRUE;
  119.             asm_vmwrite(CPU_BASED_VM_EXEC_CONTROL, process_base.all);*/
  120.         }
  121.         
  122.     }
  123.     else
  124.         DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[!] 无效ExitInterruptInfo.\n");

  125. tag_ret:
  126.     return;
  127. }

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

  132. void SetupPteNx(__int64* address, BOOLEAN setup)
  133. {
  134.         PHYSICAL_ADDRESS pa;
  135.         pa.QuadPart = 0xffffffffffffffff;
  136.         PAttachProcessStruct attach_procee = (PAttachProcessStruct)MmAllocateContiguousMemory(sizeof(AttachProcessStruct), pa);
  137.         
  138.         attach_procee->target_cr3 = directory_table_base.kernel_cr3;
  139.         attach_procee->pte = (((__int64)address >> 9) & 0x7ffffffff8) + pte_base;
  140.         attach_procee->setup = setup;

  141.         /*
  142.         *        切换Cr3并修改pte
  143.         */
  144.         AttachProcess(attach_procee->target_cr3, &attach_procee->currect_cr3);
  145.         memcpy(&attach_procee->pte_t, (void*)attach_procee->pte, 8);
  146.         attach_procee->pte_t.Bits.xd = attach_procee->setup;
  147.         memcpy((void*)attach_procee->pte, &attach_procee->pte_t, 8);
  148.         AttachProcess(attach_procee->currect_cr3, &attach_procee->currect_cr3);

  149.         MmFreeContiguousMemory(attach_procee);
  150. }

  151. void InitDirectoryTableBaseByPid(__int64 pid)
  152. {
  153.         PEPROCESS pEProcess;

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

  159. void UnlimitHareWareBreakpoint(int index)
  160. {
  161.         UNICODE_STRING unicode_PsLookUpProcessByProcessId;
  162.         UNICODE_STRING unicode_MiSystemFault;

  163.         idt_hook_config.Bits.set_pte_nx = TRUE;

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

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

  168.         InitDirectoryTableBaseByPid(3724);
  169.         SetupPteNx(targetAddress, TRUE);
  170. }

  171. asm_AttachProcess        proc
  172.         mov                rax, cr3
  173.         mov                [rdx], rax
  174.         mov                cr3, rcx
  175.         ret
  176. asm_AttachProcess        endp
复制代码
效果图:
83bf46c52d8cded3de449e8aee9806b2.png
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|我爱代码 - 专业游戏安全与逆向论坛 ( 陇ICP备17000105号-1 )

GMT+8, 2025-4-2 02:56 , Processed in 0.048613 second(s), 24 queries .

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表