mirror of
https://github.com/momo5502/hypervisor.git
synced 2025-07-01 08:41:55 +00:00
Prepare code watching
This commit is contained in:
@ -77,7 +77,7 @@ namespace vmx
|
||||
|
||||
void update_fake_page(ept_hook& hook)
|
||||
{
|
||||
if(!hook.mapped_virtual_address)
|
||||
if (!hook.mapped_virtual_address)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -85,9 +85,9 @@ namespace vmx
|
||||
uint8_t page_copy[PAGE_SIZE];
|
||||
memcpy(page_copy, hook.mapped_virtual_address, PAGE_SIZE);
|
||||
|
||||
for(size_t i = 0; i < PAGE_SIZE; ++i)
|
||||
for (size_t i = 0; i < PAGE_SIZE; ++i)
|
||||
{
|
||||
if(hook.diff_page[i] != page_copy[i])
|
||||
if (hook.diff_page[i] != page_copy[i])
|
||||
{
|
||||
hook.diff_page[i] = page_copy[i];
|
||||
hook.fake_page[i] = page_copy[i];
|
||||
@ -121,6 +121,8 @@ namespace vmx
|
||||
memset(this->epml4, 0, sizeof(this->epml4));
|
||||
memset(this->epdpt, 0, sizeof(this->epdpt));
|
||||
memset(this->epde, 0, sizeof(this->epde));
|
||||
|
||||
memset(this->access_records, 0, sizeof(this->access_records));
|
||||
}
|
||||
|
||||
ept::~ept()
|
||||
@ -140,6 +142,14 @@ namespace vmx
|
||||
hook = hook->next_hook;
|
||||
memory::free_aligned_object(current_hook);
|
||||
}
|
||||
|
||||
auto* watch_point = this->ept_code_watch_points;
|
||||
while (watch_point)
|
||||
{
|
||||
auto* current_watch_point = watch_point;
|
||||
watch_point = watch_point->next_watch_point;
|
||||
memory::free_aligned_object(current_watch_point);
|
||||
}
|
||||
}
|
||||
|
||||
void ept::install_page_hook(void* destination, const void* source, const size_t length,
|
||||
@ -151,6 +161,33 @@ namespace vmx
|
||||
memcpy(hook->fake_page + page_offset, source, length);
|
||||
}
|
||||
|
||||
void ept::record_access(const uint64_t rip)
|
||||
{
|
||||
const auto _ = utils::finally([&]
|
||||
{
|
||||
InterlockedExchange(&this->access_records_barrier, 0);
|
||||
});
|
||||
|
||||
// Aaaahhh, fuck that xD
|
||||
while (InterlockedExchange(&this->access_records_barrier, 1))
|
||||
{
|
||||
}
|
||||
|
||||
for (unsigned long long& access_record : this->access_records)
|
||||
{
|
||||
if (access_record == 0)
|
||||
{
|
||||
access_record = rip;
|
||||
return;
|
||||
}
|
||||
|
||||
if (access_record == rip)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ept::install_hook(const void* destination, const void* source, const size_t length,
|
||||
ept_translation_hint* translation_hint)
|
||||
{
|
||||
@ -197,7 +234,7 @@ namespace vmx
|
||||
}
|
||||
}
|
||||
|
||||
void ept::handle_violation(guest_context& guest_context) const
|
||||
void ept::handle_violation(guest_context& guest_context)
|
||||
{
|
||||
vmx_exit_qualification_ept_violation violation_qualification{};
|
||||
violation_qualification.flags = guest_context.exit_qualification;
|
||||
@ -208,6 +245,32 @@ namespace vmx
|
||||
}
|
||||
|
||||
const auto physical_base_address = reinterpret_cast<uint64_t>(PAGE_ALIGN(guest_context.guest_physical_address));
|
||||
|
||||
// watch-point stuff
|
||||
|
||||
auto* watch_point = this->find_ept_code_watch_point(physical_base_address);
|
||||
if (watch_point)
|
||||
{
|
||||
if (!violation_qualification.ept_executable && violation_qualification.execute_access)
|
||||
{
|
||||
watch_point->target_page->execute_access = 1;
|
||||
watch_point->target_page->read_access = 0;
|
||||
guest_context.increment_rip = false;
|
||||
}
|
||||
|
||||
if (violation_qualification.ept_executable && violation_qualification.read_access)
|
||||
{
|
||||
watch_point->target_page->execute_access = 0;
|
||||
watch_point->target_page->read_access = 1;
|
||||
guest_context.increment_rip = false;
|
||||
this->record_access(guest_context.guest_rip);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// ept-hooking stuff
|
||||
|
||||
auto* hook = this->find_ept_hook(physical_base_address);
|
||||
if (!hook)
|
||||
{
|
||||
@ -283,6 +346,30 @@ namespace vmx
|
||||
}
|
||||
}
|
||||
|
||||
void ept::install_code_watch_point(const uint64_t physical_page)
|
||||
{
|
||||
const auto physical_base_address = reinterpret_cast<uint64_t>(PAGE_ALIGN(physical_page));
|
||||
|
||||
if (this->find_ept_code_watch_point(physical_base_address))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto* watch_point = this->allocate_ept_code_watch_point();
|
||||
if (!watch_point)
|
||||
{
|
||||
throw std::runtime_error("Failed to allocate watch point");
|
||||
}
|
||||
|
||||
this->split_large_page(physical_base_address);
|
||||
|
||||
watch_point->target_page = this->get_pml1_entry(physical_base_address);
|
||||
if (!watch_point->target_page)
|
||||
{
|
||||
throw std::runtime_error("Failed to get PML1 entry for target address");
|
||||
}
|
||||
}
|
||||
|
||||
ept_pointer ept::get_ept_pointer() const
|
||||
{
|
||||
const auto ept_pml4_physical_address = memory::get_physical_address(const_cast<pml4*>(&this->epml4[0]));
|
||||
@ -404,6 +491,36 @@ namespace vmx
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ept_code_watch_point* ept::allocate_ept_code_watch_point()
|
||||
{
|
||||
auto* watch_point = memory::allocate_aligned_object<ept_code_watch_point>();
|
||||
if (!watch_point)
|
||||
{
|
||||
throw std::runtime_error("Failed to allocate ept watch point object");
|
||||
}
|
||||
|
||||
watch_point->next_watch_point = this->ept_code_watch_points;
|
||||
this->ept_code_watch_points = watch_point;
|
||||
|
||||
return watch_point;
|
||||
}
|
||||
|
||||
ept_code_watch_point* ept::find_ept_code_watch_point(const uint64_t physical_address) const
|
||||
{
|
||||
auto* watch_point = this->ept_code_watch_points;
|
||||
while (watch_point)
|
||||
{
|
||||
if (watch_point->physical_base_address == physical_address)
|
||||
{
|
||||
return watch_point;
|
||||
}
|
||||
|
||||
watch_point = watch_point->next_watch_point;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ept_hook* ept::get_or_create_ept_hook(void* destination, ept_translation_hint* translation_hint)
|
||||
{
|
||||
const auto virtual_target = PAGE_ALIGN(destination);
|
||||
@ -575,4 +692,17 @@ namespace vmx
|
||||
memory::free_non_paged_object(current_hint);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t* ept::get_access_records(size_t* count)
|
||||
{
|
||||
size_t i = 0;
|
||||
for (const auto& record : this->access_records)
|
||||
{
|
||||
if (record == 0) break;
|
||||
++i;
|
||||
}
|
||||
|
||||
*count = i;
|
||||
return this->access_records;
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,12 @@ namespace vmx
|
||||
ept_split* next_split{nullptr};
|
||||
};
|
||||
|
||||
struct ept_code_watch_point
|
||||
{
|
||||
uint64_t physical_base_address{};
|
||||
pml1* target_page{};
|
||||
ept_code_watch_point* next_watch_point{nullptr};
|
||||
};
|
||||
|
||||
struct ept_hook
|
||||
{
|
||||
@ -68,11 +74,13 @@ namespace vmx
|
||||
|
||||
void initialize();
|
||||
|
||||
void install_code_watch_point(uint64_t physical_page);
|
||||
|
||||
void install_hook(const void* destination, const void* source, size_t length,
|
||||
ept_translation_hint* translation_hint = nullptr);
|
||||
void disable_all_hooks() const;
|
||||
|
||||
void handle_violation(guest_context& guest_context) const;
|
||||
void handle_violation(guest_context& guest_context);
|
||||
void handle_misconfiguration(guest_context& guest_context) const;
|
||||
|
||||
ept_pointer get_ept_pointer() const;
|
||||
@ -81,13 +89,19 @@ namespace vmx
|
||||
static ept_translation_hint* generate_translation_hints(const void* destination, size_t length);
|
||||
static void free_translation_hints(ept_translation_hint* hints);
|
||||
|
||||
uint64_t* get_access_records(size_t* count);
|
||||
|
||||
private:
|
||||
DECLSPEC_PAGE_ALIGN pml4 epml4[EPT_PML4E_ENTRY_COUNT];
|
||||
DECLSPEC_PAGE_ALIGN pml3 epdpt[EPT_PDPTE_ENTRY_COUNT];
|
||||
DECLSPEC_PAGE_ALIGN pml2 epde[EPT_PDPTE_ENTRY_COUNT][EPT_PDE_ENTRY_COUNT];
|
||||
|
||||
uint64_t access_records[1024];
|
||||
volatile long access_records_barrier{0};
|
||||
|
||||
ept_split* ept_splits{nullptr};
|
||||
ept_hook* ept_hooks{nullptr};
|
||||
ept_code_watch_point* ept_code_watch_points{nullptr};
|
||||
|
||||
pml2* get_pml2_entry(uint64_t physical_address);
|
||||
pml1* get_pml1_entry(uint64_t physical_address);
|
||||
@ -97,11 +111,16 @@ namespace vmx
|
||||
ept_hook* allocate_ept_hook(uint64_t physical_address);
|
||||
ept_hook* find_ept_hook(uint64_t physical_address) const;
|
||||
|
||||
ept_code_watch_point* allocate_ept_code_watch_point();
|
||||
ept_code_watch_point* find_ept_code_watch_point(uint64_t physical_address) const;
|
||||
|
||||
ept_hook* get_or_create_ept_hook(void* destination, ept_translation_hint* translation_hint = nullptr);
|
||||
|
||||
void split_large_page(uint64_t physical_address);
|
||||
|
||||
void install_page_hook(void* destination, const void* source, size_t length,
|
||||
ept_translation_hint* translation_hint = nullptr);
|
||||
|
||||
void record_access(uint64_t rip);
|
||||
};
|
||||
}
|
||||
|
Reference in New Issue
Block a user