From ff4664e48fcc84ea3b95cd189c4b3c12d7ecc610 Mon Sep 17 00:00:00 2001 From: DoranekoSystems Date: Sun, 26 Jan 2025 10:11:07 +0900 Subject: [PATCH] memory: Optimize gum_memory_write for Linux/Android --- gum/backend-linux/gummemory-linux.c | 59 +++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 3 deletions(-) diff --git a/gum/backend-linux/gummemory-linux.c b/gum/backend-linux/gummemory-linux.c index 3a972d6f2..28fc1ec2b 100644 --- a/gum/backend-linux/gummemory-linux.c +++ b/gum/backend-linux/gummemory-linux.c @@ -20,19 +20,26 @@ #if defined (HAVE_I386) && GLIB_SIZEOF_VOID_P == 4 # define GUM_SYS_PROCESS_VM_READV 347 +# define GUM_SYS_PROCESS_VM_WRITEV 348 #elif defined (HAVE_I386) && GLIB_SIZEOF_VOID_P == 8 # define GUM_SYS_PROCESS_VM_READV 310 +# define GUM_SYS_PROCESS_VM_WRITEV 311 #elif defined (HAVE_ARM) # define GUM_SYS_PROCESS_VM_READV (__NR_SYSCALL_BASE + 376) +# define GUM_SYS_PROCESS_VM_WRITEV (__NR_SYSCALL_BASE + 377) #elif defined (HAVE_ARM64) # define GUM_SYS_PROCESS_VM_READV 270 +# define GUM_SYS_PROCESS_VM_WRITEV 271 #elif defined (HAVE_MIPS) # if _MIPS_SIM == _MIPS_SIM_ABI32 # define GUM_SYS_PROCESS_VM_READV (__NR_Linux + 345) +# define GUM_SYS_PROCESS_VM_WRITEV (__NR_Linux + 346) # elif _MIPS_SIM == _MIPS_SIM_ABI64 # define GUM_SYS_PROCESS_VM_READV (__NR_Linux + 304) +# define GUM_SYS_PROCESS_VM_WRITEV (__NR_Linux + 305) # elif _MIPS_SIM == _MIPS_SIM_NABI32 # define GUM_SYS_PROCESS_VM_READV (__NR_Linux + 309) +# define GUM_SYS_PROCESS_VM_WRITEV (__NR_Linux + 310) # else # error Unexpected MIPS ABI # endif @@ -48,6 +55,11 @@ static gssize gum_libc_process_vm_readv (pid_t pid, const struct iovec * remote_iov, gulong riovcnt, gulong flags); +static gssize gum_libc_process_vm_writev (pid_t pid, + const struct iovec * local_iov, gulong liovcnt, + const struct iovec * remote_iov, gulong riovcnt, + gulong flags); + gboolean gum_memory_is_readable (gconstpointer address, gsize len) @@ -152,11 +164,40 @@ gum_memory_write (gpointer address, gsize len) { gboolean success = FALSE; + static gboolean kernel_feature_likely_enabled = TRUE; + gboolean still_pending = TRUE; + + if (kernel_feature_likely_enabled && gum_linux_check_kernel_version (3, 2, 0)) + { + gssize n; + struct iovec local_iov = { + .iov_base = (void *) bytes, + .iov_len = len + }; + struct iovec remote_iov = { + .iov_base = address, + .iov_len = len + }; + + n = gum_libc_process_vm_writev (getpid (), &local_iov, 1, &remote_iov, 1, 0); + if (n > 0) + { + success = (n == len); + } - if (gum_memory_is_writable (address, len)) + if (n == -1 && errno == ENOSYS) + kernel_feature_likely_enabled = FALSE; + else + still_pending = FALSE; + } + + if (still_pending) { - memcpy (address, bytes, len); - success = TRUE; + if (gum_memory_is_writable (address, len)) + { + memcpy (address, bytes, len); + success = TRUE; + } } return success; @@ -320,3 +361,15 @@ gum_libc_process_vm_readv (pid_t pid, return syscall (GUM_SYS_PROCESS_VM_READV, pid, local_iov, liovcnt, remote_iov, riovcnt, flags); } + +static gssize +gum_libc_process_vm_writev (pid_t pid, + const struct iovec * local_iov, + gulong liovcnt, + const struct iovec * remote_iov, + gulong riovcnt, + gulong flags) +{ + return syscall (GUM_SYS_PROCESS_VM_WRITEV, pid, local_iov, liovcnt, remote_iov, + riovcnt, flags); +}