├── .gitignore ├── agent.version ├── victim.c ├── COPYING ├── agent.c ├── inject.c ├── README.md └── Makefile /.gitignore: -------------------------------------------------------------------------------- 1 | /bin/ 2 | /ext/ 3 | -------------------------------------------------------------------------------- /agent.version: -------------------------------------------------------------------------------- 1 | EXAMPLE_AGENT_1.0 { 2 | global: 3 | example_agent_main; 4 | 5 | local: 6 | *; 7 | }; 8 | -------------------------------------------------------------------------------- /victim.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int 6 | main (int argc, char * argv[]) 7 | { 8 | printf ("Victim running with PID %d\n", getpid ()); 9 | 10 | while (1) 11 | { 12 | int fd; 13 | 14 | fd = open ("/etc/hosts", O_RDONLY); 15 | if (fd != -1) 16 | close (fd); 17 | 18 | fd = open ("/etc/passwd", O_RDONLY); 19 | if (fd != -1) 20 | close (fd); 21 | 22 | sleep (1); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /agent.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static int replacement_open (const char * path, int oflag, ...); 5 | 6 | void 7 | example_agent_main (const gchar * data, gboolean * stay_resident) 8 | { 9 | GumInterceptor * interceptor; 10 | 11 | /* We don't want to our library to be unloaded after we return. */ 12 | *stay_resident = TRUE; 13 | 14 | gum_init_embedded (); 15 | 16 | g_printerr ("example_agent_main()\n"); 17 | 18 | interceptor = gum_interceptor_obtain (); 19 | 20 | /* Transactions are optional but improve performance with multiple hooks. */ 21 | gum_interceptor_begin_transaction (interceptor); 22 | 23 | gum_interceptor_replace (interceptor, 24 | (gpointer) gum_module_find_export_by_name (NULL, "open"), replacement_open, NULL); 25 | /* 26 | * ^ 27 | * | 28 | * This is using replace(), but there's also attach() which can be used to hook 29 | * functions without any knowledge of argument types, calling convention, etc. 30 | * It can even be used to put a probe in the middle of a function. 31 | */ 32 | 33 | gum_interceptor_end_transaction (interceptor); 34 | } 35 | 36 | static int 37 | replacement_open (const char * path, int oflag, ...) 38 | { 39 | g_printerr ("open(\"%s\", 0x%x)\n", path, oflag); 40 | 41 | return open (path, oflag); 42 | } 43 | -------------------------------------------------------------------------------- /inject.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int 9 | main (int argc, char * argv[]) 10 | { 11 | int result = 0; 12 | const char * path = "/data/local/tmp/android-inject-example/agent.so"; 13 | const char * context = "u:object_r:frida_file:s0"; 14 | FridaInjector * injector; 15 | int pid; 16 | GError * error; 17 | guint id; 18 | 19 | frida_init (); 20 | 21 | if (argc != 2) 22 | goto bad_usage; 23 | 24 | pid = atoi (argv[1]); 25 | if (pid <= 0) 26 | goto bad_usage; 27 | 28 | frida_selinux_patch_policy (); 29 | 30 | if (setxattr (path, XATTR_NAME_SELINUX, context, strlen (context) + 1, 0) != 0) 31 | goto setxattr_failed; 32 | 33 | injector = frida_injector_new (); 34 | 35 | error = NULL; 36 | id = frida_injector_inject_library_file_sync (injector, pid, path, "example_agent_main", "example data", NULL, &error); 37 | if (error != NULL) 38 | { 39 | g_printerr ("%s\n", error->message); 40 | g_clear_error (&error); 41 | 42 | result = 1; 43 | } 44 | 45 | frida_injector_close_sync (injector, NULL, NULL); 46 | g_object_unref (injector); 47 | 48 | frida_deinit (); 49 | 50 | return result; 51 | 52 | bad_usage: 53 | { 54 | g_printerr ("Usage: %s \n", argv[0]); 55 | frida_deinit (); 56 | return 1; 57 | } 58 | setxattr_failed: 59 | { 60 | g_printerr ("Failed to set SELinux permissions\n"); 61 | frida_deinit (); 62 | return 1; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # android-inject-custom 2 | 3 | Example showing how to use Frida for standalone injection of a custom 4 | payload. The payload is a .so that uses Gum, Frida's low-level instrumentation 5 | library, to hook `open()` and print the arguments on `stderr` every time it's 6 | called. The payload could be any shared library as long as it exports a function 7 | with the name that you specify when calling `inject_library_file_sync()`. 8 | 9 | In our example we named it `example_agent_main`. This function will also be 10 | passed a string of data, which you can use for application-specific purposes. 11 | 12 | Note that only the build system is Android-specific, so this example is 13 | easily portable to all other OSes supported by Frida. 14 | 15 | # Prerequisites 16 | 17 | - Android NDK r21 18 | - Rooted Android device 19 | 20 | # Preparing the build environment 21 | 22 | Point `$ANDROID_NDK_ROOT` to your NDK path. 23 | 24 | # Running 25 | 26 | ```sh 27 | $ make 28 | ``` 29 | 30 | This will build the injector, the payload, and an example program you 31 | can inject the payload into to easily observe the results. 32 | 33 | Next copy the `bin/` directory somewhere on your Android device, and in one 34 | terminal adb shell into your device and launch the `victim` binary: 35 | 36 | ```sh 37 | $ ./victim 38 | Victim running with PID 1303 39 | ``` 40 | 41 | Then in another terminal change directory to where the `inject` binary 42 | is and run it: 43 | 44 | ```sh 45 | $ ./inject 1303 46 | $ 47 | ``` 48 | 49 | You should now see a message printed by the `victim` process every time 50 | `open()` is called. 51 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | host_arch := arm64 2 | host_compiler_triplet := aarch64-linux-android21- 3 | host_tool_triplet := aarch64-linux-android- 4 | host_cflags := 5 | host_ldflags := -landroid 6 | 7 | ndk_toolchain_bindir := $(ANDROID_NDK_ROOT)/toolchains/llvm/prebuilt/$(shell uname -s | tr '[A-Z]' '[a-z]')-$(shell uname -m)/bin 8 | 9 | CC := $(ndk_toolchain_bindir)/$(host_compiler_triplet)clang 10 | CFLAGS := -DANDROID -Os -Wall -fPIC -ffunction-sections -fdata-sections $(host_cflags) 11 | LDFLAGS := -fuse-ld=gold -Wl,--icf=all -Wl,--gc-sections -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now $(host_ldflags) 12 | STRIP := $(ndk_toolchain_bindir)/$(host_tool_triplet)strip --strip-all 13 | 14 | frida_version := 12.9.4 15 | frida_os_arch := android-$(host_arch) 16 | frida_core_devkit_url := https://github.com/frida/frida/releases/download/$(frida_version)/frida-core-devkit-$(frida_version)-$(frida_os_arch).tar.xz 17 | frida_gum_devkit_url := https://github.com/frida/frida/releases/download/$(frida_version)/frida-gum-devkit-$(frida_version)-$(frida_os_arch).tar.xz 18 | 19 | all: bin/inject bin/agent.so bin/victim 20 | 21 | deploy: bin/inject bin/agent.so bin/victim 22 | adb shell "rm -rf /data/local/tmp/android-inject-example" 23 | adb push bin/* /data/local/tmp/android-inject-example 24 | 25 | bin/inject: inject.c ext/frida-core/.stamp 26 | @mkdir -p $(@D) 27 | $(CC) -Wl,-pie $(CFLAGS) -I./ext/frida-core inject.c -o $@ -L./ext/frida-core -lfrida-core $(LDFLAGS) 28 | $(STRIP) $@ 29 | 30 | bin/agent.so: agent.c ext/frida-gum/.stamp 31 | @mkdir -p $(@D) 32 | $(CC) -shared $(CFLAGS) -I./ext/frida-gum agent.c -o $@ -L./ext/frida-gum -lfrida-gum -Wl,--version-script,agent.version $(LDFLAGS) 33 | $(STRIP) $@ 34 | 35 | bin/victim: victim.c 36 | @mkdir -p $(@D) 37 | $(CC) -Wl,-pie $(CFLAGS) victim.c -o $@ $(LDFLAGS) 38 | $(STRIP) $@ 39 | 40 | ext/frida-core/.stamp: 41 | @mkdir -p $(@D) 42 | @rm -f $(@D)/* 43 | curl -Ls $(frida_core_devkit_url) | xz -d | tar -C $(@D) -xf - 44 | @touch $@ 45 | 46 | ext/frida-gum/.stamp: 47 | @mkdir -p $(@D) 48 | @rm -f $(@D)/* 49 | curl -Ls $(frida_gum_devkit_url) | xz -d | tar -C $(@D) -xf - 50 | @touch $@ 51 | 52 | .PHONY: all deploy 53 | --------------------------------------------------------------------------------