Merge branch 'dev' into 'master'

dev merge

See merge request _xeroxz/bluepill!1
merge-requests/2/merge
_xeroxz 3 years ago
commit 9cf112c442

Binary file not shown.

@ -46,10 +46,21 @@ auto drv_entry(PDRIVER_OBJECT driver_object, PUNICODE_STRING registry_path) -> N
// copy the guest IDT entries...
memcpy(idt::table, (void*)idt_value.base_address, idt_value.limit);
// change gp, pf, and de to vmxroot handlers...
idt::table[general_protection] = idt::create_entry(hv::idt_addr_t{ __gp_handler }, idt::ist_idx::gp);
idt::table[page_fault] = idt::create_entry(hv::idt_addr_t{ __pf_handler }, idt::ist_idx::pf);
idt::table[divide_error] = idt::create_entry(hv::idt_addr_t{ __de_handler }, idt::ist_idx::de);
idt::table[general_protection] =
idt::create_entry(hv::idt_addr_t
{ __gp_handler }, idt::ist_idx::gp);
idt::table[page_fault] =
idt::create_entry(hv::idt_addr_t
{ __pf_handler }, idt::ist_idx::pf);
idt::table[divide_error] =
idt::create_entry(hv::idt_addr_t
{ __de_handler }, idt::ist_idx::de);
idt::table[non_maskable_interrupt] =
idt::create_entry(hv::idt_addr_t
{ __nmi_handler }, idt::ist_idx::nmi);
// used for SEH in vmxroot fault handler...
idt::image_base = driver_object->DriverStart;

@ -39,6 +39,44 @@ auto exit_handler(hv::pguest_registers regs) -> void
regs->rdx = result[3];
break;
}
case VMX_EXIT_REASON_NMI_WINDOW:
{
vmentry_interrupt_information interrupt{};
interrupt.interruption_type = interruption_type::non_maskable_interrupt;
interrupt.vector = EXCEPTION_NMI;
interrupt.valid = true;
__vmx_vmwrite(VMCS_CTRL_VMENTRY_INTERRUPTION_INFORMATION_FIELD, interrupt.flags);
__vmx_vmwrite(VMCS_VMEXIT_INTERRUPTION_ERROR_CODE, NULL);
ia32_vmx_procbased_ctls_register procbased_ctls;
ia32_vmx_pinbased_ctls_register pinbased_ctls;
__vmx_vmread(VMCS_CTRL_PROCESSOR_BASED_VM_EXECUTION_CONTROLS, &procbased_ctls.flags);
__vmx_vmread(VMCS_CTRL_PIN_BASED_VM_EXECUTION_CONTROLS, &pinbased_ctls.flags);
procbased_ctls.nmi_window_exiting = false;
pinbased_ctls.virtual_nmi = false;
__vmx_vmwrite(VMCS_CTRL_PROCESSOR_BASED_VM_EXECUTION_CONTROLS, procbased_ctls.flags);
__vmx_vmwrite(VMCS_CTRL_PIN_BASED_VM_EXECUTION_CONTROLS, pinbased_ctls.flags);
return; // dont advance rip...
}
case VMX_EXIT_REASON_EXCEPTION_OR_NMI:
{
ia32_vmx_procbased_ctls_register procbased_ctls;
ia32_vmx_pinbased_ctls_register pinbased_ctls;
__vmx_vmread(VMCS_CTRL_PROCESSOR_BASED_VM_EXECUTION_CONTROLS, &procbased_ctls.flags);
__vmx_vmread(VMCS_CTRL_PIN_BASED_VM_EXECUTION_CONTROLS, &pinbased_ctls.flags);
procbased_ctls.nmi_window_exiting = true;
pinbased_ctls.virtual_nmi = true;
__vmx_vmwrite(VMCS_CTRL_PROCESSOR_BASED_VM_EXECUTION_CONTROLS, procbased_ctls.flags);
__vmx_vmwrite(VMCS_CTRL_PIN_BASED_VM_EXECUTION_CONTROLS, pinbased_ctls.flags);
return; // dont advance rip...
}
case VMX_EXIT_REASON_EXECUTE_XSETBV:
{
hv::msr_split value{};
@ -65,9 +103,11 @@ auto exit_handler(hv::pguest_registers regs) -> void
__except (EXCEPTION_EXECUTE_HANDLER)
{
vmentry_interrupt_information interrupt{};
interrupt.flags = interruption_type::hardware_exception;
interrupt.interruption_type = interruption_type::hardware_exception;
interrupt.vector = EXCEPTION_GP_FAULT;
interrupt.valid = true;
interrupt.deliver_error_code = true;
__vmx_vmwrite(VMCS_CTRL_VMENTRY_INTERRUPTION_INFORMATION_FIELD, interrupt.flags);
__vmx_vmwrite(VMCS_VMEXIT_INTERRUPTION_ERROR_CODE, g_vcpu->error_code);
@ -94,9 +134,11 @@ auto exit_handler(hv::pguest_registers regs) -> void
__except (EXCEPTION_EXECUTE_HANDLER)
{
vmentry_interrupt_information interrupt{};
interrupt.flags = interruption_type::hardware_exception;
interrupt.interruption_type = interruption_type::hardware_exception;
interrupt.vector = EXCEPTION_GP_FAULT;
interrupt.valid = true;
interrupt.deliver_error_code = true;
__vmx_vmwrite(VMCS_CTRL_VMENTRY_INTERRUPTION_INFORMATION_FIELD, interrupt.flags);
__vmx_vmwrite(VMCS_VMEXIT_INTERRUPTION_ERROR_CODE, g_vcpu->error_code);
@ -110,11 +152,6 @@ auto exit_handler(hv::pguest_registers regs) -> void
value.high = regs->rdx;
__try
{
__writemsr(regs->rcx, value.value);
break;
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
/*
EXCEPTION WARNING:
@ -122,10 +159,17 @@ auto exit_handler(hv::pguest_registers regs) -> void
If the value in ECX specifies a reserved or unimplemented MSR address.
#UD If the LOCK prefix is used.
*/
__writemsr(regs->rcx, value.value);
break;
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
vmentry_interrupt_information interrupt{};
interrupt.flags = interruption_type::hardware_exception;
interrupt.interruption_type = interruption_type::hardware_exception;
interrupt.vector = EXCEPTION_GP_FAULT;
interrupt.valid = true;
interrupt.deliver_error_code = true;
__vmx_vmwrite(VMCS_CTRL_VMENTRY_INTERRUPTION_INFORMATION_FIELD, interrupt.flags);
__vmx_vmwrite(VMCS_VMEXIT_INTERRUPTION_ERROR_CODE, g_vcpu->error_code);
@ -213,7 +257,7 @@ auto exit_handler(hv::pguest_registers regs) -> void
else
{
vmentry_interrupt_information interrupt{};
interrupt.flags = interruption_type::hardware_exception;
interrupt.interruption_type = interruption_type::hardware_exception;
interrupt.vector = EXCEPTION_INVALID_OPCODE;
interrupt.valid = true;
@ -232,12 +276,11 @@ auto exit_handler(hv::pguest_registers regs) -> void
case VMX_EXIT_REASON_EXECUTE_VMXON:
{
vmentry_interrupt_information interrupt{};
interrupt.flags = interruption_type::hardware_exception;
interrupt.interruption_type = interruption_type::hardware_exception;
interrupt.vector = EXCEPTION_INVALID_OPCODE;
interrupt.valid = true;
__vmx_vmwrite(VMCS_CTRL_VMENTRY_INTERRUPTION_INFORMATION_FIELD, interrupt.flags);
// manual says there will never be an error code... so just put null...
__vmx_vmwrite(VMCS_VMEXIT_INTERRUPTION_ERROR_CODE, NULL);
return; // dont advance rip...
}

@ -253,7 +253,7 @@ namespace hv
u64 rax;
} guest_registers, * pguest_registers;
typedef struct _idt_regs_t
typedef struct _idt_regs_ecode_t
{
u64 r15;
u64 r14;
@ -277,7 +277,32 @@ namespace hv
::rflags rflags;
u64 rsp;
u64 ss_selector;
} idt_regs_t, *pidt_regs_t;
} idt_regs_ecode_t, *pidt_regs_ecode_t;
typedef struct _idt_regs_t
{
u64 r15;
u64 r14;
u64 r13;
u64 r12;
u64 r11;
u64 r10;
u64 r9;
u64 r8;
u64 rbp;
u64 rdi;
u64 rsi;
u64 rdx;
u64 rcx;
u64 rbx;
u64 rax;
u64 rip;
u64 cs_selector;
::rflags rflags;
u64 rsp;
u64 ss_selector;
} idt_regs_t, * pidt_regs_t;
union msr_split
{
@ -657,7 +682,10 @@ namespace hv
u64 vmcs_phys;
u64 vmxon_phys;
u64 host_stack;
u64 error_code;
u64 nmi_code;
tss64 tss;
segment_descriptor_64* gdt;
} vcpu_ctx, * pvcpu_ctx;

@ -10156,6 +10156,8 @@ typedef union
#define IA32_VMX_PROCBASED_CTLS 0x00000482
typedef union
{
uint64_t flags;
struct
{
uint64_t reserved1 : 2;
@ -10429,8 +10431,6 @@ typedef union
#define IA32_VMX_PROCBASED_CTLS_ACTIVATE_SECONDARY_CONTROLS(_) (((_) >> 31) & 0x01)
uint64_t reserved7 : 32;
};
uint64_t flags;
} ia32_vmx_procbased_ctls_register;

@ -1,6 +1,7 @@
#include "idt.hpp"
#include "debug.hpp"
auto seh_handler(hv::pidt_regs_t regs) -> void
auto seh_handler_ecode(hv::pidt_regs_ecode_t regs) -> void
{
g_vcpu->error_code = regs->error_code;
const auto rva = regs->rip - reinterpret_cast<u64>(idt::image_base);
@ -45,6 +46,68 @@ auto seh_handler(hv::pidt_regs_t regs) -> void
}
}
// probably should make a single SEH handler instead of having 2...
// maybe instead of passing the stack (rsp), just pass RIP and have seh_handler
// calc the catch block and return the address...
auto seh_handler(hv::pidt_regs_t regs) -> void
{
const auto rva = regs->rip - reinterpret_cast<u64>(idt::image_base);
const auto nt_headers = reinterpret_cast<IMAGE_NT_HEADERS64*>(
reinterpret_cast<u64>(idt::image_base) +
reinterpret_cast<IMAGE_DOS_HEADER*>(idt::image_base)->e_lfanew);
const auto exception =
&nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION];
const auto functions =
reinterpret_cast<RUNTIME_FUNCTION*>(
reinterpret_cast<u64>(idt::image_base) + exception->VirtualAddress);
for (auto idx = 0; idx < exception->Size / sizeof(RUNTIME_FUNCTION); ++idx)
{
const auto function = &functions[idx];
if (!(rva >= function->BeginAddress && rva < function->EndAddress))
continue;
const auto unwind_info =
reinterpret_cast<UNWIND_INFO*>(
reinterpret_cast<u64>(idt::image_base) + function->UnwindData);
if (!(unwind_info->Flags & UNW_FLAG_EHANDLER))
continue;
const auto scope_table =
reinterpret_cast<SCOPE_TABLE*>(
reinterpret_cast<u64>(&unwind_info->UnwindCode[
(unwind_info->CountOfCodes + 1) & ~1]) + sizeof(u32));
for (auto entry = 0; entry < scope_table->Count; ++entry)
{
const auto scope_record = &scope_table->ScopeRecords[entry];
if (rva >= scope_record->BeginAddress && rva < scope_record->EndAddress)
{
regs->rip = reinterpret_cast<u64>(idt::image_base) + scope_record->JumpTarget;
return;
}
}
}
}
auto nmi_handler(hv::pidt_regs_t regs) -> void
{
ia32_vmx_procbased_ctls_register procbased_ctls;
ia32_vmx_pinbased_ctls_register pinbased_ctls;
__vmx_vmread(VMCS_CTRL_PROCESSOR_BASED_VM_EXECUTION_CONTROLS, &procbased_ctls.flags);
__vmx_vmread(VMCS_CTRL_PIN_BASED_VM_EXECUTION_CONTROLS, &pinbased_ctls.flags);
procbased_ctls.nmi_window_exiting = true;
pinbased_ctls.virtual_nmi = true;
__vmx_vmwrite(VMCS_CTRL_PROCESSOR_BASED_VM_EXECUTION_CONTROLS, procbased_ctls.flags);
__vmx_vmwrite(VMCS_CTRL_PIN_BASED_VM_EXECUTION_CONTROLS, pinbased_ctls.flags);
}
namespace idt
{
auto create_entry(hv::idt_addr_t idt_handler, u8 ist_index) -> hv::idt_entry_t

@ -8,13 +8,17 @@
extern "C" void __gp_handler(void);
extern "C" void __pf_handler(void);
extern "C" void __de_handler(void);
extern "C" void __nmi_handler(void);
extern "C" void nmi_handler(hv::pidt_regs_t regs);
extern "C" void seh_handler(hv::pidt_regs_t regs);
extern "C" void seh_handler_ecode(hv::pidt_regs_ecode_t regs);
namespace idt
{
__declspec(allocate(".idt"))
inline hv::idt_entry_t table[256];
enum ist_idx : u8 { de = 4, pf = 5, gp = 6};
enum ist_idx : u8 { nmi = 3, de = 4, pf = 5, gp = 6};
inline void* image_base = nullptr; // used for SEH...
auto create_entry(hv::idt_addr_t idt_handler, u8 ist_index) -> hv::idt_entry_t;

@ -1,7 +1,92 @@
extern seh_handler : proc
extern nmi_handler : proc
extern seh_handler_ecode : proc
.code
__nmi_handler proc
push rax
push rbx
push rcx
push rdx
push rsi
push rdi
push rbp
push r8
push r9
push r10
push r11
push r12
push r13
push r14
push r15
mov rcx, rsp
sub rsp, 20h
call nmi_handler
add rsp, 20h
pop r15
pop r14
pop r13
pop r12
pop r11
pop r10
pop r9
pop r8
pop rbp
pop rdi
pop rsi
pop rdx
pop rcx
pop rbx
pop rax
iretq
__nmi_handler endp
; #DE has no error code...
__de_handler proc
push rax
push rbx
push rcx
push rdx
push rsi
push rdi
push rbp
push r8
push r9
push r10
push r11
push r12
push r13
push r14
push r15
mov rcx, rsp
sub rsp, 20h
call seh_handler
add rsp, 20h
pop r15
pop r14
pop r13
pop r12
pop r11
pop r10
pop r9
pop r8
pop rbp
pop rdi
pop rsi
pop rdx
pop rcx
pop rbx
pop rax
iretq
__de_handler endp
; PF and GP have error code...
__pf_handler proc
__gp_handler proc
push rax
@ -22,7 +107,7 @@ __gp_handler proc
mov rcx, rsp
sub rsp, 20h
call seh_handler
call seh_handler_ecode
add rsp, 20h
pop r15
@ -45,5 +130,4 @@ __gp_handler proc
iretq
__gp_handler endp
__pf_handler endp
__de_handler endp
end

@ -162,6 +162,7 @@ namespace vmcs
if (vmx_basic.vmx_controls)
{
msr_fix_value.flags = __readmsr(IA32_VMX_TRUE_PINBASED_CTLS);
pinbased_ctls.nmi_exiting = true;
pinbased_ctls.flags &= msr_fix_value.allowed_1_settings;
pinbased_ctls.flags |= msr_fix_value.allowed_0_settings;
__vmx_vmwrite(VMCS_CTRL_PIN_BASED_VM_EXECUTION_CONTROLS, pinbased_ctls.flags);
@ -188,6 +189,7 @@ namespace vmcs
else
{
msr_fix_value.flags = __readmsr(IA32_VMX_PINBASED_CTLS);
pinbased_ctls.nmi_exiting = true;
pinbased_ctls.flags &= msr_fix_value.allowed_1_settings;
pinbased_ctls.flags |= msr_fix_value.allowed_0_settings;
__vmx_vmwrite(VMCS_CTRL_PIN_BASED_VM_EXECUTION_CONTROLS, pinbased_ctls.flags);

Loading…
Cancel
Save