diff --git a/bindings/gumjs/gumquickprocess.c b/bindings/gumjs/gumquickprocess.c index 37ec3d1ae..5db951042 100644 --- a/bindings/gumjs/gumquickprocess.c +++ b/bindings/gumjs/gumquickprocess.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2020-2022 Ole André Vadla Ravnås - * Copyright (C) 2020 Francesco Tamagni + * Copyright (C) 2020-2023 Francesco Tamagni * * Licence: wxWindows Library Licence, Version 3.1 */ @@ -78,6 +78,8 @@ struct _GumQuickFindRangeByAddressContext GumQuickCore * core; }; +static void gumjs_free_main_module_value (GumQuickProcess * self); +GUMJS_DECLARE_GETTER (gumjs_process_get_main_module) GUMJS_DECLARE_FUNCTION (gumjs_process_get_current_dir) GUMJS_DECLARE_FUNCTION (gumjs_process_get_home_dir) GUMJS_DECLARE_FUNCTION (gumjs_process_get_tmp_dir) @@ -114,6 +116,7 @@ static const JSCFunctionListEntry gumjs_process_entries[] = JS_PROP_STRING_DEF ("arch", GUM_SCRIPT_ARCH, JS_PROP_C_W_E), JS_PROP_STRING_DEF ("platform", GUM_SCRIPT_PLATFORM, JS_PROP_C_W_E), JS_PROP_INT32_DEF ("pointerSize", GLIB_SIZEOF_VOID_P, JS_PROP_C_W_E), + JS_CGETSET_DEF ("mainModule", gumjs_process_get_main_module, NULL), JS_CFUNC_DEF ("getCurrentDir", 0, gumjs_process_get_current_dir), JS_CFUNC_DEF ("getHomeDir", 0, gumjs_process_get_home_dir), JS_CFUNC_DEF ("getTmpDir", 0, gumjs_process_get_tmp_dir), @@ -142,6 +145,7 @@ _gum_quick_process_init (GumQuickProcess * self, self->module = module; self->core = core; + self->main_module_value = JS_UNINITIALIZED; _gum_quick_core_store_module_data (core, "process", self); @@ -163,12 +167,24 @@ void _gum_quick_process_flush (GumQuickProcess * self) { g_clear_pointer (&self->exception_handler, gum_quick_exception_handler_free); + gumjs_free_main_module_value (self); } void _gum_quick_process_dispose (GumQuickProcess * self) { g_clear_pointer (&self->exception_handler, gum_quick_exception_handler_free); + gumjs_free_main_module_value (self); +} + +static void +gumjs_free_main_module_value (GumQuickProcess * self) +{ + if (JS_IsUninitialized (self->main_module_value)) + return; + + JS_FreeValue (self->core->ctx, self->main_module_value); + self->main_module_value = JS_UNINITIALIZED; } void @@ -182,6 +198,21 @@ gumjs_get_parent_module (GumQuickCore * core) return _gum_quick_core_load_module_data (core, "process"); } +GUMJS_DEFINE_GETTER (gumjs_process_get_main_module) +{ + GumQuickProcess * self; + + self = gumjs_get_parent_module (core); + + if (JS_IsUninitialized (self->main_module_value)) + { + self->main_module_value = _gum_quick_module_new (ctx, + gum_process_get_main_module (), self->module); + } + + return JS_DupValue (ctx, self->main_module_value); +} + GUMJS_DEFINE_FUNCTION (gumjs_process_get_current_dir) { JSValue result; diff --git a/bindings/gumjs/gumquickprocess.h b/bindings/gumjs/gumquickprocess.h index 5ae272207..e8811e756 100644 --- a/bindings/gumjs/gumquickprocess.h +++ b/bindings/gumjs/gumquickprocess.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2020 Ole André Vadla Ravnås + * Copyright (C) 2023 Francesco Tamagni * * Licence: wxWindows Library Licence, Version 3.1 */ @@ -20,6 +21,7 @@ struct _GumQuickProcess GumQuickModule * module; GumQuickCore * core; + JSValue main_module_value; GumQuickExceptionHandler * exception_handler; }; diff --git a/bindings/gumjs/gumv8process.cpp b/bindings/gumjs/gumv8process.cpp index 3b89aed8e..19eaf5717 100644 --- a/bindings/gumjs/gumv8process.cpp +++ b/bindings/gumjs/gumv8process.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2010-2022 Ole André Vadla Ravnås - * Copyright (C) 2020 Francesco Tamagni + * Copyright (C) 2020-2023 Francesco Tamagni * * Licence: wxWindows Library Licence, Version 3.1 */ @@ -63,6 +63,7 @@ struct GumV8FindModuleByNameContext GumV8Process * parent; }; +GUMJS_DECLARE_GETTER (gumjs_process_get_main_module) GUMJS_DECLARE_FUNCTION (gumjs_process_get_current_dir) GUMJS_DECLARE_FUNCTION (gumjs_process_get_home_dir) GUMJS_DECLARE_FUNCTION (gumjs_process_get_tmp_dir) @@ -93,6 +94,13 @@ static gboolean gum_v8_exception_handler_on_exception ( const gchar * gum_v8_script_exception_type_to_string (GumExceptionType type); +static const GumV8Property gumjs_process_values[] = +{ + { "mainModule", gumjs_process_get_main_module, NULL }, + + { NULL, NULL } +}; + static const GumV8Function gumjs_process_functions[] = { { "getCurrentDir", gumjs_process_get_current_dir }, @@ -122,6 +130,8 @@ _gum_v8_process_init (GumV8Process * self, self->module = module; self->core = core; + auto process_module = External::New (isolate, self); + auto process = _gum_v8_create_module ("Process", scope, isolate); process->Set (_gum_v8_string_new_ascii (isolate, "id"), Number::New (isolate, gum_process_get_id ()), ReadOnly); @@ -136,7 +146,8 @@ _gum_v8_process_init (GumV8Process * self, process->Set (_gum_v8_string_new_ascii (isolate, "codeSigningPolicy"), String::NewFromUtf8 (isolate, gum_code_signing_policy_to_string ( gum_process_get_code_signing_policy ())).ToLocalChecked (), ReadOnly); - _gum_v8_module_add (External::New (isolate, self), process, + _gum_v8_module_add (process_module, process, gumjs_process_values, isolate); + _gum_v8_module_add (process_module, process, gumjs_process_functions, isolate); } @@ -149,12 +160,18 @@ void _gum_v8_process_flush (GumV8Process * self) { g_clear_pointer (&self->exception_handler, gum_v8_exception_handler_free); + + delete self->main_module_value; + self->main_module_value = nullptr; } void _gum_v8_process_dispose (GumV8Process * self) { g_clear_pointer (&self->exception_handler, gum_v8_exception_handler_free); + + delete self->main_module_value; + self->main_module_value = nullptr; } void @@ -162,6 +179,21 @@ _gum_v8_process_finalize (GumV8Process * self) { } +GUMJS_DEFINE_GETTER (gumjs_process_get_main_module) +{ + auto self = module; + + if (self->main_module_value == nullptr) + { + self->main_module_value = new Global (isolate, + _gum_v8_module_value_new (gum_process_get_main_module (), + self->module)); + } + + info.GetReturnValue ().Set ( + Local::New (isolate, *module->main_module_value)); +} + GUMJS_DEFINE_FUNCTION (gumjs_process_get_current_dir) { gchar * dir_opsys = g_get_current_dir (); diff --git a/bindings/gumjs/gumv8process.h b/bindings/gumjs/gumv8process.h index 724aea469..03547e96d 100644 --- a/bindings/gumjs/gumv8process.h +++ b/bindings/gumjs/gumv8process.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2010-2020 Ole André Vadla Ravnås + * Copyright (C) 2023 Francesco Tamagni * * Licence: wxWindows Library Licence, Version 3.1 */ @@ -17,6 +18,7 @@ struct GumV8Process GumV8Module * module; GumV8Core * core; + v8::Global * main_module_value; GumV8ExceptionHandler * exception_handler; }; diff --git a/gum/backend-darwin/gumprocess-darwin.c b/gum/backend-darwin/gumprocess-darwin.c index 29c8f9185..a620827e8 100644 --- a/gum/backend-darwin/gumprocess-darwin.c +++ b/gum/backend-darwin/gumprocess-darwin.c @@ -1,7 +1,7 @@ /* * Copyright (C) 2010-2023 Ole André Vadla Ravnås * Copyright (C) 2015 Asger Hautop Drewsen - * Copyright (C) 2022 Francesco Tamagni + * Copyright (C) 2022-2023 Francesco Tamagni * Copyright (C) 2022 Håvard Sørbø * Copyright (C) 2023 Alex Soler * @@ -448,6 +448,24 @@ _gum_process_enumerate_threads (GumFoundThreadFunc func, gum_darwin_enumerate_threads (mach_task_self (), func, user_data); } +gboolean +_gum_process_collect_main_module (const GumModuleDetails * details, + gpointer user_data) +{ + GumModuleDetails ** out = user_data; + gum_mach_header_t * header; + + header = GSIZE_TO_POINTER (details->range->base_address); + if (header->filetype == MH_EXECUTE) + { + *out = gum_module_details_copy (details); + + return FALSE; + } + + return TRUE; +} + void _gum_process_enumerate_modules (GumFoundModuleFunc func, gpointer user_data) diff --git a/gum/backend-freebsd/gumprocess-freebsd.c b/gum/backend-freebsd/gumprocess-freebsd.c index 10ee5f7ba..e8bfebd6b 100644 --- a/gum/backend-freebsd/gumprocess-freebsd.c +++ b/gum/backend-freebsd/gumprocess-freebsd.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2022-2023 Ole André Vadla Ravnås + * Copyright (C) 2023 Francesco Tamagni * * Licence: wxWindows Library Licence, Version 3.1 */ @@ -475,6 +476,17 @@ gum_query_program_path_for_target (int target, } } +gboolean +_gum_process_collect_main_module (const GumModuleDetails * details, + gpointer user_data) +{ + GumModuleDetails ** out = user_data; + + *out = gum_module_details_copy (details); + + return FALSE; +} + void _gum_process_enumerate_modules (GumFoundModuleFunc func, gpointer user_data) diff --git a/gum/backend-linux/gumprocess-linux.c b/gum/backend-linux/gumprocess-linux.c index 3a67baee0..26183febd 100644 --- a/gum/backend-linux/gumprocess-linux.c +++ b/gum/backend-linux/gumprocess-linux.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2010-2023 Ole André Vadla Ravnås * Copyright (C) 2023 Håvard Sørbø + * Copyright (C) 2023 Francesco Tamagni * * Licence: wxWindows Library Licence, Version 3.1 */ @@ -1043,6 +1044,17 @@ gum_store_cpu_context (GumThreadId thread_id, memcpy (user_data, cpu_context, sizeof (GumCpuContext)); } +gboolean +_gum_process_collect_main_module (const GumModuleDetails * details, + gpointer user_data) +{ + GumModuleDetails ** out = user_data; + + *out = gum_module_details_copy (details); + + return FALSE; +} + void _gum_process_enumerate_modules (GumFoundModuleFunc func, gpointer user_data) diff --git a/gum/backend-qnx/gumprocess-qnx.c b/gum/backend-qnx/gumprocess-qnx.c index 90027025c..1c863a681 100644 --- a/gum/backend-qnx/gumprocess-qnx.c +++ b/gum/backend-qnx/gumprocess-qnx.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2015-2023 Ole André Vadla Ravnås + * Copyright (C) 2023 Francesco Tamagni * * Licence: wxWindows Library Licence, Version 3.1 */ @@ -262,6 +263,17 @@ gum_store_cpu_context (GumThreadId thread_id, memcpy (user_data, cpu_context, sizeof (GumCpuContext)); } +gboolean +_gum_process_collect_main_module (const GumModuleDetails * details, + gpointer user_data) +{ + GumModuleDetails ** out = user_data; + + *out = gum_module_details_copy (details); + + return FALSE; +} + void _gum_process_enumerate_modules (GumFoundModuleFunc func, gpointer user_data) diff --git a/gum/backend-windows/gumprocess-windows.c b/gum/backend-windows/gumprocess-windows.c index 84a199fdb..72cc35667 100644 --- a/gum/backend-windows/gumprocess-windows.c +++ b/gum/backend-windows/gumprocess-windows.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2009-2023 Ole André Vadla Ravnås + * Copyright (C) 2023 Francesco Tamagni * * Licence: wxWindows Library Licence, Version 3.1 */ @@ -260,6 +261,17 @@ gum_windows_get_thread_details (DWORD thread_id, return success; } +gboolean +_gum_process_collect_main_module (const GumModuleDetails * details, + gpointer user_data) +{ + GumModuleDetails ** out = user_data; + + *out = gum_module_details_copy (details); + + return FALSE; +} + void _gum_process_enumerate_modules (GumFoundModuleFunc func, gpointer user_data) diff --git a/gum/gumprocess-priv.h b/gum/gumprocess-priv.h index c8cde5111..dea0d5e0e 100644 --- a/gum/gumprocess-priv.h +++ b/gum/gumprocess-priv.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2017-2023 Ole André Vadla Ravnås + * Copyright (C) 2023 Francesco Tamagni * * Licence: wxWindows Library Licence, Version 3.1 */ @@ -13,6 +14,8 @@ G_BEGIN_DECLS G_GNUC_INTERNAL void _gum_process_enumerate_threads (GumFoundThreadFunc func, gpointer user_data); +G_GNUC_INTERNAL gboolean _gum_process_collect_main_module ( + const GumModuleDetails * details, gpointer user_data); G_GNUC_INTERNAL void _gum_process_enumerate_modules (GumFoundModuleFunc func, gpointer user_data); G_GNUC_INTERNAL void _gum_process_enumerate_ranges (GumPageProtection prot, diff --git a/gum/gumprocess.c b/gum/gumprocess.c index f721ac5f0..be427ab4e 100644 --- a/gum/gumprocess.c +++ b/gum/gumprocess.c @@ -1,11 +1,13 @@ /* * Copyright (C) 2015-2023 Ole André Vadla Ravnås + * Copyright (C) 2023 Francesco Tamagni * * Licence: wxWindows Library Licence, Version 3.1 */ #include "gumprocess-priv.h" +#include "gum-init.h" #include "gumcloak.h" typedef struct _GumEmitThreadsContext GumEmitThreadsContext; @@ -48,6 +50,7 @@ struct _GumResolveSymbolContext static gboolean gum_emit_thread_if_not_cloaked ( const GumThreadDetails * details, gpointer user_data); +static void gum_deinit_main_module (void); static gboolean gum_try_resolve_module_pointer_from ( const GumModuleDetails * details, gpointer user_data); static gboolean gum_emit_module_if_not_cloaked ( @@ -146,6 +149,37 @@ gum_emit_thread_if_not_cloaked (const GumThreadDetails * details, return ctx->func (details, ctx->user_data); } +/** + * gum_process_get_main_module: + * + * Returns the details of the module representing the main executable + * of the process. + */ +const GumModuleDetails * +gum_process_get_main_module (void) +{ + static gsize cached_result = 0; + + if (g_once_init_enter (&cached_result)) + { + GumModuleDetails * result; + + gum_process_enumerate_modules (_gum_process_collect_main_module, &result); + + _gum_register_destructor (gum_deinit_main_module); + + g_once_init_leave (&cached_result, GPOINTER_TO_SIZE (result) + 1); + } + + return GSIZE_TO_POINTER (cached_result) - 1; +} + +static void +gum_deinit_main_module (void) +{ + gum_module_details_free ((GumModuleDetails *) gum_process_get_main_module ()); +} + /** * gum_process_resolve_module_pointer: * @ptr: memory location potentially belonging to a module diff --git a/gum/gumprocess.h b/gum/gumprocess.h index 466f8835b..68185ab96 100644 --- a/gum/gumprocess.h +++ b/gum/gumprocess.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2008-2023 Ole André Vadla Ravnås - * Copyright (C) 2020 Francesco Tamagni + * Copyright (C) 2020-2023 Francesco Tamagni * * Licence: wxWindows Library Licence, Version 3.1 */ @@ -205,6 +205,7 @@ GUM_API gboolean gum_process_modify_thread (GumThreadId thread_id, GumModifyThreadFunc func, gpointer user_data, GumModifyThreadFlags flags); GUM_API void gum_process_enumerate_threads (GumFoundThreadFunc func, gpointer user_data); +GUM_API const GumModuleDetails * gum_process_get_main_module (void); GUM_API gboolean gum_process_resolve_module_pointer (gconstpointer ptr, gchar ** path, GumMemoryRange * range); GUM_API void gum_process_enumerate_modules (GumFoundModuleFunc func,