- Apply patch.
- Build the helper blob, e.g.:
make -C src/linux/helpers FRIDA_HOST=android-x86_64
Last active
January 23, 2026 22:52
-
-
Save oleavr/0788840e8f33bd1888a4450540cfbc58 to your computer and use it in GitHub Desktop.
How to debug zymbiote.c
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| diff --git a/src/linux/helpers/zymbiote.c b/src/linux/helpers/zymbiote.c | |
| index bffe8bde..8f3d55fc 100644 | |
| --- a/src/linux/helpers/zymbiote.c | |
| +++ b/src/linux/helpers/zymbiote.c | |
| @@ -2,6 +2,7 @@ | |
| #include <jni.h> | |
| #include <signal.h> | |
| #include <stdbool.h> | |
| +#include <android/log.h> | |
| #include <sys/socket.h> | |
| #include <sys/un.h> | |
| @@ -23,6 +24,7 @@ struct _FridaApi | |
| ssize_t (* recv) (int sockfd, void * buf, size_t len, int flags); | |
| int (* close) (int fd); | |
| int (* raise) (int sig); | |
| + int (* __android_log_print) (int prio, const char * tag, const char * fmt, ...); | |
| }; | |
| static volatile const FridaApi frida = | |
| @@ -50,13 +52,18 @@ frida_zymbiote_replacement_set_argv0 (JNIEnv * env, jobject clazz, jstring name) | |
| socklen_t addrlen; | |
| unsigned int name_len; | |
| + frida.__android_log_print (ANDROID_LOG_INFO, "Frida", "Zymbiote speaking"); | |
| + | |
| *frida.art_method_slot = frida.original_set_argv0; | |
| frida.original_set_argv0 (env, clazz, name); | |
| fd = frida.socket (AF_UNIX, SOCK_STREAM, 0); | |
| if (fd == -1) | |
| + { | |
| + frida.__android_log_print (ANDROID_LOG_INFO, "Frida", "socket() failed"); | |
| goto beach; | |
| + } | |
| addr.sun_family = AF_UNIX; | |
| addr.sun_path[0] = '\0'; | |
| @@ -77,7 +84,10 @@ frida_zymbiote_replacement_set_argv0 (JNIEnv * env, jobject clazz, jstring name) | |
| addrlen = (socklen_t) (offsetof (struct sockaddr_un, sun_path) + 1u + name_len); | |
| if (frida_connect (fd, (const struct sockaddr *) &addr, addrlen) == -1) | |
| + { | |
| + frida.__android_log_print (ANDROID_LOG_INFO, "Frida", "connect() failed"); | |
| goto beach; | |
| + } | |
| { | |
| const char * name_utf8; | |
| @@ -104,8 +114,14 @@ frida_zymbiote_replacement_set_argv0 (JNIEnv * env, jobject clazz, jstring name) | |
| iov[1].iov_base = (void *) name_utf8; | |
| iov[1].iov_len = header.package_name_len; | |
| + frida.__android_log_print (ANDROID_LOG_INFO, "Frida", "Sending hello with pid=%u ppid=%u package_name=\"%s\"", | |
| + header.pid, header.ppid, name_utf8); | |
| + | |
| if (!frida_sendmsg_all (fd, iov, 2, MSG_NOSIGNAL)) | |
| + { | |
| + frida.__android_log_print (ANDROID_LOG_INFO, "Frida", "sendmsg() failed"); | |
| goto beach; | |
| + } | |
| (*env)->ReleaseStringUTFChars (env, name, name_utf8); | |
| } | |
| @@ -114,12 +130,17 @@ frida_zymbiote_replacement_set_argv0 (JNIEnv * env, jobject clazz, jstring name) | |
| uint8_t rx; | |
| if (frida_recv (fd, &rx, 1, 0) != 1) | |
| + { | |
| + frida.__android_log_print (ANDROID_LOG_INFO, "Frida", "recv() failed"); | |
| goto beach; | |
| + } | |
| } | |
| success = true; | |
| beach: | |
| + frida.__android_log_print (ANDROID_LOG_INFO, "Frida", "beach reached => fd=%d success=%s", fd, success ? "true" : "false"); | |
| + | |
| if (fd != -1) | |
| frida.close (fd); | |
| diff --git a/src/linux/linux-host-session.vala b/src/linux/linux-host-session.vala | |
| index db4c078c..9bfff34f 100644 | |
| --- a/src/linux/linux-host-session.vala | |
| +++ b/src/linux/linux-host-session.vala | |
| @@ -981,6 +981,12 @@ namespace Frida { | |
| if (runtime_entry == null) | |
| throw new Error.NOT_SUPPORTED ("Unable to detect libandroid_runtime.so entry"); | |
| + var liblog_entry = ProcMapsSoEntry.find_by_path (pid, "/system/lib64/liblog.so"); | |
| + if (liblog_entry == null) | |
| + liblog_entry = ProcMapsSoEntry.find_by_path (pid, "/system/lib/liblog.so"); | |
| + if (liblog_entry == null) | |
| + throw new Error.NOT_SUPPORTED ("Unable to detect liblog.so entry"); | |
| + | |
| Gum.ElfModule libc; | |
| try { | |
| libc = new Gum.ElfModule.from_file (libc_path); | |
| @@ -995,6 +1001,13 @@ namespace Frida { | |
| throw new Error.NOT_SUPPORTED ("Unable to parse libandroid_runtime.so: %s", e.message); | |
| } | |
| + Gum.ElfModule liblog; | |
| + try { | |
| + liblog = new Gum.ElfModule.from_file (liblog_entry.path); | |
| + } catch (Gum.Error e) { | |
| + throw new Error.NOT_SUPPORTED ("Unable to parse liblog.so: %s", e.message); | |
| + } | |
| + | |
| uint64 set_argv0_address = 0; | |
| runtime.enumerate_exports (e => { | |
| if (e.name == "_Z27android_os_Process_setArgV0P7_JNIEnvP8_jobjectP8_jstring") { | |
| @@ -1097,6 +1110,15 @@ namespace Frida { | |
| cursor += pointer_size; | |
| } | |
| + liblog.enumerate_exports (e => { | |
| + if (e.name == "__android_log_print") { | |
| + payload.write_pointer (cursor, liblog_entry.base_address + e.address); | |
| + cursor += pointer_size; | |
| + return false; | |
| + } | |
| + return true; | |
| + }); | |
| + | |
| return new ZymbiotePrepResult () { | |
| process_memory = fd, | |
| already_patched = already_patched, | |
| @@ -1140,7 +1162,10 @@ namespace Frida { | |
| private async void handle_zymbiote_connection (ZymbioteConnection connection) { | |
| try { | |
| + printerr ("[handle_zymbiote_connection %p] >>>\n", connection); | |
| var hello = yield connection.read_hello (io_cancellable); | |
| + printerr ("[handle_zymbiote_connection %p]\tGot hello with pid=%u ppid=%u package_name=\"%s\"\n", | |
| + connection, hello.pid, hello.ppid, hello.package_name); | |
| connection.patches_to_revert = zymbiote_patches[hello.ppid]; | |
| @@ -1148,20 +1173,26 @@ namespace Frida { | |
| Promise<uint> spawn_request; | |
| if (spawn_requests.unset (hello.package_name, out spawn_request)) { | |
| + printerr ("[handle_zymbiote_connection %p]\t Matches spawn request\n", connection); | |
| spawn_request.resolve (hello.pid); | |
| needs_resume = true; | |
| } else if (spawn_gating_enabled) { | |
| + printerr ("[handle_zymbiote_connection %p]\t Delegating to spawn gating\n", connection); | |
| var spawn_info = HostSpawnInfo (hello.pid, hello.package_name); | |
| pending_spawn[hello.pid] = spawn_info; | |
| spawn_added (spawn_info); | |
| needs_resume = true; | |
| + } else { | |
| + printerr ("[handle_zymbiote_connection %p]\t Ignoring this one (resuming right away)\n", connection); | |
| } | |
| if (needs_resume) | |
| zymbiote_connections[hello.pid] = connection; | |
| else | |
| connection.resume.begin (io_cancellable); | |
| + printerr ("[handle_zymbiote_connection %p] <<<\n", connection); | |
| } catch (GLib.Error e) { | |
| + printerr ("[handle_zymbiote_connection %p] <<< Oops: %s\n", connection, e.message); | |
| } | |
| } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment