Skip to content

Commit

Permalink
move object enumeration in libdrakvuf
Browse files Browse the repository at this point in the history
  • Loading branch information
archercreat committed Oct 31, 2023
1 parent c932689 commit f36efb5
Show file tree
Hide file tree
Showing 8 changed files with 198 additions and 3 deletions.
14 changes: 14 additions & 0 deletions src/libdrakvuf/libdrakvuf.h
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,12 @@ typedef struct _module_info
bool is_wow_process ; /* Is WoW64 process? */
} module_info_t ;

typedef struct _object_info
{
addr_t base_addr;
unicode_string_t* name;
} object_info_t;

bool drakvuf_enumerate_processes(drakvuf_t drakvuf,
void (*visitor_func)(drakvuf_t drakvuf, addr_t process, void* visitor_ctx),
void* visitor_ctx) NOEXCEPT;
Expand All @@ -666,6 +672,10 @@ bool drakvuf_enumerate_process_modules(drakvuf_t drakvuf,
bool (*visitor_func)(drakvuf_t drakvuf, const module_info_t* module_info, bool* need_free, bool* need_stop, void* visitor_ctx),
void* visitor_ctx) NOEXCEPT;

bool drakvuf_enumerate_object_directory(drakvuf_t drakvuf,
void (*visitor_func)(drakvuf_t drakvuf, const object_info_t* object_info, void* visitor_ctx),
void* visitor_ctx) NOEXCEPT;

bool drakvuf_is_crashreporter(drakvuf_t drakvuf,
drakvuf_trap_info_t* info,
vmi_pid_t* pid) NOEXCEPT;
Expand Down Expand Up @@ -702,6 +712,10 @@ unicode_string_t* drakvuf_read_unicode32(drakvuf_t drakvuf, drakvuf_trap_info_t*

unicode_string_t* drakvuf_read_unicode32_va(drakvuf_t drakvuf, addr_t vaddr, vmi_pid_t pid) NOEXCEPT;

unicode_string_t* drakvuf_get_object_type_name(drakvuf_t drakvuf, addr_t object) NOEXCEPT;

unicode_string_t* drakvuf_get_object_name(drakvuf_t drakvuf, addr_t object) NOEXCEPT;

bool drakvuf_get_module_base_addr( drakvuf_t drakvuf,
addr_t module_list_head,
const char* module_name,
Expand Down
42 changes: 42 additions & 0 deletions src/libdrakvuf/os.c
Original file line number Diff line number Diff line change
Expand Up @@ -915,6 +915,20 @@ bool drakvuf_enumerate_process_modules(drakvuf_t drakvuf, addr_t eprocess, bool
return ret;
}

bool drakvuf_enumerate_object_directory(drakvuf_t drakvuf, void (*visitor_func)(drakvuf_t drakvuf, const object_info_t* object_info, void* visitor_ctx), void* visitor_ctx)
{
bool ret = false;

if (drakvuf->osi.enumerate_object_directory)
{
drakvuf_lock_and_get_vmi(drakvuf);
ret = drakvuf->osi.enumerate_object_directory(drakvuf, visitor_func, visitor_ctx);
drakvuf_release_vmi(drakvuf);
}

return ret;
}

bool drakvuf_is_crashreporter(drakvuf_t drakvuf, drakvuf_trap_info_t* info, vmi_pid_t* pid)
{
bool ret = false;
Expand Down Expand Up @@ -1191,3 +1205,31 @@ const kernel_version_t* drakvuf_get_kernel_version(drakvuf_t drakvuf, drakvuf_tr

return ret;
}

unicode_string_t* drakvuf_get_object_name(drakvuf_t drakvuf, addr_t object)
{
unicode_string_t* ret = NULL;

if (drakvuf->osi.get_object_name)
{
drakvuf_lock_and_get_vmi(drakvuf);
ret = drakvuf->osi.get_object_name(drakvuf, object);
drakvuf_release_vmi(drakvuf);
}

return ret;
}

unicode_string_t* drakvuf_get_object_type_name(drakvuf_t drakvuf, addr_t object)
{
unicode_string_t* ret = NULL;

if (drakvuf->osi.get_object_type_name)
{
drakvuf_lock_and_get_vmi(drakvuf);
ret = drakvuf->osi.get_object_type_name(drakvuf, object);
drakvuf_release_vmi(drakvuf);
}

return ret;
}
9 changes: 9 additions & 0 deletions src/libdrakvuf/os.h
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,9 @@ typedef struct os_interface
bool (*enumerate_process_modules)
(drakvuf_t drakvuf, addr_t eprocess, bool (*visitor_func)(drakvuf_t drakvuf, const module_info_t* module_info, bool* need_free, bool* need_stop, void* visitor_ctx), void* visitor_ctx);

bool (*enumerate_object_directory)
(drakvuf_t drakvuf, void (*visitor_func)(drakvuf_t drakvuf, const object_info_t* object_info, void* visitor_ctx), void* visitor_ctx);

bool (*is_crashreporter)
(drakvuf_t drakvuf, drakvuf_trap_info_t* info, vmi_pid_t* pid);

Expand Down Expand Up @@ -314,6 +317,12 @@ typedef struct os_interface
bool (*get_kernel_symbol_va)
(drakvuf_t drakvuf, const char* function, addr_t* va);

unicode_string_t* (*get_object_name)
(drakvuf_t drakvuf, addr_t object);

unicode_string_t* (*get_object_type_name)
(drakvuf_t drakvuf, addr_t object);

} os_interface_t;

bool set_os_windows(drakvuf_t drakvuf);
Expand Down
3 changes: 3 additions & 0 deletions src/libdrakvuf/private.h
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,9 @@ struct drakvuf
xen_pfn_t max_gpfn;
addr_t kernbase;
addr_t kpgd;
uint8_t ob_header_cookie;
addr_t ob_infomask2off;
addr_t ob_type_table;

size_t address_width;

Expand Down
6 changes: 6 additions & 0 deletions src/libdrakvuf/win-offsets-map.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ static const char* win_offset_names[__WIN_OFFSETS_MAX][2] =
[KPCR_PRCBDATA] = {"_KPCR", "PrcbData" },
[KPCR_IRQL] = { "_KPCR", "Irql" },
[KPRCB_CURRENTTHREAD] = { "_KPRCB", "CurrentThread" },
[KPRCB_RSPBASE] = { "_KPRCB", "RspBase" },
[KTHREAD_APCSTATE] = {"_KTHREAD", "ApcState" },
[KTHREAD_APCSTATEINDEX] = {"_KTHREAD", "ApcStateIndex" },
[KTHREAD_PROCESS] = {"_KTHREAD", "Process" },
Expand All @@ -195,6 +196,11 @@ static const char* win_offset_names[__WIN_OFFSETS_MAX][2] =
[CLIENT_ID_UNIQUETHREAD] = {"_CLIENT_ID", "UniqueThread" },
[OBJECT_HEADER_TYPEINDEX] = { "_OBJECT_HEADER", "TypeIndex" },
[OBJECT_HEADER_BODY] = { "_OBJECT_HEADER", "Body" },
[OBJECT_HEADER_INFOMASK] = { "_OBJECT_HEADER", "InfoMask" },
[OBJECT_HEADER_NAME_INFO_NAME] = { "_OBJECT_HEADER_NAME_INFO", "Name" },
[OBJECT_DIRECTORY_ENTRY_CHAINLINK] = { "_OBJECT_DIRECTORY_ENTRY", "ChainLink" },
[OBJECT_DIRECTORY_ENTRY_OBJECT] = { "_OBJECT_DIRECTORY_ENTRY", "Object" },
[OBJECT_TYPE_NAME] = { "_OBJECT_TYPE", "Name" },
[POOL_HEADER_BLOCKSIZE] = {"_POOL_HEADER", "BlockSize" },
[POOL_HEADER_POOLTYPE] = {"_POOL_HEADER", "PoolType" },
[POOL_HEADER_POOLTAG] = {"_POOL_HEADER", "PoolTag" },
Expand Down
7 changes: 6 additions & 1 deletion src/libdrakvuf/win-offsets.h
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,11 @@ enum win_offsets

OBJECT_HEADER_TYPEINDEX,
OBJECT_HEADER_BODY,

OBJECT_HEADER_INFOMASK,
OBJECT_HEADER_NAME_INFO_NAME,
OBJECT_DIRECTORY_ENTRY_CHAINLINK,
OBJECT_DIRECTORY_ENTRY_OBJECT,
OBJECT_TYPE_NAME,
POOL_HEADER_BLOCKSIZE,
POOL_HEADER_POOLTYPE,
POOL_HEADER_POOLTAG,
Expand Down Expand Up @@ -259,6 +263,7 @@ enum win_sizes
{
EPROCESS,
HANDLE_TABLE_ENTRY,
OBJECT_HEADER,

__WIN_SIZES_MAX
};
Expand Down
116 changes: 114 additions & 2 deletions src/libdrakvuf/win.c
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,107 @@ static bool find_kernbase(drakvuf_t drakvuf)
return 1;
}

unicode_string_t* win_get_object_name(drakvuf_t drakvuf, addr_t object)
{
// Object header is always present before actual object.
//
size_t ptrsize = drakvuf_get_address_width(drakvuf);
addr_t header = object - drakvuf->sizes[OBJECT_HEADER] + ptrsize;

uint8_t infomask = 0, name_info_off = 0;

if (VMI_SUCCESS != vmi_read_8_va(drakvuf->vmi, header + drakvuf->offsets[OBJECT_HEADER_INFOMASK], 0, &infomask))
return NULL;
// Get object name. Some objects are anonymous. See ObQueryNameInfo for more info.
//
if (infomask & 2)
{
if (VMI_SUCCESS != vmi_read_8_va(drakvuf->vmi, drakvuf->ob_infomask2off + (infomask & 3), 0, &name_info_off))
return NULL;
return drakvuf_read_unicode_va(drakvuf, header - name_info_off + drakvuf->offsets[OBJECT_HEADER_NAME_INFO_NAME], 0);
}
return NULL;
}

unicode_string_t* win_get_object_type_name(drakvuf_t drakvuf, addr_t object)
{
// Object header is always present before actual object.
//
size_t ptrsize = drakvuf_get_address_width(drakvuf);
addr_t header = object - drakvuf->sizes[OBJECT_HEADER] + ptrsize;

uint8_t index = 0;
if (VMI_SUCCESS != vmi_read_8_va(drakvuf->vmi, header + drakvuf->offsets[OBJECT_HEADER_TYPEINDEX], 0, &index))
{
return NULL;
}
// https://medium.com/@ashabdalhalim/a-light-on-windows-10s-object-header-typeindex-value-e8f907e7073a
// Due to security mitigations type_index is no longer equals to index in ObTypeIndexTable array on win 10
// but calculated as following:
if (vmi_get_winver(drakvuf->vmi) == VMI_OS_WINDOWS_10)
{
index = index ^ ((header >> 8) & 0xff) ^ drakvuf->ob_header_cookie;
}

addr_t type = 0;
if (VMI_SUCCESS != vmi_read_addr_va(drakvuf->vmi, drakvuf->ob_type_table + index * ptrsize, 0, &type))
{
return NULL;
}
return drakvuf_read_unicode_va(drakvuf, type + drakvuf->offsets[OBJECT_TYPE_NAME], 0);
}

static bool enumerate_directory(drakvuf_t drakvuf, addr_t directory, void (*visitor_func)(drakvuf_t drakvuf, const object_info_t* object_info, void* visitor_ctx), void* visitor_ctx)
{
// There is only 37 _OBJECT_DIRECTORY_ENTRY entries in object directory:
// 0: kd> dt nt!_OBJECT_DIRECTORY
// +0x000 HashBuckets : [37] Ptr64 _OBJECT_DIRECTORY_ENTRY
// +0x128 Lock : _EX_PUSH_LOCK
// ...
for (int i = 0; i < 37; i++)
{
addr_t bucket = 0;
if (VMI_SUCCESS != vmi_read_addr_va(drakvuf->vmi, directory + drakvuf_get_address_width(drakvuf) * i, 0, &bucket) || !bucket)
continue;

while (true)
{
addr_t object = 0;
if (VMI_SUCCESS != vmi_read_addr_va(drakvuf->vmi, bucket + drakvuf->offsets[OBJECT_DIRECTORY_ENTRY_OBJECT], 0, &object) || !object)
break;

unicode_string_t* name = win_get_object_type_name(drakvuf, object);
if (!name)
{
return false;
}

object_info_t object_info = { .base_addr = object, .name = name };
visitor_func(drakvuf, &object_info, visitor_ctx);

if (!strcmp((const char*)name->contents, "Directory"))
{
enumerate_directory(drakvuf, object, visitor_func, visitor_ctx);
}
vmi_free_unicode_str(name);

if (VMI_SUCCESS != vmi_read_addr_va(drakvuf->vmi, bucket + drakvuf->offsets[OBJECT_DIRECTORY_ENTRY_CHAINLINK], 0, &bucket) || !bucket)
break;
}
}
return true;
}

bool win_enumerate_object_directory(drakvuf_t drakvuf, void (*visitor_func)(drakvuf_t drakvuf, const object_info_t* object_info, void* visitor_ctx), void* visitor_ctx)
{
addr_t root_directory_object = 0;
if (VMI_SUCCESS != vmi_read_addr_ksym(drakvuf->vmi, "ObpRootDirectoryObject", &root_directory_object))
{
return false;
}
return enumerate_directory(drakvuf, root_directory_object, visitor_func, visitor_ctx);
}

bool win_is_wow64(drakvuf_t drakvuf, drakvuf_trap_info_t* info)
{
// check if we're in kernel mode
Expand Down Expand Up @@ -554,11 +655,19 @@ bool set_os_windows(drakvuf_t drakvuf)
PRINT_DEBUG("Loaded WoW64 offsets...\n");
}

if ( VMI_FAILURE == vmi_get_struct_size_from_json(drakvuf->vmi, vmi_get_kernel_json(drakvuf->vmi), "_HANDLE_TABLE_ENTRY", &drakvuf->sizes[HANDLE_TABLE_ENTRY]) )
if (VMI_FAILURE == vmi_get_struct_size_from_json(drakvuf->vmi, vmi_get_kernel_json(drakvuf->vmi), "_HANDLE_TABLE_ENTRY", &drakvuf->sizes[HANDLE_TABLE_ENTRY] ) ||
VMI_FAILURE == vmi_get_struct_size_from_json(drakvuf->vmi, vmi_get_kernel_json(drakvuf->vmi), "_OBJECT_HEADER", &drakvuf->sizes[OBJECT_HEADER]))
{
return 0;
}

if (VMI_FAILURE == vmi_translate_ksym2v(drakvuf->vmi, "ObpInfoMaskToOffset", &drakvuf->ob_infomask2off) ||
VMI_FAILURE == vmi_translate_ksym2v(drakvuf->vmi, "ObTypeIndexTable", &drakvuf->ob_type_table))
{
return 0;
}
if ( VMI_FAILURE == vmi_get_struct_size_from_json(drakvuf->vmi, vmi_get_kernel_json(drakvuf->vmi), "_EPROCESS", &drakvuf->sizes[EPROCESS]) )

if (vmi_get_winver(drakvuf->vmi) == VMI_OS_WINDOWS_10 && VMI_FAILURE == vmi_read_8_ksym(drakvuf->vmi, "ObHeaderCookie", &drakvuf->ob_header_cookie))
{
return 0;
}
Expand Down Expand Up @@ -606,6 +715,7 @@ bool set_os_windows(drakvuf_t drakvuf)
drakvuf->osi.enumerate_processes_with_module = win_enumerate_processes_with_module;
drakvuf->osi.enumerate_drivers = win_enumerate_drivers;
drakvuf->osi.enumerate_process_modules = win_enumerate_process_modules;
drakvuf->osi.enumerate_object_directory = win_enumerate_object_directory;
drakvuf->osi.is_crashreporter = win_is_crashreporter;
drakvuf->osi.find_mmvad = win_find_mmvad;
drakvuf->osi.traverse_mmvad = win_traverse_mmvad;
Expand All @@ -625,6 +735,8 @@ bool set_os_windows(drakvuf_t drakvuf)
drakvuf->osi.get_rspbase = win_get_rspbase;
drakvuf->osi.get_kernel_symbol_rva = win_get_kernel_symbol_rva;
drakvuf->osi.get_kernel_symbol_va = win_get_kernel_symbol_va;
drakvuf->osi.get_object_type_name = win_get_object_type_name;
drakvuf->osi.get_object_name = win_get_object_name;

return true;
}
4 changes: 4 additions & 0 deletions src/libdrakvuf/win.h
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ bool win_find_eprocess(drakvuf_t drakvuf, vmi_pid_t find_pid, const char* find_p
bool win_enumerate_processes(drakvuf_t drakvuf, void (*visitor_func)(drakvuf_t drakvuf, addr_t eprocess, void* visitor_ctx), void* visitor_ctx);
bool win_enumerate_processes_with_module(drakvuf_t drakvuf, const char* module_name, bool (*visitor_func)(drakvuf_t drakvuf, const module_info_t* module_info, void* visitor_ctx), void* visitor_ctx);
bool win_enumerate_drivers(drakvuf_t drakvuf, bool (*visitor_func)(drakvuf_t drakvuf, const module_info_t* module_info, bool* need_free, bool* need_stop, void* visitor_ctx), void* visitor_ctx);
bool win_enumerate_object_directory(drakvuf_t drakvuf, void (*visitor_func)(drakvuf_t drakvuf, const object_info_t* object_info, void* visitor_ctx), void* visitor_ctx);

bool win_is_crashreporter(drakvuf_t drakvuf, drakvuf_trap_info_t* info, vmi_pid_t* pid);

Expand Down Expand Up @@ -221,4 +222,7 @@ bool win_get_kernel_symbol_rva(drakvuf_t drakvuf, const char* function, addr_t*

bool win_get_kernel_symbol_va(drakvuf_t drakvuf, const char* function, addr_t* va);

unicode_string_t* win_get_object_name(drakvuf_t drakvuf, addr_t object);
unicode_string_t* win_get_object_type_name(drakvuf_t drakvuf, addr_t object);

#endif

0 comments on commit f36efb5

Please sign in to comment.