Compare commits

..
Author SHA1 Message Date
Ole André Vadla Ravnås 3f3457b249 subprojects: Prepare for release 2026-02-16 22:45:39 +01:00
Ole André Vadla Ravnås f1c0e87871 subprojects: Bump outdated 2026-02-16 22:08:06 +01:00
Ole André Vadla Ravnås 6096046b05 syscall-tracer: Decode timespec values
Recognize timespec pointer arguments and decode them into structured
values rather than emitting opaque byte arrays.

Supports both __kernel_timespec and old_timespec32 layouts.
2026-02-16 21:27:26 +01:00
Ole André Vadla Ravnås c0815c4d1a syscall-tracer: Fix a stylistic inconsistency 2026-02-16 21:24:05 +01:00
Ole André Vadla Ravnås ab42fcb1ed syscall-tracer: Remove a redundant check 2026-02-16 21:23:52 +01:00
Ole André Vadla Ravnås cd0a327a3c syscall-tracer: Fix raw attachment lifetime
The GVariant was previously created from data freed before return,
leaving it with a dangling pointer.
2026-02-16 21:01:17 +01:00
Ole André Vadla Ravnås 51ff27a08b syscall-tracer: Fix multi-attachment parsing
Fix parsing of multiple attachments by encoding how much space is
reserved for each attachment.
2026-02-16 20:56:54 +01:00
Ole André Vadla Ravnås 6b54eeb7d8 subprojects: Prepare for release 2026-02-14 10:52:09 +01:00
Ole André Vadla Ravnås 08de3d3d07 subprojects: Bump outdated 2026-02-14 10:50:25 +01:00
Ole André Vadla Ravnås 174b93cbd4 xpc-service: Drop support for redundant casts 2026-02-14 10:44:29 +01:00
Ole André Vadla Ravnås d0f8162a65 android: Fix a stylistic inconsistency 2026-02-13 22:53:59 +01:00
Ole André Vadla Ravnås a3427baeb3 subprojects: Prepare for release 2026-02-13 22:48:30 +01:00
Ole André Vadla Ravnås c792a09002 subprojects: Bump outdated 2026-02-13 22:47:31 +01:00
Ole André Vadla Ravnås 27605f7fde android: Defer spawn completion until setArgV0()
Only record the package name in selinux_android_setcontext(), and delay
contacting RoboLauncher until setArgV0(). This ensures ART is ready so
frida-java-bridge can attach to the VM.

Also refactor Zymbiote code and improve naming.
2026-02-13 22:46:03 +01:00
Ole André Vadla Ravnås ba8784fe8c subprojects: Prepare for release 2026-02-13 15:12:30 +01:00
Ole André Vadla Ravnås 0a6c2103fa subprojects: Bump outdated 2026-02-13 15:09:43 +01:00
Ole André Vadla Ravnås 14de0ef567 android: Fix spawn package name logic on new OSes
Where we should be hooking selinux_android_setcontext() to infer it,
like we used to.
2026-02-13 14:39:22 +01:00
Ole André Vadla Ravnås 4165572919 linux: Avoid repeated /proc/pid/maps parsing
By folding the ProcMapsSoEntry functionality into ProcMapsSnapshot.
2026-02-13 14:39:17 +01:00
35 changed files with 605 additions and 1138 deletions

No files matched your search

-16
View File
@@ -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)
+17 -13
View File
@@ -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 () {
+5 -6
View File
@@ -34,7 +34,6 @@ native_outdir := $(artifacts_dir)/native/$(host_arch)
bpf_outdir := $(artifacts_dir)/bpf
bpf_noarch_progs := \
activity-sampler \
softwall \
$(NULL)
bpf_arch_progs := \
syscall-tracer \
@@ -50,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.
+1
View File
@@ -6,6 +6,7 @@ SECTIONS {
KEEP(*(.text.entrypoint))
*(.text*)
*(.rodata*)
*(.data*)
}
.dynstr : { *(.dynstr) }
+1 -5
View File
@@ -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,
)
-275
View File
@@ -1,275 +0,0 @@
#include <stdbool.h>
#include <stdint.h>
#include <linux/bpf.h>
#include <bpf/bpf_core_read.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#define MAX_TARGET_TGIDS 4096
#define MAX_TARGET_UIDS 256
#define MAX_RULES 4096
#define MAX_INODE_INDEX 8192
#define MAX_AUDIT_EVENTS (1 << 20)
typedef struct _Event Event;
typedef __u16 EventType;
typedef struct _AuditEvent AuditEvent;
typedef struct _InodeKey InodeKey;
typedef struct _FileOpenRule FileOpenRule;
typedef struct _Stats Stats;
struct _Event
{
__u64 time_ns;
__u32 tgid;
__u32 tid;
EventType type;
__u16 _pad0;
};
enum _EventType
{
EVENT_TYPE_AUDIT
};
struct _AuditEvent
{
Event parent;
__u32 rule_id;
__u32 _pad0;
};
struct _InodeKey
{
__u64 dev;
__u64 ino;
};
struct _FileOpenRule
{
__u64 dev;
__u64 ino;
__s32 errno_neg;
__u32 _pad0;
};
struct _Stats
{
__u64 emitted_events;
__u64 emitted_bytes;
__u64 dropped_events;
__u64 dropped_bytes;
};
struct
{
__uint (type, BPF_MAP_TYPE_HASH);
__uint (max_entries, MAX_TARGET_TGIDS);
__type (key, __u32);
__type (value, __u8);
}
target_tgids SEC (".maps");
struct
{
__uint (type, BPF_MAP_TYPE_HASH);
__uint (max_entries, MAX_TARGET_UIDS);
__type (key, __u32);
__type (value, __u8);
}
target_uids SEC (".maps");
struct
{
__uint (type, BPF_MAP_TYPE_HASH);
__uint (max_entries, MAX_RULES);
__type (key, __u32);
__type (value, FileOpenRule);
}
rules_by_id SEC (".maps");
struct
{
__uint (type, BPF_MAP_TYPE_HASH);
__uint (max_entries, MAX_INODE_INDEX);
__type (key, InodeKey);
__type (value, __u32);
}
inode_index SEC (".maps");
struct
{
__uint (type, BPF_MAP_TYPE_RINGBUF);
__uint (max_entries, MAX_AUDIT_EVENTS);
}
audit_events SEC (".maps");
struct
{
__uint (type, BPF_MAP_TYPE_PERCPU_ARRAY);
__uint (max_entries, 1);
__type (key, __u32);
__type (value, Stats);
}
stats SEC (".maps");
typedef __u32 dev_t;
struct super_block
{
dev_t s_dev;
} __attribute__ ((preserve_access_index));
struct inode
{
struct super_block * i_sb;
unsigned long i_ino;
} __attribute__ ((preserve_access_index));
struct file
{
struct inode * f_inode;
} __attribute__ ((preserve_access_index));
static bool should_enforce_current (__u32 * out_tgid, __u32 * out_tid);
static Stats * get_ringbuf_stats (void);
static void note_emit (Stats * stats, __u64 bytes);
static void note_drop (Stats * stats, __u64 wanted_bytes);
static AuditEvent * reserve_audit_event (void);
static bool get_file_inode_key (struct file * file, InodeKey * out_key);
SEC ("lsm/file_open")
int
BPF_PROG (on_file_open, struct file * file)
{
__u32 tgid, tid;
if (!should_enforce_current (&tgid, &tid))
return 0;
InodeKey key;
if (!get_file_inode_key (file, &key))
return 0;
__u32 * rule_id = bpf_map_lookup_elem (&inode_index, &key);
if (rule_id == NULL)
return 0;
FileOpenRule * rule = bpf_map_lookup_elem (&rules_by_id, rule_id);
if (rule == NULL)
return 0;
AuditEvent * ev = reserve_audit_event ();
if (ev != NULL)
{
ev->parent.time_ns = bpf_ktime_get_ns ();
ev->parent.tgid = tgid;
ev->parent.tid = tid;
ev->parent.type = EVENT_TYPE_AUDIT;
ev->rule_id = *rule_id;
ev->_pad0 = 0;
bpf_ringbuf_submit (ev, 0);
}
return rule->errno_neg;
}
static bool
should_enforce_current (__u32 * out_tgid, __u32 * out_tid)
{
__u64 pid_tgid = bpf_get_current_pid_tgid ();
__u32 tgid = pid_tgid >> 32;
__u32 tid = (__u32) pid_tgid;
*out_tgid = tgid;
*out_tid = tid;
__u8 * tgid_enabled = bpf_map_lookup_elem (&target_tgids, &tgid);
if (tgid_enabled != NULL)
return true;
__u64 uid_gid = bpf_get_current_uid_gid ();
__u32 uid = (__u32) uid_gid;
__u8 * uid_enabled = bpf_map_lookup_elem (&target_uids, &uid);
if (uid_enabled != NULL)
return true;
return false;
}
static bool
get_file_inode_key (struct file * file, InodeKey * out_key)
{
if (file == NULL)
return false;
struct inode * inode = BPF_CORE_READ (file, f_inode);
if (inode == NULL)
return false;
out_key->dev = BPF_CORE_READ (inode, i_sb, s_dev);
out_key->ino = BPF_CORE_READ (inode, i_ino);
return true;
}
static AuditEvent *
reserve_audit_event (void)
{
void * event = bpf_ringbuf_reserve (&audit_events, sizeof (AuditEvent), 0);
Stats * stats = get_ringbuf_stats ();
if (event != NULL)
note_emit (stats, sizeof (AuditEvent));
else
note_drop (stats, sizeof (AuditEvent));
return (AuditEvent *) event;
}
static Stats *
get_ringbuf_stats (void)
{
__u32 key = 0;
return bpf_map_lookup_elem (&stats, &key);
}
static void
note_emit (Stats * stats, __u64 bytes)
{
if (stats == NULL)
return;
stats->emitted_events++;
stats->emitted_bytes += bytes;
}
static void
note_drop (Stats * stats, __u64 wanted_bytes)
{
if (stats == NULL)
return;
stats->dropped_events++;
stats->dropped_bytes += wanted_bytes;
}
char LICENSE[] SEC ("license") = "Dual BSD/GPL";
+30 -22
View File
@@ -83,7 +83,8 @@ struct _AttachmentHeader
{
AttachmentType type;
__u16 arg_index;
__u32 len;
__u16 capacity;
__u16 size;
};
enum _AttachmentType
@@ -483,8 +484,8 @@ static void fill_syscall_event (SyscallEvent * e, EventType type, __u32 tgid, __
void * ctx);
static void fill_enter_args (__u64 args[SYSCALL_NARGS], struct trace_event_raw_sys_enter * ctx);
static __u16 write_attach_str_arg (AttachmentHeader * h, __u16 arg_index, __u8 * dst, __u32 dst_cap, const void * user_str);
static __u16 write_attach_bytes_arg (AttachmentHeader * h, __u16 arg_index, __u8 * dst, __u32 dst_cap,
static void write_attach_str_arg (AttachmentHeader * h, __u16 arg_index, __u8 * dst, __u32 dst_cap, const void * user_str);
static void write_attach_bytes_arg (AttachmentHeader * h, __u16 arg_index, __u8 * dst, __u32 dst_cap,
const void * user_src, __u32 n);
static __u16 write_attach_dentry_path (AttachmentHeader * h, __u16 arg_index, __u8 * dst, __u32 dst_cap, struct file * file);
@@ -861,16 +862,17 @@ on_sys_exit (struct trace_event_raw_sys_exit * ctx)
ev->attach.type = ATTACHMENT_STRING;
ev->attach.arg_index = in->u.str_out_copy.arg_index;
ev->attach.capacity = MAX_PATH;
if (to_copy == (MAX_PATH - 1))
{
ev->attach.len = (MAX_PATH - 1) + 1;
ev->attach.size = (MAX_PATH - 1) + 1;
bpf_probe_read_user (&ev->data[0], MAX_PATH - 1, (void *) in->u.str_out_copy.user_ptr);
ev->data[MAX_PATH - 1] = '\0';
}
else
{
ev->attach.len = to_copy + 1;
ev->attach.size = to_copy + 1;
if (to_copy != 0)
bpf_probe_read_user (&ev->data[0], to_copy, (void *) in->u.str_out_copy.user_ptr);
ev->data[to_copy] = '\0';
@@ -927,7 +929,8 @@ on_sys_exit (struct trace_event_raw_sys_exit * ctx)
ev->attach.type = ATTACHMENT_BYTES;
ev->attach.arg_index = in->u.stat_out_copy.arg_index;
ev->attach.len = to_copy;
ev->attach.capacity = MAX_STAT;
ev->attach.size = to_copy;
if (to_copy != 0)
bpf_probe_read_user (&ev->data[0], to_copy, (void *) in->u.stat_out_copy.user_ptr);
@@ -988,7 +991,8 @@ on_sys_exit (struct trace_event_raw_sys_exit * ctx)
ev->attach.type = ATTACHMENT_BYTES;
ev->attach.arg_index = in->u.sock_out_copy.arg_index;
ev->attach.len = to_copy;
ev->attach.capacity = MAX_SOCK;
ev->attach.size = to_copy;
if (to_copy != 0)
bpf_probe_read_user (&ev->data[0], to_copy, (void *) in->u.sock_out_copy.user_ptr);
@@ -1225,30 +1229,35 @@ fill_enter_args (__u64 args[SYSCALL_NARGS], struct trace_event_raw_sys_enter * c
args[5] = (__u64) ctx->args[5];
}
static __u16
static void
write_attach_str_arg (AttachmentHeader * h, __u16 arg_index, __u8 * dst, __u32 dst_cap, const void * user_str)
{
h->type = ATTACHMENT_STRING;
h->arg_index = arg_index;
h->len = 0;
h->capacity = dst_cap;
long r = bpf_probe_read_user_str (dst, dst_cap, user_str);
__u32 used = (r > 0) ? (__u32) r : 0;
h->len = used;
return (__u16) used;
if (r >= 1)
{
h->size = r;
}
else
{
h->size = 1;
dst[0] = '\0';
}
}
static __u16
static void
write_attach_bytes_arg (AttachmentHeader * h, __u16 arg_index, __u8 * dst, __u32 dst_cap, const void * user_src, __u32 n)
{
h->type = ATTACHMENT_BYTES;
h->arg_index = arg_index;
h->capacity = dst_cap;
if (n == 0)
{
h->len = 0;
return 0;
h->size = 0;
return;
}
if (n > dst_cap)
@@ -1256,9 +1265,7 @@ write_attach_bytes_arg (AttachmentHeader * h, __u16 arg_index, __u8 * dst, __u32
bpf_probe_read_user (dst, n, user_src);
h->len = n;
return (__u16) n;
h->size = n;
}
static __u16
@@ -1268,7 +1275,8 @@ write_attach_dentry_path (AttachmentHeader * h, __u16 arg_index, __u8 * dst, __u
h->type = ATTACHMENT_STRING;
h->arg_index = arg_index;
h->len = 0;
h->capacity = dst_cap;
h->size = 0;
__u32 key = 0;
ScratchArea * sa = bpf_map_lookup_elem (&scratch_area, &key);
@@ -1370,7 +1378,7 @@ flush:
if (n != 0)
bpf_probe_read_kernel (dst, n, b->buf);
h->len = n;
h->size = n;
return (__u16) n;
}
+155 -83
View File
@@ -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;
+279 -332
View File
@@ -405,9 +405,6 @@ namespace Frida {
if (protocol == "syscall-trace")
return new SyscallTraceServiceSession ();
if (protocol == "softwall")
return new SoftwallServiceSession ();
throw new Error.NOT_SUPPORTED ("Unsupported service address");
}
@@ -903,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;
@@ -919,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;
@@ -955,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);
}
}
@@ -996,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;
@@ -1081,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",
@@ -1108,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;
@@ -1120,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")]
@@ -2057,13 +2175,16 @@ namespace Frida {
uint32 idx = h->arg_index;
assert (idx < nargs);
var len = h->len;
assert (a + len <= payload_end);
var capacity = h->capacity;
assert (a + capacity <= payload_end);
Variant v = decode_attachment_value (type, sig, idx, (SyscallTracer.AttachmentType) h->type, a, len);
var size = h->size;
assert (a + size <= payload_end);
Variant v = decode_attachment_value (type, sig, idx, (SyscallTracer.AttachmentType) h->type, a, size);
attachments.add_value (new Variant.tuple ({ idx, new Variant.variant (v) }));
a += len;
a += capacity;
}
Variant args_v;
@@ -2112,23 +2233,44 @@ namespace Frida {
case SyscallTracer.AttachmentType.STRING:
return (string) data;
case SyscallTracer.AttachmentType.BYTES: {
if (arg_type != null && arg_type == "struct sockaddr *") {
Variant? sa = try_decode_sockaddr (data, len);
if (sa != null)
return sa;
if (arg_type != null) {
Variant? v = try_decode_timespec (arg_type, data, len);
if (v == null)
v = try_decode_sockaddr (arg_type, data, len);
if (v != null)
return v;
}
var b = new uint8[len];
if (len != 0)
Memory.copy (b, data, len);
return Variant.new_from_data<void> (new VariantType ("ay"), b, true);
var b = new Bytes (((uint8[]) data)[:len]);
return Variant.new_from_data (new VariantType ("ay"), b.get_data (), true, (owned) b);
}
default:
assert_not_reached ();
}
}
private static Variant? try_decode_sockaddr (uint8 * data, size_t len) {
private static Variant? try_decode_timespec (string arg_type, uint8 * data, size_t len) {
if (arg_type.has_suffix ("struct __kernel_timespec *")) {
assert (len == 2 * sizeof (int64));
var p = (int64 *) data;
return new Variant.tuple ({ p[0], p[1] });
}
if (arg_type.has_suffix ("struct old_timespec32 *")) {
assert (len == 2 * sizeof (int32));
var p = (int32 *) data;
return new Variant.tuple ({ p[0], p[1] });
}
return null;
}
private static Variant? try_decode_sockaddr (string arg_type, uint8 * data, size_t len) {
if (arg_type != "struct sockaddr *")
return null;
if (len < 2)
return null;
@@ -2169,9 +2311,6 @@ namespace Frida {
});
}
case Posix.AF_UNIX: {
if (len < 2)
return null;
var path = (char *) (data + 2);
size_t path_bytes = size_t.min (len - 2, 108);
@@ -2201,7 +2340,6 @@ namespace Frida {
return new Variant.tuple ({ "unix", (string) str });
}
default:
return null;
}
@@ -2247,267 +2385,76 @@ namespace Frida {
return null;
}
}
private sealed class SoftwallServiceSession : Object, ServiceSession {
private Softwall? wall = new Softwall ();
private const size_t MAX_BATCH_BYTES = 4U * 1024U * 1024U;
construct {
wall.events_available.connect (on_events_available);
private static string inet_ntop_to_string (int af, uint8 * src, size_t srclen) {
uint8 buf[46];
unowned string? res = Posix.inet_ntop (af, src, buf);
return (res != null) ? res : "?";
}
public async void activate (Cancellable? cancellable) throws Error, IOError {
ensure_active ();
private static uint32 resolve_uid_from_username (string name) throws Error {
unowned Posix.Passwd? pw = Posix.getpwnam (name);
if (pw == null)
throw new Error.INVALID_ARGUMENT ("Unknown user: %s", name);
return (uint32) pw.pw_uid;
}
private void ensure_active () throws Error {
if (wall == null)
throw new Error.INVALID_OPERATION ("Service is closed");
private delegate void UInt32Handler (uint32 v) throws Error;
private delegate void StringHandler (string s) throws Error;
if (wall.state == Softwall.State.STOPPED)
wall.start ();
}
private static uint32[] read_uint32_array (VariantReader reader) throws Error {
uint n = reader.count_elements ();
var arr = new uint32[n];
public async void cancel (Cancellable? cancellable) throws IOError {
if (wall == null)
return;
for (uint i = 0; i != n; i++) {
int64 v = reader.read_element (i).get_int64_value ();
if (v < 0 || v > uint32.MAX)
throw new Error.INVALID_ARGUMENT ("Value is out of range");
wall.stop ();
wall = null;
close ();
}
public async Variant request (Variant parameters, Cancellable? cancellable = null) throws Error, IOError {
ensure_active ();
var reader = new VariantReader (parameters);
string type = reader.read_member ("type").get_string_value ();
reader.end_member ();
var reply = new VariantBuilder (VariantType.VARDICT);
if (type == "read-events") {
var events = new VariantBuilder (new VariantType ("av"));
size_t total = 0;
var drain_status = wall.drain_events (ev => {
Variant item = new Variant.tuple ({
"audit",
ev->parent.time_ns,
ev->parent.tgid,
ev->parent.tid,
ev->rule_id
});
size_t item_size = (size_t) item.get_size ();
if (total != 0 && total + item_size > MAX_BATCH_BYTES)
return Softwall.EventFlow.STOP;
events.add_value (new Variant.variant (item));
total += item_size;
return Softwall.EventFlow.CONTINUE;
});
vardict_add (reply, "events", events.end ());
vardict_add (reply, "status",
(drain_status == Softwall.DrainStatus.DRAINED) ? "drained" : "more");
return reply.end ();
arr[i] = (uint32) v;
reader.end_element ();
}
if (type == "read-stats") {
var stats = wall.read_stats ();
return arr;
}
vardict_add (reply, "emitted-events", stats.emitted_events);
vardict_add (reply, "emitted-bytes", stats.emitted_bytes);
private static uint64[] read_uint64_array (VariantReader reader) throws Error {
uint n = reader.count_elements ();
var arr = new uint64[n];
vardict_add (reply, "dropped-events", stats.dropped_events);
vardict_add (reply, "dropped-bytes", stats.dropped_bytes);
return reply.end ();
for (uint i = 0; i != n; i++) {
arr[i] = reader.read_element (i).get_uint64_value ();
reader.end_element ();
}
if (type == "add-targets") {
if (reader.has_member ("pids")) {
reader.read_member ("pids");
foreach_uint32 (reader, pid => wall.add_target_tgid (pid));
reader.end_member ();
}
if (reader.has_member ("uids")) {
reader.read_member ("uids");
foreach_uint32 (reader, uid => wall.add_target_uid (uid));
reader.end_member ();
}
if (reader.has_member ("users")) {
reader.read_member ("users");
foreach_string (reader, username => {
var uid = resolve_uid_from_username (username);
wall.add_target_uid (uid);
});
reader.end_member ();
}
return reply.end ();
}
if (type == "remove-targets") {
if (reader.has_member ("pids")) {
reader.read_member ("pids");
foreach_uint32 (reader, pid => wall.remove_target_tgid (pid));
reader.end_member ();
}
if (reader.has_member ("uids")) {
reader.read_member ("uids");
foreach_uint32 (reader, uid => wall.remove_target_uid (uid));
reader.end_member ();
}
if (reader.has_member ("users")) {
reader.read_member ("users");
foreach_string (reader, username => {
var uid = resolve_uid_from_username (username);
wall.remove_target_uid (uid);
});
reader.end_member ();
}
return reply.end ();
}
if (type == "add-rule") {
reader.read_member ("rule");
reader.read_member ("when");
if (!reader.has_member ("file_open"))
throw new Error.INVALID_ARGUMENT ("Unsupported rule.when (expected file_open)");
reader.read_member ("file_open");
string path = reader.read_member ("path").get_string_value ();
reader.end_member (); /* path */
reader.end_member (); /* file_open */
reader.end_member (); /* when */
string action_str = reader.read_member ("action").get_string_value ();
reader.end_member (); /* action */
reader.end_member (); /* rule */
var action = parse_action (action_str);
var id = wall.add_file_open_rule (path, action);
vardict_add (reply, "id", id);
return reply.end ();
}
if (type == "remove-rule") {
uint32 id = (uint32) reader.read_member ("id").get_int64_value ();
reader.end_member ();
wall.remove_rule (id);
return reply.end ();
}
throw new Error.INVALID_ARGUMENT ("Unsupported request type: %s", type);
return arr;
}
private void on_events_available () {
var b = new VariantBuilder (VariantType.VARDICT);
vardict_add (b, "type", "events-available");
message (b.end ());
}
private static void foreach_uint32 (VariantReader reader, UInt32Handler cb) throws Error {
uint n = reader.count_elements ();
for (uint i = 0; i != n; i++) {
int64 v = reader.read_element (i).get_int64_value ();
if (v < 0 || v > uint32.MAX)
throw new Error.INVALID_ARGUMENT ("Value is out of range");
private static Softwall.Action parse_action (string s) throws Error {
switch (s) {
case "deny":
return Softwall.Action.DENY;
case "not-found":
return Softwall.Action.NOT_FOUND;
default:
throw new Error.INVALID_ARGUMENT ("Unsupported action: %s", s);
cb ((uint32) v);
reader.end_element ();
}
}
}
private string inet_ntop_to_string (int af, uint8 * src, size_t srclen) {
uint8 buf[46];
unowned string? res = Posix.inet_ntop (af, src, buf);
return (res != null) ? res : "?";
}
private uint32 resolve_uid_from_username (string name) throws Error {
unowned Posix.Passwd? pw = Posix.getpwnam (name);
if (pw == null)
throw new Error.INVALID_ARGUMENT ("Unknown user: %s", name);
return (uint32) pw.pw_uid;
}
private delegate void UInt32Handler (uint32 v) throws Error;
private delegate void StringHandler (string s) throws Error;
private uint32[] read_uint32_array (VariantReader reader) throws Error {
uint n = reader.count_elements ();
var arr = new uint32[n];
for (uint i = 0; i != n; i++) {
int64 v = reader.read_element (i).get_int64_value ();
if (v < 0 || v > uint32.MAX)
throw new Error.INVALID_ARGUMENT ("Value is out of range");
arr[i] = (uint32) v;
reader.end_element ();
private static void foreach_string (VariantReader reader, StringHandler cb) throws Error {
uint n = reader.count_elements ();
for (uint i = 0; i != n; i++) {
unowned string s = reader.read_element (i).get_string_value ();
cb (s);
reader.end_element ();
}
}
return arr;
}
private uint64[] read_uint64_array (VariantReader reader) throws Error {
uint n = reader.count_elements ();
var arr = new uint64[n];
for (uint i = 0; i != n; i++) {
arr[i] = reader.read_element (i).get_uint64_value ();
reader.end_element ();
private static void vardict_add (VariantBuilder b, string key, Variant val) {
b.add_value (new Variant.dict_entry (new Variant.string (key), new Variant.variant (val)));
}
return arr;
}
private void foreach_uint32 (VariantReader reader, UInt32Handler cb) throws Error {
uint n = reader.count_elements ();
for (uint i = 0; i != n; i++) {
int64 v = reader.read_element (i).get_int64_value ();
if (v < 0 || v > uint32.MAX)
throw new Error.INVALID_ARGUMENT ("Value is out of range");
cb ((uint32) v);
reader.end_element ();
}
}
private void foreach_string (VariantReader reader, StringHandler cb) throws Error {
uint n = reader.count_elements ();
for (uint i = 0; i != n; i++) {
unowned string s = reader.read_element (i).get_string_value ();
cb (s);
reader.end_element ();
}
}
private void vardict_add (VariantBuilder b, string key, Variant val) {
b.add_value (new Variant.dict_entry (new Variant.string (key), new Variant.variant (val)));
}
}
+100 -71
View File
@@ -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 {
-298
View File
@@ -1,298 +0,0 @@
public sealed class Frida.Softwall : Object {
public signal void events_available ();
public State state {
get {
return _state;
}
}
public enum State {
STOPPED,
STARTED,
}
private State _state = STOPPED;
private BpfMap? target_tgids;
private BpfMap? target_uids;
private BpfMap? rules_by_id;
private BpfMap? inode_index;
private BpfMap? stats;
private BpfRingbufReader? events_reader;
private IOChannel? events_channel;
private Source? events_source;
private Gee.Collection<BpfLink> links = new Gee.ArrayList<BpfLink> ();
private uint32 next_rule_id = 1;
protected override void dispose () {
stop ();
base.dispose ();
}
public void start () throws Error {
assert (state == STOPPED);
var obj = BpfObject.open ("softwall.elf", Frida.Data.HelperBackend.get_softwall_elf_blob ().data);
target_tgids = obj.maps.get_by_name ("target_tgids");
target_uids = obj.maps.get_by_name ("target_uids");
rules_by_id = obj.maps.get_by_name ("rules_by_id");
inode_index = obj.maps.get_by_name ("inode_index");
var events = obj.maps.get_by_name ("audit_events");
stats = obj.maps.get_by_name ("stats");
obj.prepare ();
events_reader = new BpfRingbufReader (events);
obj.load ();
foreach (var program in obj.programs) {
var link = program.attach ();
links.add (link);
}
events_channel = new IOChannel.unix_new (events.fd);
arm_events_watch ();
_state = STARTED;
}
public void stop () {
events_source?.destroy ();
events_source = null;
events_channel = null;
events_reader = null;
links.clear ();
stats = null;
inode_index = null;
rules_by_id = null;
target_uids = null;
target_tgids = null;
next_rule_id = 1;
_state = STOPPED;
}
public void add_target_tgid (uint tgid) throws Error {
target_tgids.update_u32_u8 (tgid, 1);
}
public void remove_target_tgid (uint tgid) throws Error {
target_tgids.remove_u32 (tgid);
}
public void add_target_uid (uint uid) throws Error {
target_uids.update_u32_u8 (uid, 1);
}
public void remove_target_uid (uint uid) throws Error {
target_uids.remove_u32 (uid);
}
public enum Action {
DENY,
NOT_FOUND,
}
public uint32 add_file_open_rule (string path, Action action) throws Error {
assert (state == STARTED);
uint64 dev, ino;
resolve_path_to_inode (path, out dev, out ino);
var id = next_rule_id++;
var errno_neg = map_action_to_errno (action);
var rule = FileOpenRule ();
rule.dev = dev;
rule.ino = ino;
rule.errno_neg = errno_neg;
rule._pad0 = 0;
rules_by_id.update_raw ((uint8[]) &id, (uint8[]) &rule);
var key = InodeKey ();
key.dev = dev;
key.ino = ino;
inode_index.update_raw ((uint8[]) &key, (uint8[]) &id);
return id;
}
public void remove_rule (uint32 id) throws Error {
assert (state == STARTED);
var rule = FileOpenRule ();
try {
rules_by_id.lookup_raw ((uint8[]) &id, (uint8[]) &rule);
} catch (Error e) {
throw new Error.INVALID_ARGUMENT ("Unknown rule id: %u".printf (id));
}
var key = InodeKey ();
key.dev = rule.dev;
key.ino = rule.ino;
try {
inode_index.remove_raw ((uint8[]) &key);
} catch (Error e) {
}
rules_by_id.remove_u32 (id);
}
public DrainStatus drain_events (AuditEventHandler on_event) {
var status = events_reader.drain (payload => {
assert (payload.length >= sizeof (AuditEvent));
var e = (AuditEvent *) payload;
return (on_event (e) == CONTINUE)
? BpfRingbufReader.RecordAction.CONTINUE
: BpfRingbufReader.RecordAction.STOP;
});
if (status == DRAINED)
arm_events_watch ();
return (status == DRAINED)
? DrainStatus.DRAINED
: DrainStatus.STOPPED;
}
public enum DrainStatus {
DRAINED,
STOPPED,
}
public delegate EventFlow AuditEventHandler (AuditEvent * ev);
public enum EventFlow {
CONTINUE,
STOP,
}
private void arm_events_watch () {
if (events_source != null)
return;
var src = new IOSource (events_channel, IOCondition.IN);
var state = new AuditEventsWatchState (this);
src.set_callback (state.on_ready);
src.attach (MainContext.get_thread_default ());
events_source = src;
}
private class AuditEventsWatchState : Object {
public unowned Softwall wall;
public AuditEventsWatchState (Softwall wall) {
this.wall = wall;
}
public bool on_ready (IOChannel ch, IOCondition cond) {
wall.on_events_readable ();
return Source.REMOVE;
}
}
private void on_events_readable () {
events_source?.destroy ();
events_source = null;
events_available ();
}
public Stats read_stats () throws Error {
Stats total = Stats ();
uint32 key = 0;
stats.foreach_percpu_value<Stats?> ((uint8[]) &key, (cpu, s) => {
total.emitted_events += s.emitted_events;
total.emitted_bytes += s.emitted_bytes;
total.dropped_events += s.dropped_events;
total.dropped_bytes += s.dropped_bytes;
});
return total;
}
private static int32 map_action_to_errno (Action action) {
switch (action) {
case Action.NOT_FOUND:
return -Posix.ENOENT;
case Action.DENY:
default:
return -Posix.EACCES;
}
}
private static void resolve_path_to_inode (string path, out uint64 dev, out uint64 ino) throws Error {
Posix.Stat st;
if (Posix.stat (path, out st) != 0)
throw new Error.INVALID_ARGUMENT ("Unable to stat path: %s", path);
dev = (uint64) st.st_dev;
ino = (uint64) st.st_ino;
}
public struct Event {
public uint64 time_ns;
public uint32 tgid;
public uint32 tid;
public uint16 type;
public uint16 _pad0;
}
public enum EventType {
AUDIT
}
public struct AuditEvent {
public Event parent;
public uint32 rule_id;
public uint32 _pad0;
}
public struct InodeKey {
public uint64 dev;
public uint64 ino;
}
private struct FileOpenRule {
public uint64 dev;
public uint64 ino;
public int32 errno_neg;
public uint32 _pad0;
}
public struct Stats {
public uint64 emitted_events;
public uint64 emitted_bytes;
public uint64 dropped_events;
public uint64 dropped_bytes;
}
}
+9 -7
View File
@@ -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;
+2 -1
View File
@@ -321,7 +321,8 @@ public sealed class Frida.SyscallTracer : Object {
public struct AttachmentHeader {
public uint16 type;
public uint16 arg_index;
public uint32 len;
public uint16 capacity;
public uint16 size;
}
public enum AttachmentType {
+5 -8
View File
@@ -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',
@@ -333,7 +333,6 @@ if have_local_backend
'linux' / 'frida-helper-types.vala',
'linux' / 'activity-sampler.vala',
'linux' / 'syscall-tracer.vala',
'linux' / 'softwall.vala',
'linux' / 'symbol-resolver.vala',
'linux' / 'proc-maps.vala',
]
@@ -363,9 +362,8 @@ if have_local_backend
'linux' / 'frida-helper-backend.resources',
helpers_native_dir / 'bootstrapper.bin',
helpers_native_dir / 'loader.bin',
helpers_bpf_noarch_dir / 'activity-sampler.elf',
helpers_bpf_noarch_dir / 'activity-sampler.elf',
helpers_bpf_arch_dir / 'syscall-tracer.elf',
helpers_bpf_noarch_dir / 'softwall.elf',
],
output: [
'frida-data-helper-backend.vapi',
@@ -381,7 +379,6 @@ if have_local_backend
'@INPUT2@',
'@INPUT3@',
'@INPUT4@',
'@INPUT5@',
],
)
helper_backend_sources += [helper_backend_data]
+1 -1
View File
@@ -1,6 +1,6 @@
[wrap-git]
url = https://github.com/frida/frida-gum.git
revision = bda339b66655f29b5e82277b68235addfbd8fac7
revision = 17.7.3
depth = 1
[provide]