static void gum_v8_memory_read (GumMemoryValueType type, const GumV8Args * args, ReturnValue<Value> return_value) { auto core = args->core; auto isolate = core->isolate; auto exceptor = core->exceptor; gpointer address; gssize length = -1; GumExceptorScope scope; Local<Value> result; switch (type) { case GUM_MEMORY_VALUE_BYTE_ARRAY: if (!_gum_v8_args_parse (args, "pZ", &address, &length)) return; break; case GUM_MEMORY_VALUE_C_STRING: case GUM_MEMORY_VALUE_UTF8_STRING: case GUM_MEMORY_VALUE_UTF16_STRING: case GUM_MEMORY_VALUE_ANSI_STRING: if (!_gum_v8_args_parse (args, "p|z", &address, &length)) return; break; default: if (!_gum_v8_args_parse (args, "p", &address)) return; break; } if (gum_exceptor_try (exceptor, &scope)) { switch (type) { case GUM_MEMORY_VALUE_POINTER: result = _gum_v8_native_pointer_new (*((gpointer *) address), core); break; case GUM_MEMORY_VALUE_S8: result = Integer::New (isolate, *((gint8 *) address)); break; case GUM_MEMORY_VALUE_U8: result = Integer::NewFromUnsigned (isolate, *((guint8 *) address)); break; case GUM_MEMORY_VALUE_S16: result = Integer::New (isolate, *((gint16 *) address)); break; case GUM_MEMORY_VALUE_U16: result = Integer::NewFromUnsigned (isolate, *((guint16 *) address)); break; case GUM_MEMORY_VALUE_S32: result = Integer::New (isolate, *((gint32 *) address)); break; case GUM_MEMORY_VALUE_U32: result = Integer::NewFromUnsigned (isolate, *((guint32 *) address)); break; case GUM_MEMORY_VALUE_S64: result = _gum_v8_int64_new (*((gint64 *) address), core); break; case GUM_MEMORY_VALUE_U64: result = _gum_v8_uint64_new (*((guint64 *) address), core); break; case GUM_MEMORY_VALUE_LONG: result = _gum_v8_int64_new (*((glong *) address), core); break; case GUM_MEMORY_VALUE_ULONG: result = _gum_v8_uint64_new (*((gulong *) address), core); break; case GUM_MEMORY_VALUE_FLOAT: result = Number::New (isolate, *((gfloat *) address)); break; case GUM_MEMORY_VALUE_DOUBLE: result = Number::New (isolate, *((gdouble *) address)); break; case GUM_MEMORY_VALUE_BYTE_ARRAY: { auto data = (guint8 *) address; if (data == NULL) { result = Null (isolate); break; } if (length > 0) { guint8 dummy_to_trap_bad_pointer_early; memcpy (&dummy_to_trap_bad_pointer_early, data, sizeof (guint8)); result = ArrayBuffer::New (isolate, g_memdup (data, length), length, ArrayBufferCreationMode::kInternalized); } else { result = ArrayBuffer::New (isolate, 0); } break; } case GUM_MEMORY_VALUE_C_STRING: { auto data = (gchar *) address; if (data == NULL) { result = Null (isolate); break; } if (length != 0) { guint8 dummy_to_trap_bad_pointer_early; memcpy (&dummy_to_trap_bad_pointer_early, data, sizeof (guint8)); result = String::NewFromOneByte (isolate, (const uint8_t *) data, NewStringType::kNormal, length).ToLocalChecked (); } else { result = String::Empty (isolate); } break; } case GUM_MEMORY_VALUE_UTF8_STRING: { auto data = (gchar *) address; if (data == NULL) { result = Null (isolate); break; } if (length != 0) { guint8 dummy_to_trap_bad_pointer_early; memcpy (&dummy_to_trap_bad_pointer_early, data, sizeof (guint8)); result = String::NewFromUtf8 (isolate, data, String::kNormalString, length); } else { result = String::Empty (isolate); } break; } case GUM_MEMORY_VALUE_UTF16_STRING: { auto str_utf16 = (gunichar2 *) address; if (str_utf16 == NULL) { result = Null (isolate); break; } if (length != 0) { guint8 dummy_to_trap_bad_pointer_early; memcpy (&dummy_to_trap_bad_pointer_early, str_utf16, sizeof (guint8)); } glong size; auto str_utf8 = g_utf16_to_utf8 (str_utf16, length, NULL, &size, NULL); if (str_utf8 == NULL) { _gum_v8_throw_ascii_literal (isolate, "invalid string"); break; } if (size != 0) { result = String::NewFromUtf8 (isolate, str_utf8, String::kNormalString, size); } else { result = String::Empty (isolate); } g_free (str_utf8); break; } case GUM_MEMORY_VALUE_ANSI_STRING: { #ifdef G_OS_WIN32 auto str_ansi = (gchar *) address; if (str_ansi == NULL) { result = Null (isolate); break; } if (length != 0) { guint8 dummy_to_trap_bad_pointer_early; memcpy (&dummy_to_trap_bad_pointer_early, str_ansi, sizeof (guint8)); auto str_utf8 = gum_ansi_string_to_utf8 (str_ansi, length); auto size = g_utf8_offset_to_pointer (str_utf8, g_utf8_strlen (str_utf8, -1)) - str_utf8; result = String::NewFromUtf8 (isolate, str_utf8, String::kNormalString, size); g_free (str_utf8); } else { result = String::Empty (isolate); } #else _gum_v8_throw_ascii_literal (isolate, "ANSI API is only applicable on Windows"); #endif break; } default: g_assert_not_reached (); } } if (gum_exceptor_catch (exceptor, &scope)) { _gum_v8_throw_native (&scope.exception, core); } else { if (!result.IsEmpty ()) return_value.Set (result); } }
static void gum_v8_kernel_read (GumMemoryValueType type, const GumV8Args * args, ReturnValue<Value> return_value) { auto core = args->core; auto isolate = core->isolate; if (!gum_v8_kernel_check_api_available (isolate)) return; GumAddress address; gssize length = 0; switch (type) { case GUM_MEMORY_VALUE_BYTE_ARRAY: case GUM_MEMORY_VALUE_C_STRING: case GUM_MEMORY_VALUE_UTF8_STRING: case GUM_MEMORY_VALUE_UTF16_STRING: if (!_gum_v8_args_parse (args, "QZ", &address, &length)) return; break; default: if (!_gum_v8_args_parse (args, "Q", &address)) return; break; } if (address == 0) { return_value.Set (Null (isolate)); return; } if (length == 0) { switch (type) { case GUM_MEMORY_VALUE_S8: case GUM_MEMORY_VALUE_U8: length = 1; break; case GUM_MEMORY_VALUE_S16: case GUM_MEMORY_VALUE_U16: length = 2; break; case GUM_MEMORY_VALUE_S32: case GUM_MEMORY_VALUE_U32: case GUM_MEMORY_VALUE_FLOAT: length = 4; break; case GUM_MEMORY_VALUE_S64: case GUM_MEMORY_VALUE_U64: case GUM_MEMORY_VALUE_LONG: case GUM_MEMORY_VALUE_ULONG: case GUM_MEMORY_VALUE_DOUBLE: length = 8; break; default: g_assert_not_reached (); } } Local<Value> result; if (length > 0) { gsize n_bytes_read; auto data = gum_kernel_read (address, length, &n_bytes_read); if (data == NULL) { _gum_v8_throw_ascii (isolate, "access violation reading 0x%" G_GINT64_MODIFIER "x", address); return; } switch (type) { case GUM_MEMORY_VALUE_S8: result = Integer::New (isolate, *((gint8 *) data)); break; case GUM_MEMORY_VALUE_U8: result = Integer::NewFromUnsigned (isolate, *((guint8 *) data)); break; case GUM_MEMORY_VALUE_S16: result = Integer::New (isolate, *((gint16 *) data)); break; case GUM_MEMORY_VALUE_U16: result = Integer::NewFromUnsigned (isolate, *((guint16 *) data)); break; case GUM_MEMORY_VALUE_S32: result = Integer::New (isolate, *((gint32 *) data)); break; case GUM_MEMORY_VALUE_U32: result = Integer::NewFromUnsigned (isolate, *((guint32 *) data)); break; case GUM_MEMORY_VALUE_S64: result = _gum_v8_int64_new (*((gint64 *) data), core); break; case GUM_MEMORY_VALUE_U64: result = _gum_v8_uint64_new (*((guint64 *) data), core); break; case GUM_MEMORY_VALUE_LONG: result = _gum_v8_int64_new (*((glong *) data), core); break; case GUM_MEMORY_VALUE_ULONG: result = _gum_v8_uint64_new (*((gulong *) data), core); break; case GUM_MEMORY_VALUE_FLOAT: result = Number::New (isolate, *((gfloat *) data)); break; case GUM_MEMORY_VALUE_DOUBLE: result = Number::New (isolate, *((gdouble *) data)); break; case GUM_MEMORY_VALUE_BYTE_ARRAY: result = ArrayBuffer::New (isolate, data, n_bytes_read, ArrayBufferCreationMode::kInternalized); break; case GUM_MEMORY_VALUE_C_STRING: { gchar * str = g_utf8_make_valid ((gchar *) data, length); result = String::NewFromUtf8 (isolate, str, String::kNormalString); g_free (str); break; } case GUM_MEMORY_VALUE_UTF8_STRING: { const gchar * end; if (!g_utf8_validate ((gchar *) data, length, &end)) { _gum_v8_throw_ascii (isolate, "can't decode byte 0x%02x in position %u", (guint8) *end, (guint) (end - (gchar *) data)); break; } result = String::NewFromUtf8 (isolate, (gchar *) data, String::kNormalString, length); break; } case GUM_MEMORY_VALUE_UTF16_STRING: { auto str_utf16 = (gunichar2 *) data; glong size; auto str_utf8 = g_utf16_to_utf8 (str_utf16, length, NULL, &size, NULL); if (str_utf8 == NULL) { _gum_v8_throw_ascii_literal (isolate, "invalid string"); break; } if (size != 0) { result = String::NewFromUtf8 (isolate, str_utf8, String::kNormalString, size); } else { result = String::Empty (isolate); } g_free (str_utf8); break; } } } else { switch (type) { case GUM_MEMORY_VALUE_C_STRING: case GUM_MEMORY_VALUE_UTF8_STRING: case GUM_MEMORY_VALUE_UTF16_STRING: result = String::Empty (isolate); break; case GUM_MEMORY_VALUE_BYTE_ARRAY: result = ArrayBuffer::New (isolate, 0); break; default: _gum_v8_throw_ascii (isolate, "please provide a length > 0"); return; } } if (!result.IsEmpty()) return_value.Set (result); }