Skip to content

Commit

Permalink
libuserhook: extract common trap_loaded_dll_targets function
Browse files Browse the repository at this point in the history
  • Loading branch information
disaykin committed Dec 29, 2023
1 parent d39fba6 commit 49cebf8
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 84 deletions.
6 changes: 4 additions & 2 deletions src/libusermode/uh-private.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -293,9 +293,11 @@ class userhook : public pluginex
};

proc_data_t get_proc_data(drakvuf_t drakvuf, const drakvuf_trap_info_t* info);
bool make_trap(vmi_instance_t vmi, drakvuf_t drakvuf, drakvuf_trap_info* info, hook_target_entry_t* target, addr_t exec_func);
bool is_pagetable_loaded(vmi_instance_t vmi, const drakvuf_trap_info* info, addr_t vaddr);
bool make_trap(vmi_instance_t vmi, drakvuf_t drakvuf, addr_t process_dtb, hook_target_entry_t* target, addr_t exec_func);
bool is_pagetable_loaded(vmi_instance_t vmi, addr_t vaddr, addr_t process_dtb);
void resolve_dll_targets(vmi_instance_t vmi, dll_t* dll_meta, addr_t process_dtb);
void trap_loaded_dll_targets(drakvuf_t drakvuf, dll_t* dll_meta, addr_t process_dtb, const proc_data_t& proc_data);


event_response_t internal_perform_hooking_pf(drakvuf_t drakvuf, drakvuf_trap_info* info, userhook* plugin, dll_t* dll_meta);
event_response_t internal_perform_hooking_injection(drakvuf_t drakvuf, drakvuf_trap_info* info, userhook* plugin, dll_t* dll_meta);
Expand Down
43 changes: 38 additions & 5 deletions src/libusermode/userhook.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ static dll_t* create_dll_meta(drakvuf_t drakvuf, drakvuf_trap_info* info, userho
return &it->second.back();
}

bool make_trap(vmi_instance_t vmi, drakvuf_t drakvuf, drakvuf_trap_info* info, hook_target_entry_t* target, addr_t exec_func)
bool make_trap(vmi_instance_t vmi, drakvuf_t drakvuf, addr_t process_dtb, hook_target_entry_t* target, addr_t exec_func)
{
if (target->trap)
{
Expand All @@ -313,7 +313,7 @@ bool make_trap(vmi_instance_t vmi, drakvuf_t drakvuf, drakvuf_trap_info* info, h
// that's why we'll manually resolve vaddr and store paddr under trap->breakpoint.addr
addr_t pa;

if (vmi_pagetable_lookup(vmi, info->regs->cr3, exec_func, &pa) != VMI_SUCCESS)
if (vmi_pagetable_lookup(vmi, process_dtb, exec_func, &pa) != VMI_SUCCESS)
{
PRINT_DEBUG("[USERHOOK] Failed to lookup paddr in make_trap\n");
return false;
Expand All @@ -340,10 +340,10 @@ bool make_trap(vmi_instance_t vmi, drakvuf_t drakvuf, drakvuf_trap_info* info, h
return false;
}

bool is_pagetable_loaded(vmi_instance_t vmi, const drakvuf_trap_info* info, addr_t vaddr)
bool is_pagetable_loaded(vmi_instance_t vmi, addr_t vaddr, addr_t process_dtb)
{
page_info_t pinfo;
return vmi_pagetable_lookup_extended(vmi, info->regs->cr3, vaddr, &pinfo) == VMI_SUCCESS;
return vmi_pagetable_lookup_extended(vmi, process_dtb, vaddr, &pinfo) == VMI_SUCCESS;
}

void resolve_dll_targets(vmi_instance_t vmi, dll_t* dll_meta, addr_t process_dtb)
Expand Down Expand Up @@ -377,6 +377,39 @@ void resolve_dll_targets(vmi_instance_t vmi, dll_t* dll_meta, addr_t process_dtb
}
}

void trap_loaded_dll_targets(drakvuf_t drakvuf, dll_t* dll_meta, addr_t process_dtb, const proc_data_t& proc_data)
{
auto vmi = vmi_lock_guard(drakvuf);

for (auto& target : dll_meta->targets)
{
if (target.state == HOOK_FIRST_TRY || target.state == HOOK_PAGEFAULT_RETRY)
{
addr_t exec_func = target.target_addr;

if (is_pagetable_loaded(vmi, exec_func, process_dtb))
{
target.pid = proc_data.pid;
if (make_trap(vmi, drakvuf, process_dtb, &target, exec_func))
target.state = HOOK_OK;
else
target.state = HOOK_FAILED;
}
else if (target.state == HOOK_PAGEFAULT_RETRY)
target.state = HOOK_FAILED;

if (target.state == HOOK_OK || target.state == HOOK_FAILED)
{
PRINT_DEBUG("[USERHOOK] Hook %s (vaddr = 0x%llx, dll_base = 0x%llx, result = %s)\n",
target.target_name.c_str(),
(unsigned long long)exec_func,
(unsigned long long)dll_meta->v.real_dll_base,
target.state == HOOK_OK ? "OK" : "FAIL");
}
}
}
}

static event_response_t perform_hooking(drakvuf_t drakvuf, drakvuf_trap_info* info, userhook* plugin, dll_t* dll_meta)
{
bool was_hooked = dll_meta->v.is_hooked;
Expand Down Expand Up @@ -723,7 +756,7 @@ static event_response_t copy_on_write_ret_cb(drakvuf_t drakvuf, drakvuf_trap_inf
hook->trap = nullptr;
hook->pid = proc_data.pid;

make_trap(vmi, drakvuf, info, hook, hook_va);
make_trap(vmi, drakvuf, info->regs->cr3, hook, hook_va);
}
}

Expand Down
59 changes: 19 additions & 40 deletions src/libusermode/userhook_inject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ event_response_t internal_perform_hooking_injection(drakvuf_t drakvuf, drakvuf_t

while (dll_meta->pf_current_addr <= dll_meta->pf_max_addr)
{
if (is_pagetable_loaded(vmi, info, dll_meta->pf_current_addr))
if (is_pagetable_loaded(vmi, dll_meta->pf_current_addr, info->regs->cr3))
{
PRINT_DEBUG("[USERHOOK] Export info accessible OK %llx\n", (unsigned long long)dll_meta->pf_current_addr);
dll_meta->pf_current_addr += VMI_PS_4KB;
Expand All @@ -227,49 +227,28 @@ event_response_t internal_perform_hooking_injection(drakvuf_t drakvuf, drakvuf_t

resolve_dll_targets(vmi, dll_meta, info->regs->cr3);

trap_loaded_dll_targets(drakvuf, dll_meta, info->regs->cr3, proc_data);

for (auto& target : dll_meta->targets)
{
if (target.state == HOOK_FIRST_TRY || target.state == HOOK_PAGEFAULT_RETRY)
{
addr_t exec_func = target.target_addr;

if (is_pagetable_loaded(vmi, info, exec_func))
{
target.pid = proc_data.pid;
if (make_trap(vmi, drakvuf, info, &target, exec_func))
target.state = HOOK_OK;
else
target.state = HOOK_FAILED;
}
else if (target.state == HOOK_FIRST_TRY)
{
addr_t stack_pointer;
if (inject_copy_memory(plugin, drakvuf, info, info->trap->cb, dll_meta->set_stack_marker(), exec_func, &stack_pointer))
{
PRINT_DEBUG("[USERHOOK] Target addr not accessible, page fault %llx\n", (unsigned long long)exec_func);
target.state = HOOK_PAGEFAULT_RETRY;
get_trap_params<call_result_t>(info->trap)->set_result_call_params(info, stack_pointer);
plugin->increment_injection_in_progress_count(proc_data);
}
else
{
PRINT_DEBUG("[USERHOOK] Failed to request page fault for DTB %llx, address %llx\n",
(unsigned long long)info->regs->cr3, (unsigned long long)exec_func);
target.state = HOOK_FAILED;
}
return VMI_EVENT_RESPONSE_NONE;
}
else // target.state == HOOK_PAGEFAULT_RETRY
{
target.state = HOOK_FAILED;
}
if (target.state != HOOK_FIRST_TRY) continue;

PRINT_DEBUG("[USERHOOK] Hook %s (vaddr = 0x%llx, dll_base = 0x%llx, result = %s)\n",
target.target_name.c_str(),
(unsigned long long)exec_func,
(unsigned long long)dll_meta->v.real_dll_base,
target.state == HOOK_OK ? "OK" : "FAIL");
addr_t exec_func = target.target_addr;
addr_t stack_pointer;
if (inject_copy_memory(plugin, drakvuf, info, info->trap->cb, dll_meta->set_stack_marker(), exec_func, &stack_pointer))
{
PRINT_DEBUG("[USERHOOK] Target addr not accessible, page fault %llx\n", (unsigned long long)exec_func);
target.state = HOOK_PAGEFAULT_RETRY;
get_trap_params<call_result_t>(info->trap)->set_result_call_params(info, stack_pointer);
plugin->increment_injection_in_progress_count(proc_data);
}
else
{
PRINT_DEBUG("[USERHOOK] Failed to request page fault for DTB %llx, address %llx\n",
(unsigned long long)info->regs->cr3, (unsigned long long)exec_func);
target.state = HOOK_FAILED;
}
return VMI_EVENT_RESPONSE_NONE;
}

PRINT_DEBUG("[USERHOOK] Done, flag DLL as hooked\n");
Expand Down
53 changes: 16 additions & 37 deletions src/libusermode/userhook_pf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ event_response_t internal_perform_hooking_pf(drakvuf_t drakvuf, drakvuf_trap_inf

while (dll_meta->pf_current_addr <= dll_meta->pf_max_addr)
{
if (is_pagetable_loaded(vmi, info, dll_meta->pf_current_addr))
if (is_pagetable_loaded(vmi, dll_meta->pf_current_addr, info->regs->cr3))
{
PRINT_DEBUG("[USERHOOK] Export info accessible OK %llx\n", (unsigned long long)dll_meta->pf_current_addr);
dll_meta->pf_current_addr += VMI_PS_4KB;
Expand All @@ -190,46 +190,25 @@ event_response_t internal_perform_hooking_pf(drakvuf_t drakvuf, drakvuf_trap_inf

resolve_dll_targets(vmi, dll_meta, info->regs->cr3);

trap_loaded_dll_targets(drakvuf, dll_meta, info->regs->cr3, proc_data);

for (auto& target : dll_meta->targets)
{
if (target.state == HOOK_FIRST_TRY || target.state == HOOK_PAGEFAULT_RETRY)
if (target.state != HOOK_FIRST_TRY) continue;

addr_t exec_func = target.target_addr;
if (vmi_request_page_fault(vmi, info->vcpu, exec_func, 0) == VMI_SUCCESS)
{
addr_t exec_func = target.target_addr;

if (is_pagetable_loaded(vmi, info, exec_func))
{
target.pid = proc_data.pid;
if (make_trap(vmi, drakvuf, info, &target, exec_func))
target.state = HOOK_OK;
else
target.state = HOOK_FAILED;
}
else if (target.state == HOOK_FIRST_TRY)
{
if (vmi_request_page_fault(vmi, info->vcpu, exec_func, 0) == VMI_SUCCESS)
{
target.state = HOOK_PAGEFAULT_RETRY;
plugin->increment_injection_in_progress_count(proc_data);
}
else
{
PRINT_DEBUG("[USERHOOK] Failed to request page fault for DTB %llx, address %llx\n",
(unsigned long long)info->regs->cr3, (unsigned long long)exec_func);
target.state = HOOK_FAILED;
}
return VMI_EVENT_RESPONSE_NONE;
}
else // target.state == HOOK_PAGEFAULT_RETRY
{
target.state = HOOK_FAILED;
}

PRINT_DEBUG("[USERHOOK] Hook %s (vaddr = 0x%llx, dll_base = 0x%llx, result = %s)\n",
target.target_name.c_str(),
(unsigned long long)exec_func,
(unsigned long long)dll_meta->v.real_dll_base,
target.state == HOOK_OK ? "OK" : "FAIL");
target.state = HOOK_PAGEFAULT_RETRY;
plugin->increment_injection_in_progress_count(proc_data);
}
else
{
PRINT_DEBUG("[USERHOOK] Failed to request page fault for DTB %llx, address %llx\n",
(unsigned long long)info->regs->cr3, (unsigned long long)exec_func);
target.state = HOOK_FAILED;
}
return VMI_EVENT_RESPONSE_NONE;
}

PRINT_DEBUG("[USERHOOK] Done, flag DLL as hooked\n");
Expand Down

0 comments on commit 49cebf8

Please sign in to comment.