Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add CpuContext and ThreadId to MemoryAccessMonitor callbacks #801

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions bindings/gumjs/gumquickmemory.c
Original file line number Diff line number Diff line change
Expand Up @@ -157,13 +157,15 @@ GUMJS_DECLARE_FUNCTION (gumjs_memory_access_monitor_disable)
static void gum_quick_memory_clear_monitor (GumQuickMemory * self,
JSContext * ctx);

GUMJS_DECLARE_GETTER (gumjs_memory_access_details_get_thread_id)
GUMJS_DECLARE_GETTER (gumjs_memory_access_details_get_operation)
GUMJS_DECLARE_GETTER (gumjs_memory_access_details_get_from)
GUMJS_DECLARE_GETTER (gumjs_memory_access_details_get_address)
GUMJS_DECLARE_GETTER (gumjs_memory_access_details_get_range_index)
GUMJS_DECLARE_GETTER (gumjs_memory_access_details_get_page_index)
GUMJS_DECLARE_GETTER (gumjs_memory_access_details_get_pages_completed)
GUMJS_DECLARE_GETTER (gumjs_memory_access_details_get_pages_total)
GUMJS_DECLARE_GETTER (gumjs_memory_access_details_get_context)

static const JSCFunctionListEntry gumjs_memory_entries[] =
{
Expand Down Expand Up @@ -219,6 +221,7 @@ static const JSClassDef gumjs_memory_access_details_def =

static const JSCFunctionListEntry gumjs_memory_access_details_entries[] =
{
JS_CGETSET_DEF ("threadId", gumjs_memory_access_details_get_thread_id, NULL),
JS_CGETSET_DEF ("operation", gumjs_memory_access_details_get_operation, NULL),
JS_CGETSET_DEF ("from", gumjs_memory_access_details_get_from, NULL),
JS_CGETSET_DEF ("address", gumjs_memory_access_details_get_address, NULL),
Expand All @@ -230,6 +233,7 @@ static const JSCFunctionListEntry gumjs_memory_access_details_entries[] =
gumjs_memory_access_details_get_pages_completed, NULL),
JS_CGETSET_DEF ("pagesTotal", gumjs_memory_access_details_get_pages_total,
NULL),
JS_CGETSET_DEF ("context", gumjs_memory_access_details_get_context, NULL),
};

void
Expand Down Expand Up @@ -1271,6 +1275,16 @@ gum_quick_memory_access_details_get (JSContext * ctx,
return TRUE;
}

GUMJS_DEFINE_GETTER (gumjs_memory_access_details_get_thread_id)
{
const GumMemoryAccessDetails * details;

if (!gum_quick_memory_access_details_get (ctx, this_val, core, &details))
return JS_EXCEPTION;

return JS_NewInt64 (ctx, details->thread_id);
}

GUMJS_DEFINE_GETTER (gumjs_memory_access_details_get_operation)
{
const GumMemoryAccessDetails * details;
Expand Down Expand Up @@ -1340,3 +1354,14 @@ GUMJS_DEFINE_GETTER (gumjs_memory_access_details_get_pages_total)

return JS_NewUint32 (ctx, details->pages_total);
}

GUMJS_DEFINE_GETTER (gumjs_memory_access_details_get_context)
{
const GumMemoryAccessDetails * details;

if (!gum_quick_memory_access_details_get (ctx, this_val, core, &details))
return JS_EXCEPTION;

return _gum_quick_cpu_context_new (ctx, details->context,
GUM_CPU_CONTEXT_READWRITE, core, NULL);
}
6 changes: 6 additions & 0 deletions bindings/gumjs/gumv8memory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1214,6 +1214,9 @@ gum_v8_memory_on_access (GumMemoryAccessMonitor * monitor,
ScriptScope script_scope (core->script);

auto d = Object::New (isolate);
_gum_v8_object_set (d, "threadId", Number::New (isolate, details->thread_id),
core);

_gum_v8_object_set_ascii (d, "operation",
_gum_v8_memory_operation_to_string (details->operation), core);
_gum_v8_object_set_pointer (d, "from", details->from, core);
Expand All @@ -1224,6 +1227,9 @@ gum_v8_memory_on_access (GumMemoryAccessMonitor * monitor,
_gum_v8_object_set_uint (d, "pagesCompleted", details->pages_completed, core);
_gum_v8_object_set_uint (d, "pagesTotal", details->pages_total, core);

auto cpu_context = _gum_v8_cpu_context_new_mutable (details->context, core);
_gum_v8_object_set (d, "context", cpu_context, core);

auto on_access (Local<Function>::New (isolate, *self->on_access));
Local<Value> argv[] = { d };
auto result = on_access->Call (isolate->GetCurrentContext (),
Expand Down
2 changes: 2 additions & 0 deletions gum/backend-posix/gummemoryaccessmonitor-posix.c
Original file line number Diff line number Diff line change
Expand Up @@ -377,9 +377,11 @@ gum_memory_access_monitor_on_exception (GumExceptionDetails * details,
if (details->type != GUM_EXCEPTION_ACCESS_VIOLATION)
return FALSE;

d.thread_id = details->thread_id;
d.operation = details->memory.operation;
d.from = details->address;
d.address = details->memory.address;
d.context = &details->context;

for (i = 0; i != self->pages->len; i++)
{
Expand Down
2 changes: 2 additions & 0 deletions gum/backend-windows/gummemoryaccessmonitor-windows.c
Original file line number Diff line number Diff line change
Expand Up @@ -433,9 +433,11 @@ gum_memory_access_monitor_on_exception (GumExceptionDetails * details,

self = GUM_MEMORY_ACCESS_MONITOR (user_data);

d.thread_id = details->thread_id;
d.operation = details->memory.operation;
d.from = details->address;
d.address = details->memory.address;
d.context = &details->context;

for (i = 0; i != self->num_pages; i++)
{
Expand Down
4 changes: 4 additions & 0 deletions gum/gummemoryaccessmonitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#define __GUM_MEMORY_ACCESS_MONITOR_H__

#include <gum/gummemory.h>
#include <gum/gumprocess.h>

G_BEGIN_DECLS

Expand All @@ -22,6 +23,7 @@ typedef void (* GumMemoryAccessNotify) (GumMemoryAccessMonitor * monitor,

struct _GumMemoryAccessDetails
{
GumThreadId thread_id;
GumMemoryOperation operation;
gpointer from;
gpointer address;
Expand All @@ -30,6 +32,8 @@ struct _GumMemoryAccessDetails
guint page_index;
guint pages_completed;
guint pages_total;

GumCpuContext * context;
};

GUM_API GumMemoryAccessMonitor * gum_memory_access_monitor_new (
Expand Down
65 changes: 64 additions & 1 deletion tests/core/memoryaccessmonitor.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,21 @@ TESTCASE (notify_on_read_access)
volatile guint8 * bytes = GSIZE_TO_POINTER (fixture->range.base_address);
guint8 val;
volatile GumMemoryAccessDetails * d = &fixture->last_details;
GumThreadId thread_id;

bytes[fixture->offset_in_first_page] = 0x13;
bytes[fixture->offset_in_second_page] = 0x37;

ENABLE_MONITOR ();

val = bytes[fixture->offset_in_first_page];

thread_id = gum_process_get_current_thread_id ();
g_assert_cmpuint (d->thread_id, ==, thread_id);

g_assert_cmpuint (fixture->number_of_notifies, ==, 1);
g_assert_cmpint (d->operation, ==, GUM_MEMOP_READ);
g_assert_true (d->from != NULL && d->from != d->address);

g_assert_true (d->address == bytes + fixture->offset_in_first_page);
g_assert_cmpuint (val, ==, 0x13);

Expand All @@ -46,19 +51,40 @@ TESTCASE (notify_on_read_access)
val = bytes[fixture->offset_in_second_page];
g_assert_cmpuint (fixture->number_of_notifies, ==, 2);
g_assert_cmpuint (val, ==, 0x37);

/*
* Perform some basic architecture agnostic checks on the Cpu Context, the
* program counter should match the `from` field and the stack pointer
* should be non-zero.
*/
#if defined (HAVE_I386) && GLIB_SIZEOF_VOID_P == 4
g_assert_true (d->from == GSIZE_TO_POINTER (d->context->eip));
g_assert_true (0 != GSIZE_TO_POINTER (d->context->esp));
#elif defined (HAVE_I386) && GLIB_SIZEOF_VOID_P == 8
g_assert_true (d->from == GSIZE_TO_POINTER (d->context->rip));
g_assert_true (0 != GSIZE_TO_POINTER (d->context->rsp));
#else
g_assert_true (d->from == GSIZE_TO_POINTER (d->context->pc));
g_assert_true (0 != GSIZE_TO_POINTER (d->context->sp));
#endif
}

TESTCASE (notify_on_write_access)
{
volatile guint8 * bytes = GSIZE_TO_POINTER (fixture->range.base_address);
guint8 val;
volatile GumMemoryAccessDetails * d = &fixture->last_details;
GumThreadId thread_id;

bytes[fixture->offset_in_first_page] = 0x13;

ENABLE_MONITOR ();

bytes[fixture->offset_in_first_page] = 0x14;

thread_id = gum_process_get_current_thread_id ();
g_assert_cmpuint (d->thread_id, ==, thread_id);

g_assert_cmpuint (fixture->number_of_notifies, ==, 1);
g_assert_cmpint (d->operation, ==, GUM_MEMOP_WRITE);
g_assert_true (d->from != NULL && d->from != d->address);
Expand All @@ -67,21 +93,58 @@ TESTCASE (notify_on_write_access)
val = bytes[fixture->offset_in_first_page];
g_assert_cmpuint (fixture->number_of_notifies, ==, 1);
g_assert_cmpuint (val, ==, 0x14);

/*
* Perform some basic architecture agnostic checks on the Cpu Context, the
* program counter should match the `from` field and the stack pointer
* should be non-zero.
*/
#if defined (HAVE_I386) && GLIB_SIZEOF_VOID_P == 4
g_assert_true (d->from == GSIZE_TO_POINTER (d->context->eip));
g_assert_true (0 != GSIZE_TO_POINTER (d->context->esp));
#elif defined (HAVE_I386) && GLIB_SIZEOF_VOID_P == 8
g_assert_true (d->from == GSIZE_TO_POINTER (d->context->rip));
g_assert_true (0 != GSIZE_TO_POINTER (d->context->rsp));
#else
g_assert_true (d->from == GSIZE_TO_POINTER (d->context->pc));
g_assert_true (0 != GSIZE_TO_POINTER (d->context->sp));
#endif
}

TESTCASE (notify_on_execute_access)
{
volatile GumMemoryAccessDetails * d = &fixture->last_details;
GumThreadId thread_id;

ENABLE_MONITOR ();

fixture->nop_function_in_third_page ();

thread_id = gum_process_get_current_thread_id ();
g_assert_cmpuint (d->thread_id, ==, thread_id);

g_assert_cmpuint (fixture->number_of_notifies, ==, 1);
g_assert_cmpint (d->operation, ==, GUM_MEMOP_EXECUTE);
g_assert_true (d->from != NULL && d->from == d->address);

fixture->nop_function_in_third_page ();
g_assert_cmpuint (fixture->number_of_notifies, ==, 1);

/*
* Perform some basic architecture agnostic checks on the Cpu Context, the
* program counter should match the `from` field and the stack pointer
* should be non-zero.
*/
#if defined (HAVE_I386) && GLIB_SIZEOF_VOID_P == 4
g_assert_true (d->from == GSIZE_TO_POINTER (d->context->eip));
g_assert_true (0 != GSIZE_TO_POINTER (d->context->esp));
#elif defined (HAVE_I386) && GLIB_SIZEOF_VOID_P == 8
g_assert_true (d->from == GSIZE_TO_POINTER (d->context->rip));
g_assert_true (0 != GSIZE_TO_POINTER (d->context->rsp));
#else
g_assert_true (d->from == GSIZE_TO_POINTER (d->context->pc));
g_assert_true (0 != GSIZE_TO_POINTER (d->context->sp));
#endif
}

TESTCASE (notify_should_include_progress)
Expand Down
Loading
Loading