mirror of
https://github.com/frida/frida-core.git
synced 2026-11-08 17:12:49 -10:00
Compare commits
11
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6b54eeb7d8 | ||
|
|
08de3d3d07 | ||
|
|
174b93cbd4 | ||
|
|
d0f8162a65 | ||
|
|
a3427baeb3 | ||
|
|
c792a09002 | ||
|
|
27605f7fde | ||
|
|
ba8784fe8c | ||
|
|
0a6c2103fa | ||
|
|
14de0ef567 | ||
|
|
4165572919 |
No files matched your search
@@ -2462,26 +2462,10 @@ namespace Frida {
|
||||
|
||||
private static void add_variant_value_of_type (Variant val, string type, Fruity.XpcBodyBuilder builder) throws Error {
|
||||
switch (type) {
|
||||
case "bool":
|
||||
check_type (val, VariantType.BOOLEAN);
|
||||
builder.add_bool_value (val.get_boolean ());
|
||||
break;
|
||||
case "int64":
|
||||
check_type (val, VariantType.INT64);
|
||||
builder.add_int64_value (val.get_int64 ());
|
||||
break;
|
||||
case "uint64":
|
||||
check_type (val, VariantType.UINT64);
|
||||
builder.add_uint64_value (val.get_uint64 ());
|
||||
break;
|
||||
case "data":
|
||||
check_type (val, new VariantType ("ay"));
|
||||
builder.add_data_value (val.get_data_as_bytes ());
|
||||
break;
|
||||
case "string":
|
||||
check_type (val, VariantType.STRING);
|
||||
builder.add_string_value (val.get_string ());
|
||||
break;
|
||||
case "uuid":
|
||||
check_type (val, new VariantType ("ay"));
|
||||
if (val.get_size () != 16)
|
||||
|
||||
@@ -813,22 +813,23 @@ namespace Frida {
|
||||
private const uint64 SOCK_CLOEXEC = 0x80000;
|
||||
|
||||
private sealed class InjectSession : SeizeSession {
|
||||
private static ProcMapsSoEntry local_libc;
|
||||
private static ProcMapsSnapshot.Mapping local_libc;
|
||||
private static uint64 mmap_offset;
|
||||
private static uint64 munmap_offset;
|
||||
|
||||
private static string fallback_ld;
|
||||
private static string fallback_libc;
|
||||
|
||||
private static ProcMapsSoEntry? local_android_ld;
|
||||
private static ProcMapsSnapshot.Mapping? local_android_ld;
|
||||
|
||||
static construct {
|
||||
var libc = Gum.Process.get_libc_module ();
|
||||
uint local_pid = Posix.getpid ();
|
||||
local_libc = ProcMapsSoEntry.find_by_path (local_pid, libc.path);
|
||||
var local_maps = ProcMapsSnapshot.from_pid (local_pid);
|
||||
local_libc = local_maps.find_module_by_path (libc.path);
|
||||
assert (local_libc != null);
|
||||
mmap_offset = (uint64) (uintptr) libc.find_export_by_name ("mmap") - local_libc.base_address;
|
||||
munmap_offset = (uint64) (uintptr) libc.find_export_by_name ("munmap") - local_libc.base_address;
|
||||
mmap_offset = (uint64) (uintptr) libc.find_export_by_name ("mmap") - local_libc.start;
|
||||
munmap_offset = (uint64) (uintptr) libc.find_export_by_name ("munmap") - local_libc.start;
|
||||
|
||||
try {
|
||||
var program = new Gum.ElfModule.from_file ("/proc/self/exe");
|
||||
@@ -846,7 +847,7 @@ namespace Frida {
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
local_android_ld = ProcMapsSoEntry.find_by_path (local_pid, fallback_ld);
|
||||
local_android_ld = local_maps.find_module_by_path (fallback_ld);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1051,9 +1052,10 @@ namespace Frida {
|
||||
uint64 allocation_base = 0;
|
||||
size_t allocation_size = size_t.max (bootstrapper_size, loader_size) + stack_size;
|
||||
|
||||
var remote_maps = ProcMapsSnapshot.from_pid (pid);
|
||||
var remote_libc = remote_maps.find_module_by_path (local_libc.path);
|
||||
uint64 remote_mmap = 0;
|
||||
uint64 remote_munmap = 0;
|
||||
ProcMapsSoEntry? remote_libc = ProcMapsSoEntry.find_by_path (pid, local_libc.path);
|
||||
#if ANDROID
|
||||
bool same_libc = remote_libc != null
|
||||
&& remote_libc.device.major == local_libc.device.major
|
||||
@@ -1066,8 +1068,8 @@ namespace Frida {
|
||||
&& remote_libc.path == local_libc.path;
|
||||
#endif
|
||||
if (same_libc) {
|
||||
remote_mmap = remote_libc.base_address + mmap_offset;
|
||||
remote_munmap = remote_libc.base_address + munmap_offset;
|
||||
remote_mmap = remote_libc.start + mmap_offset;
|
||||
remote_munmap = remote_libc.start + munmap_offset;
|
||||
}
|
||||
|
||||
if (remote_mmap != 0) {
|
||||
@@ -1165,7 +1167,9 @@ namespace Frida {
|
||||
result.context.libc = &result.libc;
|
||||
|
||||
if (result.context.rtld_flavor == ANDROID && result.libc.dlopen == null) {
|
||||
ProcMapsSoEntry? remote_ld = ProcMapsSoEntry.find_by_address (pid, (uintptr) result.context.rtld_base);
|
||||
if (restart_after_libc_load)
|
||||
remote_maps = ProcMapsSnapshot.from_pid (pid);
|
||||
var remote_ld = remote_maps.find_mapping ((uintptr) result.context.rtld_base);
|
||||
bool same_ld = remote_ld != null && local_android_ld != null
|
||||
&& remote_ld.device.equals (local_android_ld.device)
|
||||
&& remote_ld.inode == local_android_ld.inode;
|
||||
@@ -1217,9 +1221,9 @@ namespace Frida {
|
||||
}
|
||||
}
|
||||
|
||||
private static void * rebase_pointer (uintptr local_ptr, ProcMapsSoEntry local_module, ProcMapsSoEntry remote_module) {
|
||||
var offset = local_ptr - local_module.base_address;
|
||||
return (void *) (remote_module.base_address + offset);
|
||||
private static void * rebase_pointer (uintptr local_ptr, ProcMapsSnapshot.Mapping local, ProcMapsSnapshot.Mapping remote) {
|
||||
var offset = local_ptr - local.start;
|
||||
return (void *) (remote.start + offset);
|
||||
}
|
||||
|
||||
private static string make_fallback_address () {
|
||||
|
||||
@@ -49,11 +49,11 @@ bpf_arch_pairs := \
|
||||
|
||||
build-native: ext/linux/tools/include/nolibc/nolibc.h
|
||||
rm -rf build
|
||||
$(MESON) setup --cross-file $(crossfile) -Db_lto=true build
|
||||
$(MESON) compile -C build
|
||||
install -m644 build/bootstrapper.bin $(native_outdir)/bootstrapper.bin
|
||||
install -m644 build/loader.bin $(native_outdir)/loader.bin
|
||||
[ -f build/zymbiote.bin ] && install -m644 build/zymbiote.bin $(native_outdir)/zymbiote.bin || true
|
||||
$(MESON) setup --prefix /usr --cross-file $(crossfile) -Db_lto=true build
|
||||
DESTDIR=$(abspath build/dist) $(MESON) install -C build
|
||||
for f in build/dist/usr/share/frida-helpers/*; do \
|
||||
install -m644 $$f $(native_outdir)/; \
|
||||
done
|
||||
|
||||
bpf_targets :=
|
||||
bpf_obj := $(build_dir)/module.o
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -6,6 +6,7 @@ SECTIONS {
|
||||
KEEP(*(.text.entrypoint))
|
||||
*(.text*)
|
||||
*(.rodata*)
|
||||
*(.data*)
|
||||
}
|
||||
|
||||
.dynstr : { *(.dynstr) }
|
||||
|
||||
@@ -94,14 +94,10 @@ if host_machine.system() == 'android'
|
||||
endif
|
||||
zymbiote = shared_module('zymbiote', ['zymbiote.c'],
|
||||
name_prefix: '',
|
||||
name_suffix: 'elf',
|
||||
c_args: zymbiote_flags + extra_flags,
|
||||
link_args: extra_link_args,
|
||||
link_depends: [helper_lds],
|
||||
)
|
||||
custom_target('zymbiote-bin',
|
||||
input: [zymbiote],
|
||||
output: ['zymbiote.bin'],
|
||||
command: [objcopy, objcopy_flags, '@INPUT0@', '@OUTPUT0@'],
|
||||
install_dir: 'share' / 'frida-helpers',
|
||||
install: true,
|
||||
)
|
||||
|
||||
+155
-83
@@ -2,18 +2,28 @@
|
||||
#include <jni.h>
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
typedef struct _FridaApi FridaApi;
|
||||
typedef struct _ZymbioteContext ZymbioteContext;
|
||||
|
||||
struct _FridaApi
|
||||
struct _ZymbioteContext
|
||||
{
|
||||
char name[64];
|
||||
char socket_path[64];
|
||||
|
||||
void ** art_method_slot;
|
||||
void * payload_base;
|
||||
size_t payload_size;
|
||||
size_t payload_original_protection;
|
||||
|
||||
char * package_name;
|
||||
|
||||
int (* original_setcontext) (uid_t uid, bool is_system_server, const char * seinfo, const char * name);
|
||||
void (* original_set_argv0) (JNIEnv * env, jobject clazz, jstring name);
|
||||
|
||||
int (* mprotect) (void * addr, size_t len, int prot);
|
||||
char * (* strdup) (const char * s);
|
||||
void (* free) (void * ptr);
|
||||
int (* socket) (int domain, int type, int protocol);
|
||||
int (* connect) (int sockfd, const struct sockaddr * addr, socklen_t addrlen);
|
||||
int * (* __errno) (void);
|
||||
@@ -25,12 +35,17 @@ struct _FridaApi
|
||||
int (* raise) (int sig);
|
||||
};
|
||||
|
||||
static volatile const FridaApi frida =
|
||||
ZymbioteContext zymbiote =
|
||||
{
|
||||
.name = "/frida-zymbiote-00000000000000000000000000000000",
|
||||
.socket_path = "/frida-zymbiote-00000000000000000000000000000000",
|
||||
};
|
||||
|
||||
static int frida_stop_and_return (JNIEnv * env, jobject clazz, jstring name);
|
||||
int frida_zymbiote_replacement_setargv0 (JNIEnv * env, jobject clazz, jstring name);
|
||||
int frida_zymbiote_replacement_setcontext (uid_t uid, bool is_system_server, const char * seinfo, const char * name);
|
||||
|
||||
static void frida_wait_for_permission_to_resume (const char * package_name, bool * revert_now);
|
||||
|
||||
static int frida_stop_and_return_from_setargv0 (JNIEnv * env, jobject clazz, jstring name);
|
||||
|
||||
static int frida_get_errno (void);
|
||||
|
||||
@@ -42,19 +57,71 @@ static ssize_t frida_recv (int sockfd, void * buf, size_t len, int flags);
|
||||
__attribute__ ((section (".text.entrypoint")))
|
||||
__attribute__ ((visibility ("default")))
|
||||
int
|
||||
frida_zymbiote_replacement_set_argv0 (JNIEnv * env, jobject clazz, jstring name)
|
||||
frida_zymbiote_replacement_setcontext (uid_t uid, bool is_system_server, const char * seinfo, const char * name)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = zymbiote.original_setcontext (uid, is_system_server, seinfo, name);
|
||||
if (res == -1)
|
||||
return -1;
|
||||
|
||||
if (zymbiote.package_name == NULL)
|
||||
{
|
||||
zymbiote.mprotect (zymbiote.payload_base, zymbiote.payload_size, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
zymbiote.package_name = zymbiote.strdup (name);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
__attribute__ ((section (".text.entrypoint")))
|
||||
__attribute__ ((visibility ("default")))
|
||||
int
|
||||
frida_zymbiote_replacement_setargv0 (JNIEnv * env, jobject clazz, jstring name)
|
||||
{
|
||||
const char * name_utf8;
|
||||
bool revert_now;
|
||||
|
||||
zymbiote.original_set_argv0 (env, clazz, name);
|
||||
|
||||
if (zymbiote.package_name != NULL)
|
||||
name_utf8 = zymbiote.package_name;
|
||||
else
|
||||
name_utf8 = (*env)->GetStringUTFChars (env, name, NULL);
|
||||
|
||||
frida_wait_for_permission_to_resume (name_utf8, &revert_now);
|
||||
|
||||
if (zymbiote.package_name != NULL)
|
||||
{
|
||||
zymbiote.free (zymbiote.package_name);
|
||||
zymbiote.package_name = NULL;
|
||||
zymbiote.mprotect (zymbiote.payload_base, zymbiote.payload_size, zymbiote.payload_original_protection);
|
||||
}
|
||||
else
|
||||
{
|
||||
(*env)->ReleaseStringUTFChars (env, name, name_utf8);
|
||||
}
|
||||
|
||||
if (revert_now)
|
||||
{
|
||||
__attribute__ ((musttail))
|
||||
return frida_stop_and_return_from_setargv0 (env, clazz, name);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
frida_wait_for_permission_to_resume (const char * package_name, bool * revert_now)
|
||||
{
|
||||
bool success = false;
|
||||
int fd;
|
||||
struct sockaddr_un addr;
|
||||
socklen_t addrlen;
|
||||
unsigned int name_len;
|
||||
|
||||
*frida.art_method_slot = frida.original_set_argv0;
|
||||
*revert_now = false;
|
||||
|
||||
frida.original_set_argv0 (env, clazz, name);
|
||||
|
||||
fd = frida.socket (AF_UNIX, SOCK_STREAM, 0);
|
||||
fd = zymbiote.socket (AF_UNIX, SOCK_STREAM, 0);
|
||||
if (fd == -1)
|
||||
goto beach;
|
||||
|
||||
@@ -62,15 +129,15 @@ frida_zymbiote_replacement_set_argv0 (JNIEnv * env, jobject clazz, jstring name)
|
||||
addr.sun_path[0] = '\0';
|
||||
|
||||
name_len = 0;
|
||||
for (unsigned int i = 0; i != sizeof (frida.name); i++)
|
||||
for (unsigned int i = 0; i != sizeof (zymbiote.socket_path); i++)
|
||||
{
|
||||
if (frida.name[i] == '\0')
|
||||
if (zymbiote.socket_path[i] == '\0')
|
||||
break;
|
||||
|
||||
if (1u + i >= sizeof (addr.sun_path))
|
||||
break;
|
||||
|
||||
addr.sun_path[1u + i] = frida.name[i];
|
||||
addr.sun_path[1u + i] = zymbiote.socket_path[i];
|
||||
name_len++;
|
||||
}
|
||||
|
||||
@@ -80,7 +147,6 @@ frida_zymbiote_replacement_set_argv0 (JNIEnv * env, jobject clazz, jstring name)
|
||||
goto beach;
|
||||
|
||||
{
|
||||
const char * name_utf8;
|
||||
struct
|
||||
{
|
||||
uint32_t pid;
|
||||
@@ -89,25 +155,21 @@ frida_zymbiote_replacement_set_argv0 (JNIEnv * env, jobject clazz, jstring name)
|
||||
} header;
|
||||
struct iovec iov[2];
|
||||
|
||||
name_utf8 = (*env)->GetStringUTFChars (env, name, NULL);
|
||||
|
||||
header.pid = frida.getpid ();
|
||||
header.ppid = frida.getppid ();
|
||||
header.pid = zymbiote.getpid ();
|
||||
header.ppid = zymbiote.getppid ();
|
||||
|
||||
header.package_name_len = 0;
|
||||
while (name_utf8[header.package_name_len] != '\0')
|
||||
while (package_name[header.package_name_len] != '\0')
|
||||
header.package_name_len++;
|
||||
|
||||
iov[0].iov_base = &header;
|
||||
iov[0].iov_len = sizeof (header);
|
||||
|
||||
iov[1].iov_base = (void *) name_utf8;
|
||||
iov[1].iov_base = (void *) package_name;
|
||||
iov[1].iov_len = header.package_name_len;
|
||||
|
||||
if (!frida_sendmsg_all (fd, iov, 2, MSG_NOSIGNAL))
|
||||
goto beach;
|
||||
|
||||
(*env)->ReleaseStringUTFChars (env, name, name_utf8);
|
||||
}
|
||||
|
||||
{
|
||||
@@ -117,86 +179,96 @@ frida_zymbiote_replacement_set_argv0 (JNIEnv * env, jobject clazz, jstring name)
|
||||
goto beach;
|
||||
}
|
||||
|
||||
success = true;
|
||||
*revert_now = true;
|
||||
|
||||
beach:
|
||||
if (fd != -1)
|
||||
frida.close (fd);
|
||||
|
||||
if (success)
|
||||
{
|
||||
__attribute__ ((musttail))
|
||||
return frida_stop_and_return (env, clazz, name);
|
||||
}
|
||||
|
||||
return 0;
|
||||
zymbiote.close (fd);
|
||||
}
|
||||
|
||||
__attribute__ ((naked, noinline))
|
||||
static int
|
||||
frida_stop_and_return (JNIEnv * env, jobject clazz, jstring name)
|
||||
{
|
||||
#if defined (__i386__)
|
||||
__asm__ __volatile__ (
|
||||
"movl $%c[sig], 4(%%esp)\n"
|
||||
|
||||
"call 1f\n"
|
||||
"1: pop %%eax\n"
|
||||
# define FRIDA_TAILCALL_TO_RAISE_SIGSTOP() \
|
||||
__asm__ __volatile__ ( \
|
||||
"movl $%c[sig], 4(%%esp)\n" \
|
||||
\
|
||||
"call 1f\n" \
|
||||
"1: pop %%eax\n" \
|
||||
\
|
||||
"addl $(zymbiote-1b), %%eax\n" \
|
||||
"movl %c[raise_off](%%eax), %%eax\n" \
|
||||
\
|
||||
"jmp *%%eax\n" \
|
||||
: \
|
||||
: [sig] "i" (SIGSTOP), \
|
||||
[raise_off] "i" (offsetof (ZymbioteContext, raise)) \
|
||||
: "eax", "memory" \
|
||||
)
|
||||
|
||||
"addl $(frida-1b), %%eax\n"
|
||||
"movl %c[raise_off](%%eax), %%eax\n"
|
||||
|
||||
"jmp *%%eax\n"
|
||||
:
|
||||
: [sig] "i" (SIGSTOP),
|
||||
[raise_off] "i" (offsetof (FridaApi, raise))
|
||||
: "eax", "memory");
|
||||
#elif defined (__x86_64__)
|
||||
__asm__ __volatile__ (
|
||||
"mov $%c[sig], %%edi\n"
|
||||
|
||||
"leaq frida(%%rip), %%r11\n"
|
||||
"movq %c[raise_off](%%r11), %%r11\n"
|
||||
# define FRIDA_TAILCALL_TO_RAISE_SIGSTOP() \
|
||||
__asm__ __volatile__ ( \
|
||||
"mov $%c[sig], %%edi\n" \
|
||||
\
|
||||
"leaq zymbiote(%%rip), %%r11\n" \
|
||||
"movq %c[raise_off](%%r11), %%r11\n" \
|
||||
\
|
||||
"jmp *%%r11\n" \
|
||||
: \
|
||||
: [sig] "i" (SIGSTOP), \
|
||||
[raise_off] "i" (offsetof (ZymbioteContext, raise)) \
|
||||
: "r11", "rdi", "memory" \
|
||||
)
|
||||
|
||||
"jmp *%%r11\n"
|
||||
:
|
||||
: [sig] "i" (SIGSTOP),
|
||||
[raise_off] "i" (offsetof (FridaApi, raise))
|
||||
: "r11", "rdi", "memory");
|
||||
#elif defined (__arm__)
|
||||
__asm__ __volatile__ (
|
||||
"mov r0, %[sig]\n"
|
||||
|
||||
"adr r12, frida\n"
|
||||
"ldr r12, [r12, %[raise_off]]\n"
|
||||
# define FRIDA_TAILCALL_TO_RAISE_SIGSTOP() \
|
||||
__asm__ __volatile__ ( \
|
||||
"mov r0, %[sig]\n" \
|
||||
\
|
||||
"adr r12, zymbiote\n" \
|
||||
"ldr r12, [r12, %[raise_off]]\n" \
|
||||
\
|
||||
"bx r12\n" \
|
||||
: \
|
||||
: [sig] "i" (SIGSTOP), \
|
||||
[raise_off] "i" (offsetof (ZymbioteContext, raise)) \
|
||||
: "r12", "memory" \
|
||||
)
|
||||
|
||||
"bx r12\n"
|
||||
:
|
||||
: [sig] "i" (SIGSTOP),
|
||||
[raise_off] "i" (offsetof (FridaApi, raise))
|
||||
: "r12", "memory");
|
||||
#elif defined (__aarch64__)
|
||||
__asm__ __volatile__ (
|
||||
"mov w0, #%[sig]\n"
|
||||
|
||||
"adrp x16, frida\n"
|
||||
"add x16, x16, :lo12:frida\n"
|
||||
"ldr x16, [x16, %[raise_off]]\n"
|
||||
# define FRIDA_TAILCALL_TO_RAISE_SIGSTOP() \
|
||||
__asm__ __volatile__ ( \
|
||||
"mov w0, #%[sig]\n" \
|
||||
\
|
||||
"adrp x16, zymbiote\n" \
|
||||
"add x16, x16, :lo12:zymbiote\n" \
|
||||
"ldr x16, [x16, %[raise_off]]\n" \
|
||||
\
|
||||
"br x16\n" \
|
||||
: \
|
||||
: [sig] "i" (SIGSTOP), \
|
||||
[raise_off] "i" (offsetof (ZymbioteContext, raise)) \
|
||||
: "x16", "memory" \
|
||||
)
|
||||
|
||||
"br x16\n"
|
||||
:
|
||||
: [sig] "i" (SIGSTOP),
|
||||
[raise_off] "i" (offsetof (FridaApi, raise))
|
||||
: "x16", "memory");
|
||||
#else
|
||||
# error Unsupported architecture
|
||||
#endif
|
||||
|
||||
__attribute__ ((naked, noinline))
|
||||
static int
|
||||
frida_stop_and_return_from_setargv0 (JNIEnv * env, jobject clazz, jstring name)
|
||||
{
|
||||
FRIDA_TAILCALL_TO_RAISE_SIGSTOP ();
|
||||
}
|
||||
|
||||
static int
|
||||
frida_get_errno (void)
|
||||
{
|
||||
return *frida.__errno ();
|
||||
return *zymbiote.__errno ();
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -204,7 +276,7 @@ frida_connect (int sockfd, const struct sockaddr * addr, socklen_t addrlen)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (frida.connect (sockfd, addr, addrlen) == 0)
|
||||
if (zymbiote.connect (sockfd, addr, addrlen) == 0)
|
||||
return 0;
|
||||
|
||||
if (frida_get_errno () == EINTR)
|
||||
@@ -219,7 +291,7 @@ frida_sendmsg (int sockfd, const struct msghdr * msg, int flags)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
ssize_t n = frida.sendmsg (sockfd, msg, flags);
|
||||
ssize_t n = zymbiote.sendmsg (sockfd, msg, flags);
|
||||
if (n != -1)
|
||||
return n;
|
||||
|
||||
@@ -283,7 +355,7 @@ frida_recv (int sockfd, void * buf, size_t len, int flags)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
ssize_t n = frida.recv (sockfd, buf, len, flags);
|
||||
ssize_t n = zymbiote.recv (sockfd, buf, len, flags);
|
||||
if (n != -1)
|
||||
return n;
|
||||
|
||||
|
||||
@@ -900,10 +900,19 @@ namespace Frida {
|
||||
}
|
||||
|
||||
if (prep.already_patched) {
|
||||
patches.apply (prep.replaced_ptr, prep.process_memory, prep.art_method_slot,
|
||||
new Bytes (prep.original_ptr));
|
||||
patches.apply (prep.replaced_setargv0_ptr, prep.process_memory, prep.setargv0_slot,
|
||||
new Bytes (prep.original_setargv0_ptr));
|
||||
} else {
|
||||
patches.apply (prep.replaced_ptr, prep.process_memory, prep.art_method_slot);
|
||||
patches.apply (prep.replaced_setargv0_ptr, prep.process_memory, prep.setargv0_slot);
|
||||
}
|
||||
|
||||
if (prep.setcontext_slot != 0) {
|
||||
if (prep.already_patched) {
|
||||
patches.apply (prep.replaced_setcontext_ptr, prep.process_memory, prep.setcontext_slot,
|
||||
new Bytes (prep.original_setcontext_ptr));
|
||||
} else {
|
||||
patches.apply (prep.replaced_setcontext_ptr, prep.process_memory, prep.setcontext_slot);
|
||||
}
|
||||
}
|
||||
|
||||
zymbiote_patches[pid] = patches;
|
||||
@@ -916,9 +925,13 @@ namespace Frida {
|
||||
public FileDescriptor process_memory;
|
||||
public bool already_patched;
|
||||
|
||||
public uint64 art_method_slot;
|
||||
public uint8[] original_ptr;
|
||||
public uint8[] replaced_ptr;
|
||||
public uint64 setargv0_slot;
|
||||
public uint8[] original_setargv0_ptr;
|
||||
public uint8[] replaced_setargv0_ptr;
|
||||
|
||||
public uint64 setcontext_slot;
|
||||
public uint8[] original_setcontext_ptr;
|
||||
public uint8[] replaced_setcontext_ptr;
|
||||
|
||||
public Bytes payload;
|
||||
public uint64 payload_base;
|
||||
@@ -952,35 +965,38 @@ namespace Frida {
|
||||
|
||||
private static ZymbiotePrepResult do_prepare_zymbiote_injection (uint pid, string server_name) throws Error, IOError {
|
||||
uint64 payload_base = 0;
|
||||
string? payload_path = null;
|
||||
int payload_original_protection = 0;
|
||||
unowned string? payload_path = null;
|
||||
uint64 payload_file_offset = 0;
|
||||
string? libc_path = null;
|
||||
string? runtime_path = null;
|
||||
Gee.List<Gum.MemoryRange?> heap_candidates = new Gee.ArrayList<Gum.MemoryRange?> ();
|
||||
unowned string? libc_path = null;
|
||||
unowned string? libselinux_path = null;
|
||||
unowned string? runtime_path = null;
|
||||
Gee.List<ProcMapsSnapshot.Mapping> heap_candidates = new Gee.ArrayList<ProcMapsSnapshot.Mapping> ();
|
||||
|
||||
var iter = ProcMapsIter.for_pid (pid);
|
||||
while (iter.next ()) {
|
||||
string path = iter.path;
|
||||
string flags = iter.flags;
|
||||
if (path.has_suffix ("/libstagefright.so") && "x" in flags) {
|
||||
var maps = ProcMapsSnapshot.from_pid (pid);
|
||||
|
||||
foreach (var m in maps) {
|
||||
unowned string path = m.path;
|
||||
if (path.has_suffix ("/libstagefright.so") && m.readable && m.executable) {
|
||||
if (payload_base == 0) {
|
||||
payload_base = iter.end_address - Gum.query_page_size ();
|
||||
payload_base = m.end - Gum.query_page_size ();
|
||||
payload_original_protection = Posix.PROT_READ | Posix.PROT_EXEC;
|
||||
if (m.writable)
|
||||
payload_original_protection |= Posix.PROT_WRITE;
|
||||
payload_path = path;
|
||||
payload_file_offset = iter.file_offset;
|
||||
payload_file_offset = m.file_offset;
|
||||
}
|
||||
} else if (path.has_suffix ("/libc.so")) {
|
||||
if (libc_path == null)
|
||||
libc_path = path;
|
||||
} else if (path.has_suffix ("/libselinux.so")) {
|
||||
if (libselinux_path == null)
|
||||
libselinux_path = path;
|
||||
} else if (path.has_suffix ("/libandroid_runtime.so")) {
|
||||
if (runtime_path == null)
|
||||
runtime_path = path;
|
||||
} else if (flags == "rw-p" && is_boot_heap (path)) {
|
||||
uint64 start = iter.start_address;
|
||||
uint64 end = iter.end_address;
|
||||
heap_candidates.add (Gum.MemoryRange () {
|
||||
base_address = start,
|
||||
size = (size_t) (end - start),
|
||||
});
|
||||
} else if (is_boot_heap (m)) {
|
||||
heap_candidates.add (m);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -993,81 +1009,182 @@ namespace Frida {
|
||||
if (heap_candidates.is_empty)
|
||||
throw new Error.NOT_SUPPORTED ("Unable to detect any VM heap candidates");
|
||||
|
||||
var libc_entry = ProcMapsSoEntry.find_by_path (pid, libc_path);
|
||||
if (libc_entry == null)
|
||||
throw new Error.NOT_SUPPORTED ("Unable to detect libc.so entry");
|
||||
var libc_mapping = maps.find_module_by_path (libc_path);
|
||||
if (libc_mapping == null)
|
||||
throw new Error.NOT_SUPPORTED ("Unable to detect mapping for %s", libc_path);
|
||||
|
||||
var runtime_entry = ProcMapsSoEntry.find_by_path (pid, runtime_path);
|
||||
if (runtime_entry == null)
|
||||
throw new Error.NOT_SUPPORTED ("Unable to detect libandroid_runtime.so entry");
|
||||
var runtime_mapping = maps.find_module_by_path (runtime_path);
|
||||
if (runtime_mapping == null)
|
||||
throw new Error.NOT_SUPPORTED ("Unable to detect mapping for %s", runtime_path);
|
||||
|
||||
Gum.ElfModule libc;
|
||||
try {
|
||||
libc = new Gum.ElfModule.from_file (libc_path);
|
||||
} catch (Gum.Error e) {
|
||||
throw new Error.NOT_SUPPORTED ("Unable to parse libc.so: %s", e.message);
|
||||
throw new Error.NOT_SUPPORTED ("Unable to parse %s: %s", libc_path, e.message);
|
||||
}
|
||||
|
||||
uint64 original_setcontext = 0;
|
||||
if (libselinux_path != null) {
|
||||
Gum.ElfModule? libselinux;
|
||||
try {
|
||||
libselinux = new Gum.ElfModule.from_file (libselinux_path);
|
||||
} catch (Gum.Error e) {
|
||||
throw new Error.NOT_SUPPORTED ("Unable to parse %s: %s", libselinux_path, e.message);
|
||||
}
|
||||
|
||||
var libselinux_mapping = maps.find_module_by_path (libselinux_path);
|
||||
if (libselinux_mapping == null)
|
||||
throw new Error.NOT_SUPPORTED ("Unable to detect mapping for %s", libselinux_path);
|
||||
|
||||
libselinux.enumerate_exports (e => {
|
||||
if (e.name == "selinux_android_setcontext") {
|
||||
original_setcontext = libselinux_mapping.start + e.address;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
Gum.ElfModule runtime;
|
||||
try {
|
||||
runtime = new Gum.ElfModule.from_file (runtime_path);
|
||||
} catch (Gum.Error e) {
|
||||
throw new Error.NOT_SUPPORTED ("Unable to parse libandroid_runtime.so: %s", e.message);
|
||||
throw new Error.NOT_SUPPORTED ("Unable to parse %s: %s", runtime_path, e.message);
|
||||
}
|
||||
|
||||
uint64 set_argv0_address = 0;
|
||||
uint64 original_setargv0 = 0;
|
||||
uint64 setcontext_slot = 0;
|
||||
runtime.enumerate_exports (e => {
|
||||
if (e.name == "_Z27android_os_Process_setArgV0P7_JNIEnvP8_jobjectP8_jstring") {
|
||||
set_argv0_address = runtime_entry.base_address + e.address;
|
||||
original_setargv0 = runtime_mapping.start + e.address;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
if (set_argv0_address == 0)
|
||||
if (original_setcontext != 0) {
|
||||
runtime.enumerate_imports (i => {
|
||||
if (i.name == "selinux_android_setcontext") {
|
||||
setcontext_slot = runtime_mapping.start + i.slot;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (original_setargv0 == 0)
|
||||
throw new Error.NOT_SUPPORTED ("Unable to locate android.os.Process.setArgV0(); please file a bug");
|
||||
|
||||
uint pointer_size = ("/lib64/" in libc_path) ? 8 : 4;
|
||||
uint pointer_size = libc.pointer_size;
|
||||
|
||||
var original_ptr = new uint8[pointer_size];
|
||||
var replaced_ptr = new uint8[pointer_size];
|
||||
|
||||
(new Buffer (new Bytes.static (original_ptr), ByteOrder.HOST, pointer_size)).write_pointer (0, set_argv0_address);
|
||||
(new Buffer (new Bytes.static (replaced_ptr), ByteOrder.HOST, pointer_size)).write_pointer (0, payload_base);
|
||||
uint64 replacement_setargv0;
|
||||
uint64 replacement_setcontext;
|
||||
Bytes payload = make_zymbiote_payload (server_name, payload_base, payload_original_protection, libc, libc_mapping,
|
||||
original_setargv0, original_setcontext, out replacement_setargv0, out replacement_setcontext);
|
||||
|
||||
var fd = open_process_memory (pid);
|
||||
|
||||
uint64 art_method_slot = 0;
|
||||
var original_setargv0_ptr = new uint8[pointer_size];
|
||||
var original_setcontext_ptr = new uint8[pointer_size];
|
||||
var replaced_setargv0_ptr = new uint8[pointer_size];
|
||||
var replaced_setcontext_ptr = new uint8[pointer_size];
|
||||
|
||||
(new Buffer (new Bytes.static (original_setargv0_ptr), ByteOrder.HOST, pointer_size))
|
||||
.write_pointer (0, original_setargv0);
|
||||
(new Buffer (new Bytes.static (original_setcontext_ptr), ByteOrder.HOST, pointer_size))
|
||||
.write_pointer (0, original_setcontext);
|
||||
(new Buffer (new Bytes.static (replaced_setargv0_ptr), ByteOrder.HOST, pointer_size))
|
||||
.write_pointer (0, replacement_setargv0);
|
||||
(new Buffer (new Bytes.static (replaced_setcontext_ptr), ByteOrder.HOST, pointer_size))
|
||||
.write_pointer (0, replacement_setcontext);
|
||||
|
||||
uint64 setargv0_slot = 0;
|
||||
bool already_patched = false;
|
||||
foreach (var candidate in heap_candidates) {
|
||||
var heap = new uint8[candidate.size];
|
||||
var n = fd.pread (heap, candidate.base_address);
|
||||
var n = fd.pread (heap, candidate.start);
|
||||
if (n != heap.length)
|
||||
throw new Error.NOT_SUPPORTED ("Short read");
|
||||
|
||||
void * p = memmem (heap, original_ptr);
|
||||
void * p = memmem (heap, original_setargv0_ptr);
|
||||
if (p == null) {
|
||||
p = memmem (heap, replaced_ptr);
|
||||
p = memmem (heap, replaced_setargv0_ptr);
|
||||
already_patched = p != null;
|
||||
}
|
||||
|
||||
if (p != null) {
|
||||
art_method_slot = candidate.base_address + ((uint8 *) p - (uint8 *) heap);
|
||||
setargv0_slot = candidate.start + ((uint8 *) p - (uint8 *) heap);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (art_method_slot == 0)
|
||||
throw new Error.NOT_SUPPORTED ("Unable to locate method slot; please file a bug");
|
||||
if (setargv0_slot == 0)
|
||||
throw new Error.NOT_SUPPORTED ("Unable to locate android.os.Process.setArgV0() slot; please file a bug");
|
||||
|
||||
return new ZymbiotePrepResult () {
|
||||
process_memory = fd,
|
||||
already_patched = already_patched,
|
||||
|
||||
setargv0_slot = setargv0_slot,
|
||||
original_setargv0_ptr = original_setargv0_ptr,
|
||||
replaced_setargv0_ptr = replaced_setargv0_ptr,
|
||||
|
||||
setcontext_slot = setcontext_slot,
|
||||
original_setcontext_ptr = original_setcontext_ptr,
|
||||
replaced_setcontext_ptr = replaced_setcontext_ptr,
|
||||
|
||||
payload = payload,
|
||||
payload_base = payload_base,
|
||||
payload_path = payload_path,
|
||||
payload_file_offset = payload_file_offset,
|
||||
};
|
||||
}
|
||||
|
||||
private static Bytes make_zymbiote_payload (string server_name, uint64 payload_base, int payload_original_protection,
|
||||
Gum.ElfModule libc, ProcMapsSnapshot.Mapping libc_mapping, uint64 original_setargv0,
|
||||
uint64 original_setcontext, out uint64 replacement_setargv0, out uint64 replacement_setcontext) {
|
||||
var pointer_size = libc.pointer_size;
|
||||
|
||||
var blob = (pointer_size == 8)
|
||||
#if ARM || ARM64
|
||||
? Frida.Data.Android.get_zymbiote_arm64_bin_blob ()
|
||||
: Frida.Data.Android.get_zymbiote_arm_bin_blob ();
|
||||
? Frida.Data.Android.get_zymbiote_arm64_elf_blob ()
|
||||
: Frida.Data.Android.get_zymbiote_arm_elf_blob ();
|
||||
#else
|
||||
? Frida.Data.Android.get_zymbiote_x86_64_bin_blob ()
|
||||
: Frida.Data.Android.get_zymbiote_x86_bin_blob ();
|
||||
? Frida.Data.Android.get_zymbiote_x86_64_elf_blob ()
|
||||
: Frida.Data.Android.get_zymbiote_x86_elf_blob ();
|
||||
#endif
|
||||
|
||||
unowned uint8[] payload_template = blob.data;
|
||||
Gum.ElfModule zymbiote;
|
||||
try {
|
||||
zymbiote = new Gum.ElfModule.from_blob (new Bytes.static (blob.data));
|
||||
} catch (Gum.Error e) {
|
||||
assert_not_reached ();
|
||||
}
|
||||
|
||||
Gum.ElfSegmentDetails? text = null;
|
||||
zymbiote.enumerate_segments (s => {
|
||||
if ((s.protection & Gum.PageProtection.EXECUTE) != 0) {
|
||||
text = s;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
assert (text != null);
|
||||
|
||||
uint64 setargv0 = 0;
|
||||
uint64 setcontext = 0;
|
||||
zymbiote.enumerate_exports (e => {
|
||||
if (e.name == "frida_zymbiote_replacement_setargv0")
|
||||
setargv0 = payload_base + (e.address - text.vm_address);
|
||||
else if (e.name == "frida_zymbiote_replacement_setcontext")
|
||||
setcontext = payload_base + (e.address - text.vm_address);
|
||||
return true;
|
||||
});
|
||||
assert (setargv0 != 0);
|
||||
assert (setcontext != 0);
|
||||
replacement_setargv0 = setargv0;
|
||||
replacement_setcontext = setcontext;
|
||||
|
||||
unowned uint8[] payload_template = blob.data[text.file_offset:text.file_offset + text.file_size];
|
||||
|
||||
void * p = memmem (payload_template, "/frida-zymbiote-00000000000000000000000000000000".data);
|
||||
assert (p != null);
|
||||
size_t data_offset = (uint8 *) p - (uint8 *) payload_template;
|
||||
@@ -1078,13 +1195,27 @@ namespace Frida {
|
||||
payload.write_string (cursor, server_name);
|
||||
cursor += 64;
|
||||
|
||||
payload.write_pointer (cursor, art_method_slot);
|
||||
payload.write_pointer (cursor, payload_base);
|
||||
cursor += pointer_size;
|
||||
|
||||
payload.write_pointer (cursor, set_argv0_address);
|
||||
payload.write_pointer (cursor, payload_template.length);
|
||||
cursor += pointer_size;
|
||||
|
||||
payload.write_pointer (cursor, payload_original_protection);
|
||||
cursor += pointer_size;
|
||||
|
||||
cursor += pointer_size;
|
||||
|
||||
payload.write_pointer (cursor, original_setcontext);
|
||||
cursor += pointer_size;
|
||||
|
||||
payload.write_pointer (cursor, original_setargv0);
|
||||
cursor += pointer_size;
|
||||
|
||||
string[] wanted = {
|
||||
"mprotect",
|
||||
"strdup",
|
||||
"free",
|
||||
"socket",
|
||||
"connect",
|
||||
"__errno",
|
||||
@@ -1105,7 +1236,7 @@ namespace Frida {
|
||||
libc.enumerate_exports (e => {
|
||||
if (index_of.has_key (e.name)) {
|
||||
int idx = index_of[e.name];
|
||||
addrs[idx] = libc_entry.base_address + e.address;
|
||||
addrs[idx] = libc_mapping.start + e.address;
|
||||
pending--;
|
||||
}
|
||||
return pending != 0;
|
||||
@@ -1117,26 +1248,16 @@ namespace Frida {
|
||||
cursor += pointer_size;
|
||||
}
|
||||
|
||||
return new ZymbiotePrepResult () {
|
||||
process_memory = fd,
|
||||
already_patched = already_patched,
|
||||
|
||||
art_method_slot = art_method_slot,
|
||||
original_ptr = original_ptr,
|
||||
replaced_ptr = replaced_ptr,
|
||||
|
||||
payload = payload.bytes,
|
||||
payload_base = payload_base,
|
||||
payload_path = payload_path,
|
||||
payload_file_offset = payload_file_offset,
|
||||
};
|
||||
return payload.bytes;
|
||||
}
|
||||
|
||||
private static bool is_boot_heap (string path) {
|
||||
private static bool is_boot_heap (ProcMapsSnapshot.Mapping m) {
|
||||
if (!m.readable || !m.writable || m.executable || m.shared)
|
||||
return false;
|
||||
return
|
||||
"boot.art" in path ||
|
||||
"boot-framework.art" in path ||
|
||||
"dalvik-LinearAlloc" in path;
|
||||
"boot.art" in m.path ||
|
||||
"boot-framework.art" in m.path ||
|
||||
"dalvik-LinearAlloc" in m.path;
|
||||
}
|
||||
|
||||
[CCode (cname = "memmem", cheader_filename = "string.h")]
|
||||
|
||||
+100
-71
@@ -8,27 +8,42 @@ namespace Frida {
|
||||
|
||||
private Gee.List<Mapping> maps = new Gee.ArrayList<Mapping> ();
|
||||
|
||||
private const uint64 VM_READ = 1;
|
||||
private const uint64 VM_WRITE = 2;
|
||||
private const uint64 VM_EXEC = 4;
|
||||
private const uint64 VM_SHARED = 8;
|
||||
|
||||
public class Mapping {
|
||||
public uint64 start;
|
||||
public uint64 end;
|
||||
public size_t size {
|
||||
get {
|
||||
return (size_t) (end - start);
|
||||
}
|
||||
}
|
||||
public uint64 file_offset;
|
||||
|
||||
public bool readable;
|
||||
public bool writable;
|
||||
public bool executable;
|
||||
public bool shared;
|
||||
|
||||
public DevId device;
|
||||
public uint64 inode;
|
||||
|
||||
public string module_id;
|
||||
public string path;
|
||||
|
||||
public uint32 start_gen;
|
||||
public uint32 end_gen;
|
||||
}
|
||||
|
||||
public static ProcMapsSnapshot from_pid (uint32 pid) throws Error {
|
||||
public static ProcMapsSnapshot from_pid (uint32 pid) {
|
||||
var snap = new ProcMapsSnapshot ();
|
||||
snap.build_from_pid (pid);
|
||||
return snap;
|
||||
}
|
||||
|
||||
private void build_from_pid (uint32 pid) throws Error {
|
||||
private void build_from_pid (uint32 pid) {
|
||||
maps.clear ();
|
||||
|
||||
var it = ProcMapsIter.for_pid (pid);
|
||||
@@ -40,10 +55,16 @@ namespace Frida {
|
||||
m.end = it.end_address;
|
||||
m.file_offset = it.file_offset;
|
||||
|
||||
string flags = it.flags;
|
||||
m.readable = flags[0] == 'r';
|
||||
m.writable = flags[1] == 'w';
|
||||
m.executable = flags[2] == 'x';
|
||||
m.shared = flags[3] == 's';
|
||||
|
||||
m.device = it.device;
|
||||
m.inode = it.inode;
|
||||
|
||||
m.module_id = normalize_module_id (it.path);
|
||||
m.path = normalize_path (it.path);
|
||||
|
||||
m.start_gen = 1;
|
||||
m.end_gen = 0;
|
||||
@@ -52,17 +73,26 @@ namespace Frida {
|
||||
}
|
||||
}
|
||||
|
||||
public void apply_create (uint32 new_gen, uint64 start, uint64 end, uint64 file_offset, DevId device, uint64 inode,
|
||||
string module_id) {
|
||||
public void apply_create (uint32 new_gen, uint64 start, uint64 end, uint64 file_offset, uint64 vm_flags, DevId device,
|
||||
uint64 inode, string path) {
|
||||
end_range_at_gen (start, end, new_gen);
|
||||
|
||||
var m = new Mapping ();
|
||||
|
||||
m.start = start;
|
||||
m.end = end;
|
||||
m.file_offset = file_offset;
|
||||
|
||||
m.readable = (vm_flags & VM_READ) != 0;
|
||||
m.writable = (vm_flags & VM_WRITE) != 0;
|
||||
m.executable = (vm_flags & VM_EXEC) != 0;
|
||||
m.shared = (vm_flags & VM_SHARED) != 0;
|
||||
|
||||
m.device = device;
|
||||
m.inode = inode;
|
||||
m.module_id = module_id;
|
||||
|
||||
m.path = path;
|
||||
|
||||
m.start_gen = new_gen;
|
||||
m.end_gen = 0;
|
||||
|
||||
@@ -108,7 +138,7 @@ namespace Frida {
|
||||
dead.file_offset = m.file_offset;
|
||||
dead.device = m.device;
|
||||
dead.inode = m.inode;
|
||||
dead.module_id = m.module_id;
|
||||
dead.path = m.path;
|
||||
dead.start_gen = m.start_gen;
|
||||
dead.end_gen = gen;
|
||||
|
||||
@@ -128,7 +158,7 @@ namespace Frida {
|
||||
dead.file_offset = m.file_offset + (start - m.start);
|
||||
dead.device = m.device;
|
||||
dead.inode = m.inode;
|
||||
dead.module_id = m.module_id;
|
||||
dead.path = m.path;
|
||||
dead.start_gen = m.start_gen;
|
||||
dead.end_gen = gen;
|
||||
|
||||
@@ -146,7 +176,7 @@ namespace Frida {
|
||||
dead.file_offset = m.file_offset + (start - m.start);
|
||||
dead.device = m.device;
|
||||
dead.inode = m.inode;
|
||||
dead.module_id = m.module_id;
|
||||
dead.path = m.path;
|
||||
dead.start_gen = m.start_gen;
|
||||
dead.end_gen = gen;
|
||||
|
||||
@@ -156,7 +186,7 @@ namespace Frida {
|
||||
right.file_offset = m.file_offset + (end - m.start);
|
||||
right.device = m.device;
|
||||
right.inode = m.inode;
|
||||
right.module_id = m.module_id;
|
||||
right.path = m.path;
|
||||
right.start_gen = m.start_gen;
|
||||
right.end_gen = 0;
|
||||
|
||||
@@ -168,13 +198,21 @@ namespace Frida {
|
||||
}
|
||||
}
|
||||
|
||||
private static string normalize_module_id (string path) {
|
||||
private static string normalize_path (string path) {
|
||||
const string suffix = " (deleted)";
|
||||
if (path.has_suffix (suffix))
|
||||
return path.substring (0, path.length - suffix.length);
|
||||
return path;
|
||||
}
|
||||
|
||||
public Gee.Iterator<Mapping> iterator () {
|
||||
return maps.iterator ();
|
||||
}
|
||||
|
||||
public Mapping? find_mapping (uint64 addr) {
|
||||
return find_mapping_at_gen (addr, gen);
|
||||
}
|
||||
|
||||
public Mapping? find_mapping_at_gen (uint64 addr, uint32 gen) {
|
||||
int lo = 0;
|
||||
int hi = maps.size - 1;
|
||||
@@ -224,92 +262,83 @@ namespace Frida {
|
||||
bool not_ended = m.end_gen == 0 || gen < m.end_gen;
|
||||
return started && not_ended;
|
||||
}
|
||||
}
|
||||
|
||||
public class ProcMapsSoEntry {
|
||||
public uint64 base_address;
|
||||
public string path;
|
||||
public DevId device;
|
||||
public uint64 inode;
|
||||
|
||||
private ProcMapsSoEntry (uint64 base_address, string path, DevId device, uint64 inode) {
|
||||
this.base_address = base_address;
|
||||
this.path = path;
|
||||
this.device = device;
|
||||
this.inode = inode;
|
||||
public Mapping? find_module_by_path (string path) {
|
||||
return find_module_by_path_at_gen (path, gen);
|
||||
}
|
||||
|
||||
public static ProcMapsSoEntry? find_by_address (uint pid, uint64 address) {
|
||||
var iter = ProcMapsIter.for_pid (pid);
|
||||
while (iter.next ()) {
|
||||
uint64 start = iter.start_address;
|
||||
uint64 end = iter.end_address;
|
||||
if (address >= start && address < end)
|
||||
return new ProcMapsSoEntry (start, iter.path, iter.device, iter.inode);
|
||||
}
|
||||
public Mapping? find_module_by_path_at_gen (string path, uint32 at_gen) {
|
||||
Mapping? best_base = null;
|
||||
int best_score = int.MIN;
|
||||
|
||||
return null;
|
||||
}
|
||||
Mapping? cur_base = null;
|
||||
uint cur_total = 0;
|
||||
uint cur_exec = 0;
|
||||
|
||||
public static ProcMapsSoEntry? find_by_path (uint pid, string path) {
|
||||
var candidates = new Gee.ArrayList<Candidate> ();
|
||||
Candidate? latest_candidate = null;
|
||||
var iter = ProcMapsIter.for_pid (pid);
|
||||
#if ANDROID
|
||||
unowned string libc_path = Gum.Process.get_libc_module ().path;
|
||||
#endif
|
||||
while (iter.next ()) {
|
||||
string current_path = iter.path;
|
||||
if (current_path == "[page size compat]")
|
||||
|
||||
for (int i = 0; i < maps.size; i++) {
|
||||
var m = maps[i];
|
||||
if (!mapping_alive_at (m, at_gen))
|
||||
continue;
|
||||
if (current_path != path) {
|
||||
latest_candidate = null;
|
||||
|
||||
unowned string mp = m.path;
|
||||
|
||||
if (mp == "[page size compat]")
|
||||
continue;
|
||||
|
||||
if (mp != path) {
|
||||
consider_candidate (ref best_base, ref best_score, cur_base, cur_total, cur_exec);
|
||||
cur_base = null;
|
||||
cur_total = 0;
|
||||
cur_exec = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
string flags = iter.flags;
|
||||
|
||||
#if ANDROID
|
||||
if (current_path == libc_path && flags[3] == 's')
|
||||
if (mp == libc_path && m.shared)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
if (iter.file_offset == 0) {
|
||||
latest_candidate = new Candidate () {
|
||||
entry = new ProcMapsSoEntry (iter.start_address, current_path, iter.device, iter.inode),
|
||||
total_ranges = 0,
|
||||
executable_ranges = 0,
|
||||
};
|
||||
candidates.add (latest_candidate);
|
||||
if (m.file_offset == 0) {
|
||||
consider_candidate (ref best_base, ref best_score, cur_base, cur_total, cur_exec);
|
||||
cur_base = m;
|
||||
cur_total = 0;
|
||||
cur_exec = 0;
|
||||
}
|
||||
|
||||
if (latest_candidate != null) {
|
||||
latest_candidate.total_ranges++;
|
||||
if (flags[2] == 'x')
|
||||
latest_candidate.executable_ranges++;
|
||||
if (cur_base != null) {
|
||||
cur_total++;
|
||||
if (m.executable)
|
||||
cur_exec++;
|
||||
}
|
||||
}
|
||||
|
||||
candidates.sort ((a, b) => b.score () - a.score ());
|
||||
consider_candidate (ref best_base, ref best_score, cur_base, cur_total, cur_exec);
|
||||
|
||||
if (candidates.is_empty)
|
||||
return null;
|
||||
|
||||
return candidates.first ().entry;
|
||||
return best_base;
|
||||
}
|
||||
|
||||
private class Candidate {
|
||||
public ProcMapsSoEntry entry;
|
||||
public uint total_ranges;
|
||||
public uint executable_ranges;
|
||||
private static void consider_candidate (ref Mapping? best_base, ref int best_score, Mapping? candidate_base, uint total,
|
||||
uint exec) {
|
||||
if (candidate_base == null)
|
||||
return;
|
||||
|
||||
public int score () {
|
||||
int result = (int) total_ranges;
|
||||
if (executable_ranges == 0)
|
||||
result = -result;
|
||||
return result;
|
||||
int score = score_candidate (total, exec);
|
||||
if (score > best_score) {
|
||||
best_score = score;
|
||||
best_base = candidate_base;
|
||||
}
|
||||
}
|
||||
|
||||
private static int score_candidate (uint total, uint exec) {
|
||||
int score = (int) total;
|
||||
if (exec == 0)
|
||||
score = -score;
|
||||
return score;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ProcMapsIter {
|
||||
|
||||
@@ -12,6 +12,7 @@ public sealed class Frida.SymbolResolver : Object {
|
||||
public uint64 end;
|
||||
|
||||
public uint64 file_offset;
|
||||
public uint64 vm_flags;
|
||||
public DevId device;
|
||||
public uint64 inode;
|
||||
public string? path;
|
||||
@@ -34,12 +35,12 @@ public sealed class Frida.SymbolResolver : Object {
|
||||
}
|
||||
|
||||
uint mod_idx;
|
||||
if (!used_index.has_key (m.module_id)) {
|
||||
if (!used_index.has_key (m.path)) {
|
||||
mod_idx = used_modules.size;
|
||||
used_index[m.module_id] = mod_idx;
|
||||
used_modules.add (m.module_id);
|
||||
used_index[m.path] = mod_idx;
|
||||
used_modules.add (m.path);
|
||||
} else {
|
||||
mod_idx = used_index[m.module_id];
|
||||
mod_idx = used_index[m.path];
|
||||
}
|
||||
|
||||
uint64 rel64 = (addr - m.start) + m.file_offset;
|
||||
@@ -92,6 +93,7 @@ public sealed class Frida.SymbolResolver : Object {
|
||||
ev.start = start;
|
||||
ev.end = end;
|
||||
ev.file_offset = file_offset;
|
||||
ev.vm_flags = vm_flags;
|
||||
ev.device = device;
|
||||
ev.inode = inode;
|
||||
ev.path = path;
|
||||
@@ -143,8 +145,8 @@ public sealed class Frida.SymbolResolver : Object {
|
||||
q.unset (next_gen);
|
||||
|
||||
if (ev.is_create) {
|
||||
string module_id = make_module_id (ev.device, ev.inode, ev.path);
|
||||
snap.apply_create (next_gen, ev.start, ev.end, ev.file_offset, ev.device, ev.inode, module_id);
|
||||
string path = make_path (ev.device, ev.inode, ev.path);
|
||||
snap.apply_create (next_gen, ev.start, ev.end, ev.file_offset, ev.vm_flags, ev.device, ev.inode, path);
|
||||
} else {
|
||||
snap.apply_destroy_range (next_gen, ev.start, ev.end);
|
||||
}
|
||||
@@ -159,7 +161,7 @@ public sealed class Frida.SymbolResolver : Object {
|
||||
cache.clear ();
|
||||
}
|
||||
|
||||
private static string make_module_id (DevId device, uint64 inode, string? path) {
|
||||
private static string make_path (DevId device, uint64 inode, string? path) {
|
||||
if (path != null)
|
||||
return path;
|
||||
|
||||
|
||||
+4
-4
@@ -38,10 +38,10 @@ if host_os == 'android' or have_droidy_backend
|
||||
input: [
|
||||
'android.resources',
|
||||
android_helper_dex,
|
||||
fs.copyfile(helpers_native_prefix / 'x86' / 'zymbiote.bin', 'zymbiote-x86.bin'),
|
||||
fs.copyfile(helpers_native_prefix / 'x86_64' / 'zymbiote.bin', 'zymbiote-x86_64.bin'),
|
||||
fs.copyfile(helpers_native_prefix / 'arm' / 'zymbiote.bin', 'zymbiote-arm.bin'),
|
||||
fs.copyfile(helpers_native_prefix / 'arm64' / 'zymbiote.bin', 'zymbiote-arm64.bin'),
|
||||
fs.copyfile(helpers_native_prefix / 'x86' / 'zymbiote.elf', 'zymbiote-x86.elf'),
|
||||
fs.copyfile(helpers_native_prefix / 'x86_64' / 'zymbiote.elf', 'zymbiote-x86_64.elf'),
|
||||
fs.copyfile(helpers_native_prefix / 'arm' / 'zymbiote.elf', 'zymbiote-arm.elf'),
|
||||
fs.copyfile(helpers_native_prefix / 'arm64' / 'zymbiote.elf', 'zymbiote-arm64.elf'),
|
||||
],
|
||||
output: [
|
||||
'frida-data-android.vapi',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[wrap-git]
|
||||
url = https://github.com/frida/frida-gum.git
|
||||
revision = bda339b66655f29b5e82277b68235addfbd8fac7
|
||||
revision = 17.7.2
|
||||
depth = 1
|
||||
|
||||
[provide]
|
||||
|
||||
Reference in new issue
Block a user