From db8bc7313278a851a71d7ae105b4b9fb08f6d3fe Mon Sep 17 00:00:00 2001 From: Zero Hu <632284304@qq.com> Date: Mon, 3 Jan 2022 12:28:38 +0000 Subject: [PATCH] Replace vmexit_handler.cpp --- Voyager/PayLoad (Intel)/vmexit_handler.cpp | 366 +++++++++++++++------ 1 file changed, 270 insertions(+), 96 deletions(-) diff --git a/Voyager/PayLoad (Intel)/vmexit_handler.cpp b/Voyager/PayLoad (Intel)/vmexit_handler.cpp index b456ccf..97ccd5c 100644 --- a/Voyager/PayLoad (Intel)/vmexit_handler.cpp +++ b/Voyager/PayLoad (Intel)/vmexit_handler.cpp @@ -1,5 +1,11 @@ +//#include "ept.h" #include "vmexit.h" +typedef LARGE_INTEGER PHYSICAL_ADDRESS, * PPHYSICAL_ADDRESS; + +#define EPT_PD_MASK (~((ULONG64)(0x200000 - 1))) + + #if WINVER > 1803 void vmexit_handler(pcontext_t* context, void* unknown) #else @@ -21,110 +27,240 @@ void vmexit_handler(pcontext_t context, void* unknown) { switch ((vmexit_command_t)guest_registers->rdx) { - case vmexit_command_t::init_page_tables: - { - guest_registers->rax = (u64) mm::init(); - break; - } - case vmexit_command_t::get_dirbase: - { - auto command_data = - vmexit::get_command(guest_registers->r8); + case vmexit_command_t::init_page_tables: + { + dbg::print("init_page_tables:\n"); + guest_registers->rax = (u64)mm::init(); + break; + } + case vmexit_command_t::get_dirbase: + { + //dbg::print("get_dirbase\n"); + auto command_data = + vmexit::get_command(guest_registers->r8); - u64 guest_dirbase; - __vmx_vmread(VMCS_GUEST_CR3, &guest_dirbase); + u64 guest_dirbase; + __vmx_vmread(VMCS_GUEST_CR3, &guest_dirbase); - // cr3 can contain other high bits so just to be safe - // get the pfn and bitshift it... - guest_dirbase = cr3{ guest_dirbase }.pml4_pfn << 12; - command_data.dirbase = guest_dirbase; - guest_registers->rax = (u64) vmxroot_error_t::error_success; + // cr3 can contain other high bits so just to be safe + // get the pfn and bitshift it... + guest_dirbase = cr3{ guest_dirbase }.pml4_pfn << 12; + command_data.dirbase = guest_dirbase; + guest_registers->rax = (u64)vmxroot_error_t::error_success; - vmexit::set_command( - guest_registers->r8, command_data); - break; - } - case vmexit_command_t::read_guest_phys: - { - auto command_data = - vmexit::get_command(guest_registers->r8); - - u64 guest_dirbase; - __vmx_vmread(VMCS_GUEST_CR3, &guest_dirbase); - // from 1809-1909 PCIDE is enabled in CR4 and so cr3 contains some other stuff... - guest_dirbase = cr3{ guest_dirbase }.pml4_pfn << 12; - - guest_registers->rax = - (u64) mm::read_guest_phys( - guest_dirbase, - command_data.copy_phys.phys_addr, - command_data.copy_phys.buffer, - command_data.copy_phys.size); - - vmexit::set_command( - guest_registers->r8, command_data); - break; - } - case vmexit_command_t::write_guest_phys: - { - auto command_data = - vmexit::get_command(guest_registers->r8); - - u64 guest_dirbase; - __vmx_vmread(VMCS_GUEST_CR3, &guest_dirbase); - // from 1809-1909 PCIDE is enabled in CR4 and so cr3 contains some other stuff... - guest_dirbase = cr3{ guest_dirbase }.pml4_pfn << 12; - - guest_registers->rax = - (u64) mm::write_guest_phys( - guest_dirbase, - command_data.copy_phys.phys_addr, - command_data.copy_phys.buffer, - command_data.copy_phys.size); - - vmexit::set_command( - guest_registers->r8, command_data); - break; - } - case vmexit_command_t::copy_guest_virt: - { - auto command_data = - vmexit::get_command(guest_registers->r8); - - auto virt_data = command_data.copy_virt; - guest_registers->rax = - (u64)mm::copy_guest_virt( - virt_data.dirbase_src, - virt_data.virt_src, - virt_data.dirbase_dest, - virt_data.virt_dest, - virt_data.size); - break; - } - case vmexit_command_t::translate: - { - auto command_data = - vmexit::get_command(guest_registers->r8); + vmexit::set_command( + guest_registers->r8, command_data); + break; + } + case vmexit_command_t::read_guest_phys: + { + //dbg::print("read_guest_phys\n"); + auto command_data = + vmexit::get_command(guest_registers->r8); - u64 guest_dirbase; - __vmx_vmread(VMCS_GUEST_CR3, &guest_dirbase); - guest_dirbase = cr3{ guest_dirbase }.pml4_pfn << 12; + u64 guest_dirbase; + __vmx_vmread(VMCS_GUEST_CR3, &guest_dirbase); + // from 1809-1909 PCIDE is enabled in CR4 and so cr3 contains some other stuff... + guest_dirbase = cr3{ guest_dirbase }.pml4_pfn << 12; - command_data.translate_virt.phys_addr = - mm::translate_guest_virtual(guest_dirbase, - command_data.translate_virt.virt_src); + guest_registers->rax = + (u64)mm::read_guest_phys( + guest_dirbase, + command_data.copy_phys.phys_addr, + command_data.copy_phys.buffer, + command_data.copy_phys.size); - guest_registers->rax = - (u64) vmxroot_error_t::error_success; + vmexit::set_command( + guest_registers->r8, command_data); + break; + } + case vmexit_command_t::write_guest_phys: + { + //dbg::print("write_guest_phys\n"); + auto command_data = + vmexit::get_command(guest_registers->r8); - vmexit::set_command( - guest_registers->r8, command_data); - break; - } - default: - break; - } + u64 guest_dirbase; + __vmx_vmread(VMCS_GUEST_CR3, &guest_dirbase); + // from 1809-1909 PCIDE is enabled in CR4 and so cr3 contains some other stuff... + guest_dirbase = cr3{ guest_dirbase }.pml4_pfn << 12; + + guest_registers->rax = + (u64)mm::write_guest_phys( + guest_dirbase, + command_data.copy_phys.phys_addr, + command_data.copy_phys.buffer, + command_data.copy_phys.size); + + vmexit::set_command( + guest_registers->r8, command_data); + break; + } + case vmexit_command_t::copy_guest_virt: + { + //dbg::print("copy_guest_virt\n"); + auto command_data = + vmexit::get_command(guest_registers->r8); + + auto virt_data = command_data.copy_virt; + guest_registers->rax = + (u64)mm::copy_guest_virt( + virt_data.dirbase_src, + virt_data.virt_src, + virt_data.dirbase_dest, + virt_data.virt_dest, + virt_data.size); + break; + } + case vmexit_command_t::translate: + { + //dbg::print("translate\n"); + auto command_data = + vmexit::get_command(guest_registers->r8); + + u64 guest_dirbase; + __vmx_vmread(VMCS_GUEST_CR3, &guest_dirbase); + guest_dirbase = cr3{ guest_dirbase }.pml4_pfn << 12; + + command_data.translate_virt.phys_addr = + mm::translate_guest_virtual(guest_dirbase, + command_data.translate_virt.virt_src); + guest_registers->rax = + (u64)vmxroot_error_t::error_success; + + vmexit::set_command( + guest_registers->r8, command_data); + break; + } + case vmexit_command_t::add_shadow_page: + { + dbg::print("add_shadow_page\n"); + auto command_data = + vmexit::get_command(guest_registers->r8); + + u64 guest_dirbase; + __vmx_vmread(VMCS_GUEST_CR3, &guest_dirbase); + + // cr3 can contain other high bits so just to be safe + // get the pfn and bitshift it... + guest_dirbase = cr3{ guest_dirbase }.pml4_pfn << 12; + + cpuid_eax_01 cpuid_value; + __cpuid((int*)&cpuid_value, 1); + UINT32_t uProcessorNum = cpuid_value.cpuid_additional_information.initial_apic_id; + + guest_virt_t uAddr = command_data.addShadowPage.uVirtualAddrToHook; + guest_virt_t virtualRead = command_data.addShadowPage.uPageRead; + guest_virt_t virtualExecute = command_data.addShadowPage.uPageExecute; + dbg::print("ProcessorNum:%d,uAddr:%llx,virtualRead:%llx,virtualExecute:%llx\n", uProcessorNum, uAddr, virtualRead, virtualExecute); + guest_phys_t uPageRead = mm::translate_guest_virtual(guest_dirbase, virtualRead, mm::map_type_t::map_src); //save the page for read + guest_phys_t uPageExec = mm::translate_guest_virtual(guest_dirbase, virtualExecute, mm::map_type_t::map_src); //save the page for exec + dbg::print("ReadPhysical:%llx,ExecPhysical:%llx\n", uPageRead,uPageExec); + ept_pointer eptp; + mm::phys_addr_t guest_phys{ uPageExec }; + __vmx_vmread(VMCS_CTRL_EPT_POINTER, (size_t*)&eptp); + VoyagerEptAddFakePage(uAddr, uPageRead, uPageExec); //record hook information + split_2mb_to_4kb(eptp, uPageExec& EPT_PD_MASK, uPageExec& EPT_PD_MASK); + //it's all 4k page now + changeEPTAttribute(eptp, uPageExec, true);//set the page attribute to exec only + break; + } + case vmexit_command_t::add_shadow_page_phys: + { + auto command_data = + vmexit::get_command(guest_registers->r8); + + guest_virt_t uAddr = command_data.addShadowPagePhys.uVirtualAddrToHook; + + guest_phys_t uPageRead = command_data.addShadowPagePhys.uPageRead; //save the page for read + guest_phys_t uPageExec = command_data.addShadowPagePhys.uPageExecute; //save the page for exec + dbg::print("ReadPhysical:%llx,ExecPhysical:%llx\n", uPageRead, uPageExec); + ept_pointer eptp; + mm::phys_addr_t guest_phys{ uPageExec }; + __vmx_vmread(VMCS_CTRL_EPT_POINTER, (size_t*)&eptp); + VoyagerEptAddFakePage(uAddr, uPageRead, uPageExec); //record hook information + split_2mb_to_4kb(eptp, uPageExec&EPT_PD_MASK, uPageExec&EPT_PD_MASK); + //it's all 4k page now + changeEPTAttribute(eptp, uPageExec, true);//set the page attribute to exec only + break; + } + case vmexit_command_t::delete_shadow_page: + { + dbg::print("delete_shadow_page\n"); + u64 guest_dirbase; + __vmx_vmread(VMCS_GUEST_CR3, &guest_dirbase); + auto command_data = + vmexit::get_command(guest_registers->r8); + // cr3 can contain other high bits so just to be safe + // get the pfn and bitshift it... + guest_dirbase = cr3{ guest_dirbase }.pml4_pfn << 12; + + u64 uAddr = command_data.deleteShaowPage.uVirtualAddrToHook; //begin to search for the page + dbg::print("delete addr:%llx\n", uAddr); + + PSharedShadowHookData pShadowHook = (PSharedShadowHookData)&mm::ShadowHookData; + PHookInformation pInfo = NULL; + pInfo = ShpFindPatchInfoByAddress(pShadowHook, (void*)uAddr); + if (!pInfo) + { + break; + } + ept_pointer eptp; + __vmx_vmread(VMCS_CTRL_EPT_POINTER, (size_t*)&eptp); + u64 uPhyExe = pInfo->pa_base_for_exec; + u64 uPhyRW = pInfo->pa_base_for_rw; + map_4k(eptp, uPhyExe, uPhyExe); //remap to the exec page,and set page attribute to R/W only + VoyagerEptDelteFakePage(uAddr); //delete + pInfo = ShpFindPatchInfoBy2MPage((PSharedShadowHookData)&mm::ShadowHookData, (void*)uAddr); + if (!pInfo) //if no other hook information in 2M,then delete the resource + { + dbg::print("merge_4kb_to_2mb\n"); + merge_4kb_to_2mb(eptp, uPhyExe & EPT_PD_MASK, uPhyExe & EPT_PD_MASK); + } + break; + } + case vmexit_command_t::unhide_shadow_page: + { + dbg::print("unhide_shadow_page\n"); + u64 guest_dirbase; + __vmx_vmread(VMCS_GUEST_CR3, &guest_dirbase); + auto command_data = + vmexit::get_command(guest_registers->r8); + // cr3 can contain other high bits so just to be safe + // get the pfn and bitshift it... + guest_dirbase = cr3{ guest_dirbase }.pml4_pfn << 12; + + u64 uAddr = command_data.unHideShaowPage.uVirtualAddrToHook; //begin to search for the page + dbg::print("unHide addr:%llx\n", uAddr); + + PSharedShadowHookData pShadowHook = (PSharedShadowHookData)&mm::ShadowHookData; + PHookInformation pInfo = NULL; + pInfo = ShpFindPatchInfoByAddress(pShadowHook, (void*)uAddr); + if (!pInfo) + { + break; + } + ept_pointer eptp; + __vmx_vmread(VMCS_CTRL_EPT_POINTER, (size_t*)&eptp); + u64 uPhyExe = pInfo->pa_base_for_exec; + u64 uPhyRW = pInfo->pa_base_for_rw; + map_4k(eptp, uPhyExe, uPhyExe); //remap to exec,and set page attribute to RWE + break; + } + case vmexit_command_t::disable_page_protection: + { + auto command_data = + vmexit::get_command(guest_registers->r8); + guest_phys_t uPagePhyAddr = command_data.disablePageProtection.phys_addr; + ept_pointer eptp; + __vmx_vmread(VMCS_CTRL_EPT_POINTER, (size_t*)&eptp); + disablePageProtection(eptp, uPagePhyAddr); + break; + } + default: + break; + } // advance instruction pointer... size_t rip, exec_len; __vmx_vmread(VMCS_GUEST_RIP, &rip); @@ -133,6 +269,44 @@ void vmexit_handler(pcontext_t context, void* unknown) return; } } + else if (vmexit_reason == VMX_EXIT_REASON_EPT_VIOLATION) + { + //dbg::print("[EPT Violation]\n"); + EptViolationQualification exit_qualification; + __vmx_vmread(VMCS_EXIT_QUALIFICATION, (size_t*)&exit_qualification); + u64 fault_pa = 0, fault_va = 0; + __vmx_vmread(VMCS_GUEST_PHYSICAL_ADDRESS, (size_t*)&fault_pa); + if (exit_qualification.fields.valid_guest_linear_address) + { + __vmx_vmread(VMCS_EXIT_GUEST_LINEAR_ADDRESS, (size_t*)&fault_va); + } + else + { + fault_va = 0; + } + + if (exit_qualification.fields.ept_readable || + exit_qualification.fields.ept_writeable || + exit_qualification.fields.ept_executable) + { + dbg::print("[EPT Violation] fault_va:%llx,fault_pa:%llx\n", fault_va, fault_pa); + ept_pointer eptp; + + __vmx_vmread(VMCS_CTRL_EPT_POINTER, (size_t*)&eptp); + // EPT entry is present. Permission violation. + if (exit_qualification.fields.caused_by_translation) + { + bool isHandled = VoyagerHandleEptViolation(&exit_qualification,(void*)fault_va);//replace + if (isHandled) + { + dbg::print("Ept Violation have handled\n"); + UtilInveptGlobal(eptp); + return; + } + } + + } + } // call original vmexit handler... reinterpret_cast(