mirror of
https://github.com/momo5502/hypervisor.git
synced 2025-07-03 01:31:51 +00:00
Compare commits
27 Commits
hwl
...
aab19ccb34
Author | SHA1 | Date | |
---|---|---|---|
aab19ccb34 | |||
4051223045 | |||
dbc7b5422e | |||
de99750e53 | |||
5a796c7aae | |||
af3d08e791 | |||
8da8fa7f8e | |||
111b9c9a01 | |||
243ddeebdb | |||
a6e484d9df | |||
b3dec2e80c | |||
4d68b0bb78 | |||
79fd28ad7e | |||
7073f7169a | |||
b74f712975 | |||
e9d4b3345c | |||
55234c3504 | |||
69f66d11e4 | |||
2d8de2835c | |||
b9c4d85bb0 | |||
30873e4ebb | |||
53c24b8325 | |||
0896133821 | |||
d5bf81d99b | |||
761490c808 | |||
c1d0a354c2 | |||
08727330e1 |
15
.github/dependabot.yml
vendored
15
.github/dependabot.yml
vendored
@ -1,7 +1,12 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: gitsubmodule
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
open-pull-requests-limit: 10
|
||||
- package-ecosystem: gitsubmodule
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: monthly
|
||||
open-pull-requests-limit: 10
|
||||
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: monthly
|
||||
|
9
.github/workflows/build.yml
vendored
9
.github/workflows/build.yml
vendored
@ -20,7 +20,7 @@ jobs:
|
||||
- release
|
||||
steps:
|
||||
- name: Check out files
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: 0
|
||||
@ -38,13 +38,10 @@ jobs:
|
||||
uses: ammaraskar/msvc-problem-matcher@master
|
||||
|
||||
- name: Setup DevCmd
|
||||
uses: ilammy/msvc-dev-cmd@v1.12.0
|
||||
uses: ilammy/msvc-dev-cmd@v1.13.0
|
||||
with:
|
||||
arch: x64
|
||||
|
||||
- name: Setup Ninja
|
||||
uses: ashutoshvarma/setup-ninja@master
|
||||
|
||||
- name: Configure CMake
|
||||
run: cmake --preset=${{matrix.configuration}}
|
||||
|
||||
@ -52,7 +49,7 @@ jobs:
|
||||
run: cmake --build --preset=${{matrix.configuration}}
|
||||
|
||||
- name: Upload ${{matrix.configuration}} binaries
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{matrix.configuration}} binaries
|
||||
path: |
|
||||
|
2
external/FindWDK
vendored
2
external/FindWDK
vendored
Submodule external/FindWDK updated: c941028b26...04b4151f6d
2
external/ia32-doc
vendored
2
external/ia32-doc
vendored
Submodule external/ia32-doc updated: 77e021b690...2bc5284e04
@ -7,16 +7,6 @@
|
||||
#include "memory.hpp"
|
||||
#include "vmx.hpp"
|
||||
|
||||
#define MTRR_PAGE_SIZE 4096
|
||||
#define MTRR_PAGE_MASK (~(MTRR_PAGE_SIZE-1))
|
||||
|
||||
#define ADDRMASK_EPT_PML1_OFFSET(_VAR_) ((_VAR_) & 0xFFFULL)
|
||||
|
||||
#define ADDRMASK_EPT_PML1_INDEX(_VAR_) (((_VAR_) & 0x1FF000ULL) >> 12)
|
||||
#define ADDRMASK_EPT_PML2_INDEX(_VAR_) (((_VAR_) & 0x3FE00000ULL) >> 21)
|
||||
#define ADDRMASK_EPT_PML3_INDEX(_VAR_) (((_VAR_) & 0x7FC0000000ULL) >> 30)
|
||||
#define ADDRMASK_EPT_PML4_INDEX(_VAR_) (((_VAR_) & 0xFF8000000000ULL) >> 39)
|
||||
|
||||
namespace vmx
|
||||
{
|
||||
namespace
|
||||
@ -301,7 +291,7 @@ namespace vmx
|
||||
|
||||
// --------------------------
|
||||
|
||||
epdpte temp_epdpte;
|
||||
pml1 temp_epdpte{};
|
||||
temp_epdpte.flags = 0;
|
||||
temp_epdpte.read_access = 1;
|
||||
temp_epdpte.write_access = 1;
|
||||
@ -316,7 +306,7 @@ namespace vmx
|
||||
|
||||
// --------------------------
|
||||
|
||||
epde_2mb temp_epde{};
|
||||
pml2 temp_epde{};
|
||||
temp_epde.flags = 0;
|
||||
temp_epde.read_access = 1;
|
||||
temp_epde.write_access = 1;
|
||||
@ -410,18 +400,18 @@ namespace vmx
|
||||
}
|
||||
|
||||
const auto* pml2 = reinterpret_cast<pml2_ptr*>(pml2_entry);
|
||||
auto* pml1 = this->find_pml1_table(pml2->page_frame_number * PAGE_SIZE);
|
||||
if (!pml1)
|
||||
auto* pml1_table = this->find_pml1_table(pml2->page_frame_number * PAGE_SIZE);
|
||||
if (!pml1_table)
|
||||
{
|
||||
pml1 = static_cast<epte*>(memory::get_virtual_address(pml2->page_frame_number * PAGE_SIZE));
|
||||
pml1_table = static_cast<pml1*>(memory::get_virtual_address(pml2->page_frame_number * PAGE_SIZE));
|
||||
}
|
||||
|
||||
if (!pml1)
|
||||
if (!pml1_table)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &pml1[ADDRMASK_EPT_PML1_INDEX(physical_address)];
|
||||
return &pml1_table[ADDRMASK_EPT_PML1_INDEX(physical_address)];
|
||||
}
|
||||
|
||||
pml1* ept::find_pml1_table(const uint64_t physical_address)
|
||||
@ -561,7 +551,7 @@ namespace vmx
|
||||
|
||||
auto& split = this->allocate_ept_split();
|
||||
|
||||
epte pml1_template{};
|
||||
pml1 pml1_template{};
|
||||
pml1_template.flags = 0;
|
||||
pml1_template.read_access = 1;
|
||||
pml1_template.write_access = 1;
|
||||
|
@ -3,13 +3,30 @@
|
||||
#define DECLSPEC_PAGE_ALIGN DECLSPEC_ALIGN(PAGE_SIZE)
|
||||
#include "list.hpp"
|
||||
|
||||
|
||||
#define MTRR_PAGE_SIZE 4096
|
||||
#define MTRR_PAGE_MASK (~(MTRR_PAGE_SIZE-1))
|
||||
|
||||
#define ADDRMASK_EPT_PML1_OFFSET(_VAR_) ((_VAR_) & 0xFFFULL)
|
||||
|
||||
#define ADDRMASK_EPT_PML1_INDEX(_VAR_) (((_VAR_) & 0x1FF000ULL) >> 12)
|
||||
#define ADDRMASK_EPT_PML2_INDEX(_VAR_) (((_VAR_) & 0x3FE00000ULL) >> 21)
|
||||
#define ADDRMASK_EPT_PML3_INDEX(_VAR_) (((_VAR_) & 0x7FC0000000ULL) >> 30)
|
||||
#define ADDRMASK_EPT_PML4_INDEX(_VAR_) (((_VAR_) & 0xFF8000000000ULL) >> 39)
|
||||
|
||||
|
||||
namespace vmx
|
||||
{
|
||||
using pml4 = ept_pml4;
|
||||
using pml3 = epdpte;
|
||||
using pml2 = epde_2mb;
|
||||
using pml2_ptr = epde;
|
||||
using pml1 = epte;
|
||||
using pml4 = ept_pml4e;
|
||||
using pml3 = ept_pdpte;
|
||||
using pml2 = ept_pde_2mb;
|
||||
using pml2_ptr = ept_pde;
|
||||
using pml1 = ept_pte;
|
||||
|
||||
using pml4_entry = pml4e_64;
|
||||
using pml3_entry = pdpte_64;
|
||||
using pml2_entry = pde_64;
|
||||
using pml1_entry = pte_64;
|
||||
|
||||
struct ept_split
|
||||
{
|
||||
|
@ -13,6 +13,14 @@
|
||||
#define DPL_USER 3
|
||||
#define DPL_SYSTEM 0
|
||||
|
||||
typedef struct _EPROCESS
|
||||
{
|
||||
DISPATCHER_HEADER Header;
|
||||
LIST_ENTRY ProfileListHead;
|
||||
ULONG_PTR DirectoryTableBase;
|
||||
UCHAR Data[1];
|
||||
} EPROCESS, *PEPROCESS;
|
||||
|
||||
namespace
|
||||
{
|
||||
hypervisor* instance{nullptr};
|
||||
@ -45,6 +53,12 @@ namespace
|
||||
return cpuid_data[0] == 'momo';
|
||||
}
|
||||
|
||||
void enable_syscall_hooking()
|
||||
{
|
||||
int32_t cpu_info[4]{0};
|
||||
__cpuidex(cpu_info, 0x41414141, 0x42424243);
|
||||
}
|
||||
|
||||
void cpature_special_registers(vmx::special_registers& special_registers)
|
||||
{
|
||||
special_registers.cr0 = __readcr0();
|
||||
@ -63,7 +77,7 @@ namespace
|
||||
// See: https://github.com/ionescu007/SimpleVisor/issues/48
|
||||
#define capture_cpu_context(launch_context) \
|
||||
cpature_special_registers((launch_context).special_registers);\
|
||||
RtlCaptureContext(&(launch_context).context_frame)
|
||||
RtlCaptureContext(&(launch_context).context_frame);
|
||||
|
||||
void restore_descriptor_tables(vmx::launch_context& launch_context)
|
||||
{
|
||||
@ -455,78 +469,378 @@ void vmx_handle_invd()
|
||||
__wbinvd();
|
||||
}
|
||||
|
||||
bool log_other_call(uintptr_t guest_rip, bool rdtsc)
|
||||
void inject_interuption(const interruption_type type, const exception_vector vector, const bool deliver_code,
|
||||
const uint32_t error_code)
|
||||
{
|
||||
if (guest_rip < 0x140000000 || guest_rip > 0x15BC27000)
|
||||
vmentry_interrupt_information interrupt{};
|
||||
interrupt.valid = true;
|
||||
interrupt.interruption_type = type;
|
||||
interrupt.vector = vector;
|
||||
interrupt.deliver_error_code = deliver_code;
|
||||
|
||||
__vmx_vmwrite(VMCS_CTRL_VMENTRY_INTERRUPTION_INFORMATION_FIELD, interrupt.flags);
|
||||
|
||||
if (deliver_code)
|
||||
{
|
||||
return false;
|
||||
__vmx_vmwrite(VMCS_CTRL_VMENTRY_INTERRUPTION_INFORMATION_FIELD, error_code);
|
||||
}
|
||||
}
|
||||
|
||||
const auto is_privileged = (read_vmx(VMCS_GUEST_CS_SELECTOR) &
|
||||
SEGMENT_ACCESS_RIGHTS_DESCRIPTOR_PRIVILEGE_LEVEL_MASK) == DPL_SYSTEM;
|
||||
if(is_privileged)
|
||||
void inject_invalid_opcode()
|
||||
{
|
||||
inject_interuption(hardware_exception, invalid_opcode, false, 0);
|
||||
}
|
||||
|
||||
void inject_page_fault(const uint64_t page_fault_address)
|
||||
{
|
||||
__writecr2(page_fault_address);
|
||||
|
||||
page_fault_exception error_code{};
|
||||
error_code.flags = 0;
|
||||
|
||||
inject_interuption(hardware_exception, page_fault, true, error_code.flags);
|
||||
}
|
||||
|
||||
void inject_page_fault(const void* page_fault_address)
|
||||
{
|
||||
inject_page_fault(reinterpret_cast<uint64_t>(page_fault_address));
|
||||
}
|
||||
|
||||
cr3 get_current_process_cr3()
|
||||
{
|
||||
cr3 guest_cr3{};
|
||||
guest_cr3.flags = PsGetCurrentProcess()->DirectoryTableBase;
|
||||
|
||||
return guest_cr3;
|
||||
}
|
||||
|
||||
template <size_t Length>
|
||||
bool is_mem_equal(const uint8_t* ptr, const uint8_t (&array)[Length])
|
||||
{
|
||||
for (size_t i = 0; i < Length; ++i)
|
||||
{
|
||||
return false;
|
||||
if (ptr[i] != array[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const auto proc = process::get_current_process();
|
||||
|
||||
const auto filename = proc.get_image_filename();
|
||||
if (!string::equal(filename, "HogwartsLegacy"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
debug_log("%s (%s): %llX\n", rdtsc ? "RDTSC" : "RDTSCP",
|
||||
filename,
|
||||
guest_rip);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool log_cpuid_call(uintptr_t guest_rip, uintptr_t rax, uintptr_t rcx, const INT32* cpu_info)
|
||||
void set_exception_bit(const exception_vector bit, const bool value)
|
||||
{
|
||||
if (guest_rip < 0x140000000 || guest_rip > 0x15BC27000)
|
||||
auto exception_bitmap = read_vmx(VMCS_CTRL_EXCEPTION_BITMAP);
|
||||
|
||||
if (value)
|
||||
{
|
||||
return false;
|
||||
exception_bitmap |= 1ULL << bit;
|
||||
}
|
||||
else
|
||||
{
|
||||
exception_bitmap &= ~(1ULL << bit);
|
||||
}
|
||||
|
||||
const auto is_privileged = (read_vmx(VMCS_GUEST_CS_SELECTOR) &
|
||||
SEGMENT_ACCESS_RIGHTS_DESCRIPTOR_PRIVILEGE_LEVEL_MASK) == DPL_SYSTEM;
|
||||
if (is_privileged)
|
||||
__vmx_vmwrite(VMCS_CTRL_EXCEPTION_BITMAP, exception_bitmap);
|
||||
}
|
||||
|
||||
void vmx_enable_syscall_hooks(const bool enable)
|
||||
{
|
||||
ULARGE_INTEGER msr{};
|
||||
ia32_efer_register efer_register{};
|
||||
ia32_vmx_basic_register vmx_basic_register{};
|
||||
ia32_vmx_exit_ctls_register exit_ctls_register{};
|
||||
ia32_vmx_entry_ctls_register entry_ctls_register{};
|
||||
|
||||
vmx_basic_register.flags = __readmsr(IA32_VMX_BASIC);
|
||||
exit_ctls_register.flags = read_vmx(VMCS_CTRL_PRIMARY_VMEXIT_CONTROLS);
|
||||
entry_ctls_register.flags = read_vmx(VMCS_CTRL_VMENTRY_CONTROLS);
|
||||
|
||||
efer_register.flags = __readmsr(IA32_EFER);
|
||||
|
||||
// ---------------------------------------
|
||||
|
||||
efer_register.syscall_enable = !enable;
|
||||
exit_ctls_register.save_ia32_efer = enable;
|
||||
entry_ctls_register.load_ia32_efer = enable;
|
||||
|
||||
// ---------------------------------------
|
||||
|
||||
if (enable)
|
||||
{
|
||||
return false;
|
||||
msr.QuadPart = __readmsr(vmx_basic_register.vmx_controls ? IA32_VMX_TRUE_ENTRY_CTLS : IA32_VMX_ENTRY_CTLS);
|
||||
__vmx_vmwrite(VMCS_CTRL_VMENTRY_CONTROLS, adjust_msr(msr, entry_ctls_register.flags));
|
||||
|
||||
msr.QuadPart = __readmsr(vmx_basic_register.vmx_controls ? IA32_VMX_TRUE_EXIT_CTLS : IA32_VMX_EXIT_CTLS);
|
||||
__vmx_vmwrite(VMCS_CTRL_PRIMARY_VMEXIT_CONTROLS, adjust_msr(msr, exit_ctls_register.flags));
|
||||
}
|
||||
|
||||
const auto proc = process::get_current_process();
|
||||
__vmx_vmwrite(VMCS_GUEST_EFER, efer_register.flags);
|
||||
|
||||
const auto filename = proc.get_image_filename();
|
||||
if (!string::equal(filename, "HogwartsLegacy"))
|
||||
set_exception_bit(invalid_opcode, enable);
|
||||
}
|
||||
|
||||
enum class syscall_state
|
||||
{
|
||||
is_sysret,
|
||||
is_syscall,
|
||||
page_fault,
|
||||
none,
|
||||
};
|
||||
|
||||
class scoped_cr3_switch
|
||||
{
|
||||
public:
|
||||
scoped_cr3_switch()
|
||||
{
|
||||
return false;
|
||||
original_cr3_.flags = __readcr3();
|
||||
}
|
||||
|
||||
scoped_cr3_switch(const cr3 new_cr3)
|
||||
: scoped_cr3_switch()
|
||||
{
|
||||
this->set_cr3(new_cr3);
|
||||
}
|
||||
|
||||
debug_log("CPUID call (%s): %llX - (EAX: %08X - ECX: %08X) - (EAX: %08X - EBX: %08X - ECX: %08X - EDX: %08X)\n",
|
||||
filename,
|
||||
guest_rip, rax, rcx, cpu_info[0], cpu_info[1], cpu_info[2], cpu_info[3]);
|
||||
scoped_cr3_switch(const scoped_cr3_switch&) = delete;
|
||||
scoped_cr3_switch& operator=(const scoped_cr3_switch&) = delete;
|
||||
|
||||
//debug_log("OVERHEAD\n");
|
||||
scoped_cr3_switch(scoped_cr3_switch&&) = delete;
|
||||
scoped_cr3_switch& operator=(scoped_cr3_switch&&) = delete;
|
||||
|
||||
~scoped_cr3_switch()
|
||||
{
|
||||
__writecr3(original_cr3_.flags);
|
||||
}
|
||||
|
||||
void set_cr3(const cr3 new_cr3)
|
||||
{
|
||||
this->must_restore_ = true;
|
||||
__writecr3(new_cr3.flags);
|
||||
}
|
||||
|
||||
private:
|
||||
bool must_restore_{false};
|
||||
cr3 original_cr3_{};
|
||||
};
|
||||
|
||||
template <size_t Length>
|
||||
bool read_data_or_page_fault(uint8_t (&array)[Length], const uint8_t* base)
|
||||
{
|
||||
for (size_t offset = 0; offset < Length;)
|
||||
{
|
||||
auto* current_base = base + offset;
|
||||
auto* current_destination = array + offset;
|
||||
auto read_length = Length - offset;
|
||||
|
||||
const auto* page_start = static_cast<uint8_t*>(PAGE_ALIGN(current_base));
|
||||
const auto* next_page = page_start + PAGE_SIZE;
|
||||
|
||||
if (current_base + read_length > next_page)
|
||||
{
|
||||
read_length = next_page - current_base;
|
||||
}
|
||||
|
||||
offset += read_length;
|
||||
|
||||
const auto physical_base = memory::get_physical_address(const_cast<uint8_t*>(current_base));
|
||||
|
||||
if (!physical_base)
|
||||
{
|
||||
inject_page_fault(current_base);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!memory::read_physical_memory(current_destination, physical_base, read_length))
|
||||
{
|
||||
// Not sure if we can recover from that :(
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
syscall_state get_syscall_state(const vmx::guest_context& guest_context)
|
||||
{
|
||||
scoped_cr3_switch cr3_switch{};
|
||||
|
||||
constexpr auto PCID_NONE = 0x000;
|
||||
constexpr auto PCID_MASK = 0x003;
|
||||
|
||||
cr3 guest_cr3{};
|
||||
guest_cr3.flags = read_vmx(VMCS_GUEST_CR3);
|
||||
|
||||
if ((guest_cr3.flags & PCID_MASK) != PCID_NONE)
|
||||
{
|
||||
cr3_switch.set_cr3(get_current_process_cr3());
|
||||
}
|
||||
|
||||
const auto* rip = reinterpret_cast<uint8_t*>(guest_context.guest_rip);
|
||||
|
||||
constexpr uint8_t syscall_bytes[] = {0x0F, 0x05};
|
||||
constexpr uint8_t sysret_bytes[] = {0x48, 0x0F, 0x07};
|
||||
|
||||
constexpr auto max_byte_length = max(sizeof(sysret_bytes), sizeof(syscall_bytes));
|
||||
|
||||
uint8_t data[max_byte_length];
|
||||
|
||||
if (!read_data_or_page_fault(data, rip))
|
||||
{
|
||||
return syscall_state::page_fault;
|
||||
}
|
||||
|
||||
if (is_mem_equal(data, syscall_bytes))
|
||||
{
|
||||
return syscall_state::is_syscall;
|
||||
}
|
||||
|
||||
if (is_mem_equal(data, sysret_bytes))
|
||||
{
|
||||
return syscall_state::is_sysret;
|
||||
}
|
||||
|
||||
return syscall_state::none;
|
||||
}
|
||||
|
||||
void vmx_handle_exception(vmx::guest_context& guest_context)
|
||||
{
|
||||
vmexit_interrupt_information interrupt{};
|
||||
interrupt.flags = static_cast<uint32_t>(read_vmx(VMCS_VMEXIT_INTERRUPTION_INFORMATION));
|
||||
|
||||
if (interrupt.interruption_type == non_maskable_interrupt
|
||||
&& interrupt.vector == nmi)
|
||||
{
|
||||
// TODO ?
|
||||
return;
|
||||
}
|
||||
|
||||
if (interrupt.vector == invalid_opcode)
|
||||
{
|
||||
guest_context.increment_rip = false;
|
||||
|
||||
const auto state = get_syscall_state(guest_context);
|
||||
|
||||
if (state == syscall_state::page_fault)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto proc = process::get_current_process();
|
||||
|
||||
const auto filename = proc.get_image_filename();
|
||||
if (string::equal(filename, "explorer.exe"))
|
||||
{
|
||||
debug_log("Explorer SYSCALL: %d\n", static_cast<uint32_t>(guest_context.vp_regs->Rax));
|
||||
}
|
||||
|
||||
if (state == syscall_state::is_syscall)
|
||||
{
|
||||
const auto instruction_length = read_vmx(VMCS_VMEXIT_INSTRUCTION_LENGTH);
|
||||
|
||||
const auto star = __readmsr(IA32_STAR);
|
||||
const auto lstar = __readmsr(IA32_LSTAR);
|
||||
const auto fmask = __readmsr(IA32_FMASK);
|
||||
|
||||
guest_context.vp_regs->Rcx = guest_context.guest_rip + instruction_length;
|
||||
guest_context.guest_rip = lstar;
|
||||
__vmx_vmwrite(VMCS_GUEST_RIP, guest_context.guest_rip);
|
||||
|
||||
|
||||
guest_context.vp_regs->R11 = guest_context.guest_e_flags;
|
||||
guest_context.guest_e_flags &= ~(fmask | RFLAGS_RESUME_FLAG_FLAG);
|
||||
__vmx_vmwrite(VMCS_GUEST_RFLAGS, guest_context.guest_e_flags);
|
||||
|
||||
|
||||
vmx::gdt_entry gdt_entry{};
|
||||
gdt_entry.selector.flags = static_cast<uint16_t>((star >> 32) & ~3);
|
||||
gdt_entry.base = 0;
|
||||
gdt_entry.limit = 0xFFFFF;
|
||||
gdt_entry.access_rights.flags = 0xA09B;
|
||||
|
||||
__vmx_vmwrite(VMCS_GUEST_CS_SELECTOR, gdt_entry.selector.flags);
|
||||
__vmx_vmwrite(VMCS_GUEST_CS_LIMIT, gdt_entry.limit);
|
||||
__vmx_vmwrite(VMCS_GUEST_CS_ACCESS_RIGHTS, gdt_entry.access_rights.flags);
|
||||
__vmx_vmwrite(VMCS_GUEST_CS_BASE, gdt_entry.base);
|
||||
|
||||
gdt_entry = {};
|
||||
gdt_entry.selector.flags = static_cast<uint16_t>(((star >> 32) & ~3) + 8);
|
||||
gdt_entry.base = 0;
|
||||
gdt_entry.limit = 0xFFFFF;
|
||||
gdt_entry.access_rights.flags = 0xC093;
|
||||
|
||||
__vmx_vmwrite(VMCS_GUEST_SS_SELECTOR, gdt_entry.selector.flags);
|
||||
__vmx_vmwrite(VMCS_GUEST_SS_LIMIT, gdt_entry.limit);
|
||||
__vmx_vmwrite(VMCS_GUEST_SS_ACCESS_RIGHTS, gdt_entry.access_rights.flags);
|
||||
__vmx_vmwrite(VMCS_GUEST_SS_BASE, gdt_entry.base);
|
||||
}
|
||||
else if (state == syscall_state::is_sysret)
|
||||
{
|
||||
const auto star = __readmsr(IA32_STAR);
|
||||
|
||||
guest_context.vp_regs->Rip = guest_context.vp_regs->Rcx;
|
||||
__vmx_vmwrite(VMCS_GUEST_RIP, guest_context.vp_regs->Rip);
|
||||
|
||||
guest_context.guest_e_flags = (guest_context.vp_regs->R11 & 0x3C7FD7) | 2;
|
||||
__vmx_vmwrite(VMCS_GUEST_RFLAGS, guest_context.guest_e_flags);
|
||||
|
||||
vmx::gdt_entry gdt_entry{};
|
||||
gdt_entry.selector.flags = static_cast<uint16_t>(((star >> 48) + 16) | 3);
|
||||
gdt_entry.base = 0;
|
||||
gdt_entry.limit = 0xFFFFF;
|
||||
gdt_entry.access_rights.flags = 0xA0FB;
|
||||
|
||||
__vmx_vmwrite(VMCS_GUEST_CS_SELECTOR, gdt_entry.selector.flags);
|
||||
__vmx_vmwrite(VMCS_GUEST_CS_LIMIT, gdt_entry.limit);
|
||||
__vmx_vmwrite(VMCS_GUEST_CS_ACCESS_RIGHTS, gdt_entry.access_rights.flags);
|
||||
__vmx_vmwrite(VMCS_GUEST_CS_BASE, gdt_entry.base);
|
||||
|
||||
gdt_entry = {};
|
||||
gdt_entry.selector.flags = static_cast<uint16_t>(((star >> 48) + 8) | 3);
|
||||
gdt_entry.base = 0;
|
||||
gdt_entry.limit = 0xFFFFF;
|
||||
gdt_entry.access_rights.flags = 0xC0F3;
|
||||
|
||||
__vmx_vmwrite(VMCS_GUEST_SS_SELECTOR, gdt_entry.selector.flags);
|
||||
__vmx_vmwrite(VMCS_GUEST_SS_LIMIT, gdt_entry.limit);
|
||||
__vmx_vmwrite(VMCS_GUEST_SS_ACCESS_RIGHTS, gdt_entry.access_rights.flags);
|
||||
__vmx_vmwrite(VMCS_GUEST_SS_BASE, gdt_entry.base);
|
||||
}
|
||||
else
|
||||
{
|
||||
inject_invalid_opcode();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
__vmx_vmwrite(VMCS_CTRL_VMENTRY_INTERRUPTION_INFORMATION_FIELD, interrupt.flags);
|
||||
if (interrupt.error_code_valid)
|
||||
{
|
||||
__vmx_vmwrite(VMCS_CTRL_VMENTRY_EXCEPTION_ERROR_CODE, read_vmx(VMCS_VMEXIT_INTERRUPTION_ERROR_CODE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool is_system()
|
||||
{
|
||||
return (read_vmx(VMCS_GUEST_CS_SELECTOR) & SEGMENT_ACCESS_RIGHTS_DESCRIPTOR_PRIVILEGE_LEVEL_MASK) == DPL_SYSTEM;
|
||||
}
|
||||
|
||||
void vmx_handle_cpuid(vmx::guest_context& guest_context)
|
||||
{
|
||||
INT32 cpu_info[4]{0, 0, 0, 0};
|
||||
if (guest_context.vp_regs->Rax == 0x41414141 &&
|
||||
guest_context.vp_regs->Rcx == 0x42424243 &&
|
||||
is_system())
|
||||
{
|
||||
vmx_enable_syscall_hooks(true);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto is_privileged = (read_vmx(VMCS_GUEST_CS_SELECTOR) &
|
||||
SEGMENT_ACCESS_RIGHTS_DESCRIPTOR_PRIVILEGE_LEVEL_MASK) == DPL_SYSTEM;
|
||||
INT32 cpu_info[4];
|
||||
|
||||
if (guest_context.vp_regs->Rax == 0x41414141 &&
|
||||
guest_context.vp_regs->Rcx == 0x42424242 &&
|
||||
is_privileged)
|
||||
is_system())
|
||||
{
|
||||
guest_context.exit_vm = true;
|
||||
return;
|
||||
@ -535,15 +849,6 @@ void vmx_handle_cpuid(vmx::guest_context& guest_context)
|
||||
__cpuidex(cpu_info, static_cast<int32_t>(guest_context.vp_regs->Rax),
|
||||
static_cast<int32_t>(guest_context.vp_regs->Rcx));
|
||||
|
||||
bool should_zero = false;
|
||||
if (!is_privileged)
|
||||
{
|
||||
should_zero = log_cpuid_call(guest_context.guest_rip, guest_context.vp_regs->Rax, guest_context.vp_regs->Rcx,
|
||||
cpu_info);
|
||||
}
|
||||
|
||||
const auto _rax = guest_context.vp_regs->Rax;
|
||||
|
||||
if (guest_context.vp_regs->Rax == 1)
|
||||
{
|
||||
cpu_info[2] |= HYPERV_HYPERVISOR_PRESENT_BIT;
|
||||
@ -553,107 +858,6 @@ void vmx_handle_cpuid(vmx::guest_context& guest_context)
|
||||
cpu_info[0] = 'momo';
|
||||
}
|
||||
|
||||
if (should_zero)
|
||||
{
|
||||
// [MOMO] CPUID call(HogwartsLegacy) : 140D2451B - (EAX : 80000006 - ECX : 00000000) - (EAX : 00000000 - EBX : 00000000 - ECX : 01006040 - EDX : 00000000)
|
||||
// [MOMO] CPUID call (HogwartsLegacy): 1405F4817 - (EAX: 00000004 - ECX: 00000000) - (EAX: 1C004121 - EBX: 01C0003F - ECX: 0000003F - EDX: 00000000)
|
||||
|
||||
bool allow_all = true;
|
||||
|
||||
// not sure if necessary
|
||||
/*if (_rax == 0 && allow_all)
|
||||
{
|
||||
cpu_info[0] = 0x00000016;
|
||||
cpu_info[1] = 0x756E6547;
|
||||
cpu_info[2] = 0x6C65746E;
|
||||
cpu_info[3] = 0x49656E69;
|
||||
}
|
||||
else if (_rax == 4 && allow_all)
|
||||
{
|
||||
cpu_info[0] = 0x00000000;
|
||||
cpu_info[1] = 0x01C0003F;
|
||||
cpu_info[2] = 0x0000003F;
|
||||
cpu_info[3] = 0x00000000;
|
||||
}
|
||||
else if (_rax == 7 && allow_all)
|
||||
{
|
||||
cpu_info[0] = 0x1C004121;
|
||||
cpu_info[1] = 0x029C6FBF;
|
||||
cpu_info[2] = 0x40000000;
|
||||
cpu_info[3] = (INT32)0xBC002E00;
|
||||
}
|
||||
else if (_rax == 0x80000000 && allow_all)
|
||||
{
|
||||
cpu_info[0] = (INT32)0x80000008;
|
||||
cpu_info[1] = 0x00000000;
|
||||
cpu_info[2] = 0x00000000;
|
||||
cpu_info[3] = 0x00000000;
|
||||
}
|
||||
else if (_rax == 0x80000006 && allow_all)
|
||||
{
|
||||
cpu_info[0] = 0x00000000;
|
||||
cpu_info[1] = 0x00000000;
|
||||
cpu_info[2] = 0x01006040;
|
||||
cpu_info[3] = 0x00000000;
|
||||
}
|
||||
|
||||
|
||||
// absolutely necessary v
|
||||
else*/ if (_rax == 1 && allow_all)
|
||||
{
|
||||
cpu_info[0] = 0x000306A9;
|
||||
cpu_info[1] = 0x02100800;
|
||||
cpu_info[2] = 0x7FBAE3FF & (~0xC000000);
|
||||
//cpu_info[0] = 0x000906EA;
|
||||
//cpu_info[1] = 0x04100800;
|
||||
//cpu_info[2] = 0x7FFAFBFF & (~0xC000000);
|
||||
|
||||
cpu_info[3] = (INT32)0xBFEBFBFF ;
|
||||
}
|
||||
else if (_rax == 0x80000002)
|
||||
{
|
||||
cpu_info[0] = 0x65746E49;
|
||||
cpu_info[1] = 0x2952286C;
|
||||
cpu_info[2] = 0x726F4320;
|
||||
cpu_info[3] = 0x4D542865;
|
||||
}
|
||||
else if (_rax == 0x80000003)
|
||||
{
|
||||
cpu_info[0] = 0x37692029;
|
||||
cpu_info[1] = 0x3538382D;
|
||||
cpu_info[2] = 0x43204830;
|
||||
cpu_info[3] = 0x40205550;
|
||||
}
|
||||
else if (_rax == 0x80000004)
|
||||
{
|
||||
cpu_info[0] = 0x362E3220;
|
||||
cpu_info[1] = 0x7A484730;
|
||||
cpu_info[2] = 0x00000000;
|
||||
cpu_info[3] = 0x00000000;
|
||||
}
|
||||
else if(false)
|
||||
{
|
||||
cpu_info[0] = 0;
|
||||
cpu_info[1] = 0;
|
||||
cpu_info[2] = 0;
|
||||
cpu_info[3] = 0;
|
||||
debug_log("Not zeroing!\n");
|
||||
}
|
||||
|
||||
/* should_zero &= _rax == 1
|
||||
|| _rax == 0x80000002
|
||||
|| _rax == 0x80000003
|
||||
|| _rax == 0x80000004;
|
||||
*
|
||||
if (should_zero)
|
||||
{
|
||||
cpu_info[0] = 0;
|
||||
cpu_info[1] = 0;
|
||||
cpu_info[2] = 0;
|
||||
cpu_info[3] = 0;
|
||||
}*/
|
||||
}
|
||||
|
||||
guest_context.vp_regs->Rax = cpu_info[0];
|
||||
guest_context.vp_regs->Rbx = cpu_info[1];
|
||||
guest_context.vp_regs->Rcx = cpu_info[2];
|
||||
@ -703,37 +907,12 @@ void vmx_dispatch_vm_exit(vmx::guest_context& guest_context, const vmx::state& v
|
||||
case VMX_EXIT_REASON_EPT_MISCONFIGURATION:
|
||||
vm_state.ept->handle_misconfiguration(guest_context);
|
||||
break;
|
||||
case VMX_EXIT_REASON_EXECUTE_RDTSC:
|
||||
{
|
||||
//debug_log("VM exit: VMX_EXIT_REASON_EXECUTE_RDTSC\n");
|
||||
|
||||
ULARGE_INTEGER tsc{};
|
||||
|
||||
tsc.QuadPart = __rdtsc();
|
||||
|
||||
guest_context.vp_regs->Rax = tsc.LowPart;
|
||||
guest_context.vp_regs->Rdx = tsc.HighPart;
|
||||
|
||||
log_other_call(guest_context.guest_rip, true);
|
||||
case VMX_EXIT_REASON_EXCEPTION_OR_NMI:
|
||||
vmx_handle_exception(guest_context);
|
||||
break;
|
||||
}
|
||||
case VMX_EXIT_REASON_EXECUTE_RDTSCP:
|
||||
{
|
||||
//debug_log("VM exit: VMX_EXIT_REASON_EXECUTE_RDTSCP\n");
|
||||
|
||||
uint32_t _rcx{};
|
||||
ULARGE_INTEGER tsc{};
|
||||
tsc.QuadPart = __rdtscp(&_rcx);
|
||||
|
||||
guest_context.vp_regs->Rax = tsc.LowPart;
|
||||
guest_context.vp_regs->Rdx = tsc.HighPart;
|
||||
guest_context.vp_regs->Rcx = _rcx;
|
||||
|
||||
log_other_call(guest_context.guest_rip, false);
|
||||
break;
|
||||
}
|
||||
//case VMX_EXIT_REASON_EXECUTE_RDTSC:
|
||||
// break;
|
||||
default:
|
||||
//debug_log("Unknown VM exit: %X\n",(uint32_t) guest_context.exit_reason);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -810,7 +989,6 @@ void setup_vmcs_for_cpu(vmx::state& vm_state)
|
||||
ia32_vmx_procbased_ctls_register procbased_ctls_register{};
|
||||
procbased_ctls_register.activate_secondary_controls = 1;
|
||||
procbased_ctls_register.use_msr_bitmaps = 1;
|
||||
procbased_ctls_register.rdtsc_exiting = 0;
|
||||
|
||||
__vmx_vmwrite(VMCS_CTRL_PROCESSOR_BASED_VM_EXECUTION_CONTROLS,
|
||||
adjust_msr(launch_context->msr_data[14],
|
||||
@ -818,7 +996,7 @@ void setup_vmcs_for_cpu(vmx::state& vm_state)
|
||||
|
||||
ia32_vmx_exit_ctls_register exit_ctls_register{};
|
||||
exit_ctls_register.host_address_space_size = 1;
|
||||
__vmx_vmwrite(VMCS_CTRL_VMEXIT_CONTROLS,
|
||||
__vmx_vmwrite(VMCS_CTRL_PRIMARY_VMEXIT_CONTROLS,
|
||||
adjust_msr(launch_context->msr_data[15],
|
||||
exit_ctls_register.flags));
|
||||
|
||||
@ -909,7 +1087,8 @@ void setup_vmcs_for_cpu(vmx::state& vm_state)
|
||||
__vmx_vmwrite(VMCS_GUEST_DEBUGCTL, state->debug_control);
|
||||
__vmx_vmwrite(VMCS_GUEST_DR7, state->kernel_dr7);
|
||||
|
||||
const auto stack_pointer = reinterpret_cast<uintptr_t>(vm_state.stack_buffer) + KERNEL_STACK_SIZE - sizeof(CONTEXT);
|
||||
const auto stack_pointer = reinterpret_cast<uintptr_t>(vm_state.stack_buffer) + KERNEL_STACK_SIZE - sizeof(
|
||||
CONTEXT);
|
||||
|
||||
__vmx_vmwrite(VMCS_GUEST_RSP, stack_pointer);
|
||||
__vmx_vmwrite(VMCS_GUEST_RIP, reinterpret_cast<uintptr_t>(vm_launch));
|
||||
@ -972,6 +1151,8 @@ void hypervisor::enable_core(const uint64_t system_directory_table_base)
|
||||
{
|
||||
throw std::runtime_error("Hypervisor is not present");
|
||||
}
|
||||
|
||||
enable_syscall_hooking();
|
||||
}
|
||||
|
||||
void hypervisor::disable_core()
|
||||
|
@ -68,6 +68,18 @@ namespace memory
|
||||
return memory;
|
||||
}
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
|
||||
bool read_physical_memory(void* destination, uint64_t physical_address, const size_t size)
|
||||
{
|
||||
size_t bytes_read{};
|
||||
MM_COPY_ADDRESS source{};
|
||||
source.PhysicalAddress.QuadPart = static_cast<int64_t>(physical_address);
|
||||
|
||||
return MmCopyMemory(destination, source, size, MM_COPY_MEMORY_PHYSICAL, &bytes_read) == STATUS_SUCCESS &&
|
||||
bytes_read == size;
|
||||
}
|
||||
|
||||
uint64_t get_physical_address(void* address)
|
||||
{
|
||||
return static_cast<uint64_t>(MmGetPhysicalAddress(address).QuadPart);
|
||||
|
@ -10,6 +10,9 @@ namespace memory
|
||||
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||
void* allocate_aligned_memory(size_t size);
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
bool read_physical_memory(void* destination, uint64_t physical_address, size_t size);
|
||||
|
||||
uint64_t get_physical_address(void* address);
|
||||
void* get_virtual_address(uint64_t address);
|
||||
|
||||
|
@ -56,6 +56,29 @@ MmAllocateContiguousNodeMemory(
|
||||
|
||||
// ----------------------------------------
|
||||
|
||||
typedef struct _MM_COPY_ADDRESS {
|
||||
union {
|
||||
PVOID VirtualAddress;
|
||||
PHYSICAL_ADDRESS PhysicalAddress;
|
||||
};
|
||||
} MM_COPY_ADDRESS, * PMMCOPY_ADDRESS;
|
||||
|
||||
#define MM_COPY_MEMORY_PHYSICAL 0x1
|
||||
#define MM_COPY_MEMORY_VIRTUAL 0x2
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
NTKERNELAPI
|
||||
NTSTATUS
|
||||
MmCopyMemory(
|
||||
_In_ PVOID TargetAddress,
|
||||
_In_ MM_COPY_ADDRESS SourceAddress,
|
||||
_In_ SIZE_T NumberOfBytes,
|
||||
_In_ ULONG Flags,
|
||||
_Out_ PSIZE_T NumberOfBytesTransferred
|
||||
);
|
||||
|
||||
// ----------------------------------------
|
||||
|
||||
NTSYSAPI
|
||||
VOID
|
||||
NTAPI
|
||||
|
@ -10,7 +10,7 @@ namespace string
|
||||
|
||||
char* get_va_buffer();
|
||||
|
||||
template <typename... Args>
|
||||
template <typename ...Args>
|
||||
const char* va(const char* message, Args&&... args)
|
||||
{
|
||||
auto* buffer = get_va_buffer();
|
||||
@ -25,9 +25,9 @@ namespace string
|
||||
return !s2;
|
||||
}
|
||||
|
||||
while(*s1)
|
||||
while (*s1)
|
||||
{
|
||||
if(*(s1++) != *(s2++))
|
||||
if (*(s1++) != *(s2++))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -45,12 +45,25 @@ namespace
|
||||
static driver hypervisor{};
|
||||
static driver_device device{};
|
||||
|
||||
if (!hypervisor)
|
||||
if (!device)
|
||||
{
|
||||
try
|
||||
{
|
||||
hypervisor = create_driver();
|
||||
}catch(...){}
|
||||
device = create_driver_device();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
if (device)
|
||||
{
|
||||
return device;
|
||||
}
|
||||
|
||||
if (!hypervisor)
|
||||
{
|
||||
hypervisor = create_driver();
|
||||
}
|
||||
|
||||
if (!device)
|
||||
|
@ -87,7 +87,12 @@ void patch_t6(const uint32_t pid)
|
||||
|
||||
void try_patch_t6()
|
||||
{
|
||||
const auto pid = get_process_id_from_window(nullptr, "Call of Duty" "\xAE" ": Black Ops II - Multiplayer");
|
||||
auto pid = get_process_id_from_window(nullptr, "Call of Duty" "\xAE" ": Black Ops II - Multiplayer");
|
||||
if (!pid)
|
||||
{
|
||||
pid = get_process_id_from_window("CoDBlackOps", nullptr);
|
||||
}
|
||||
|
||||
if (pid)
|
||||
{
|
||||
printf("Patching T6...\n");
|
||||
|
Reference in New Issue
Block a user