Skip to content

Commit

Permalink
libusermode: add command line switch for pf/injection mode (#1718)
Browse files Browse the repository at this point in the history
* libusermode: add command line switch for pf/injection mode

* fix compilation
  • Loading branch information
disaykin authored Oct 2, 2023
1 parent 6a714f9 commit b482a45
Show file tree
Hide file tree
Showing 12 changed files with 97 additions and 92 deletions.
7 changes: 0 additions & 7 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -625,13 +625,6 @@ AC_ARG_ENABLE([debug],
[debug="no"])
AM_CONDITIONAL([DEBUG], [test x$debug = xyes])

AC_ARG_ENABLE([libusermodeinjections],
[AS_HELP_STRING([--enable-libusermodeinjections],
[Use injections instead of page faults in libusermode @<:@no@:>@])],
[libusermodeinjections="$enableval"],
[libusermodeinjections="no"])
AM_CONDITIONAL([LIBUSERMODE_USE_INJECTION], [test x$libusermodeinjections = xyes])

AC_ARG_ENABLE([sanitize],
[AS_HELP_STRING([--enable-sanitize],
[Enable sanitizers to be compiled @<:@no@:>@])],
Expand Down
4 changes: 2 additions & 2 deletions src/libinjector/libinjector.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@
#ifndef LIBINJECTOR_H
#define LIBINJECTOR_H

#include <libdrakvuf/libdrakvuf.h>

#ifdef __cplusplus
extern "C" {
#define NOEXCEPT noexcept
Expand All @@ -114,8 +116,6 @@ extern "C" {

#pragma GCC visibility push(default)

#include <libdrakvuf/libdrakvuf.h>

typedef struct injector* injector_t;

typedef enum
Expand Down
4 changes: 0 additions & 4 deletions src/libusermode/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -145,10 +145,6 @@ AM_CXXFLAGS += -pg
endif
endif

if LIBUSERMODE_USE_INJECTION
AM_CXXFLAGS += -DLIBUSERMODE_USE_INJECTION
endif

noinst_LTLIBRARIES= libusermode.la
libusermode_la_SOURCES= $(sources)
libusermode_la_LIBADD = ../libdrakvuf/libdrakvuf.la
Expand Down
74 changes: 36 additions & 38 deletions src/libusermode/running.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -234,25 +234,26 @@ event_response_t hook_process_cb(
{
rh_data_t* rh_data = static_cast<rh_data_t*>(info->trap->data);
userhook* userhook_plugin = rh_data->userhook_plugin;
auto proc_data = get_proc_data(drakvuf, info);

#ifdef LIBUSERMODE_USE_INJECTION
if (!rh_data->inject_in_progress)
if (userhook_plugin->injection_mode)
{
if (info->proc_data.pid != rh_data->target_process_pid)
return VMI_EVENT_RESPONSE_NONE;
}
else
{
if (!drakvuf_check_return_context(drakvuf, info, rh_data->target_process_pid, rh_data->target_process_tid, rh_data->target_process_rsp))
return VMI_EVENT_RESPONSE_NONE;
if (!rh_data->inject_in_progress)
{
if (proc_data.pid != rh_data->target_process_pid)
return VMI_EVENT_RESPONSE_NONE;
}
else
{
if (!drakvuf_check_return_context(drakvuf, info, rh_data->target_process_pid, rh_data->target_process_tid, rh_data->target_process_rsp))
return VMI_EVENT_RESPONSE_NONE;

memcpy(info->regs, &rh_data->regs, sizeof(x86_registers_t));
rh_data->inject_in_progress = false;
memcpy(info->regs, &rh_data->regs, sizeof(x86_registers_t));
rh_data->inject_in_progress = false;
}
}
#else
if (info->proc_data.pid != rh_data->target_process_pid)
else if (proc_data.pid != rh_data->target_process_pid)
return VMI_EVENT_RESPONSE_NONE;
#endif

if (rh_data->state == HOOK_FIRST_TRY)
{
Expand Down Expand Up @@ -283,14 +284,14 @@ event_response_t hook_process_cb(
}
}

#ifndef LIBUSERMODE_USE_INJECTION
userhook_plugin->pf_in_progress.erase(std::make_pair(info->proc_data.pid, info->proc_data.tid));
#endif
if (!userhook_plugin->injection_mode)
{
userhook_plugin->pf_in_progress.erase(std::make_pair(proc_data.pid, proc_data.tid));
}

// Now let's try to resolve physical address of the target function.
addr_t func_pa = 0;
{
// Lock vmi.
auto vmi = vmi_lock_guard(drakvuf);
if (VMI_SUCCESS != vmi_pagetable_lookup(vmi, rh_data->target_process_dtb, rh_data->func_addr, &func_pa))
{
Expand All @@ -302,31 +303,29 @@ event_response_t hook_process_cb(
}

// Otherwise request page fault, exit and wait for hook_process_cb to be hit again.
#ifndef LIBUSERMODE_USE_INJECTION
if (VMI_SUCCESS == vmi_request_page_fault(vmi, info->vcpu, rh_data->func_addr, 0))
#else
memcpy(&rh_data->regs, info->regs, sizeof(x86_registers_t));
rh_data->target_process_tid = info->proc_data.tid;
rh_data->target_process_rsp = info->regs->rsp;
rh_data->inject_in_progress = true;
addr_t stack_pointer;
if (inject_copy_memory(userhook_plugin, drakvuf, info, info->trap->cb, nullptr, rh_data->func_addr, &stack_pointer))
#endif
if (userhook_plugin->injection_mode)
{
rh_data->state = HOOK_PAGEFAULT_RETRY;
#ifndef LIBUSERMODE_USE_INJECTION
userhook_plugin->pf_in_progress.insert(std::make_pair(info->proc_data.pid, info->proc_data.tid));
#endif
return VMI_EVENT_RESPONSE_NONE;
memcpy(&rh_data->regs, info->regs, sizeof(x86_registers_t));
rh_data->target_process_tid = proc_data.tid;
rh_data->target_process_rsp = info->regs->rsp;
rh_data->inject_in_progress = true;
addr_t stack_pointer;
if (inject_copy_memory(userhook_plugin, drakvuf, info, info->trap->cb, nullptr, rh_data->func_addr, &stack_pointer))
{
rh_data->state = HOOK_PAGEFAULT_RETRY;
return VMI_EVENT_RESPONSE_NONE;
}
}
else
else if (VMI_SUCCESS == vmi_request_page_fault(vmi, info->vcpu, rh_data->func_addr, 0))
{
userhook_plugin->remove_running_rh_trap(drakvuf, info->trap);
rh_data->state = HOOK_PAGEFAULT_RETRY;
userhook_plugin->pf_in_progress.insert(std::make_pair(proc_data.pid, proc_data.tid));
return VMI_EVENT_RESPONSE_NONE;
}

userhook_plugin->remove_running_rh_trap(drakvuf, info->trap);
return VMI_EVENT_RESPONSE_NONE;
}
} // Unlock Vmi.
}

// We have managed to resolve the physical address. Place the trap.
drakvuf_trap_t* trap = new drakvuf_trap_t();
Expand All @@ -345,7 +344,6 @@ event_response_t hook_process_cb(
return VMI_EVENT_RESPONSE_NONE;
}


static
event_response_t wait_for_target_process_cb(
drakvuf_t drakvuf,
Expand Down
22 changes: 8 additions & 14 deletions src/libusermode/uh-private.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,6 @@ struct copy_on_write_result_t : public call_result_t
class userhook : public pluginex
{
public:
drakvuf_t m_drakvuf = nullptr;
addr_t copy_virt_mem_va{0};

userhook(userhook const&) = delete;
Expand All @@ -259,15 +258,10 @@ class userhook : public pluginex

std::map<vmi_pid_t, module_context_t> proc_ntdll;

#ifndef LIBUSERMODE_USE_INJECTION
std::set<std::pair<vmi_pid_t, uint32_t /*thread_id*/>> pf_in_progress;
#endif
const bool injection_mode;
std::set<std::pair<vmi_pid_t, uint32_t /*tid*/>> pf_in_progress;

static userhook& get_instance(drakvuf_t drakvuf)
{
static userhook instance(drakvuf);
return instance;
}
static userhook& get_instance(drakvuf_t drakvuf);

static bool is_supported(drakvuf_t drakvuf);
void register_plugin(drakvuf_t drakvuf, usermode_cb_registration reg);
Expand All @@ -280,7 +274,7 @@ class userhook : public pluginex
void remove_running_rh_trap(drakvuf_t drakvuf, drakvuf_trap_t* trap);

private:
userhook(drakvuf_t drakvuf); // Force get_instance().
userhook(drakvuf_t drakvuf, bool injection_mode_enabled); // Force get_instance().
~userhook();

// We need to keep these for memory management purposes.
Expand All @@ -293,17 +287,17 @@ 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);
event_response_t internal_perform_hooking(drakvuf_t drakvuf, drakvuf_trap_info* info, userhook* plugin, dll_t* dll_meta);

#ifdef LIBUSERMODE_USE_INJECTION
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);

bool inject_copy_memory(userhook* plugin, drakvuf_t drakvuf,
drakvuf_trap_info_t* info,
event_response_t (*cb)(drakvuf_t, drakvuf_trap_info_t*),
uint64_t* stack_marker,
addr_t addr,
addr_t* stack_pointer);
#else

event_response_t system_service_handler_hook_cb(drakvuf_t drakvuf, drakvuf_trap_info_t* info);
#endif

#endif
44 changes: 32 additions & 12 deletions src/libusermode/userhook.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,18 @@
#include "utils.hpp"
#include "uh-private.hpp"

static bool g_injection_mode_enabled = false;

void userhooks_set_injection_mode(bool enable)
{
g_injection_mode_enabled = enable;
}

userhook& userhook::get_instance(drakvuf_t drakvuf)
{
static userhook instance(drakvuf, g_injection_mode_enabled);
return instance;
}

static void wrap_delete(drakvuf_trap_t* trap)
{
Expand Down Expand Up @@ -347,7 +359,12 @@ bool is_pagetable_loaded(vmi_instance_t vmi, const drakvuf_trap_info* info, addr
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;
event_response_t ret = internal_perform_hooking(drakvuf, info, plugin, dll_meta);

event_response_t ret;
if (plugin->injection_mode)
ret = internal_perform_hooking_injection(drakvuf, info, plugin, dll_meta);
else
ret = internal_perform_hooking_pf(drakvuf, info, plugin, dll_meta);

if (!was_hooked && dll_meta->v.is_hooked)
{
Expand Down Expand Up @@ -779,29 +796,26 @@ bool userhook::is_supported(drakvuf_t drakvuf)
}
} // Unlock vmi.

#ifndef LIBUSERMODE_USE_INJECTION
page_mode_t pm = drakvuf_get_page_mode(drakvuf);
if (pm != VMI_PM_IA32E)
if (!g_injection_mode_enabled && pm != VMI_PM_IA32E)
{
PRINT_DEBUG("[USERHOOK] Usermode hooking is not yet supported on this architecture/bitness.\n");
return false;
}
#endif

return true;
}

userhook::userhook(drakvuf_t drakvuf): pluginex(drakvuf, OUTPUT_DEFAULT), m_drakvuf(drakvuf)
userhook::userhook(drakvuf_t drakvuf, bool injection_mode_enabled): pluginex(drakvuf, OUTPUT_DEFAULT), injection_mode(injection_mode_enabled)
{
if (!is_supported(drakvuf))
throw -1;

if (!drakvuf_get_kernel_struct_members_array_rva(drakvuf, offset_names, __OFFSET_MAX, offsets.data()))
{
PRINT_DEBUG("[USERHOOK] Failed to get kernel struct member offsets\n");
#ifndef LIBUSERMODE_USE_INJECTION
throw -1;
#endif
if (!this->injection_mode)
throw -1;
}

this->copy_virt_mem_va =
Expand All @@ -810,12 +824,18 @@ userhook::userhook(drakvuf_t drakvuf): pluginex(drakvuf, OUTPUT_DEFAULT), m_drak
breakpoint_in_system_process_searcher bp;
if (!register_trap<call_result_t>(nullptr, protect_virtual_memory_hook_cb, bp.for_syscall_name("NtProtectVirtualMemory"), nullptr, UNLIMITED_TTL) ||
!register_trap<call_result_t>(nullptr, map_view_of_section_hook_cb, bp.for_syscall_name("NtMapViewOfSection"), nullptr, UNLIMITED_TTL) ||
#ifndef LIBUSERMODE_USE_INJECTION
!register_trap(nullptr, system_service_handler_hook_cb, bp.for_syscall_name("KiSystemServiceHandler"), nullptr, UNLIMITED_TTL) ||
#endif
!register_trap(nullptr, clean_process_address_space_hook_cb, bp.for_syscall_name("MmCleanProcessAddressSpace"), nullptr, UNLIMITED_TTL) ||
!register_trap(nullptr, copy_on_write_handler, bp.for_syscall_name("MiCopyOnWrite"), nullptr, UNLIMITED_TTL))
throw -1;

if (!this->injection_mode)
{
bool const is64bit = (drakvuf_get_page_mode(drakvuf) == VMI_PM_IA32E);
const char* exception_handler = is64bit ? "KiSystemServiceHandler" : "ExecuteHandler";

if (!register_trap(nullptr, system_service_handler_hook_cb, bp.for_syscall_name(exception_handler), nullptr, UNLIMITED_TTL))
throw -1;
}
}

userhook::~userhook()
Expand All @@ -828,7 +848,7 @@ userhook::~userhook()
{
if (target.state == HOOK_OK)
{
drakvuf_remove_trap(m_drakvuf, target.trap, wrap_delete);
drakvuf_remove_trap(this->drakvuf, target.trap, wrap_delete);
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/libusermode/userhook.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,4 +282,7 @@ void drakvuf_request_userhook_on_running_process(drakvuf_t drakvuf, addr_t targe


void drakvuf_remove_running_trap(drakvuf_t drakvuf, drakvuf_trap_t* trap, drakvuf_trap_free_t free_routine);

void userhooks_set_injection_mode(bool enable);

#endif
6 changes: 1 addition & 5 deletions src/libusermode/userhook_inject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,6 @@
* *
***************************************************************************/

#ifdef LIBUSERMODE_USE_INJECTION

#include <libinjector/libinjector.h>
#include "userhook.hpp"
#include "uh-private.hpp"
Expand Down Expand Up @@ -167,7 +165,7 @@ bool inject_copy_memory(userhook* plugin, drakvuf_t drakvuf,
return true;
}

event_response_t internal_perform_hooking(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)
{
auto proc_data = get_proc_data(drakvuf, info);

Expand Down Expand Up @@ -312,5 +310,3 @@ event_response_t internal_perform_hooking(drakvuf_t drakvuf, drakvuf_trap_info*
dll_meta->v.is_hooked = true;
return VMI_EVENT_RESPONSE_NONE;
}

#endif
11 changes: 2 additions & 9 deletions src/libusermode/userhook_pf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,6 @@
* *
***************************************************************************/

#ifndef LIBUSERMODE_USE_INJECTION

#include "userhook.hpp"
#include "uh-private.hpp"

Expand All @@ -119,12 +117,9 @@ event_response_t system_service_handler_hook_cb(drakvuf_t drakvuf, drakvuf_trap_
PRINT_DEBUG("[USERHOOK] Entered system service handler\n");

auto plugin = get_trap_plugin<userhook>(info);

proc_data_t proc_data = get_proc_data(drakvuf, info);

uint32_t thread_id = proc_data.tid;

if (!thread_id)
if (!proc_data.tid)
{
PRINT_DEBUG("[USERHOOK] Failed to get thread id in system service handler!\n");
return VMI_EVENT_RESPONSE_NONE;
Expand Down Expand Up @@ -156,7 +151,7 @@ event_response_t system_service_handler_hook_cb(drakvuf_t drakvuf, drakvuf_trap_
return VMI_EVENT_RESPONSE_SET_REGISTERS;
}

event_response_t internal_perform_hooking(drakvuf_t drakvuf, drakvuf_trap_info* info, userhook* plugin, dll_t* dll_meta)
event_response_t internal_perform_hooking_pf(drakvuf_t drakvuf, drakvuf_trap_info* info, userhook* plugin, dll_t* dll_meta)
{
proc_data_t proc_data = get_proc_data(drakvuf, info);

Expand Down Expand Up @@ -277,5 +272,3 @@ event_response_t internal_perform_hooking(drakvuf_t drakvuf, drakvuf_trap_info*
dll_meta->v.is_hooked = true;
return VMI_EVENT_RESPONSE_NONE;
}

#endif
Loading

0 comments on commit b482a45

Please sign in to comment.