mirror of
https://github.com/momo5502/hypervisor.git
synced 2025-04-19 21:52:55 +00:00
Merge pull request #2 from momo5502/feature/integrity-analysis
Feature/integrity analysis
This commit is contained in:
commit
1519181150
@ -77,7 +77,7 @@ namespace vmx
|
|||||||
|
|
||||||
void update_fake_page(ept_hook& hook)
|
void update_fake_page(ept_hook& hook)
|
||||||
{
|
{
|
||||||
if(!hook.mapped_virtual_address)
|
if (!hook.mapped_virtual_address)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -85,15 +85,30 @@ namespace vmx
|
|||||||
uint8_t page_copy[PAGE_SIZE];
|
uint8_t page_copy[PAGE_SIZE];
|
||||||
memcpy(page_copy, hook.mapped_virtual_address, 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.diff_page[i] = page_copy[i];
|
||||||
hook.fake_page[i] = page_copy[i];
|
hook.fake_page[i] = page_copy[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void reset_all_watch_point_pages(ept_code_watch_point* watch_point)
|
||||||
|
{
|
||||||
|
while (watch_point)
|
||||||
|
{
|
||||||
|
if (watch_point->target_page)
|
||||||
|
{
|
||||||
|
watch_point->target_page->write_access = 0;
|
||||||
|
watch_point->target_page->read_access = 0;
|
||||||
|
watch_point->target_page->execute_access = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
watch_point = watch_point->next_watch_point;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ept_hook::ept_hook(const uint64_t physical_base)
|
ept_hook::ept_hook(const uint64_t physical_base)
|
||||||
@ -121,6 +136,8 @@ namespace vmx
|
|||||||
memset(this->epml4, 0, sizeof(this->epml4));
|
memset(this->epml4, 0, sizeof(this->epml4));
|
||||||
memset(this->epdpt, 0, sizeof(this->epdpt));
|
memset(this->epdpt, 0, sizeof(this->epdpt));
|
||||||
memset(this->epde, 0, sizeof(this->epde));
|
memset(this->epde, 0, sizeof(this->epde));
|
||||||
|
|
||||||
|
memset(this->access_records, 0, sizeof(this->access_records));
|
||||||
}
|
}
|
||||||
|
|
||||||
ept::~ept()
|
ept::~ept()
|
||||||
@ -140,6 +157,14 @@ namespace vmx
|
|||||||
hook = hook->next_hook;
|
hook = hook->next_hook;
|
||||||
memory::free_aligned_object(current_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_non_paged_object(current_watch_point);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ept::install_page_hook(void* destination, const void* source, const size_t length,
|
void ept::install_page_hook(void* destination, const void* source, const size_t length,
|
||||||
@ -151,6 +176,23 @@ namespace vmx
|
|||||||
memcpy(hook->fake_page + page_offset, source, length);
|
memcpy(hook->fake_page + page_offset, source, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ept::record_access(const uint64_t rip)
|
||||||
|
{
|
||||||
|
for (auto& 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,
|
void ept::install_hook(const void* destination, const void* source, const size_t length,
|
||||||
ept_translation_hint* translation_hint)
|
ept_translation_hint* translation_hint)
|
||||||
{
|
{
|
||||||
@ -197,7 +239,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{};
|
vmx_exit_qualification_ept_violation violation_qualification{};
|
||||||
violation_qualification.flags = guest_context.exit_qualification;
|
violation_qualification.flags = guest_context.exit_qualification;
|
||||||
@ -208,6 +250,40 @@ namespace vmx
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto physical_base_address = reinterpret_cast<uint64_t>(PAGE_ALIGN(guest_context.guest_physical_address));
|
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)
|
||||||
|
{
|
||||||
|
reset_all_watch_point_pages(this->ept_code_watch_points);
|
||||||
|
|
||||||
|
if (!violation_qualification.ept_executable && violation_qualification.execute_access)
|
||||||
|
{
|
||||||
|
watch_point->target_page->execute_access = 1;
|
||||||
|
watch_point->target_page->write_access = 0;
|
||||||
|
watch_point->target_page->read_access = 0;
|
||||||
|
guest_context.increment_rip = false;
|
||||||
|
}
|
||||||
|
else if (violation_qualification.ept_executable && (violation_qualification.read_access ||
|
||||||
|
violation_qualification.
|
||||||
|
write_access))
|
||||||
|
{
|
||||||
|
watch_point->target_page->execute_access = 0;
|
||||||
|
watch_point->target_page->read_access = 1;
|
||||||
|
watch_point->target_page->write_access = 1;
|
||||||
|
guest_context.increment_rip = false;
|
||||||
|
if (violation_qualification.read_access)
|
||||||
|
{
|
||||||
|
this->record_access(guest_context.guest_rip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ept-hooking stuff
|
||||||
|
|
||||||
auto* hook = this->find_ept_hook(physical_base_address);
|
auto* hook = this->find_ept_hook(physical_base_address);
|
||||||
if (!hook)
|
if (!hook)
|
||||||
{
|
{
|
||||||
@ -231,6 +307,7 @@ namespace vmx
|
|||||||
|
|
||||||
void ept::handle_misconfiguration(guest_context& guest_context) const
|
void ept::handle_misconfiguration(guest_context& guest_context) const
|
||||||
{
|
{
|
||||||
|
// We can actually not recover from this, but this should not occur anyways
|
||||||
guest_context.increment_rip = false;
|
guest_context.increment_rip = false;
|
||||||
guest_context.exit_vm = true;
|
guest_context.exit_vm = true;
|
||||||
}
|
}
|
||||||
@ -283,6 +360,34 @@ 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->physical_base_address = 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");
|
||||||
|
}
|
||||||
|
|
||||||
|
watch_point->target_page->write_access = 0;
|
||||||
|
watch_point->target_page->read_access = 0;
|
||||||
|
}
|
||||||
|
|
||||||
ept_pointer ept::get_ept_pointer() const
|
ept_pointer ept::get_ept_pointer() const
|
||||||
{
|
{
|
||||||
const auto ept_pml4_physical_address = memory::get_physical_address(const_cast<pml4*>(&this->epml4[0]));
|
const auto ept_pml4_physical_address = memory::get_physical_address(const_cast<pml4*>(&this->epml4[0]));
|
||||||
@ -404,6 +509,36 @@ namespace vmx
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ept_code_watch_point* ept::allocate_ept_code_watch_point()
|
||||||
|
{
|
||||||
|
auto* watch_point = memory::allocate_non_paged_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)
|
ept_hook* ept::get_or_create_ept_hook(void* destination, ept_translation_hint* translation_hint)
|
||||||
{
|
{
|
||||||
const auto virtual_target = PAGE_ALIGN(destination);
|
const auto virtual_target = PAGE_ALIGN(destination);
|
||||||
@ -575,4 +710,17 @@ namespace vmx
|
|||||||
memory::free_non_paged_object(current_hint);
|
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};
|
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
|
struct ept_hook
|
||||||
{
|
{
|
||||||
@ -68,11 +74,13 @@ namespace vmx
|
|||||||
|
|
||||||
void initialize();
|
void initialize();
|
||||||
|
|
||||||
|
void install_code_watch_point(uint64_t physical_page);
|
||||||
|
|
||||||
void install_hook(const void* destination, const void* source, size_t length,
|
void install_hook(const void* destination, const void* source, size_t length,
|
||||||
ept_translation_hint* translation_hint = nullptr);
|
ept_translation_hint* translation_hint = nullptr);
|
||||||
void disable_all_hooks() const;
|
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;
|
void handle_misconfiguration(guest_context& guest_context) const;
|
||||||
|
|
||||||
ept_pointer get_ept_pointer() const;
|
ept_pointer get_ept_pointer() const;
|
||||||
@ -81,13 +89,18 @@ namespace vmx
|
|||||||
static ept_translation_hint* generate_translation_hints(const void* destination, size_t length);
|
static ept_translation_hint* generate_translation_hints(const void* destination, size_t length);
|
||||||
static void free_translation_hints(ept_translation_hint* hints);
|
static void free_translation_hints(ept_translation_hint* hints);
|
||||||
|
|
||||||
|
uint64_t* get_access_records(size_t* count);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DECLSPEC_PAGE_ALIGN pml4 epml4[EPT_PML4E_ENTRY_COUNT];
|
DECLSPEC_PAGE_ALIGN pml4 epml4[EPT_PML4E_ENTRY_COUNT];
|
||||||
DECLSPEC_PAGE_ALIGN pml3 epdpt[EPT_PDPTE_ENTRY_COUNT];
|
DECLSPEC_PAGE_ALIGN pml3 epdpt[EPT_PDPTE_ENTRY_COUNT];
|
||||||
DECLSPEC_PAGE_ALIGN pml2 epde[EPT_PDPTE_ENTRY_COUNT][EPT_PDE_ENTRY_COUNT];
|
DECLSPEC_PAGE_ALIGN pml2 epde[EPT_PDPTE_ENTRY_COUNT][EPT_PDE_ENTRY_COUNT];
|
||||||
|
|
||||||
|
uint64_t access_records[1024];
|
||||||
|
|
||||||
ept_split* ept_splits{nullptr};
|
ept_split* ept_splits{nullptr};
|
||||||
ept_hook* ept_hooks{nullptr};
|
ept_hook* ept_hooks{nullptr};
|
||||||
|
ept_code_watch_point* ept_code_watch_points{nullptr};
|
||||||
|
|
||||||
pml2* get_pml2_entry(uint64_t physical_address);
|
pml2* get_pml2_entry(uint64_t physical_address);
|
||||||
pml1* get_pml1_entry(uint64_t physical_address);
|
pml1* get_pml1_entry(uint64_t physical_address);
|
||||||
@ -97,11 +110,16 @@ namespace vmx
|
|||||||
ept_hook* allocate_ept_hook(uint64_t physical_address);
|
ept_hook* allocate_ept_hook(uint64_t physical_address);
|
||||||
ept_hook* find_ept_hook(uint64_t physical_address) const;
|
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);
|
ept_hook* get_or_create_ept_hook(void* destination, ept_translation_hint* translation_hint = nullptr);
|
||||||
|
|
||||||
void split_large_page(uint64_t physical_address);
|
void split_large_page(uint64_t physical_address);
|
||||||
|
|
||||||
void install_page_hook(void* destination, const void* source, size_t length,
|
void install_page_hook(void* destination, const void* source, size_t length,
|
||||||
ept_translation_hint* translation_hint = nullptr);
|
ept_translation_hint* translation_hint = nullptr);
|
||||||
|
|
||||||
|
void record_access(uint64_t rip);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -192,6 +192,50 @@ bool hypervisor::install_ept_hook(const void* destination, const void* source, c
|
|||||||
return failures == 0;
|
return failures == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool hypervisor::install_ept_code_watch_point(const uint64_t physical_page, bool invalidate) const
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
this->ept_->install_code_watch_point(physical_page);
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
debug_log("Failed to install ept watch point on core %d: %s\n", thread::get_processor_index(), e.what());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
debug_log("Failed to install ept watch point on core %d.\n", thread::get_processor_index());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (invalidate)
|
||||||
|
{
|
||||||
|
thread::dispatch_on_all_cores([&]
|
||||||
|
{
|
||||||
|
this->ept_->invalidate();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hypervisor::install_ept_code_watch_points(const uint64_t* physical_pages, const size_t count) const
|
||||||
|
{
|
||||||
|
bool success = true;
|
||||||
|
for (size_t i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
success &= this->install_ept_code_watch_point(physical_pages[i], false);
|
||||||
|
}
|
||||||
|
|
||||||
|
thread::dispatch_on_all_cores([&]
|
||||||
|
{
|
||||||
|
this->ept_->invalidate();
|
||||||
|
});
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
void hypervisor::disable_all_ept_hooks() const
|
void hypervisor::disable_all_ept_hooks() const
|
||||||
{
|
{
|
||||||
this->ept_->disable_all_hooks();
|
this->ept_->disable_all_hooks();
|
||||||
@ -211,6 +255,11 @@ void hypervisor::disable_all_ept_hooks() const
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vmx::ept& hypervisor::get_ept() const
|
||||||
|
{
|
||||||
|
return *this->ept_;
|
||||||
|
}
|
||||||
|
|
||||||
hypervisor* hypervisor::get_instance()
|
hypervisor* hypervisor::get_instance()
|
||||||
{
|
{
|
||||||
return instance;
|
return instance;
|
||||||
@ -504,14 +553,13 @@ extern "C" [[ noreturn ]] void vm_exit_handler(CONTEXT* context)
|
|||||||
if (guest_context.exit_vm)
|
if (guest_context.exit_vm)
|
||||||
{
|
{
|
||||||
context->Rcx = 0x43434343;
|
context->Rcx = 0x43434343;
|
||||||
restore_descriptor_tables(vm_state->launch_context);
|
|
||||||
|
|
||||||
__writecr3(read_vmx(VMCS_GUEST_CR3));
|
|
||||||
|
|
||||||
context->Rsp = guest_context.guest_rsp;
|
context->Rsp = guest_context.guest_rsp;
|
||||||
context->Rip = guest_context.guest_rip;
|
context->Rip = guest_context.guest_rip;
|
||||||
context->EFlags = static_cast<uint32_t>(guest_context.guest_e_flags);
|
context->EFlags = static_cast<uint32_t>(guest_context.guest_e_flags);
|
||||||
|
|
||||||
|
restore_descriptor_tables(vm_state->launch_context);
|
||||||
|
|
||||||
|
__writecr3(read_vmx(VMCS_GUEST_CR3));
|
||||||
__vmx_off();
|
__vmx_off();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -21,8 +21,14 @@ public:
|
|||||||
|
|
||||||
bool install_ept_hook(const void* destination, const void* source, size_t length,
|
bool install_ept_hook(const void* destination, const void* source, size_t length,
|
||||||
vmx::ept_translation_hint* translation_hint = nullptr);
|
vmx::ept_translation_hint* translation_hint = nullptr);
|
||||||
|
|
||||||
|
bool install_ept_code_watch_point(uint64_t physical_page, bool invalidate = true) const;
|
||||||
|
bool install_ept_code_watch_points(const uint64_t* physical_pages, size_t count) const;
|
||||||
|
|
||||||
void disable_all_ept_hooks() const;
|
void disable_all_ept_hooks() const;
|
||||||
|
|
||||||
|
vmx::ept& get_ept() const;
|
||||||
|
|
||||||
static hypervisor* get_instance();
|
static hypervisor* get_instance();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -114,6 +114,9 @@ namespace
|
|||||||
|
|
||||||
void try_apply_hook(const PIO_STACK_LOCATION irp_sp)
|
void try_apply_hook(const PIO_STACK_LOCATION irp_sp)
|
||||||
{
|
{
|
||||||
|
memory::assert_readability(irp_sp->Parameters.DeviceIoControl.Type3InputBuffer,
|
||||||
|
irp_sp->Parameters.DeviceIoControl.InputBufferLength);
|
||||||
|
|
||||||
if (irp_sp->Parameters.DeviceIoControl.InputBufferLength < sizeof(hook_request))
|
if (irp_sp->Parameters.DeviceIoControl.InputBufferLength < sizeof(hook_request))
|
||||||
{
|
{
|
||||||
throw std::runtime_error("Invalid hook request");
|
throw std::runtime_error("Invalid hook request");
|
||||||
@ -126,10 +129,134 @@ namespace
|
|||||||
apply_hook(request);
|
apply_hook(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void watch_regions(const watch_request& watch_request)
|
||||||
|
{
|
||||||
|
auto* hypervisor = hypervisor::get_instance();
|
||||||
|
if (!hypervisor)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Hypervisor not installed");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<watch_region[]> buffer(new watch_region[watch_request.watch_region_count]);
|
||||||
|
if (!buffer)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Failed to copy buffer");
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(buffer.get(), watch_request.watch_regions, watch_request.watch_region_count * sizeof(watch_region));
|
||||||
|
|
||||||
|
auto watch_request_copy = watch_request;
|
||||||
|
watch_request_copy.watch_regions = buffer.get();
|
||||||
|
|
||||||
|
size_t page_count = 0;
|
||||||
|
for (size_t i = 0; i < watch_request_copy.watch_region_count; ++i)
|
||||||
|
{
|
||||||
|
const auto& watch_region = watch_request_copy.watch_regions[i];
|
||||||
|
|
||||||
|
auto start = static_cast<const uint8_t*>(watch_region.virtual_address);
|
||||||
|
auto end = start + watch_region.length;
|
||||||
|
|
||||||
|
start = static_cast<const uint8_t*>(PAGE_ALIGN(start));
|
||||||
|
end = static_cast<const uint8_t*>(PAGE_ALIGN(reinterpret_cast<uint64_t>(end) + (PAGE_SIZE - 1)));
|
||||||
|
page_count += (end - start) / PAGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
volatile long index = 0;
|
||||||
|
std::unique_ptr<uint64_t[]> page_buffer(new uint64_t[page_count]);
|
||||||
|
if (!page_buffer)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Failed to copy buffer");
|
||||||
|
}
|
||||||
|
|
||||||
|
thread::kernel_thread t([watch_request_copy, hypervisor, &index, &page_buffer]
|
||||||
|
{
|
||||||
|
debug_log("Looking up process: %d\n", watch_request_copy.process_id);
|
||||||
|
|
||||||
|
const auto process_handle = process::find_process_by_id(watch_request_copy.process_id);
|
||||||
|
if (!process_handle || !process_handle.is_alive())
|
||||||
|
{
|
||||||
|
debug_log("Bad process\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto name = process_handle.get_image_filename();
|
||||||
|
if (name)
|
||||||
|
{
|
||||||
|
debug_log("Attaching to %s\n", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
process::scoped_process_attacher attacher{process_handle};
|
||||||
|
|
||||||
|
for (size_t i = 0; i < watch_request_copy.watch_region_count; ++i)
|
||||||
|
{
|
||||||
|
const auto& watch_region = watch_request_copy.watch_regions[i];
|
||||||
|
|
||||||
|
auto start = static_cast<const uint8_t*>(watch_region.virtual_address);
|
||||||
|
auto end = start + watch_region.length;
|
||||||
|
|
||||||
|
start = static_cast<const uint8_t*>(PAGE_ALIGN(start));
|
||||||
|
end = static_cast<const uint8_t*>(PAGE_ALIGN(reinterpret_cast<uint64_t>(end) + (PAGE_SIZE - 1)));
|
||||||
|
|
||||||
|
for (auto current = start; current < end; current += PAGE_SIZE)
|
||||||
|
{
|
||||||
|
const auto physical_address = memory::get_physical_address(const_cast<uint8_t*>(current));
|
||||||
|
if (physical_address)
|
||||||
|
{
|
||||||
|
debug_log("Resolved %p -> %llX\n", current, physical_address);
|
||||||
|
page_buffer.get()[index] = physical_address;
|
||||||
|
InterlockedIncrement(&index);
|
||||||
|
//(void)hypervisor->install_ept_code_watch_point(physical_address);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
debug_log("Failed to resovle physical address for %p\n", current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
t.join();
|
||||||
|
|
||||||
|
debug_log("Installing watch points...\n");
|
||||||
|
(void)hypervisor->install_ept_code_watch_points(page_buffer.get(), index);
|
||||||
|
debug_log("Watch points installed\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void try_watch_regions(const PIO_STACK_LOCATION irp_sp)
|
||||||
|
{
|
||||||
|
memory::assert_readability(irp_sp->Parameters.DeviceIoControl.Type3InputBuffer,
|
||||||
|
irp_sp->Parameters.DeviceIoControl.InputBufferLength);
|
||||||
|
|
||||||
|
if (irp_sp->Parameters.DeviceIoControl.InputBufferLength < sizeof(watch_request))
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Invalid watch request");
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& request = *static_cast<watch_request*>(irp_sp->Parameters.DeviceIoControl.Type3InputBuffer);
|
||||||
|
memory::assert_readability(request.watch_regions, request.watch_region_count * sizeof(watch_region));
|
||||||
|
|
||||||
|
watch_regions(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
void get_records(const PIRP irp, const PIO_STACK_LOCATION irp_sp)
|
||||||
|
{
|
||||||
|
auto* hypervisor = hypervisor::get_instance();
|
||||||
|
if (!hypervisor)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Hypervisor not installed");
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t count{};
|
||||||
|
const auto records = hypervisor->get_ept().get_access_records(&count);
|
||||||
|
|
||||||
|
memset(irp->UserBuffer, 0, irp_sp->Parameters.DeviceIoControl.OutputBufferLength);
|
||||||
|
memcpy(irp->UserBuffer, records, min(irp_sp->Parameters.DeviceIoControl.OutputBufferLength, count * 8));
|
||||||
|
}
|
||||||
|
|
||||||
void handle_irp(const PIRP irp)
|
void handle_irp(const PIRP irp)
|
||||||
{
|
{
|
||||||
irp->IoStatus.Information = 0;
|
irp->IoStatus.Information = 0;
|
||||||
irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
|
irp->IoStatus.Status = STATUS_SUCCESS;
|
||||||
|
|
||||||
const auto irp_sp = IoGetCurrentIrpStackLocation(irp);
|
const auto irp_sp = IoGetCurrentIrpStackLocation(irp);
|
||||||
|
|
||||||
@ -145,6 +272,12 @@ namespace
|
|||||||
case UNHOOK_DRV_IOCTL:
|
case UNHOOK_DRV_IOCTL:
|
||||||
unhook();
|
unhook();
|
||||||
break;
|
break;
|
||||||
|
case WATCH_DRV_IOCTL:
|
||||||
|
try_watch_regions(irp_sp);
|
||||||
|
break;
|
||||||
|
case GET_RECORDS_DRV_IOCTL:
|
||||||
|
get_records(irp, irp_sp);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
debug_log("Invalid IOCTL Code: 0x%X\n", ioctr_code);
|
debug_log("Invalid IOCTL Code: 0x%X\n", ioctr_code);
|
||||||
irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
|
irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
file(GLOB_RECURSE runner_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
|
file(GLOB_RECURSE runner_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
|
||||||
file(GLOB_RECURSE runner_headers ${CMAKE_CURRENT_SOURCE_DIR}/*.hpp)
|
file(GLOB_RECURSE runner_headers ${CMAKE_CURRENT_SOURCE_DIR}/*.hpp)
|
||||||
|
|
||||||
add_executable(runner WIN32
|
add_executable(runner #WIN32
|
||||||
${runner_sources}
|
${runner_sources}
|
||||||
${runner_headers}
|
${runner_headers}
|
||||||
)
|
)
|
||||||
|
@ -24,21 +24,35 @@ bool driver_device::send(const DWORD ioctl_code, const data& input) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool driver_device::send(const DWORD ioctl_code, const data& input, data& output) const
|
bool driver_device::send(const DWORD ioctl_code, const data& input, data& output) const
|
||||||
|
{
|
||||||
|
size_t out_len = output.size();
|
||||||
|
if (this->send(ioctl_code, input.data(), input.size(), output.data(), &out_len))
|
||||||
|
{
|
||||||
|
output.resize(out_len);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool driver_device::send(const DWORD ioctl_code, const void* input, const size_t input_length, void* output,
|
||||||
|
size_t* output_length) const
|
||||||
{
|
{
|
||||||
DWORD size_returned = 0;
|
DWORD size_returned = 0;
|
||||||
const auto success = DeviceIoControl(this->device_,
|
const auto success = DeviceIoControl(this->device_,
|
||||||
ioctl_code,
|
ioctl_code,
|
||||||
const_cast<uint8_t*>(input.data()),
|
const_cast<void*>(input),
|
||||||
static_cast<DWORD>(input.size()),
|
static_cast<DWORD>(input_length),
|
||||||
output.data(),
|
output,
|
||||||
static_cast<DWORD>(output.size()),
|
static_cast<DWORD>(*output_length),
|
||||||
&size_returned,
|
&size_returned,
|
||||||
nullptr
|
nullptr
|
||||||
) != FALSE;
|
) != FALSE;
|
||||||
|
|
||||||
if (success && size_returned < output.size())
|
*output_length = 0;
|
||||||
|
if (success)
|
||||||
{
|
{
|
||||||
output.resize(size_returned);
|
*output_length = size_returned;
|
||||||
}
|
}
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
|
@ -16,6 +16,7 @@ public:
|
|||||||
using data = std::vector<uint8_t>;
|
using data = std::vector<uint8_t>;
|
||||||
bool send(DWORD ioctl_code, const data& input) const;
|
bool send(DWORD ioctl_code, const data& input) const;
|
||||||
bool send(DWORD ioctl_code, const data& input, data& output) const;
|
bool send(DWORD ioctl_code, const data& input, data& output) const;
|
||||||
|
bool send(DWORD ioctl_code, const void* input, size_t input_length, void* output, size_t* output_length) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
native_handle device_{};
|
native_handle device_{};
|
||||||
|
@ -1,115 +0,0 @@
|
|||||||
#include "../../std_include.hpp"
|
|
||||||
#include "html_frame.hpp"
|
|
||||||
|
|
||||||
doc_host_ui_handler::doc_host_ui_handler(html_frame* frame): frame_(frame)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT doc_host_ui_handler::QueryInterface(REFIID riid, LPVOID* ppvObj)
|
|
||||||
{
|
|
||||||
auto client_site = this->frame_->get_client_site();
|
|
||||||
if (client_site)
|
|
||||||
{
|
|
||||||
return client_site->QueryInterface(riid, ppvObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
return E_NOINTERFACE;
|
|
||||||
}
|
|
||||||
|
|
||||||
ULONG doc_host_ui_handler::AddRef()
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ULONG doc_host_ui_handler::Release()
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT doc_host_ui_handler::ShowContextMenu(DWORD /*dwID*/, POINT* /*ppt*/, IUnknown* /*pcmdtReserved*/,
|
|
||||||
IDispatch* /*pdispReserved*/)
|
|
||||||
{
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT doc_host_ui_handler::ShowUI(DWORD /*dwID*/, IOleInPlaceActiveObject* /*pActiveObject*/,
|
|
||||||
IOleCommandTarget* /*pCommandTarget*/,
|
|
||||||
IOleInPlaceFrame* /*pFrame*/, IOleInPlaceUIWindow* /*pDoc*/)
|
|
||||||
{
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT doc_host_ui_handler::HideUI()
|
|
||||||
{
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT doc_host_ui_handler::UpdateUI()
|
|
||||||
{
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT doc_host_ui_handler::EnableModeless(BOOL /*fEnable*/)
|
|
||||||
{
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT doc_host_ui_handler::OnDocWindowActivate(BOOL /*fActivate*/)
|
|
||||||
{
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT doc_host_ui_handler::OnFrameWindowActivate(BOOL /*fActivate*/)
|
|
||||||
{
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT doc_host_ui_handler::ResizeBorder(LPCRECT /*prcBorder*/, IOleInPlaceUIWindow* /*pUIWindow*/,
|
|
||||||
BOOL /*fRameWindow*/)
|
|
||||||
{
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT doc_host_ui_handler::TranslateAcceleratorA(LPMSG /*lpMsg*/, const GUID* pguidCmdGroup, DWORD /*nCmdID*/)
|
|
||||||
{
|
|
||||||
pguidCmdGroup = nullptr;
|
|
||||||
return S_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT doc_host_ui_handler::GetOptionKeyPath(LPOLESTR* /*pchKey*/, DWORD /*dw*/)
|
|
||||||
{
|
|
||||||
return S_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT doc_host_ui_handler::GetDropTarget(IDropTarget* /*pDropTarget*/, IDropTarget** /*ppDropTarget*/)
|
|
||||||
{
|
|
||||||
return S_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT doc_host_ui_handler::GetExternal(IDispatch** ppDispatch)
|
|
||||||
{
|
|
||||||
*ppDispatch = this->frame_->get_html_dispatch();
|
|
||||||
return (*ppDispatch) ? S_OK : S_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT doc_host_ui_handler::FilterDataObject(IDataObject* /*pDO*/, IDataObject** ppDORet)
|
|
||||||
{
|
|
||||||
*ppDORet = nullptr;
|
|
||||||
return S_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE doc_host_ui_handler::TranslateUrl(DWORD /*dwTranslate*/, OLECHAR __RPC_FAR* /*pchURLIn*/,
|
|
||||||
OLECHAR __RPC_FAR* __RPC_FAR* ppchURLOut)
|
|
||||||
{
|
|
||||||
*ppchURLOut = nullptr;
|
|
||||||
return S_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT doc_host_ui_handler::GetHostInfo(DOCHOSTUIINFO __RPC_FAR * pInfo)
|
|
||||||
{
|
|
||||||
pInfo->cbSize = sizeof(DOCHOSTUIINFO);
|
|
||||||
pInfo->dwFlags = DOCHOSTUIFLAG_NO3DBORDER | DOCHOSTUIFLAG_DPI_AWARE /*| DOCHOSTUIFLAG_SCROLL_NO*/;
|
|
||||||
pInfo->dwDoubleClick = DOCHOSTUIDBLCLK_DEFAULT;
|
|
||||||
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
@ -1,47 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
class html_frame;
|
|
||||||
|
|
||||||
class doc_host_ui_handler final : public IDocHostUIHandler
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
doc_host_ui_handler(html_frame* frame);
|
|
||||||
virtual ~doc_host_ui_handler() = default;
|
|
||||||
|
|
||||||
private:
|
|
||||||
html_frame* frame_;
|
|
||||||
|
|
||||||
public: // IDocHostUIHandler interface
|
|
||||||
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID* ppvObj) override;
|
|
||||||
ULONG STDMETHODCALLTYPE AddRef() override;
|
|
||||||
ULONG STDMETHODCALLTYPE Release() override;
|
|
||||||
HRESULT STDMETHODCALLTYPE ShowContextMenu(
|
|
||||||
DWORD dwID,
|
|
||||||
POINT __RPC_FAR * ppt,
|
|
||||||
IUnknown __RPC_FAR * pcmdtReserved,
|
|
||||||
IDispatch __RPC_FAR * pdispReserved) override;
|
|
||||||
HRESULT STDMETHODCALLTYPE ShowUI(
|
|
||||||
DWORD dwID,
|
|
||||||
IOleInPlaceActiveObject __RPC_FAR * pActiveObject,
|
|
||||||
IOleCommandTarget __RPC_FAR * pCommandTarget,
|
|
||||||
IOleInPlaceFrame __RPC_FAR * pFrame,
|
|
||||||
IOleInPlaceUIWindow __RPC_FAR * pDoc) override;
|
|
||||||
HRESULT STDMETHODCALLTYPE GetHostInfo(DOCHOSTUIINFO __RPC_FAR * pInfo) override;
|
|
||||||
HRESULT STDMETHODCALLTYPE HideUI() override;
|
|
||||||
HRESULT STDMETHODCALLTYPE UpdateUI() override;
|
|
||||||
HRESULT STDMETHODCALLTYPE EnableModeless(BOOL fEnable) override;
|
|
||||||
HRESULT STDMETHODCALLTYPE OnDocWindowActivate(BOOL fActivate) override;
|
|
||||||
HRESULT STDMETHODCALLTYPE OnFrameWindowActivate(BOOL fActivate) override;
|
|
||||||
HRESULT STDMETHODCALLTYPE ResizeBorder(LPCRECT prcBorder, IOleInPlaceUIWindow __RPC_FAR * pUIWindow,
|
|
||||||
BOOL fRameWindow) override;
|
|
||||||
HRESULT STDMETHODCALLTYPE TranslateAccelerator(LPMSG lpMsg, const GUID __RPC_FAR * pguidCmdGroup, DWORD nCmdID)
|
|
||||||
override;
|
|
||||||
HRESULT STDMETHODCALLTYPE GetOptionKeyPath(LPOLESTR __RPC_FAR * pchKey, DWORD dw) override;
|
|
||||||
HRESULT STDMETHODCALLTYPE GetDropTarget(IDropTarget __RPC_FAR * pDropTarget,
|
|
||||||
IDropTarget __RPC_FAR *__RPC_FAR * ppDropTarget) override;
|
|
||||||
HRESULT STDMETHODCALLTYPE GetExternal(IDispatch __RPC_FAR *__RPC_FAR * ppDispatch) override;
|
|
||||||
HRESULT STDMETHODCALLTYPE TranslateUrl(DWORD dwTranslate, OLECHAR __RPC_FAR * pchURLIn,
|
|
||||||
OLECHAR __RPC_FAR *__RPC_FAR * ppchURLOut) override;
|
|
||||||
HRESULT STDMETHODCALLTYPE FilterDataObject(IDataObject __RPC_FAR * pDO, IDataObject __RPC_FAR *__RPC_FAR * ppDORet)
|
|
||||||
override;
|
|
||||||
};
|
|
@ -1,51 +0,0 @@
|
|||||||
#include "../../std_include.hpp"
|
|
||||||
#include "html_argument.hpp"
|
|
||||||
|
|
||||||
html_argument::html_argument(VARIANT* val) : value_(val)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool html_argument::is_empty() const
|
|
||||||
{
|
|
||||||
return this->value_ == nullptr || this->value_->vt == VT_EMPTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool html_argument::is_string() const
|
|
||||||
{
|
|
||||||
if (this->is_empty()) return false;
|
|
||||||
return this->value_->vt == VT_BSTR;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool html_argument::is_number() const
|
|
||||||
{
|
|
||||||
if (this->is_empty()) return false;
|
|
||||||
return this->value_->vt == VT_I4;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool html_argument::is_bool() const
|
|
||||||
{
|
|
||||||
if (this->is_empty()) return false;
|
|
||||||
return this->value_->vt == VT_BOOL;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string html_argument::get_string() const
|
|
||||||
{
|
|
||||||
if (!this->is_string()) return {};
|
|
||||||
std::wstring wide_string(this->value_->bstrVal);
|
|
||||||
#pragma warning(push)
|
|
||||||
#pragma warning(disable: 4244)
|
|
||||||
return std::string(wide_string.begin(), wide_string.end());
|
|
||||||
#pragma warning(pop)
|
|
||||||
}
|
|
||||||
|
|
||||||
int html_argument::get_number() const
|
|
||||||
{
|
|
||||||
if (!this->is_number()) return 0;
|
|
||||||
return this->value_->intVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool html_argument::get_bool() const
|
|
||||||
{
|
|
||||||
if (!this->is_bool()) return false;
|
|
||||||
return this->value_->boolVal != FALSE;
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
class html_argument final
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
html_argument(VARIANT* val);
|
|
||||||
|
|
||||||
bool is_empty() const;
|
|
||||||
|
|
||||||
bool is_string() const;
|
|
||||||
bool is_number() const;
|
|
||||||
bool is_bool() const;
|
|
||||||
|
|
||||||
std::string get_string() const;
|
|
||||||
int get_number() const;
|
|
||||||
bool get_bool() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
VARIANT* value_;
|
|
||||||
};
|
|
@ -1,67 +0,0 @@
|
|||||||
#include "../../std_include.hpp"
|
|
||||||
#include "html_frame.hpp"
|
|
||||||
|
|
||||||
html_dispatch::html_dispatch(html_frame* frame) : frame_(frame)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT html_dispatch::QueryInterface(const IID& riid, LPVOID* ppvObj)
|
|
||||||
{
|
|
||||||
if (!memcmp(&riid, &IID_IUnknown, sizeof(GUID)) ||
|
|
||||||
!memcmp(&riid, &IID_IDispatch, sizeof(GUID)))
|
|
||||||
{
|
|
||||||
*ppvObj = this;
|
|
||||||
this->AddRef();
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
*ppvObj = nullptr;
|
|
||||||
return E_NOINTERFACE;
|
|
||||||
}
|
|
||||||
|
|
||||||
ULONG html_dispatch::AddRef()
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ULONG html_dispatch::Release()
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT html_dispatch::GetTypeInfoCount(UINT* /*pctinfo*/)
|
|
||||||
{
|
|
||||||
return S_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT html_dispatch::GetTypeInfo(UINT /*iTInfo*/, LCID /*lcid*/, ITypeInfo** /*ppTInfo*/)
|
|
||||||
{
|
|
||||||
return S_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT html_dispatch::GetIDsOfNames(const IID& /*riid*/, LPOLESTR* rgszNames, UINT cNames, LCID /*lcid*/,
|
|
||||||
DISPID* rgDispId)
|
|
||||||
{
|
|
||||||
for (unsigned int i = 0; i < cNames; ++i)
|
|
||||||
{
|
|
||||||
std::wstring wide_name(rgszNames[i]);
|
|
||||||
#pragma warning(push)
|
|
||||||
#pragma warning(disable: 4244)
|
|
||||||
std::string name(wide_name.begin(), wide_name.end());
|
|
||||||
#pragma warning(pop)
|
|
||||||
|
|
||||||
|
|
||||||
rgDispId[i] = this->frame_->get_callback_id(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT html_dispatch::Invoke(DISPID dispIdMember, const IID& /*riid*/, LCID /*lcid*/, WORD /*wFlags*/,
|
|
||||||
DISPPARAMS* pDispParams,
|
|
||||||
VARIANT* pVarResult, EXCEPINFO* /*pExcepInfo*/, UINT* /*puArgErr*/)
|
|
||||||
{
|
|
||||||
html_frame::callback_params params(pDispParams, pVarResult);
|
|
||||||
this->frame_->invoke_callback(dispIdMember, ¶ms);
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
class html_frame;
|
|
||||||
|
|
||||||
class html_dispatch final : public IDispatch
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
html_dispatch(html_frame* frame);
|
|
||||||
virtual ~html_dispatch() = default;
|
|
||||||
|
|
||||||
private:
|
|
||||||
html_frame* frame_;
|
|
||||||
|
|
||||||
public: // IDispatch interface
|
|
||||||
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID FAR* ppvObj) override;
|
|
||||||
ULONG STDMETHODCALLTYPE AddRef() override;
|
|
||||||
ULONG STDMETHODCALLTYPE Release() override;
|
|
||||||
HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT* pctinfo) override;
|
|
||||||
HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) override;
|
|
||||||
HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId)
|
|
||||||
override;
|
|
||||||
HRESULT STDMETHODCALLTYPE Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams,
|
|
||||||
VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr) override;
|
|
||||||
};
|
|
@ -1,298 +0,0 @@
|
|||||||
#include "../../std_include.hpp"
|
|
||||||
#include "../../finally.hpp"
|
|
||||||
|
|
||||||
#include "../../utils/nt.hpp"
|
|
||||||
|
|
||||||
#include "html_frame.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
std::atomic<int> html_frame::frame_count_ = 0;
|
|
||||||
|
|
||||||
html_frame::callback_params::callback_params(DISPPARAMS* params, VARIANT* res) : result(res)
|
|
||||||
{
|
|
||||||
for (auto i = params->cArgs; i > 0; --i)
|
|
||||||
{
|
|
||||||
auto* param = ¶ms->rgvarg[i - 1];
|
|
||||||
this->arguments.emplace_back(param);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
html_frame::html_frame()
|
|
||||||
: in_place_frame_(this)
|
|
||||||
, in_place_site_(this)
|
|
||||||
, ui_handler_(this)
|
|
||||||
, client_site_(this)
|
|
||||||
, html_dispatch_(this)
|
|
||||||
{
|
|
||||||
if (frame_count_++ == 0 && OleInitialize(nullptr) != S_OK)
|
|
||||||
{
|
|
||||||
throw std::runtime_error("Unable to initialize the OLE library");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto needs_restart = false;
|
|
||||||
needs_restart |= set_browser_feature("FEATURE_BROWSER_EMULATION", 11000);
|
|
||||||
needs_restart |= set_browser_feature("FEATURE_GPU_RENDERING", 1);
|
|
||||||
|
|
||||||
if (needs_restart)
|
|
||||||
{
|
|
||||||
utils::nt::relaunch_self();
|
|
||||||
utils::nt::terminate(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
html_frame::~html_frame()
|
|
||||||
{
|
|
||||||
if (--frame_count_ <= 0)
|
|
||||||
{
|
|
||||||
frame_count_ = 0;
|
|
||||||
OleUninitialize();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void html_frame::object_deleter(IUnknown* object)
|
|
||||||
{
|
|
||||||
if (object)
|
|
||||||
{
|
|
||||||
object->Release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HWND html_frame::get_window() const
|
|
||||||
{
|
|
||||||
return this->window_;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<IOleObject> html_frame::get_browser_object() const
|
|
||||||
{
|
|
||||||
return this->browser_object_;
|
|
||||||
}
|
|
||||||
|
|
||||||
ole_in_place_frame* html_frame::get_in_place_frame()
|
|
||||||
{
|
|
||||||
return &this->in_place_frame_;
|
|
||||||
}
|
|
||||||
|
|
||||||
ole_in_place_site* html_frame::get_in_place_site()
|
|
||||||
{
|
|
||||||
return &this->in_place_site_;
|
|
||||||
}
|
|
||||||
|
|
||||||
doc_host_ui_handler* html_frame::get_ui_handler()
|
|
||||||
{
|
|
||||||
return &this->ui_handler_;
|
|
||||||
}
|
|
||||||
|
|
||||||
ole_client_site* html_frame::get_client_site()
|
|
||||||
{
|
|
||||||
return &this->client_site_;
|
|
||||||
}
|
|
||||||
|
|
||||||
html_dispatch* html_frame::get_html_dispatch()
|
|
||||||
{
|
|
||||||
return &this->html_dispatch_;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<IWebBrowser2> html_frame::get_web_browser() const
|
|
||||||
{
|
|
||||||
if (!this->browser_object_) return {};
|
|
||||||
|
|
||||||
IWebBrowser2* web_browser = nullptr;
|
|
||||||
if (FAILED(this->browser_object_->QueryInterface(IID_IWebBrowser2, reinterpret_cast<void**>(&web_browser)))
|
|
||||||
|| !web_browser)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
return std::shared_ptr<IWebBrowser2>(web_browser, object_deleter);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<IDispatch> html_frame::get_dispatch() const
|
|
||||||
{
|
|
||||||
const auto web_browser = this->get_web_browser();
|
|
||||||
if (!web_browser) return {};
|
|
||||||
|
|
||||||
IDispatch* dispatch = nullptr;
|
|
||||||
if (FAILED(web_browser->get_Document(&dispatch)) || !dispatch) return {};
|
|
||||||
|
|
||||||
return std::shared_ptr<IDispatch>(dispatch, object_deleter);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<IHTMLDocument2> html_frame::get_document() const
|
|
||||||
{
|
|
||||||
const auto dispatch = this->get_dispatch();
|
|
||||||
if (!dispatch) return {};
|
|
||||||
|
|
||||||
IHTMLDocument2* document = nullptr;
|
|
||||||
if (FAILED(dispatch->QueryInterface(IID_IHTMLDocument2, reinterpret_cast<void**>(&document)))
|
|
||||||
|| !document)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
return std::shared_ptr<IHTMLDocument2>(document, object_deleter);
|
|
||||||
}
|
|
||||||
|
|
||||||
void html_frame::initialize(const HWND window)
|
|
||||||
{
|
|
||||||
if (this->window_) return;
|
|
||||||
this->window_ = window;
|
|
||||||
|
|
||||||
this->create_browser();
|
|
||||||
this->initialize_browser();
|
|
||||||
}
|
|
||||||
|
|
||||||
void html_frame::create_browser()
|
|
||||||
{
|
|
||||||
LPCLASSFACTORY class_factory = nullptr;
|
|
||||||
if (FAILED(
|
|
||||||
CoGetClassObject(CLSID_WebBrowser, CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER, nullptr, IID_IClassFactory,
|
|
||||||
reinterpret_cast<void **>(&class_factory))) || !class_factory)
|
|
||||||
{
|
|
||||||
throw std::runtime_error("Unable to get the class factory");
|
|
||||||
}
|
|
||||||
|
|
||||||
IOleObject* browser_object = nullptr;
|
|
||||||
class_factory->CreateInstance(nullptr, IID_IOleObject, reinterpret_cast<void**>(&browser_object));
|
|
||||||
class_factory->Release();
|
|
||||||
|
|
||||||
if (!browser_object)
|
|
||||||
{
|
|
||||||
throw std::runtime_error("Unable to create browser object");
|
|
||||||
}
|
|
||||||
|
|
||||||
this->browser_object_ = std::shared_ptr<IOleObject>(browser_object, [](IOleObject* browser_object)
|
|
||||||
{
|
|
||||||
if (browser_object)
|
|
||||||
{
|
|
||||||
browser_object->Close(OLECLOSE_NOSAVE);
|
|
||||||
object_deleter(browser_object);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void html_frame::initialize_browser()
|
|
||||||
{
|
|
||||||
this->browser_object_->SetClientSite(this->get_client_site());
|
|
||||||
this->browser_object_->SetHostNames(L"Hostname", nullptr);
|
|
||||||
|
|
||||||
RECT rect;
|
|
||||||
GetClientRect(this->get_window(), &rect);
|
|
||||||
OleSetContainedObject(this->browser_object_.get(), TRUE);
|
|
||||||
|
|
||||||
this->browser_object_->DoVerb(OLEIVERB_SHOW, nullptr, this->get_client_site(), -1, this->get_window(), &rect);
|
|
||||||
this->resize(rect.right, rect.bottom);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool html_frame::set_browser_feature(const std::string& feature, DWORD value)
|
|
||||||
{
|
|
||||||
const auto registry_path = R"(SOFTWARE\Microsoft\Internet Explorer\Main\FeatureControl\)" + feature;
|
|
||||||
|
|
||||||
HKEY key = nullptr;
|
|
||||||
if (RegCreateKeyA(HKEY_CURRENT_USER, registry_path.data(), &key) == ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
RegCloseKey(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
key = nullptr;
|
|
||||||
if (RegOpenKeyExA(
|
|
||||||
HKEY_CURRENT_USER, registry_path.data(), 0,
|
|
||||||
KEY_ALL_ACCESS, &key) != ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
return false; // Error :(
|
|
||||||
}
|
|
||||||
|
|
||||||
const utils::nt::library self;
|
|
||||||
const auto name = self.get_name();
|
|
||||||
|
|
||||||
DWORD type{};
|
|
||||||
auto is_new = true;
|
|
||||||
if (RegQueryValueExA(key, name.data(), nullptr, &type, nullptr, nullptr) == ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
is_new = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
RegSetValueExA(key, name.data(), 0, REG_DWORD, reinterpret_cast<const BYTE*>(&value), sizeof(value));
|
|
||||||
RegCloseKey(key);
|
|
||||||
|
|
||||||
return is_new;
|
|
||||||
}
|
|
||||||
|
|
||||||
void html_frame::resize(const DWORD width, const DWORD height) const
|
|
||||||
{
|
|
||||||
auto web_browser = this->get_web_browser();
|
|
||||||
if (web_browser)
|
|
||||||
{
|
|
||||||
web_browser->put_Left(0);
|
|
||||||
web_browser->put_Top(0);
|
|
||||||
web_browser->put_Width(width);
|
|
||||||
web_browser->put_Height(height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool html_frame::load_url(const std::string& url) const
|
|
||||||
{
|
|
||||||
auto web_browser = this->get_web_browser();
|
|
||||||
if (!web_browser) return false;
|
|
||||||
|
|
||||||
std::wstring wide_url(url.begin(), url.end());
|
|
||||||
|
|
||||||
VARIANT my_url;
|
|
||||||
VariantInit(&my_url);
|
|
||||||
my_url.vt = VT_BSTR;
|
|
||||||
my_url.bstrVal = SysAllocString(wide_url.data());
|
|
||||||
|
|
||||||
const auto _ = utils::finally([&my_url]() { VariantClear(&my_url); });
|
|
||||||
if (!my_url.bstrVal) return false;
|
|
||||||
|
|
||||||
return SUCCEEDED(web_browser->Navigate2(&my_url, nullptr, nullptr, nullptr, nullptr));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool html_frame::load_html(const std::string& html) const
|
|
||||||
{
|
|
||||||
if (!this->load_url("about:blank")) return false;
|
|
||||||
|
|
||||||
const auto document = this->get_document();
|
|
||||||
if (!document) return false;
|
|
||||||
|
|
||||||
SAFEARRAYBOUND safe_array_bound = {1, 0};
|
|
||||||
auto safe_array = SafeArrayCreate(VT_VARIANT, 1, &safe_array_bound);
|
|
||||||
if (!safe_array) return false;
|
|
||||||
|
|
||||||
const auto _ = utils::finally([safe_array]() { SafeArrayDestroy(safe_array); });
|
|
||||||
|
|
||||||
VARIANT* variant = nullptr;
|
|
||||||
if (FAILED(SafeArrayAccessData(safe_array, reinterpret_cast<void**>(&variant))) || !variant) return false;
|
|
||||||
|
|
||||||
std::wstring wide_html(html.begin(), html.end());
|
|
||||||
|
|
||||||
variant->vt = VT_BSTR;
|
|
||||||
variant->bstrVal = SysAllocString(wide_html.data());
|
|
||||||
if (!variant->bstrVal) return false;
|
|
||||||
|
|
||||||
document->write(safe_array);
|
|
||||||
document->close();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int html_frame::get_callback_id(const std::string& name)
|
|
||||||
{
|
|
||||||
for (auto i = 0u; i < this->callbacks_.size(); ++i)
|
|
||||||
{
|
|
||||||
if (this->callbacks_[i].first == name)
|
|
||||||
{
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void html_frame::invoke_callback(const int id, callback_params* params)
|
|
||||||
{
|
|
||||||
if (id >= 0 && static_cast<unsigned int>(id) < this->callbacks_.size())
|
|
||||||
{
|
|
||||||
this->callbacks_[id].second(params);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void html_frame::register_callback(const std::string& name, const std::function<void(callback_params*)>& callback)
|
|
||||||
{
|
|
||||||
this->callbacks_.emplace_back(name, callback);
|
|
||||||
}
|
|
@ -1,67 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "ole_in_place_frame.hpp"
|
|
||||||
#include "ole_in_place_site.hpp"
|
|
||||||
#include "doc_host_ui_handler.hpp"
|
|
||||||
#include "ole_client_site.hpp"
|
|
||||||
#include "html_dispatch.hpp"
|
|
||||||
#include "html_argument.hpp"
|
|
||||||
|
|
||||||
class html_frame
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
class callback_params final
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
callback_params(DISPPARAMS* params, VARIANT* res);
|
|
||||||
|
|
||||||
std::vector<html_argument> arguments;
|
|
||||||
html_argument result;
|
|
||||||
};
|
|
||||||
|
|
||||||
html_frame();
|
|
||||||
virtual ~html_frame();
|
|
||||||
|
|
||||||
void initialize(HWND window);
|
|
||||||
|
|
||||||
void resize(DWORD width, DWORD height) const;
|
|
||||||
bool load_url(const std::string& url) const;
|
|
||||||
bool load_html(const std::string& html) const;
|
|
||||||
|
|
||||||
HWND get_window() const;
|
|
||||||
|
|
||||||
std::shared_ptr<IOleObject> get_browser_object() const;
|
|
||||||
std::shared_ptr<IWebBrowser2> get_web_browser() const;
|
|
||||||
std::shared_ptr<IDispatch> get_dispatch() const;
|
|
||||||
std::shared_ptr<IHTMLDocument2> get_document() const;
|
|
||||||
|
|
||||||
ole_in_place_frame* get_in_place_frame();
|
|
||||||
ole_in_place_site* get_in_place_site();
|
|
||||||
doc_host_ui_handler* get_ui_handler();
|
|
||||||
ole_client_site* get_client_site();
|
|
||||||
html_dispatch* get_html_dispatch();
|
|
||||||
|
|
||||||
int get_callback_id(const std::string& name);
|
|
||||||
void invoke_callback(int id, callback_params* params);
|
|
||||||
|
|
||||||
void register_callback(const std::string& name, const std::function<void(callback_params*)>& callback);
|
|
||||||
|
|
||||||
private:
|
|
||||||
HWND window_ = nullptr;
|
|
||||||
std::shared_ptr<IOleObject> browser_object_;
|
|
||||||
|
|
||||||
ole_in_place_frame in_place_frame_;
|
|
||||||
ole_in_place_site in_place_site_;
|
|
||||||
doc_host_ui_handler ui_handler_;
|
|
||||||
ole_client_site client_site_;
|
|
||||||
html_dispatch html_dispatch_;
|
|
||||||
|
|
||||||
std::vector<std::pair<std::string, std::function<void(callback_params*)>>> callbacks_;
|
|
||||||
|
|
||||||
void create_browser();
|
|
||||||
void initialize_browser();
|
|
||||||
|
|
||||||
static bool set_browser_feature(const std::string& feature, DWORD value);
|
|
||||||
static void object_deleter(IUnknown* object);
|
|
||||||
|
|
||||||
static std::atomic<int> frame_count_;
|
|
||||||
};
|
|
@ -1,29 +0,0 @@
|
|||||||
#include "../../std_include.hpp"
|
|
||||||
#include "html_window.hpp"
|
|
||||||
|
|
||||||
window* html_window::get_window()
|
|
||||||
{
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
html_frame* html_window::get_html_frame()
|
|
||||||
{
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
LRESULT html_window::processor(const UINT message, const WPARAM w_param, const LPARAM l_param)
|
|
||||||
{
|
|
||||||
if (message == WM_SIZE)
|
|
||||||
{
|
|
||||||
this->resize(LOWORD(l_param), HIWORD(l_param));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (message == WM_CREATE)
|
|
||||||
{
|
|
||||||
this->initialize(*this);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return window::processor(message, w_param, l_param);
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "../window.hpp"
|
|
||||||
#include "html_frame.hpp"
|
|
||||||
|
|
||||||
class html_window final : public window, public html_frame
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
~html_window() = default;
|
|
||||||
|
|
||||||
window* get_window();
|
|
||||||
html_frame* get_html_frame();
|
|
||||||
|
|
||||||
private:
|
|
||||||
LRESULT processor(UINT message, WPARAM w_param, LPARAM l_param) override;
|
|
||||||
};
|
|
@ -1,77 +0,0 @@
|
|||||||
#include "../../std_include.hpp"
|
|
||||||
#include "html_frame.hpp"
|
|
||||||
|
|
||||||
ole_client_site::ole_client_site(html_frame* frame): frame_(frame)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT ole_client_site::QueryInterface(REFIID riid, LPVOID* ppvObject)
|
|
||||||
{
|
|
||||||
if (!memcmp(&riid, &IID_IUnknown, sizeof(GUID)) ||
|
|
||||||
!memcmp(&riid, &IID_IOleClientSite, sizeof(GUID)))
|
|
||||||
{
|
|
||||||
*ppvObject = this;
|
|
||||||
this->AddRef();
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!memcmp(&riid, &IID_IOleInPlaceSite, sizeof(GUID)))
|
|
||||||
{
|
|
||||||
auto in_place_site = this->frame_->get_in_place_site();
|
|
||||||
in_place_site->AddRef();
|
|
||||||
*ppvObject = in_place_site;
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!memcmp(&riid, &IID_IDocHostUIHandler, sizeof(GUID)))
|
|
||||||
{
|
|
||||||
auto ui_handler = this->frame_->get_ui_handler();
|
|
||||||
ui_handler->AddRef();
|
|
||||||
*ppvObject = ui_handler;
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
*ppvObject = nullptr;
|
|
||||||
return E_NOINTERFACE;
|
|
||||||
}
|
|
||||||
|
|
||||||
ULONG ole_client_site::AddRef()
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ULONG ole_client_site::Release()
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT ole_client_site::SaveObject()
|
|
||||||
{
|
|
||||||
return E_NOTIMPL;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT ole_client_site::GetMoniker(DWORD /*dwAssign*/, DWORD /*dwWhichMoniker*/, IMoniker** /*ppmk*/)
|
|
||||||
{
|
|
||||||
return E_NOTIMPL;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT ole_client_site::GetContainer(LPOLECONTAINER* ppContainer)
|
|
||||||
{
|
|
||||||
*ppContainer = nullptr;
|
|
||||||
return E_NOINTERFACE;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT ole_client_site::ShowObject()
|
|
||||||
{
|
|
||||||
return NOERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT ole_client_site::OnShowWindow(BOOL /*fShow*/)
|
|
||||||
{
|
|
||||||
return E_NOTIMPL;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT ole_client_site::RequestNewObjectLayout()
|
|
||||||
{
|
|
||||||
return E_NOTIMPL;
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
class html_frame;
|
|
||||||
|
|
||||||
class ole_client_site final : public IOleClientSite
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ole_client_site(html_frame* frame);
|
|
||||||
virtual ~ole_client_site() = default;
|
|
||||||
|
|
||||||
private:
|
|
||||||
html_frame* frame_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID* ppvObject) override;
|
|
||||||
ULONG STDMETHODCALLTYPE AddRef() override;
|
|
||||||
ULONG STDMETHODCALLTYPE Release() override;
|
|
||||||
HRESULT STDMETHODCALLTYPE SaveObject() override;
|
|
||||||
HRESULT STDMETHODCALLTYPE GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, IMoniker** ppmk) override;
|
|
||||||
HRESULT STDMETHODCALLTYPE GetContainer(LPOLECONTAINER FAR* ppContainer) override;
|
|
||||||
HRESULT STDMETHODCALLTYPE ShowObject() override;
|
|
||||||
HRESULT STDMETHODCALLTYPE OnShowWindow(BOOL fShow) override;
|
|
||||||
HRESULT STDMETHODCALLTYPE RequestNewObjectLayout() override;
|
|
||||||
};
|
|
@ -1,82 +0,0 @@
|
|||||||
#include "../../std_include.hpp"
|
|
||||||
#include "html_frame.hpp"
|
|
||||||
|
|
||||||
ole_in_place_frame::ole_in_place_frame(html_frame* frame): frame_(frame)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT ole_in_place_frame::QueryInterface(REFIID /*riid*/, LPVOID* /*ppvObj*/)
|
|
||||||
{
|
|
||||||
return E_NOTIMPL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ULONG ole_in_place_frame::AddRef()
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ULONG ole_in_place_frame::Release()
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT ole_in_place_frame::GetWindow(HWND* lphwnd)
|
|
||||||
{
|
|
||||||
*lphwnd = this->frame_->get_window();
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT ole_in_place_frame::ContextSensitiveHelp(BOOL /*fEnterMode*/)
|
|
||||||
{
|
|
||||||
return E_NOTIMPL;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT ole_in_place_frame::GetBorder(LPRECT /*lprectBorder*/)
|
|
||||||
{
|
|
||||||
return E_NOTIMPL;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT ole_in_place_frame::RequestBorderSpace(LPCBORDERWIDTHS /*pborderwidths*/)
|
|
||||||
{
|
|
||||||
return E_NOTIMPL;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT ole_in_place_frame::SetBorderSpace(LPCBORDERWIDTHS /*pborderwidths*/)
|
|
||||||
{
|
|
||||||
return E_NOTIMPL;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT ole_in_place_frame::SetActiveObject(IOleInPlaceActiveObject* /*pActiveObject*/, LPCOLESTR /*pszObjName*/)
|
|
||||||
{
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT ole_in_place_frame::InsertMenus(HMENU /*hmenuShared*/, LPOLEMENUGROUPWIDTHS /*lpMenuWidths*/)
|
|
||||||
{
|
|
||||||
return E_NOTIMPL;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT ole_in_place_frame::SetMenu(HMENU /*hmenuShared*/, HOLEMENU /*holemenu*/, HWND /*hwndActiveObject*/)
|
|
||||||
{
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT ole_in_place_frame::RemoveMenus(HMENU /*hmenuShared*/)
|
|
||||||
{
|
|
||||||
return E_NOTIMPL;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT ole_in_place_frame::SetStatusText(LPCOLESTR /*pszStatusText*/)
|
|
||||||
{
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT ole_in_place_frame::EnableModeless(BOOL /*fEnable*/)
|
|
||||||
{
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT ole_in_place_frame::TranslateAcceleratorA(LPMSG /*lpmsg*/, WORD /*wID*/)
|
|
||||||
{
|
|
||||||
return E_NOTIMPL;
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
class html_frame;
|
|
||||||
|
|
||||||
class ole_in_place_frame final : public IOleInPlaceFrame
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ole_in_place_frame(html_frame* frame);
|
|
||||||
virtual ~ole_in_place_frame() = default;
|
|
||||||
|
|
||||||
private:
|
|
||||||
html_frame* frame_;
|
|
||||||
|
|
||||||
public: // IOleInPlaceFrame interface
|
|
||||||
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID FAR* ppvObj) override;
|
|
||||||
ULONG STDMETHODCALLTYPE AddRef() override;
|
|
||||||
ULONG STDMETHODCALLTYPE Release() override;
|
|
||||||
HRESULT STDMETHODCALLTYPE GetWindow(HWND FAR* lphwnd) override;
|
|
||||||
HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode) override;
|
|
||||||
HRESULT STDMETHODCALLTYPE GetBorder(LPRECT lprectBorder) override;
|
|
||||||
HRESULT STDMETHODCALLTYPE RequestBorderSpace(LPCBORDERWIDTHS pborderwidths) override;
|
|
||||||
HRESULT STDMETHODCALLTYPE SetBorderSpace(LPCBORDERWIDTHS pborderwidths) override;
|
|
||||||
HRESULT STDMETHODCALLTYPE SetActiveObject(IOleInPlaceActiveObject* pActiveObject, LPCOLESTR pszObjName) override;
|
|
||||||
HRESULT STDMETHODCALLTYPE InsertMenus(HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths) override;
|
|
||||||
HRESULT STDMETHODCALLTYPE SetMenu(HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject) override;
|
|
||||||
HRESULT STDMETHODCALLTYPE RemoveMenus(HMENU hmenuShared) override;
|
|
||||||
HRESULT STDMETHODCALLTYPE SetStatusText(LPCOLESTR pszStatusText) override;
|
|
||||||
HRESULT STDMETHODCALLTYPE EnableModeless(BOOL fEnable) override;
|
|
||||||
HRESULT STDMETHODCALLTYPE TranslateAccelerator(LPMSG lpmsg, WORD wID) override;
|
|
||||||
};
|
|
@ -1,105 +0,0 @@
|
|||||||
#include "../../std_include.hpp"
|
|
||||||
#include "html_frame.hpp"
|
|
||||||
|
|
||||||
ole_in_place_site::ole_in_place_site(html_frame* frame) : frame_(frame)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT ole_in_place_site::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
|
|
||||||
{
|
|
||||||
auto client_site = this->frame_->get_client_site();
|
|
||||||
if (client_site)
|
|
||||||
{
|
|
||||||
return client_site->QueryInterface(riid, ppvObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
return E_NOINTERFACE;
|
|
||||||
}
|
|
||||||
|
|
||||||
ULONG ole_in_place_site::AddRef()
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ULONG ole_in_place_site::Release()
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT ole_in_place_site::GetWindow(HWND* lphwnd)
|
|
||||||
{
|
|
||||||
*lphwnd = this->frame_->get_window();
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT ole_in_place_site::ContextSensitiveHelp(BOOL /*fEnterMode*/)
|
|
||||||
{
|
|
||||||
return E_NOTIMPL;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT ole_in_place_site::CanInPlaceActivate()
|
|
||||||
{
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT ole_in_place_site::OnInPlaceActivate()
|
|
||||||
{
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT ole_in_place_site::OnUIActivate()
|
|
||||||
{
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT ole_in_place_site::GetWindowContext(LPOLEINPLACEFRAME* lplpFrame, LPOLEINPLACEUIWINDOW* lplpDoc,
|
|
||||||
LPRECT /*lprcPosRect*/, LPRECT /*lprcClipRect*/,
|
|
||||||
LPOLEINPLACEFRAMEINFO lpFrameInfo)
|
|
||||||
{
|
|
||||||
*lplpFrame = this->frame_->get_in_place_frame();
|
|
||||||
*lplpDoc = nullptr;
|
|
||||||
|
|
||||||
lpFrameInfo->fMDIApp = FALSE;
|
|
||||||
lpFrameInfo->hwndFrame = this->frame_->get_window();
|
|
||||||
lpFrameInfo->haccel = nullptr;
|
|
||||||
lpFrameInfo->cAccelEntries = 0;
|
|
||||||
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT ole_in_place_site::Scroll(SIZE /*scrollExtent*/)
|
|
||||||
{
|
|
||||||
return E_NOTIMPL;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT ole_in_place_site::OnUIDeactivate(BOOL /*fUndoable*/)
|
|
||||||
{
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT ole_in_place_site::OnInPlaceDeactivate()
|
|
||||||
{
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT ole_in_place_site::DiscardUndoState()
|
|
||||||
{
|
|
||||||
return E_NOTIMPL;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT ole_in_place_site::DeactivateAndUndo()
|
|
||||||
{
|
|
||||||
return E_NOTIMPL;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT ole_in_place_site::OnPosRectChange(LPCRECT lprcPosRect)
|
|
||||||
{
|
|
||||||
IOleInPlaceObject* in_place = nullptr;
|
|
||||||
if (!this->frame_->get_browser_object()->QueryInterface(IID_IOleInPlaceObject, reinterpret_cast<void**>(&in_place)))
|
|
||||||
{
|
|
||||||
in_place->SetObjectRects(lprcPosRect, lprcPosRect);
|
|
||||||
in_place->Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
@ -1,32 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
class html_frame;
|
|
||||||
|
|
||||||
class ole_in_place_site final : public IOleInPlaceSite
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ole_in_place_site(html_frame* frame);
|
|
||||||
virtual ~ole_in_place_site() = default;
|
|
||||||
|
|
||||||
private:
|
|
||||||
html_frame* frame_;
|
|
||||||
|
|
||||||
public: // IOleInPlaceSite interface
|
|
||||||
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID FAR* ppvObj) override;
|
|
||||||
ULONG STDMETHODCALLTYPE AddRef() override;
|
|
||||||
ULONG STDMETHODCALLTYPE Release() override;
|
|
||||||
HRESULT STDMETHODCALLTYPE GetWindow(HWND FAR* lphwnd) override;
|
|
||||||
HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode) override;
|
|
||||||
HRESULT STDMETHODCALLTYPE CanInPlaceActivate() override;
|
|
||||||
HRESULT STDMETHODCALLTYPE OnInPlaceActivate() override;
|
|
||||||
HRESULT STDMETHODCALLTYPE OnUIActivate() override;
|
|
||||||
HRESULT STDMETHODCALLTYPE GetWindowContext(LPOLEINPLACEFRAME FAR* lplpFrame, LPOLEINPLACEUIWINDOW FAR* lplpDoc,
|
|
||||||
LPRECT lprcPosRect, LPRECT lprcClipRect,
|
|
||||||
LPOLEINPLACEFRAMEINFO lpFrameInfo) override;
|
|
||||||
HRESULT STDMETHODCALLTYPE Scroll(SIZE scrollExtent) override;
|
|
||||||
HRESULT STDMETHODCALLTYPE OnUIDeactivate(BOOL fUndoable) override;
|
|
||||||
HRESULT STDMETHODCALLTYPE OnInPlaceDeactivate() override;
|
|
||||||
HRESULT STDMETHODCALLTYPE DiscardUndoState() override;
|
|
||||||
HRESULT STDMETHODCALLTYPE DeactivateAndUndo() override;
|
|
||||||
HRESULT STDMETHODCALLTYPE OnPosRectChange(LPCRECT lprcPosRect) override;
|
|
||||||
};
|
|
@ -1,33 +0,0 @@
|
|||||||
#include "../std_include.hpp"
|
|
||||||
#include "../resource.hpp"
|
|
||||||
#include "launcher.hpp"
|
|
||||||
|
|
||||||
#include "../utils/nt.hpp"
|
|
||||||
|
|
||||||
launcher::launcher()
|
|
||||||
{
|
|
||||||
this->create_main_menu();
|
|
||||||
}
|
|
||||||
|
|
||||||
void launcher::create_main_menu()
|
|
||||||
{
|
|
||||||
this->main_window_.set_callback(
|
|
||||||
[](window* window, const UINT message, const WPARAM w_param, const LPARAM l_param) -> LRESULT
|
|
||||||
{
|
|
||||||
if (message == WM_CLOSE)
|
|
||||||
{
|
|
||||||
window::close_all();
|
|
||||||
}
|
|
||||||
|
|
||||||
return DefWindowProcA(*window, message, w_param, l_param);
|
|
||||||
});
|
|
||||||
|
|
||||||
this->main_window_.create("S1x", 750, 420);
|
|
||||||
this->main_window_.load_html(utils::nt::load_resource(MAIN_MENU));
|
|
||||||
this->main_window_.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
void launcher::run() const
|
|
||||||
{
|
|
||||||
window::run();
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "html/html_window.hpp"
|
|
||||||
|
|
||||||
class launcher final
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
launcher();
|
|
||||||
|
|
||||||
void run() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
html_window main_window_;
|
|
||||||
|
|
||||||
void create_main_menu();
|
|
||||||
};
|
|
@ -1,208 +0,0 @@
|
|||||||
#include "../std_include.hpp"
|
|
||||||
#include "window.hpp"
|
|
||||||
|
|
||||||
#include "../utils/nt.hpp"
|
|
||||||
|
|
||||||
std::mutex window::mutex_;
|
|
||||||
std::vector<window*> window::windows_;
|
|
||||||
|
|
||||||
window::window()
|
|
||||||
{
|
|
||||||
ZeroMemory(&this->wc_, sizeof(this->wc_));
|
|
||||||
|
|
||||||
this->classname_ = "window-base-" + std::to_string(time(nullptr));
|
|
||||||
|
|
||||||
this->wc_.cbSize = sizeof(this->wc_);
|
|
||||||
this->wc_.style = CS_HREDRAW | CS_VREDRAW;
|
|
||||||
this->wc_.lpfnWndProc = static_processor;
|
|
||||||
this->wc_.hInstance = GetModuleHandle(nullptr);
|
|
||||||
this->wc_.hCursor = LoadCursor(nullptr, IDC_ARROW);
|
|
||||||
this->wc_.hIcon = LoadIcon(this->wc_.hInstance, MAKEINTRESOURCE(102));
|
|
||||||
this->wc_.hIconSm = this->wc_.hIcon;
|
|
||||||
this->wc_.hbrBackground = HBRUSH(COLOR_WINDOW);
|
|
||||||
this->wc_.lpszClassName = this->classname_.data();
|
|
||||||
RegisterClassEx(&this->wc_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void window::create(const std::string& title, const int width, const int height, const long flags)
|
|
||||||
{
|
|
||||||
{
|
|
||||||
std::lock_guard _(mutex_);
|
|
||||||
windows_.push_back(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto x = (GetSystemMetrics(SM_CXSCREEN) - width) / 2;
|
|
||||||
const auto y = (GetSystemMetrics(SM_CYSCREEN) - height) / 2;
|
|
||||||
|
|
||||||
this->handle_ = CreateWindowExA(NULL, this->wc_.lpszClassName, title.data(), flags, x, y, width, height, nullptr,
|
|
||||||
nullptr, this->wc_.hInstance, this);
|
|
||||||
|
|
||||||
SendMessageA(this->handle_, WM_DPICHANGED, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
window::~window()
|
|
||||||
{
|
|
||||||
this->close();
|
|
||||||
UnregisterClass(this->wc_.lpszClassName, this->wc_.hInstance);
|
|
||||||
}
|
|
||||||
|
|
||||||
void window::close()
|
|
||||||
{
|
|
||||||
if (!this->handle_) return;
|
|
||||||
|
|
||||||
SendMessageA(this->handle_, WM_KILL_WINDOW, NULL, NULL);
|
|
||||||
this->handle_ = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void window::run()
|
|
||||||
{
|
|
||||||
MSG msg;
|
|
||||||
while (GetMessage(&msg, nullptr, 0, 0))
|
|
||||||
{
|
|
||||||
TranslateMessage(&msg);
|
|
||||||
DispatchMessage(&msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void window::close_all()
|
|
||||||
{
|
|
||||||
std::unique_lock lock(mutex_);
|
|
||||||
auto window_list = windows_;
|
|
||||||
lock.unlock();
|
|
||||||
|
|
||||||
const auto current_thread_id = GetCurrentThreadId();
|
|
||||||
for (auto& window : window_list)
|
|
||||||
{
|
|
||||||
const auto thread_id = GetWindowThreadProcessId(*window, nullptr);
|
|
||||||
|
|
||||||
if (thread_id == current_thread_id)
|
|
||||||
{
|
|
||||||
window->close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void window::remove_window(const window* window)
|
|
||||||
{
|
|
||||||
std::lock_guard _(mutex_);
|
|
||||||
|
|
||||||
for (auto i = windows_.begin(); i != windows_.end(); ++i)
|
|
||||||
{
|
|
||||||
if (*i == window)
|
|
||||||
{
|
|
||||||
windows_.erase(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int window::get_window_count()
|
|
||||||
{
|
|
||||||
std::lock_guard _(mutex_);
|
|
||||||
|
|
||||||
auto count = 0;
|
|
||||||
const auto current_thread_id = GetCurrentThreadId();
|
|
||||||
|
|
||||||
for (const auto& window : windows_)
|
|
||||||
{
|
|
||||||
const auto thread_id = GetWindowThreadProcessId(*window, nullptr);
|
|
||||||
|
|
||||||
if (thread_id == current_thread_id)
|
|
||||||
{
|
|
||||||
++count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
void window::show() const
|
|
||||||
{
|
|
||||||
ShowWindow(this->handle_, SW_SHOW);
|
|
||||||
UpdateWindow(this->handle_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void window::hide() const
|
|
||||||
{
|
|
||||||
ShowWindow(this->handle_, SW_HIDE);
|
|
||||||
UpdateWindow(this->handle_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void window::set_callback(const std::function<LRESULT(window*, UINT, WPARAM, LPARAM)>& callback)
|
|
||||||
{
|
|
||||||
this->callback_ = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
LRESULT window::processor(const UINT message, const WPARAM w_param, const LPARAM l_param)
|
|
||||||
{
|
|
||||||
if (message == WM_DPICHANGED)
|
|
||||||
{
|
|
||||||
const utils::nt::library user32{"user32.dll"};
|
|
||||||
const auto get_dpi = user32 ? user32.get_proc<UINT(WINAPI *)(HWND)>("GetDpiForWindow") : nullptr;
|
|
||||||
|
|
||||||
if (get_dpi)
|
|
||||||
{
|
|
||||||
const auto dpi = get_dpi(*this);
|
|
||||||
if (dpi != this->last_dpi_)
|
|
||||||
{
|
|
||||||
RECT rect;
|
|
||||||
GetWindowRect(*this, &rect);
|
|
||||||
|
|
||||||
const auto scale = dpi * 1.0 / this->last_dpi_;
|
|
||||||
this->last_dpi_ = dpi;
|
|
||||||
|
|
||||||
const auto width = rect.right - rect.left;
|
|
||||||
const auto height = rect.bottom - rect.top;
|
|
||||||
|
|
||||||
MoveWindow(*this, rect.left, rect.top, int(width * scale), int(height * scale), TRUE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (message == WM_DESTROY)
|
|
||||||
{
|
|
||||||
remove_window(this);
|
|
||||||
|
|
||||||
if (get_window_count() == 0)
|
|
||||||
{
|
|
||||||
PostQuitMessage(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (message == WM_KILL_WINDOW)
|
|
||||||
{
|
|
||||||
DestroyWindow(*this);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this->callback_)
|
|
||||||
{
|
|
||||||
return this->callback_(this, message, w_param, l_param);
|
|
||||||
}
|
|
||||||
|
|
||||||
return DefWindowProc(*this, message, w_param, l_param);
|
|
||||||
}
|
|
||||||
|
|
||||||
LRESULT CALLBACK window::static_processor(HWND hwnd, UINT message, WPARAM w_param, LPARAM l_param)
|
|
||||||
{
|
|
||||||
if (message == WM_CREATE)
|
|
||||||
{
|
|
||||||
auto data = reinterpret_cast<LPCREATESTRUCT>(l_param);
|
|
||||||
SetWindowLongPtrA(hwnd, GWLP_USERDATA, LONG_PTR(data->lpCreateParams));
|
|
||||||
|
|
||||||
static_cast<window*>(data->lpCreateParams)->handle_ = hwnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto self = reinterpret_cast<window*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
|
|
||||||
if (self) return self->processor(message, w_param, l_param);
|
|
||||||
|
|
||||||
return DefWindowProc(hwnd, message, w_param, l_param);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
window::operator HWND() const
|
|
||||||
{
|
|
||||||
return this->handle_;
|
|
||||||
}
|
|
@ -1,44 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#define WM_KILL_WINDOW (WM_USER+0)
|
|
||||||
|
|
||||||
class window
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
window();
|
|
||||||
virtual ~window();
|
|
||||||
|
|
||||||
void create(const std::string& title, int width, int height,
|
|
||||||
long flags = (WS_OVERLAPPEDWINDOW & ~(WS_THICKFRAME | WS_MAXIMIZEBOX)));
|
|
||||||
|
|
||||||
void close();
|
|
||||||
|
|
||||||
void show() const;
|
|
||||||
void hide() const;
|
|
||||||
|
|
||||||
void set_callback(const std::function<LRESULT(window*, UINT, WPARAM, LPARAM)>& callback);
|
|
||||||
|
|
||||||
operator HWND() const;
|
|
||||||
|
|
||||||
static void run();
|
|
||||||
static void close_all();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual LRESULT processor(UINT message, WPARAM w_param, LPARAM l_param);
|
|
||||||
|
|
||||||
private:
|
|
||||||
uint32_t last_dpi_ = 96;
|
|
||||||
|
|
||||||
WNDCLASSEX wc_{};
|
|
||||||
HWND handle_ = nullptr;
|
|
||||||
std::string classname_;
|
|
||||||
std::function<LRESULT(window*, UINT, WPARAM, LPARAM)> callback_;
|
|
||||||
|
|
||||||
static LRESULT CALLBACK static_processor(HWND hwnd, UINT message, WPARAM w_param, LPARAM l_param);
|
|
||||||
|
|
||||||
static std::mutex mutex_;
|
|
||||||
static std::vector<window*> windows_;
|
|
||||||
|
|
||||||
static void remove_window(const window* window);
|
|
||||||
static int get_window_count();
|
|
||||||
};
|
|
@ -1,17 +1,20 @@
|
|||||||
|
#include "std_include.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <conio.h>
|
#include <conio.h>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
#include "std_include.hpp"
|
|
||||||
#include "driver.hpp"
|
#include "driver.hpp"
|
||||||
#include "driver_device.hpp"
|
#include "driver_device.hpp"
|
||||||
|
#include "process.hpp"
|
||||||
|
|
||||||
#include <irp_data.hpp>
|
#include <irp_data.hpp>
|
||||||
|
|
||||||
#include "resource.hpp"
|
#include "resource.hpp"
|
||||||
|
#include "utils/io.hpp"
|
||||||
#include "launcher/launcher.hpp"
|
#include "utils/nt.hpp"
|
||||||
|
|
||||||
#pragma comment(lib, "Shlwapi.lib")
|
#pragma comment(lib, "Shlwapi.lib")
|
||||||
|
|
||||||
@ -76,23 +79,221 @@ std::filesystem::path extract_driver()
|
|||||||
return driver_file;
|
return driver_file;
|
||||||
}
|
}
|
||||||
|
|
||||||
void unsafe_main(const int /*argc*/, char* /*argv*/[])
|
std::vector<std::pair<size_t, size_t>> find_executable_regions(const std::string& pe_file)
|
||||||
{
|
{
|
||||||
//launcher().run();
|
std::string data{};
|
||||||
//return;
|
if (!utils::io::read_file(pe_file, &data))
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
const auto driver_file = extract_driver();
|
const utils::nt::library library(reinterpret_cast<HMODULE>(data.data()));
|
||||||
|
if (!library.is_valid())
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
driver driver{driver_file, "MomoLul"};
|
const auto section_headers = library.get_section_headers();
|
||||||
const driver_device driver_device{R"(\\.\HelloDev)"};
|
|
||||||
|
|
||||||
|
std::vector<std::pair<size_t, size_t>> regions{};
|
||||||
|
for (const auto& section_header : section_headers)
|
||||||
|
{
|
||||||
|
if (section_header->Characteristics & IMAGE_SCN_MEM_EXECUTE)
|
||||||
|
{
|
||||||
|
regions.emplace_back(section_header->VirtualAddress, section_header->Misc.VirtualSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return regions;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t get_process_id()
|
||||||
|
{
|
||||||
std::string pid_str{};
|
std::string pid_str{};
|
||||||
printf("Please enter the pid: ");
|
printf("Please enter the pid: ");
|
||||||
std::getline(std::cin, pid_str);
|
std::getline(std::cin, pid_str);
|
||||||
|
|
||||||
const auto pid = atoi(pid_str.data());
|
return atoi(pid_str.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
void watch_regions(const driver_device& driver_device, const uint32_t pid, const HMODULE module,
|
||||||
|
const std::vector<std::pair<size_t, size_t>>& regions)
|
||||||
|
{
|
||||||
|
std::vector<watch_region> watch_regions{};
|
||||||
|
watch_regions.reserve(regions.size());
|
||||||
|
|
||||||
|
for (const auto& region : regions)
|
||||||
|
{
|
||||||
|
watch_region watch_region{};
|
||||||
|
watch_region.virtual_address = reinterpret_cast<uint8_t*>(module) + region.first;
|
||||||
|
watch_region.length = region.second;
|
||||||
|
watch_regions.push_back(watch_region);
|
||||||
|
}
|
||||||
|
|
||||||
|
watch_request request{};
|
||||||
|
request.process_id = pid;
|
||||||
|
request.watch_regions = watch_regions.data();
|
||||||
|
request.watch_region_count = watch_regions.size();
|
||||||
|
|
||||||
|
driver_device::data out{};
|
||||||
|
size_t out_len = 0;
|
||||||
|
driver_device.send(WATCH_DRV_IOCTL, &request, sizeof(request), out.data(), &out_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint64_t> query_records(const driver_device& driver_device, const size_t current_size = 0)
|
||||||
|
{
|
||||||
|
std::vector<uint64_t> result{};
|
||||||
|
result.resize(std::max(size_t(1024), current_size * 2));
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
char in[1];
|
||||||
|
constexpr auto element_len = sizeof(decltype(result)::value_type);
|
||||||
|
const size_t initial_len = result.size() * element_len;
|
||||||
|
size_t out_len = initial_len;
|
||||||
|
if (!driver_device.send(GET_RECORDS_DRV_IOCTL, in, 0, result.data(), &out_len))
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
//if (out_len <= initial_len)
|
||||||
|
if (result.back() == 0)
|
||||||
|
{
|
||||||
|
//result.resize(out_len / element_len);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//result.resize((out_len / element_len) + 10);
|
||||||
|
const auto new_size = result.size() * 2;
|
||||||
|
|
||||||
|
result = {};
|
||||||
|
result.resize(result.size() * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shrink
|
||||||
|
size_t i;
|
||||||
|
for (i = result.size(); i > 0; --i)
|
||||||
|
{
|
||||||
|
if (result[i - 1] != 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.resize(i);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void report_records(const std::atomic_bool& flag, const driver_device& driver_device, const uint32_t pid,
|
||||||
|
const HMODULE target_module, const std::vector<std::pair<size_t, size_t>>& regions)
|
||||||
|
{
|
||||||
|
std::set<uint64_t> access_addresses{};
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
while (!flag)
|
||||||
|
{
|
||||||
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||||
|
const auto new_records = query_records(driver_device, access_addresses.size());
|
||||||
|
|
||||||
|
for (const auto& new_record : new_records)
|
||||||
|
{
|
||||||
|
if (access_addresses.emplace(new_record).second)
|
||||||
|
{
|
||||||
|
printf("%p\n", reinterpret_cast<void*>(new_record));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((++i) % 5 == 0)
|
||||||
|
{
|
||||||
|
watch_regions(driver_device, pid, target_module, regions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void unsafe_main(const int /*argc*/, char* /*argv*/[])
|
||||||
|
{
|
||||||
|
{
|
||||||
|
const auto driver_file = extract_driver();
|
||||||
|
|
||||||
|
driver driver{driver_file, "MomoLul"};
|
||||||
|
const driver_device driver_device{R"(\\.\HelloDev)"};
|
||||||
|
|
||||||
|
const auto pid = get_process_id();
|
||||||
|
|
||||||
|
printf("Opening process...\n");
|
||||||
|
auto proc = process::open(pid, PROCESS_QUERY_INFORMATION | PROCESS_VM_READ);
|
||||||
|
if (!proc)
|
||||||
|
{
|
||||||
|
printf("Failed to open process...\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Reading modules...\n");
|
||||||
|
const auto modules = process::get_modules(proc);
|
||||||
|
printf("Found %zu modules:\n", modules.size());
|
||||||
|
|
||||||
|
std::vector<std::string> module_files{};
|
||||||
|
module_files.reserve(modules.size());
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for (const auto& module : modules)
|
||||||
|
{
|
||||||
|
auto name = process::get_module_filename(proc, module);
|
||||||
|
printf("(%i)\t%p: %s\n", i++, static_cast<void*>(module), name.data());
|
||||||
|
module_files.emplace_back(std::move(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't need this anymore
|
||||||
|
proc = {};
|
||||||
|
|
||||||
|
std::string module_str{};
|
||||||
|
printf("\nPlease enter the module number: ");
|
||||||
|
std::getline(std::cin, module_str);
|
||||||
|
|
||||||
|
const auto module_num = atoi(module_str.data());
|
||||||
|
|
||||||
|
if (module_num < 0 || static_cast<size_t>(module_num) >= modules.size())
|
||||||
|
{
|
||||||
|
printf("Invalid module num\n");
|
||||||
|
_getch();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto target_module = modules[module_num];
|
||||||
|
const auto module_base = reinterpret_cast<uint8_t*>(target_module);
|
||||||
|
const auto& file = module_files[module_num];
|
||||||
|
printf("Analyzing %s...\n", file.data());
|
||||||
|
const auto regions = find_executable_regions(file);
|
||||||
|
|
||||||
|
printf("Executable regions:\n");
|
||||||
|
for (const auto& region : regions)
|
||||||
|
{
|
||||||
|
printf("%p - %zu\n", module_base + region.first, region.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
watch_regions(driver_device, pid, target_module, regions);
|
||||||
|
|
||||||
|
std::atomic_bool terminate{false};
|
||||||
|
std::thread t([&]()
|
||||||
|
{
|
||||||
|
printf("\nWatching access:\n");
|
||||||
|
report_records(terminate, driver_device, pid, target_module, regions);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
_getch();
|
||||||
|
|
||||||
|
terminate = true;
|
||||||
|
t.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\nWatching stopped.\n");
|
||||||
|
_getch();
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
// IW5
|
// IW5
|
||||||
insert_nop(driver_device, pid, 0x4488A8, 2); // Force calling CG_DrawFriendOrFoeTargetBoxes
|
insert_nop(driver_device, pid, 0x4488A8, 2); // Force calling CG_DrawFriendOrFoeTargetBoxes
|
||||||
insert_nop(driver_device, pid, 0x47F6C7, 2); // Ignore blind-eye perks
|
insert_nop(driver_device, pid, 0x47F6C7, 2); // Ignore blind-eye perks
|
||||||
@ -110,24 +311,26 @@ void unsafe_main(const int /*argc*/, char* /*argv*/[])
|
|||||||
constexpr uint8_t data3[] = {0xEB};
|
constexpr uint8_t data3[] = {0xEB};
|
||||||
patch_data(driver_device, pid, 0x443A2A, data3, sizeof(data3));
|
patch_data(driver_device, pid, 0x443A2A, data3, sizeof(data3));
|
||||||
patch_data(driver_device, pid, 0x443978, data3, sizeof(data3));
|
patch_data(driver_device, pid, 0x443978, data3, sizeof(data3));
|
||||||
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
insert_nop(driver_device, pid, 0x441D5A, 6);
|
insert_nop(driver_device, pid, 0x441D5A, 6);
|
||||||
insert_nop(driver_device, pid, 0x525104, 2);
|
insert_nop(driver_device, pid, 0x525104, 2);
|
||||||
insert_nop(driver_device, pid, 0x525121, 2);
|
insert_nop(driver_device, pid, 0x525121, 2);
|
||||||
|
|
||||||
constexpr uint8_t data3[] = {0xEB};
|
constexpr uint8_t data3[] = {0xEB};
|
||||||
patch_data(driver_device, pid, 0x525087, data3, sizeof(data3));
|
patch_data(driver_device, pid, 0x525087, data3, sizeof(data3));
|
||||||
patch_data(driver_device, pid, 0x524E7F, data3, sizeof(data3));
|
patch_data(driver_device, pid, 0x524E7F, data3, sizeof(data3));
|
||||||
patch_data(driver_device, pid, 0x52512C, data3, sizeof(data3));
|
patch_data(driver_device, pid, 0x52512C, data3, sizeof(data3));
|
||||||
*/
|
*/
|
||||||
printf("Press any key to disable all hooks!\n");
|
|
||||||
|
/*printf("Press any key to disable all hooks!\n");
|
||||||
(void)_getch();
|
(void)_getch();
|
||||||
|
|
||||||
remove_hooks(driver_device);
|
remove_hooks(driver_device);
|
||||||
|
|
||||||
printf("Press any key to exit!\n");
|
printf("Press any key to exit!\n");
|
||||||
(void)_getch();
|
(void)_getch();*/
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(const int argc, char* argv[])
|
int main(const int argc, char* argv[])
|
||||||
@ -140,11 +343,13 @@ int main(const int argc, char* argv[])
|
|||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
printf("Error: %s\n", e.what());
|
printf("Error: %s\n", e.what());
|
||||||
|
_getch();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
printf("An unknown error occured!\n");
|
printf("An unknown error occured!\n");
|
||||||
|
_getch();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
81
src/runner/process.cpp
Normal file
81
src/runner/process.cpp
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
#include "std_include.hpp"
|
||||||
|
#include "process.hpp"
|
||||||
|
|
||||||
|
namespace process
|
||||||
|
{
|
||||||
|
native_handle open(const uint32_t process_id, const DWORD access)
|
||||||
|
{
|
||||||
|
const auto handle = ::OpenProcess(access, FALSE, process_id);
|
||||||
|
if (handle)
|
||||||
|
{
|
||||||
|
return {handle};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<HMODULE> get_modules(const native_handle& process)
|
||||||
|
{
|
||||||
|
if (!process)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD needed = 1024;
|
||||||
|
std::vector<HMODULE> result{};
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
result.resize(needed);
|
||||||
|
if (!EnumProcessModulesEx(process, result.data(), static_cast<DWORD>(result.size()), &needed,
|
||||||
|
LIST_MODULES_ALL))
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (needed > result.size());
|
||||||
|
|
||||||
|
result.resize(needed);
|
||||||
|
|
||||||
|
// Remove duplicates
|
||||||
|
std::ranges::sort(result);
|
||||||
|
const auto last = std::ranges::unique(result).begin();
|
||||||
|
result.erase(last, result.end());
|
||||||
|
|
||||||
|
// Remove nullptr
|
||||||
|
for (auto i = result.begin(); i != result.end();)
|
||||||
|
{
|
||||||
|
if (*i == nullptr)
|
||||||
|
{
|
||||||
|
i = result.erase(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_module_filename(const native_handle& process, const HMODULE module)
|
||||||
|
{
|
||||||
|
if (!process)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string buffer{};
|
||||||
|
buffer.resize(1024);
|
||||||
|
|
||||||
|
const auto length = GetModuleFileNameExA(process, module, &buffer[0], static_cast<DWORD>(buffer.size()));
|
||||||
|
if (length > 0)
|
||||||
|
{
|
||||||
|
buffer.resize(length);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
9
src/runner/process.hpp
Normal file
9
src/runner/process.hpp
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "native_handle.hpp"
|
||||||
|
|
||||||
|
namespace process
|
||||||
|
{
|
||||||
|
native_handle open(uint32_t process_id, DWORD access);
|
||||||
|
std::vector<HMODULE> get_modules(const native_handle& process);
|
||||||
|
std::string get_module_filename(const native_handle& process, HMODULE module);
|
||||||
|
}
|
@ -1,4 +1,3 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define DRIVER_BINARY 300
|
#define DRIVER_BINARY 300
|
||||||
#define MAIN_MENU 301
|
|
||||||
|
@ -85,7 +85,6 @@ END
|
|||||||
|
|
||||||
102 ICON "resources/icon.ico"
|
102 ICON "resources/icon.ico"
|
||||||
DRIVER_BINARY RCDATA DRIVER_FILE
|
DRIVER_BINARY RCDATA DRIVER_FILE
|
||||||
MAIN_MENU RCDATA "resources/main.html"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
File diff suppressed because one or more lines are too long
@ -9,8 +9,6 @@
|
|||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#include <Shlwapi.h>
|
#include <Shlwapi.h>
|
||||||
#include <ShlObj.h>
|
#include <ShlObj.h>
|
||||||
|
#include <Psapi.h>
|
||||||
#include <MsHTML.h>
|
|
||||||
#include <MsHtmHst.h>
|
|
||||||
|
|
||||||
#pragma comment(lib, "Shlwapi.lib")
|
#pragma comment(lib, "Shlwapi.lib")
|
||||||
|
125
src/runner/utils/io.cpp
Normal file
125
src/runner/utils/io.cpp
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
#include "io.hpp"
|
||||||
|
#include "nt.hpp"
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
namespace utils::io
|
||||||
|
{
|
||||||
|
bool remove_file(const std::string& file)
|
||||||
|
{
|
||||||
|
return DeleteFileA(file.data()) == TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool move_file(const std::string& src, const std::string& target)
|
||||||
|
{
|
||||||
|
return MoveFileA(src.data(), target.data()) == TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool file_exists(const std::string& file)
|
||||||
|
{
|
||||||
|
return std::ifstream(file).good();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool write_file(const std::string& file, const std::string& data, const bool append)
|
||||||
|
{
|
||||||
|
const auto pos = file.find_last_of("/\\");
|
||||||
|
if (pos != std::string::npos)
|
||||||
|
{
|
||||||
|
create_directory(file.substr(0, pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ofstream stream(
|
||||||
|
file, std::ios::binary | std::ofstream::out | (append ? std::ofstream::app : 0));
|
||||||
|
|
||||||
|
if (stream.is_open())
|
||||||
|
{
|
||||||
|
stream.write(data.data(), data.size());
|
||||||
|
stream.close();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string read_file(const std::string& file)
|
||||||
|
{
|
||||||
|
std::string data;
|
||||||
|
read_file(file, &data);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool read_file(const std::string& file, std::string* data)
|
||||||
|
{
|
||||||
|
if (!data) return false;
|
||||||
|
data->clear();
|
||||||
|
|
||||||
|
if (file_exists(file))
|
||||||
|
{
|
||||||
|
std::ifstream stream(file, std::ios::binary);
|
||||||
|
if (!stream.is_open()) return false;
|
||||||
|
|
||||||
|
stream.seekg(0, std::ios::end);
|
||||||
|
const std::streamsize size = stream.tellg();
|
||||||
|
stream.seekg(0, std::ios::beg);
|
||||||
|
|
||||||
|
if (size > -1)
|
||||||
|
{
|
||||||
|
data->resize(static_cast<uint32_t>(size));
|
||||||
|
stream.read(const_cast<char*>(data->data()), size);
|
||||||
|
stream.close();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t file_size(const std::string& file)
|
||||||
|
{
|
||||||
|
if (file_exists(file))
|
||||||
|
{
|
||||||
|
std::ifstream stream(file, std::ios::binary);
|
||||||
|
|
||||||
|
if (stream.good())
|
||||||
|
{
|
||||||
|
stream.seekg(0, std::ios::end);
|
||||||
|
return static_cast<size_t>(stream.tellg());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool create_directory(const std::string& directory)
|
||||||
|
{
|
||||||
|
return std::filesystem::create_directories(directory);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool directory_exists(const std::string& directory)
|
||||||
|
{
|
||||||
|
return std::filesystem::is_directory(directory);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool directory_is_empty(const std::string& directory)
|
||||||
|
{
|
||||||
|
return std::filesystem::is_empty(directory);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> list_files(const std::string& directory)
|
||||||
|
{
|
||||||
|
std::vector<std::string> files;
|
||||||
|
|
||||||
|
for (auto& file : std::filesystem::directory_iterator(directory))
|
||||||
|
{
|
||||||
|
files.push_back(file.path().generic_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
|
void copy_folder(const std::filesystem::path& src, const std::filesystem::path& target)
|
||||||
|
{
|
||||||
|
std::filesystem::copy(src, target,
|
||||||
|
std::filesystem::copy_options::overwrite_existing |
|
||||||
|
std::filesystem::copy_options::recursive);
|
||||||
|
}
|
||||||
|
}
|
21
src/runner/utils/io.hpp
Normal file
21
src/runner/utils/io.hpp
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
namespace utils::io
|
||||||
|
{
|
||||||
|
bool remove_file(const std::string& file);
|
||||||
|
bool move_file(const std::string& src, const std::string& target);
|
||||||
|
bool file_exists(const std::string& file);
|
||||||
|
bool write_file(const std::string& file, const std::string& data, bool append = false);
|
||||||
|
bool read_file(const std::string& file, std::string* data);
|
||||||
|
std::string read_file(const std::string& file);
|
||||||
|
size_t file_size(const std::string& file);
|
||||||
|
bool create_directory(const std::string& directory);
|
||||||
|
bool directory_exists(const std::string& directory);
|
||||||
|
bool directory_is_empty(const std::string& directory);
|
||||||
|
std::vector<std::string> list_files(const std::string& directory);
|
||||||
|
void copy_folder(const std::filesystem::path& src, const std::filesystem::path& target);
|
||||||
|
}
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#define HOOK_DRV_IOCTL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_NEITHER, FILE_ANY_ACCESS)
|
#define HOOK_DRV_IOCTL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_NEITHER, FILE_ANY_ACCESS)
|
||||||
#define UNHOOK_DRV_IOCTL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_NEITHER, FILE_ANY_ACCESS)
|
#define UNHOOK_DRV_IOCTL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_NEITHER, FILE_ANY_ACCESS)
|
||||||
|
#define WATCH_DRV_IOCTL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_NEITHER, FILE_ANY_ACCESS)
|
||||||
|
#define GET_RECORDS_DRV_IOCTL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x803, METHOD_NEITHER, FILE_ANY_ACCESS)
|
||||||
|
|
||||||
static_assert(sizeof(void*) == 8);
|
static_assert(sizeof(void*) == 8);
|
||||||
|
|
||||||
@ -12,3 +14,16 @@ struct hook_request
|
|||||||
const void* source_data{};
|
const void* source_data{};
|
||||||
uint64_t source_data_size{};
|
uint64_t source_data_size{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct watch_region
|
||||||
|
{
|
||||||
|
const void* virtual_address{};
|
||||||
|
size_t length{};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct watch_request
|
||||||
|
{
|
||||||
|
uint32_t process_id{};
|
||||||
|
const watch_region* watch_regions{};
|
||||||
|
uint64_t watch_region_count{};
|
||||||
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user