Merge branch 'dev' into 'master'

dev merge

See merge request _xeroxz/bluepill!1
merge-requests/2/merge
_xeroxz 4 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... // copy the guest IDT entries...
memcpy(idt::table, (void*)idt_value.base_address, idt_value.limit); memcpy(idt::table, (void*)idt_value.base_address, idt_value.limit);
// change gp, pf, and de to vmxroot handlers... idt::table[general_protection] =
idt::table[general_protection] = idt::create_entry(hv::idt_addr_t{ __gp_handler }, idt::ist_idx::gp); idt::create_entry(hv::idt_addr_t
idt::table[page_fault] = idt::create_entry(hv::idt_addr_t{ __pf_handler }, idt::ist_idx::pf); { __gp_handler }, idt::ist_idx::gp);
idt::table[divide_error] = idt::create_entry(hv::idt_addr_t{ __de_handler }, idt::ist_idx::de);
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... // used for SEH in vmxroot fault handler...
idt::image_base = driver_object->DriverStart; idt::image_base = driver_object->DriverStart;

@ -39,6 +39,44 @@ auto exit_handler(hv::pguest_registers regs) -> void
regs->rdx = result[3]; regs->rdx = result[3];
break; 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: case VMX_EXIT_REASON_EXECUTE_XSETBV:
{ {
hv::msr_split value{}; hv::msr_split value{};
@ -65,9 +103,11 @@ auto exit_handler(hv::pguest_registers regs) -> void
__except (EXCEPTION_EXECUTE_HANDLER) __except (EXCEPTION_EXECUTE_HANDLER)
{ {
vmentry_interrupt_information interrupt{}; vmentry_interrupt_information interrupt{};
interrupt.flags = interruption_type::hardware_exception; interrupt.interruption_type = interruption_type::hardware_exception;
interrupt.vector = EXCEPTION_GP_FAULT; interrupt.vector = EXCEPTION_GP_FAULT;
interrupt.valid = true; interrupt.valid = true;
interrupt.deliver_error_code = true;
__vmx_vmwrite(VMCS_CTRL_VMENTRY_INTERRUPTION_INFORMATION_FIELD, interrupt.flags); __vmx_vmwrite(VMCS_CTRL_VMENTRY_INTERRUPTION_INFORMATION_FIELD, interrupt.flags);
__vmx_vmwrite(VMCS_VMEXIT_INTERRUPTION_ERROR_CODE, g_vcpu->error_code); __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) __except (EXCEPTION_EXECUTE_HANDLER)
{ {
vmentry_interrupt_information interrupt{}; vmentry_interrupt_information interrupt{};
interrupt.flags = interruption_type::hardware_exception; interrupt.interruption_type = interruption_type::hardware_exception;
interrupt.vector = EXCEPTION_GP_FAULT; interrupt.vector = EXCEPTION_GP_FAULT;
interrupt.valid = true; interrupt.valid = true;
interrupt.deliver_error_code = true;
__vmx_vmwrite(VMCS_CTRL_VMENTRY_INTERRUPTION_INFORMATION_FIELD, interrupt.flags); __vmx_vmwrite(VMCS_CTRL_VMENTRY_INTERRUPTION_INFORMATION_FIELD, interrupt.flags);
__vmx_vmwrite(VMCS_VMEXIT_INTERRUPTION_ERROR_CODE, g_vcpu->error_code); __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; value.high = regs->rdx;
__try __try
{
__writemsr(regs->rcx, value.value);
break;
}
__except (EXCEPTION_EXECUTE_HANDLER)
{ {
/* /*
EXCEPTION WARNING: 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. If the value in ECX specifies a reserved or unimplemented MSR address.
#UD If the LOCK prefix is used. #UD If the LOCK prefix is used.
*/ */
__writemsr(regs->rcx, value.value);
break;
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
vmentry_interrupt_information interrupt{}; vmentry_interrupt_information interrupt{};
interrupt.flags = interruption_type::hardware_exception; interrupt.interruption_type = interruption_type::hardware_exception;
interrupt.vector = EXCEPTION_GP_FAULT; interrupt.vector = EXCEPTION_GP_FAULT;
interrupt.valid = true; interrupt.valid = true;
interrupt.deliver_error_code = true;
__vmx_vmwrite(VMCS_CTRL_VMENTRY_INTERRUPTION_INFORMATION_FIELD, interrupt.flags); __vmx_vmwrite(VMCS_CTRL_VMENTRY_INTERRUPTION_INFORMATION_FIELD, interrupt.flags);
__vmx_vmwrite(VMCS_VMEXIT_INTERRUPTION_ERROR_CODE, g_vcpu->error_code); __vmx_vmwrite(VMCS_VMEXIT_INTERRUPTION_ERROR_CODE, g_vcpu->error_code);
@ -213,7 +257,7 @@ auto exit_handler(hv::pguest_registers regs) -> void
else else
{ {
vmentry_interrupt_information interrupt{}; vmentry_interrupt_information interrupt{};
interrupt.flags = interruption_type::hardware_exception; interrupt.interruption_type = interruption_type::hardware_exception;
interrupt.vector = EXCEPTION_INVALID_OPCODE; interrupt.vector = EXCEPTION_INVALID_OPCODE;
interrupt.valid = true; interrupt.valid = true;
@ -232,12 +276,11 @@ auto exit_handler(hv::pguest_registers regs) -> void
case VMX_EXIT_REASON_EXECUTE_VMXON: case VMX_EXIT_REASON_EXECUTE_VMXON:
{ {
vmentry_interrupt_information interrupt{}; vmentry_interrupt_information interrupt{};
interrupt.flags = interruption_type::hardware_exception; interrupt.interruption_type = interruption_type::hardware_exception;
interrupt.vector = EXCEPTION_INVALID_OPCODE; interrupt.vector = EXCEPTION_INVALID_OPCODE;
interrupt.valid = true; interrupt.valid = true;
__vmx_vmwrite(VMCS_CTRL_VMENTRY_INTERRUPTION_INFORMATION_FIELD, interrupt.flags); __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); __vmx_vmwrite(VMCS_VMEXIT_INTERRUPTION_ERROR_CODE, NULL);
return; // dont advance rip... return; // dont advance rip...
} }

@ -253,7 +253,7 @@ namespace hv
u64 rax; u64 rax;
} guest_registers, * pguest_registers; } guest_registers, * pguest_registers;
typedef struct _idt_regs_t typedef struct _idt_regs_ecode_t
{ {
u64 r15; u64 r15;
u64 r14; u64 r14;
@ -272,6 +272,31 @@ namespace hv
u64 rax; u64 rax;
u64 error_code; u64 error_code;
u64 rip;
u64 cs_selector;
::rflags rflags;
u64 rsp;
u64 ss_selector;
} 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 rip;
u64 cs_selector; u64 cs_selector;
::rflags rflags; ::rflags rflags;
@ -657,7 +682,10 @@ namespace hv
u64 vmcs_phys; u64 vmcs_phys;
u64 vmxon_phys; u64 vmxon_phys;
u64 host_stack; u64 host_stack;
u64 error_code; u64 error_code;
u64 nmi_code;
tss64 tss; tss64 tss;
segment_descriptor_64* gdt; segment_descriptor_64* gdt;
} vcpu_ctx, * pvcpu_ctx; } vcpu_ctx, * pvcpu_ctx;

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

@ -1,6 +1,7 @@
#include "idt.hpp" #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; g_vcpu->error_code = regs->error_code;
const auto rva = regs->rip - reinterpret_cast<u64>(idt::image_base); 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 namespace idt
{ {
auto create_entry(hv::idt_addr_t idt_handler, u8 ist_index) -> hv::idt_entry_t 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 __gp_handler(void);
extern "C" void __pf_handler(void); extern "C" void __pf_handler(void);
extern "C" void __de_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(hv::pidt_regs_t regs);
extern "C" void seh_handler_ecode(hv::pidt_regs_ecode_t regs);
namespace idt namespace idt
{ {
__declspec(allocate(".idt")) __declspec(allocate(".idt"))
inline hv::idt_entry_t table[256]; 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... inline void* image_base = nullptr; // used for SEH...
auto create_entry(hv::idt_addr_t idt_handler, u8 ist_index) -> hv::idt_entry_t; 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 seh_handler : proc
extern nmi_handler : proc
extern seh_handler_ecode : proc
.code .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 __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 __pf_handler proc
__gp_handler proc __gp_handler proc
push rax push rax
@ -22,7 +107,7 @@ __gp_handler proc
mov rcx, rsp mov rcx, rsp
sub rsp, 20h sub rsp, 20h
call seh_handler call seh_handler_ecode
add rsp, 20h add rsp, 20h
pop r15 pop r15
@ -45,5 +130,4 @@ __gp_handler proc
iretq iretq
__gp_handler endp __gp_handler endp
__pf_handler endp __pf_handler endp
__de_handler endp
end end

@ -162,6 +162,7 @@ namespace vmcs
if (vmx_basic.vmx_controls) if (vmx_basic.vmx_controls)
{ {
msr_fix_value.flags = __readmsr(IA32_VMX_TRUE_PINBASED_CTLS); 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_1_settings;
pinbased_ctls.flags |= msr_fix_value.allowed_0_settings; pinbased_ctls.flags |= msr_fix_value.allowed_0_settings;
__vmx_vmwrite(VMCS_CTRL_PIN_BASED_VM_EXECUTION_CONTROLS, pinbased_ctls.flags); __vmx_vmwrite(VMCS_CTRL_PIN_BASED_VM_EXECUTION_CONTROLS, pinbased_ctls.flags);
@ -188,6 +189,7 @@ namespace vmcs
else else
{ {
msr_fix_value.flags = __readmsr(IA32_VMX_PINBASED_CTLS); 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_1_settings;
pinbased_ctls.flags |= msr_fix_value.allowed_0_settings; pinbased_ctls.flags |= msr_fix_value.allowed_0_settings;
__vmx_vmwrite(VMCS_CTRL_PIN_BASED_VM_EXECUTION_CONTROLS, pinbased_ctls.flags); __vmx_vmwrite(VMCS_CTRL_PIN_BASED_VM_EXECUTION_CONTROLS, pinbased_ctls.flags);

Loading…
Cancel
Save