Skip to content

Commit

Permalink
add Bitness and FromParentModule field (#1750)
Browse files Browse the repository at this point in the history
  • Loading branch information
archercreat authored Nov 29, 2023
1 parent 7a17abe commit 30fa531
Show file tree
Hide file tree
Showing 12 changed files with 139 additions and 54 deletions.
1 change: 1 addition & 0 deletions src/libdrakvuf/drakvuf.c
Original file line number Diff line number Diff line change
Expand Up @@ -774,6 +774,7 @@ bool drakvuf_get_process_data(drakvuf_t drakvuf, addr_t process_base, proc_data_
proc_data->base_addr = proc_data_priv.base_addr;
proc_data->userid = proc_data_priv.userid;
proc_data->tid = proc_data_priv.tid;
proc_data->bitness = proc_data_priv.bitness;
drakvuf_release_vmi(drakvuf);
return success;
}
Expand Down
10 changes: 9 additions & 1 deletion src/libdrakvuf/libdrakvuf.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,14 +198,22 @@ typedef enum memaccess_type
POST
} memaccess_type_t;

typedef enum proc_type
{
PROC_TYPE_UNKNOWN = 0,
PROC_TYPE_32 = 32,
PROC_TYPE_64 = 64,
} proc_type_t;

typedef struct process_data
{
const char* name; /* Process name */
vmi_pid_t pid ; /* Process pid */
vmi_pid_t ppid ; /* Process parent pid */
addr_t base_addr ; /* Process base address */
int64_t userid ; /* Process SessionID/UID */
uint32_t tid ; /* Thread Id for Linux & Windows*/
uint32_t tid ; /* Thread Id for Linux & Windows*/
proc_type_t bitness;/* Process bitness 32/64 */
} proc_data_t ;

typedef struct drakvuf* drakvuf_t;
Expand Down
3 changes: 2 additions & 1 deletion src/libdrakvuf/private.h
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,8 @@ typedef struct process_data_priv
vmi_pid_t ppid ; /* Process parent pid */
addr_t base_addr ; /* Process base address */
int64_t userid ; /* Process SessionID/UID */
uint32_t tid; /* Thread id for Linux*/
uint32_t tid; /* Thread id for Linux*/
proc_type_t bitness;/* Process bitness 32/64 */
} proc_data_priv_t ;

struct memcb_pass
Expand Down
7 changes: 7 additions & 0 deletions src/libdrakvuf/win-processes.c
Original file line number Diff line number Diff line change
Expand Up @@ -1413,7 +1413,14 @@ bool win_get_process_data( drakvuf_t drakvuf, addr_t base_addr, proc_data_priv_t
proc_data->name = win_get_process_name( drakvuf, base_addr, true );

if ( proc_data->name )
{
ACCESS_CONTEXT(ctx,
.translate_mechanism = VMI_TM_PROCESS_PID,
.pid = 0,
);
proc_data->bitness = win_get_wow_peb(drakvuf, &ctx, base_addr) ? PROC_TYPE_32 : PROC_TYPE_64;
return true;
}
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/plugins/output_format/csvfmt.h
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,8 @@ inline void print_running_process(const char* plugin_name, drakvuf_t drakvuf, gi
keyval("Time", TimeVal{UNPACK_TIMEVAL(timestamp)}),
keyval("PID", fmt::Nval(proc_data.pid)),
keyval("PPID", fmt::Nval(proc_data.ppid)),
keyval("RunningProcess", fmt::Qstr(proc_data.name))
keyval("RunningProcess", fmt::Qstr(proc_data.name)),
keyval("Bitness", fmt::Nval(static_cast<int>(proc_data.bitness)))
);
}

Expand Down
3 changes: 2 additions & 1 deletion src/plugins/output_format/jsonfmt.h
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,8 @@ inline void print_running_process(const char* plugin_name, drakvuf_t drakvuf, gi
keyval("TimeStamp", TimeVal{UNPACK_TIMEVAL(timestamp)}),
keyval("PID", fmt::Nval(proc_data.pid)),
keyval("PPID", fmt::Nval(proc_data.ppid)),
keyval("RunningProcess", fmt::Qstr(proc_data.name))
keyval("RunningProcess", fmt::Qstr(proc_data.name)),
keyval("Bitness", fmt::Nval(static_cast<int>(proc_data.bitness)))
);
}

Expand Down
3 changes: 2 additions & 1 deletion src/plugins/output_format/kvfmt.h
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,8 @@ inline void print_running_process(const char* plugin_name, drakvuf_t drakvuf, gi
keyval("Time", TimeVal{UNPACK_TIMEVAL(timestamp)}),
keyval("PID", fmt::Nval(proc_data.pid)),
keyval("PPID", fmt::Nval(proc_data.ppid)),
keyval("RunningProcess", fmt::Qstr(proc_data.name))
keyval("RunningProcess", fmt::Qstr(proc_data.name)),
keyval("Bitness", fmt::Nval(static_cast<int>(proc_data.bitness)))
);
}

Expand Down
23 changes: 23 additions & 0 deletions src/plugins/procmon/private.h
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,29 @@ static const char* linux_offset_names[__LINUX_OFFSET_MAX][2] =
[_PATH_DENTRY] = {"path", "dentry"},
};

enum
{
USER_PROCESS_PARAMS_COMMANDLINE,
USER_PROCESS_PARAMS_IMAGEPATHNAME,
USER_PROCESS_PARAMS_DLLPATH,
USER_PROCESS_PARAMS_CURRENTDIRECTORY,
CURDIR_HANDLE,
CURDIR_DOSPATH,
CLIENT_ID_UNIQUE_THREAD,
__WINDOWS_OFFSET_MAX
};

static const char* windows_offset_names[__WINDOWS_OFFSET_MAX][2] =
{
[USER_PROCESS_PARAMS_COMMANDLINE] = { "_RTL_USER_PROCESS_PARAMETERS", "CommandLine" },
[USER_PROCESS_PARAMS_IMAGEPATHNAME] = { "_RTL_USER_PROCESS_PARAMETERS", "ImagePathName" },
[USER_PROCESS_PARAMS_DLLPATH] = { "_RTL_USER_PROCESS_PARAMETERS", "DllPath" },
[USER_PROCESS_PARAMS_CURRENTDIRECTORY] = { "_RTL_USER_PROCESS_PARAMETERS", "CurrentDirectory"},
[CURDIR_HANDLE] = { "_CURDIR", "Handle" },
[CURDIR_DOSPATH] = { "_CURDIR", "DosPath" },
[CLIENT_ID_UNIQUE_THREAD] = { "_CLIENT_ID", "UniqueThread" },
};

} // procmon_ns

#define MAX_ARG_STRLEN (4096 * 32)
Expand Down
66 changes: 33 additions & 33 deletions src/plugins/procmon/win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@
#include "winnt.h"
#include "privileges.h"

using namespace procmon_ns;

namespace
{

Expand Down Expand Up @@ -174,11 +176,11 @@ static void print_process_creation_result(
addr_t new_thread_handle, uint32_t new_tid,
addr_t user_process_parameters_addr)
{
addr_t cmdline_addr = user_process_parameters_addr + f->command_line;
addr_t imagepath_addr = user_process_parameters_addr + f->image_path_name;
addr_t dllpath_addr = user_process_parameters_addr + f->dll_path;
addr_t curdir_handle_addr = user_process_parameters_addr + f->current_directory_handle;
addr_t curdir_dospath_addr = user_process_parameters_addr + f->current_directory_dospath;
addr_t cmdline_addr = user_process_parameters_addr + f->offsets[USER_PROCESS_PARAMS_COMMANDLINE];
addr_t imagepath_addr = user_process_parameters_addr + f->offsets[USER_PROCESS_PARAMS_IMAGEPATHNAME];
addr_t dllpath_addr = user_process_parameters_addr + f->offsets[USER_PROCESS_PARAMS_DLLPATH];
addr_t curdir_handle_addr = user_process_parameters_addr + f->offsets[USER_PROCESS_PARAMS_CURRENTDIRECTORY] + f->offsets[CURDIR_HANDLE];
addr_t curdir_dospath_addr = user_process_parameters_addr + f->offsets[USER_PROCESS_PARAMS_CURRENTDIRECTORY] + f->offsets[CURDIR_DOSPATH];

unicode_string_t* cmdline_us = drakvuf_read_unicode(drakvuf, info, cmdline_addr);
unicode_string_t* imagepath_us = drakvuf_read_unicode(drakvuf, info, imagepath_addr);
Expand Down Expand Up @@ -215,6 +217,13 @@ static void print_process_creation_result(
char const* imagepath = imagepath_us ? reinterpret_cast<char const*>(imagepath_us->contents) : "";
char const* dllpath = dllpath_us ? reinterpret_cast<char const*>(dllpath_us->contents) : "";

addr_t process, dtb;
proc_data_t proc_data{};
if (drakvuf_get_process_by_pid(drakvuf, new_pid, &process, &dtb))
{
drakvuf_get_process_data(drakvuf, process, &proc_data);
}

fmt::print(f->m_output_format, "procmon", drakvuf, info,
keyval("Status", fmt::Xval(status)),
keyval("NewProcessHandle", fmt::Xval(new_process_handle)),
Expand All @@ -224,7 +233,8 @@ static void print_process_creation_result(
keyval("CommandLine", fmt::Qstr(cmdline)),
keyval("ImagePathName", fmt::Qstr(imagepath)),
keyval("DllPath", fmt::Qstr(dllpath)),
keyval("CWD", fmt::Qstr(curdir))
keyval("CWD", fmt::Qstr(curdir)),
keyval("Bitness", fmt::Nval(static_cast<int>(proc_data.bitness)))
);

g_free(cmdline);
Expand All @@ -237,6 +247,9 @@ static void print_process_creation_result(

if (dllpath_us)
vmi_free_unicode_str(dllpath_us);

if (proc_data.name)
g_free((gpointer)proc_data.name);
}

static event_response_t process_creation_return_hook(drakvuf_t drakvuf, drakvuf_trap_info_t* info)
Expand Down Expand Up @@ -311,6 +324,13 @@ static event_response_t process_create_ex_return_hook(drakvuf_t drakvuf, drakvuf
if (!drakvuf_get_pid_from_handle(drakvuf, info, process_handle, &new_pid))
new_pid = 0;

addr_t process, dtb;
proc_data_t proc_data{};
if (drakvuf_get_process_by_pid(drakvuf, new_pid, &process, &dtb))
{
drakvuf_get_process_data(drakvuf, process, &proc_data);
}

fmt::print(plugin->m_output_format, "procmon", drakvuf, info,
keyval("Status", fmt::Xval(status)),
keyval("ProcessHandle", fmt::Xval(process_handle)),
Expand All @@ -322,9 +342,13 @@ static event_response_t process_create_ex_return_hook(drakvuf_t drakvuf, drakvuf
keyval("DebugPort", fmt::Xval(params->debug_port)),
keyval("ExceptionPort", fmt::Xval(params->exception_port)),
keyval("JobMemberLevel", fmt::Nval(params->job_member_level)),
keyval("NewPid", fmt::Nval(new_pid))
keyval("NewPid", fmt::Nval(new_pid)),
keyval("Bitness", fmt::Nval(static_cast<int>(proc_data.bitness)))
);

if (proc_data.name)
g_free((gpointer)proc_data.name);

plugin->destroy_trap(info->trap);
return VMI_EVENT_RESPONSE_NONE;
}
Expand Down Expand Up @@ -616,7 +640,7 @@ static event_response_t open_thread_hook_cb(drakvuf_t drakvuf, drakvuf_trap_info
if (VMI_SUCCESS != vmi_read_32(vmi, &ctx, (uint32_t*)&params->client_id))
PRINT_DEBUG("[PROCMON] Failed to read CLIENT_ID\n");

ctx.addr += plugin->cid_tid;
ctx.addr += plugin->offsets[CLIENT_ID_UNIQUE_THREAD];
if (VMI_SUCCESS != vmi_read_32(vmi, &ctx, (uint32_t*)&params->unique_thread))
PRINT_DEBUG("[PROCMON] Failed to read CLIENT_ID.UniqueThread\n");

Expand Down Expand Up @@ -722,33 +746,9 @@ win_procmon::win_procmon(drakvuf_t drakvuf, output_format_t output) : pluginex(d
struct process_visitor_ctx ctx = { .format = output };
drakvuf_enumerate_processes(drakvuf, process_visitor, &ctx);

if (!drakvuf_get_kernel_struct_member_rva(drakvuf, "_RTL_USER_PROCESS_PARAMETERS", "CommandLine", &this->command_line))
throw -1;

if (!drakvuf_get_kernel_struct_member_rva(drakvuf, "_RTL_USER_PROCESS_PARAMETERS", "ImagePathName", &this->image_path_name))
if (!drakvuf_get_kernel_struct_members_array_rva(drakvuf, windows_offset_names, this->offsets.size(), this->offsets.data()))
throw -1;

if (!drakvuf_get_kernel_struct_member_rva(drakvuf, "_RTL_USER_PROCESS_PARAMETERS", "DllPath", &this->dll_path))
throw -1;

addr_t current_directory_offset;
if (!drakvuf_get_kernel_struct_member_rva(drakvuf, "_RTL_USER_PROCESS_PARAMETERS", "CurrentDirectory", &current_directory_offset))
throw -1;

addr_t curdir_handle_offset;
if (!drakvuf_get_kernel_struct_member_rva(drakvuf, "_CURDIR", "Handle", &curdir_handle_offset))
throw -1;

addr_t curdir_dospath_offset;
if (!drakvuf_get_kernel_struct_member_rva(drakvuf, "_CURDIR", "DosPath", &curdir_dospath_offset))
throw -1;

if (!drakvuf_get_kernel_struct_member_rva(drakvuf, "_CLIENT_ID", "UniqueThread", &this->cid_tid))
throw -1;

this->current_directory_handle = current_directory_offset + curdir_handle_offset;
this->current_directory_dospath = current_directory_offset + curdir_dospath_offset;

breakpoint_in_system_process_searcher bp;
if (!register_trap(nullptr, create_user_process_hook_cb, bp.for_syscall_name("NtCreateUserProcess")) ||
!register_trap(nullptr, create_process_ex_hook_cb, bp.for_syscall_name("NtCreateProcessEx")) ||
Expand Down
8 changes: 2 additions & 6 deletions src/plugins/procmon/win.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,16 +107,12 @@

#include <glib.h>
#include "plugins/plugins_ex.h"
#include "private.h"

class win_procmon : public pluginex
{
public:
addr_t command_line;
addr_t image_path_name;
addr_t dll_path;
addr_t current_directory_handle;
addr_t current_directory_dospath;
addr_t cid_tid;
std::array<size_t, procmon_ns::__WINDOWS_OFFSET_MAX> offsets;

win_procmon(drakvuf_t drakvuf, output_format_t output);
win_procmon(const win_procmon&) = delete;
Expand Down
64 changes: 55 additions & 9 deletions src/plugins/syscalls/win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,17 @@

using namespace syscalls_ns;

// This is the list of system libraries that use syscalls.
//
static std::string whitelisted_libraries[] =
{
"windows\\system32\\gdi32.dll",
"windows\\system32\\imm32.dll",
"windows\\system32\\ntdll.dll",
"windows\\system32\\user32.dll",
"windows\\system32\\wow64win.dll"
};

static bool enum_modules_cb(drakvuf_t dravkuf, const module_info_t* module_info, bool* need_free, bool* need_stop, void* ctx)
{
auto plugin = static_cast<win_syscalls*>(ctx);
Expand Down Expand Up @@ -300,14 +311,27 @@ static addr_t get_syscall_retaddr(drakvuf_t drakvuf, drakvuf_trap_info_t* info,
return user_ret_addr;
}

static std::optional<std::string> resolve_parent_module(drakvuf_t drakvuf, drakvuf_trap_info_t* info, win_syscalls* s)
{
vmi_lock_guard vmi(drakvuf);
addr_t rsp, top;
if (VMI_SUCCESS != vmi_read_addr_va(vmi, drakvuf_get_rspbase(drakvuf, info) - 0x10, 0, &rsp) ||
VMI_SUCCESS != vmi_read_addr_va(vmi, rsp, info->attached_proc_data.pid, &top))
{
PRINT_DEBUG("[SYSCALLS] Failed to resolve top of the stack\n");
return {};
}
return resolve_module(drakvuf, top, info->attached_proc_data.base_addr, info->attached_proc_data.pid, s);
}

/// Get module that called Nt (syscall) function and previous mode.
///
static std::pair<privilege_mode_t, std::optional<std::string>>
static std::tuple<privilege_mode_t, std::optional<std::string>, std::optional<std::string>>
get_syscall_retinfo(drakvuf_t drakvuf, drakvuf_trap_info_t* info, win_syscalls* s)
{
if (s->is32bit)
{
return { MAXIMUM_MODE, {} };
return { MAXIMUM_MODE, {}, {} };
}

privilege_mode_t mode = MAXIMUM_MODE;
Expand All @@ -319,13 +343,30 @@ static std::pair<privilege_mode_t, std::optional<std::string>>

if (mode == KERNEL_MODE)
{
return { mode, resolve_module(drakvuf, ret, info->proc_data.base_addr, 4, s) };
return { mode, resolve_module(drakvuf, ret, info->proc_data.base_addr, 4, s), {} };
}
else if (mode == USER_MODE)
{
return { mode, resolve_module(drakvuf, ret, info->attached_proc_data.base_addr, info->attached_proc_data.pid, s) };
auto module = resolve_module(drakvuf, ret, info->attached_proc_data.base_addr, info->attached_proc_data.pid, s);
// Check if module is a dll.
//
if (module.has_value())
{
auto resolved_lib = module.value();
for (auto& c : resolved_lib)
c = std::tolower(c);
for (const auto& lib : whitelisted_libraries)
{
if (resolved_lib.length() >= lib.length() &&
resolved_lib.compare(resolved_lib.length() - lib.length(), lib.length(), lib) == 0)
{
return { mode, std::move(resolved_lib), resolve_parent_module(drakvuf, info, s) };
}
}
}
return { mode, std::move(module), {} };
}
return { MAXIMUM_MODE, {} };
return { MAXIMUM_MODE, {}, {} };
}

static event_response_t syscall_cb(drakvuf_t drakvuf, drakvuf_trap_info_t* info)
Expand All @@ -336,8 +377,8 @@ static event_response_t syscall_cb(drakvuf_t drakvuf, drakvuf_trap_info_t* info)
auto num_args = sc ? sc->num_args : 0;

auto args = extract_args(drakvuf, info, s->register_size, num_args);
auto [mode, module] = get_syscall_retinfo(drakvuf, info, s);
s->print_syscall(drakvuf, info, w->num, w->type, sc, std::move(args), mode, std::move(module));
auto [mode, module, parent_module] = get_syscall_retinfo(drakvuf, info, s);
s->print_syscall(drakvuf, info, w->num, w->type, sc, std::move(args), mode, std::move(module), std::move(parent_module));

if (s->disable_sysret || s->is_stopping())
return VMI_EVENT_RESPONSE_NONE;
Expand Down Expand Up @@ -743,7 +784,8 @@ void win_syscalls::print_syscall(
drakvuf_t drakvuf, drakvuf_trap_info_t* info,
int nr, const char* module, const syscall_t* sc,
std::vector<uint64_t> args, privilege_mode_t mode,
std::optional<std::string> from_dll
std::optional<std::string> from_dll,
std::optional<std::string> from_parent_dll
)
{
if (sc)
Expand All @@ -766,12 +808,15 @@ void win_syscalls::print_syscall(
}
}

std::optional<fmt::Estr<std::string>> from_dll_opt;
std::optional<fmt::Estr<std::string>> from_dll_opt, from_parent_dll_opt;
std::optional<fmt::Rstr<const char*>> priv_mode_opt;

if (from_dll.has_value())
from_dll_opt = fmt::Estr(std::move(*from_dll));

if (from_parent_dll.has_value())
from_dll_opt = fmt::Estr(std::move(*from_parent_dll));

if (mode != MAXIMUM_MODE)
priv_mode_opt = fmt::Rstr(mode == USER_MODE ? "User" : "Kernel");

Expand All @@ -783,6 +828,7 @@ void win_syscalls::print_syscall(
keyval("NArgs", fmt::Nval(args.size())),
keyval("PreviousMode", priv_mode_opt),
keyval("FromModule", from_dll_opt),
keyval("FromParentModule", from_parent_dll_opt),
std::move(fmt_args)
);
}
Expand Down
Loading

0 comments on commit 30fa531

Please sign in to comment.