├── .cproject ├── .gitignore ├── .project ├── Makefile ├── README.md ├── android_cpp.launch ├── appfence Debug.launch ├── doc ├── eclipse_env.png ├── initial.jpg └── ndk_path.png ├── jni ├── Android.mk ├── arm │ └── ptraceaux_more.c ├── binder_helper.c ├── binder_helper.h ├── config.h ├── file_toolkit.c ├── file_toolkit.h ├── ptraceaux.c ├── ptraceaux.h ├── sandbox_helper.c ├── sandbox_helper.h ├── test.c ├── uchar.c ├── uchar.h ├── zygote_helper.c └── zygote_helper.h └── run.bat /.cproject: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 58 | 59 | 62 | 63 | 64 | 65 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # eclipse, note that we need .project and .cproject 2 | .settings 3 | 4 | # android stuff 5 | libs/ 6 | obj/ 7 | bin/ -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | appfence 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.cdt.managedbuilder.core.genmakebuilder 10 | clean,full,incremental, 11 | 12 | 13 | ?name? 14 | 15 | 16 | 17 | org.eclipse.cdt.make.core.append_environment 18 | true 19 | 20 | 21 | org.eclipse.cdt.make.core.buildArguments 22 | 23 | 24 | 25 | org.eclipse.cdt.make.core.buildCommand 26 | ndk-build 27 | 28 | 29 | org.eclipse.cdt.make.core.cleanBuildTarget 30 | clean 31 | 32 | 33 | org.eclipse.cdt.make.core.contents 34 | org.eclipse.cdt.make.core.activeConfigSettings 35 | 36 | 37 | org.eclipse.cdt.make.core.enableAutoBuild 38 | false 39 | 40 | 41 | org.eclipse.cdt.make.core.enableCleanBuild 42 | true 43 | 44 | 45 | org.eclipse.cdt.make.core.enableFullBuild 46 | true 47 | 48 | 49 | org.eclipse.cdt.make.core.stopOnError 50 | true 51 | 52 | 53 | org.eclipse.cdt.make.core.useDefaultBuildCmd 54 | true 55 | 56 | 57 | 58 | 59 | org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder 60 | full,incremental, 61 | 62 | 63 | 64 | 65 | 66 | org.eclipse.cdt.core.cnature 67 | org.eclipse.cdt.managedbuilder.core.managedBuildNature 68 | org.eclipse.cdt.managedbuilder.core.ScannerConfigNature 69 | org.eclipse.cdt.core.ccnature 70 | 71 | 72 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # dummy Makefile 2 | # You should install android NDK and include in the PATH 3 | 4 | export PATH := $(PATH):/usr/local/android-ndk-r9 5 | 6 | all: 7 | ndk-build -B 8 | 9 | clean: 10 | ndk-build clean 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Appfence 2 | ======== 3 | 4 | # This project is obsoleted. We move on extending strace not ptrace for our desired functionalities. 5 | 6 | Appfence is an android *sandbox* that provides both traditional file/network isolation as well as Android-specific sandboxing. Appfence provides two major functionalities: 7 | * redirect files accessed by the sandboxed app. Thus the sandboxed app cannot access files belonging to the same app in normal mode. 8 | * Android API sandboxing, which is under investigation. 9 | 10 | Note: Appfence operates on system call level (ptrace-based). 11 | 12 | ## Getting started 13 | 14 | ### Eclipse + CDT + Android NDK + Android SDK 15 | The project is mainly using `Android NDK` toolchain (compilers, scripts, debuggers) for development. Also `Android SDK` is needed if the actual device is needed for development. 16 | 17 | ### Eclipse setup 18 | * We need some environment variables in Eclipse for the NDK path. Here are the pics. 19 | * First setup the Android NDK path: 20 | ![][ndk_path] 21 | * Second setup the environment variables. Note that on Windows the build script is `ndkbuild.cmd`. On Linux it is `ndkbuild`. 22 | ![][eclipse_env] 23 | * Now import the project to Eclipse, you should see include/ resolved. 24 | 25 | [ndk_path]: doc/ndk_path.png "Configure NDK path in Eclipse" 26 | [eclipse_env]: doc/eclipse_env.png "Configure Eclipse environment variables for the project" 27 | 28 | ### Building the project 29 | * There is no auto build enabled. So once the code is changed, you need to go to Run->Build All. 30 | * Make sure NDK build works fine and no errors pop up (in best case, no warnings too). 31 | 32 | ### Testing (Run) 33 | * The testng can be done in an emulated device or an actual device. An external tool is provided to upload the executable and launch it. The launch configuration is `appfence cpp.launch`, which in turns calls the `run.bat` script. 34 | 35 | ### Debugging 36 | * The GDB way will come soon 37 | 38 | ### Adding src files 39 | * The `Android.mk` in the jni folder is the build script, which is straightforward. Everytime you add new source files, add it to this makefile. 40 | * The `Makefile` at the project root folder is just for non-Eclipse developers. 41 | * Note that you cannot change the `jni` folder name, which is identified by the Android build tool chain. 42 | -------------------------------------------------------------------------------- /android_cpp.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /appfence Debug.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /doc/eclipse_env.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mingyuan-xia/appfence/bd1cb724460764a443fb022920380d4560ab59ce/doc/eclipse_env.png -------------------------------------------------------------------------------- /doc/initial.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mingyuan-xia/appfence/bd1cb724460764a443fb022920380d4560ab59ce/doc/initial.jpg -------------------------------------------------------------------------------- /doc/ndk_path.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mingyuan-xia/appfence/bd1cb724460764a443fb022920380d4560ab59ce/doc/ndk_path.png -------------------------------------------------------------------------------- /jni/Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH := $(call my-dir) 2 | 3 | include $(CLEAR_VARS) 4 | 5 | LOCAL_MODULE := appfence 6 | LOCAL_SRC_FILES := uchar.c zygote_helper.c test.c ptraceaux.c sandbox_helper.c file_toolkit.c binder_helper.c 7 | 8 | include $(BUILD_EXECUTABLE) 9 | -------------------------------------------------------------------------------- /jni/arm/ptraceaux_more.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ptraceaux.c 3 | * This header hides the details about ptrace 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "ptraceaux.h" 12 | 13 | void ptrace_read_data(pid_t pid, void *buf, tracee_ptr_t addr, int nbytes) 14 | { 15 | /* standard three-variable control */ 16 | int remaining = nbytes, copy, offset = 0; 17 | char *dst = (char *)buf; 18 | tracee_ptr_t *src = addr; 19 | 20 | while (remaining > 0) { 21 | /* a tracer word */ 22 | tracer_word_t v = ptrace(PTRACE_PEEKDATA, pid, src + offset, NULL); 23 | copy = (remaining < TRACER_WORD_SIZE ? remaining : TRACER_WORD_SIZE); 24 | memcpy(dst + offset, &v, copy); 25 | offset += copy; 26 | remaining -= copy; 27 | } 28 | } 29 | 30 | int ptrace_strlen(pid_t pid, tracee_ptr_t addr) 31 | { 32 | // TODO refactoring away platform stickness 33 | int length = 0; 34 | while (1) { 35 | tracer_word_t v = ptrace(PTRACE_PEEKDATA, pid, addr + length, NULL); 36 | tracer_word_t test = 0x000000ff; 37 | for (; (test & v) != 0; test <<= 8){ 38 | length++; 39 | } 40 | if (test != 0) break; 41 | } 42 | return length; 43 | } 44 | 45 | void ptrace_write_data(pid_t pid, void *buf, tracee_ptr_t addr, int nbytes) 46 | { 47 | int remaining = nbytes, copy, offset = 0; 48 | tracee_ptr_t dst = addr; 49 | char *src = (char *)buf; 50 | while (remaining > 0) { 51 | tracer_word_t v; 52 | copy = (remaining < TRACER_WORD_SIZE ? remaining : TRACER_WORD_SIZE); 53 | if(copy < TRACER_WORD_SIZE){ 54 | /* save a few bytes beyond the scope 55 | TODO this might be problamtic 56 | when these padding bytes go accorss the page boundary to an 57 | unmapped page 58 | */ 59 | v = ptrace(PTRACE_PEEKDATA, pid, dst + offset, NULL); 60 | } 61 | memcpy(&v, (void *)(src + offset), copy); 62 | ptrace(PTRACE_POKEDATA, pid, (void *)(dst + offset), (void *)v); 63 | offset += copy; 64 | remaining -= copy; 65 | } 66 | } 67 | 68 | // ARM tool implementation 69 | 70 | #define EABI 0xef000000 71 | #define FIX_OABI 0x0ff00000 72 | #define OABI 0x0f900000 73 | #define FIX_SYS 0x000fffff 74 | 75 | long ptrace_get_syscall_nr(pid_t pid) 76 | { 77 | long scno = 0; 78 | struct pt_regs regs; 79 | ptrace(PTRACE_GETREGS, pid, NULL, ®s); 80 | scno = ptrace(PTRACE_PEEKTEXT, pid, (void *)(regs.ARM_pc - 4), NULL); 81 | if(scno == 0) { 82 | return 0; 83 | } 84 | if (scno == EABI) { 85 | scno = regs.ARM_r7; 86 | } else { 87 | if ((scno & FIX_OABI) != OABI) { 88 | return -1; 89 | } 90 | /* 91 | * Fixup the syscall number 92 | */ 93 | scno &= FIX_SYS; 94 | } 95 | return scno; 96 | } 97 | 98 | long ptrace_get_syscall_arg(pid_t pid, int n) 99 | { 100 | struct pt_regs regs; 101 | ptrace(PTRACE_GETREGS, pid, NULL, ®s); 102 | switch(n) { 103 | case 0: 104 | return regs.ARM_r0; 105 | case 1: 106 | return regs.ARM_r1; 107 | case 2: 108 | return regs.ARM_r2; 109 | case 3: 110 | return regs.ARM_r3; 111 | default: 112 | return -1; 113 | } 114 | } 115 | 116 | -------------------------------------------------------------------------------- /jni/binder_helper.c: -------------------------------------------------------------------------------- 1 | /* 2 | * binder_helper.c 3 | * implementation of binder_helper.h 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include "uchar.h" 10 | #include "binder_helper.h" 11 | #include "ptraceaux.h" 12 | #include "config.h" 13 | 14 | void binder_write_read_handler(pid_t pid); 15 | 16 | void binder_ioctl_handler(pid_t pid) 17 | { 18 | // arg1 is cmd in binder ioctl 19 | long arg1 = ptrace_get_syscall_arg(pid, 1); 20 | 21 | switch(arg1) { 22 | case BINDER_WRITE_READ: 23 | binder_write_read_handler(pid); 24 | break; 25 | default: 26 | break; 27 | } 28 | } 29 | 30 | void binder_write_read_handler(pid_t pid) 31 | { 32 | struct binder_write_read wr_buffer; 33 | // arg2 is pointer to the buffer of ioctl 34 | tracee_ptr_t arg2 = (tracee_ptr_t) ptrace_get_syscall_arg(pid, 2); 35 | 36 | ptrace_read_data(pid, &wr_buffer, arg2, sizeof(wr_buffer)); 37 | 38 | 39 | // have write command 40 | if(wr_buffer.write_size > 0) { 41 | int i = 0; 42 | uint32_t cmd; 43 | tracee_ptr_t cur = (tracee_ptr_t) (wr_buffer.write_buffer + wr_buffer.write_consumed); 44 | while((unsigned long) cur < (unsigned long) (wr_buffer.write_size + wr_buffer.write_buffer)) { 45 | /* printf("%d: ",i++); */ 46 | //read binde command from write buffer 47 | ptrace_read_data(pid, &cmd, cur, sizeof(uint32_t)); 48 | cur += sizeof(uint32_t); 49 | 50 | 51 | //depatch differen command 52 | switch(cmd){ 53 | case BC_INCREFS: 54 | case BC_ACQUIRE: 55 | case BC_RELEASE: 56 | case BC_DECREFS: 57 | case BC_FREE_BUFFER: 58 | case BC_DEAD_BINDER_DONE: 59 | cur += sizeof(uint32_t); 60 | break; 61 | case BC_INCREFS_DONE: 62 | case BC_ACQUIRE_DONE: 63 | case BC_REQUEST_DEATH_NOTIFICATION: 64 | case BC_CLEAR_DEATH_NOTIFICATION: 65 | cur += 2 * sizeof(uint32_t); 66 | break; 67 | case BC_REPLY: 68 | cur += sizeof(struct binder_transaction_data); 69 | break; 70 | case BC_TRANSACTION: { 71 | //only handle transaction 72 | struct binder_transaction_data data; 73 | ptrace_read_data(pid, &data, cur, sizeof(struct binder_transaction_data)); 74 | cur += sizeof(struct binder_transaction_data); 75 | /* if(data.code == GET_SERVICE_TRANSACTION){ */ 76 | int i; 77 | 78 | tracee_ptr_t ptr = (tracee_ptr_t)data.data.ptr.buffer + 4; 79 | 80 | // the request to service manager 81 | long len; 82 | 83 | // include/binder/parcel.cpp 84 | ptrace_read_data(pid, &len, ptr, sizeof(long)); 85 | char16_t service[len + 1]; 86 | ptrace_read_data(pid, service, ptr + sizeof(long), sizeof(char16_t) * (len + 1)); 87 | ptr +=(sizeof(long) + 2 + (len + 1) * sizeof(char16_t)); 88 | /* printf("service name: %ld ---", len); */ 89 | /* for(i = 0; i < len; i++) { */ 90 | /* printf("%c",(char)service[i]); */ 91 | /* } */ 92 | /* printf("\n"); */ 93 | 94 | // TODO: identify service base on service name and handler different service separately 95 | 96 | if(CONTENT_SANDBOX_ENABLED && strcmp12(service, ICONTENT_PROVIDER) == 0 || (strcmp12(service, IACTIVITY_MANAGER) == 0)){ //&& data.code == GET_CONTENT_PROVIDER_TRANSACTION)){ 97 | char16_t all_data[data.data_size / 2]; 98 | ptrace_read_data(pid, (void *)all_data, (tracee_ptr_t)data.data.ptr.buffer, data.data_size); 99 | int com = 0; 100 | for(i = 0; i < data.data_size / 2; i++){ 101 | if(strpreg12(&all_data[i], SANDBOX_CONTENT_PROVIDER) == 0) { 102 | com = i; 103 | strchpre12(&all_data[i], SANDBOX_CONTENT_PROVIDER_FAKE_PREFIX); 104 | } 105 | printf("%c", all_data[i]); 106 | } 107 | printf("\n"); 108 | if(com > 0){ 109 | /* for(i = 0; i < data.data_size / 2; i++){ */ 110 | /* printf("%c|", all_data[i]); */ 111 | /* } */ 112 | /* printf("\n"); */ 113 | ptrace_write_data(pid, all_data, (tracee_ptr_t) data.data.ptr.buffer, data.data_size); 114 | } 115 | } 116 | /* printf("service name: "); */ 117 | /* ptrace_read_data(pid, &len, (void *)ptr, sizeof(int)); */ 118 | /* printf("%d ---- ", len); */ 119 | /* char16_t service_name[len + 1]; */ 120 | 121 | /* } */ 122 | } 123 | break; 124 | default: 125 | printf("error: process: %d get unknow command: %d\n", pid, cmd); 126 | break; 127 | } 128 | /* printf("\n"); */ 129 | } 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /jni/binder_helper.h: -------------------------------------------------------------------------------- 1 | /* 2 | * binder_helper.h 3 | * function provide binder intercept 4 | */ 5 | 6 | #ifndef BINDER_HELPER_H_ 7 | #define BINDER_HELPER_H_ 8 | 9 | #define ISERVICE_MANAGER "android.os.IServiceManager" 10 | #define ICONTENT_PROVIDER "android.content.IContentProvider" 11 | #define ICONTENT_SERVICE "android.content.IContentService" 12 | #define IACTIVITY_MANAGER "android.app.IActivityManager" 13 | #define IPACKAGE_MANAGER "android.content.pm.IPackageManager" 14 | 15 | 16 | // copy from adroid.os.IBinder 17 | #define FIRST_CALL_TRANSACTION 0x00000001 18 | 19 | // copy from include/binder/IServiceManager.h 20 | enum{ 21 | GET_SERVICE_TRANSACTION = FIRST_CALL_TRANSACTION, 22 | CHECK_SERVICE_TRANSACTION, 23 | ADD_SERVICE_TRANSACTION, 24 | LIST_SERVICES_TRANSACTION, 25 | }; 26 | 27 | // copy from android.app.IActivityManager 28 | enum{ 29 | GET_CONTENT_PROVIDER_TRANSACTION = FIRST_CALL_TRANSACTION + 28, 30 | }; 31 | 32 | // binder ioctl handler 33 | void binder_ioctl_handler(pid_t pid); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /jni/config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * config.h 3 | * This header contains constants that alter the behavior of appfence 4 | */ 5 | 6 | #ifndef CONFIG_H_ 7 | #define CONFIG_H_ 8 | 9 | #define SANDBOX_ARCH_ARM 10 | // #define SANDBOX_ARCH_X86 11 | 12 | #define SANDBOX_ENABLED 1 13 | 14 | #define PROCESS_FILTER_ENABLED 0 15 | #define PROCESS_FILTER_PATH "/data/local/filter.cfg" 16 | 17 | #define FILE_SANDBOX_ENABLED 1 18 | #define CONTENT_SANDBOX_ENABLED 0 19 | 20 | #define SANDBOX_PATH_INTERNAL "/data/data /data/user/0" 21 | #define SANDBOX_PATH_EXTERNAL "/mnt/sdcard /sdcard /storage/sdcard" 22 | 23 | #define SANDBOX_PATH_INTERNAL_EXCLUDE "/lib" 24 | 25 | #define SANDBOX_STORAGE_PATH "/data/sandbox/" 26 | #define SANDBOX_LINK "/data/s" 27 | 28 | #define SANDBOX_CONTENT_PROVIDER "com.android.contacts" 29 | #define SANDBOX_CONTENT_PROVIDER_FAKE_PREFIX "com" 30 | 31 | #endif /* CONFIG_H_ */ 32 | 33 | -------------------------------------------------------------------------------- /jni/file_toolkit.c: -------------------------------------------------------------------------------- 1 | /* 2 | * file_toolkit.c 3 | * implementation of file_toolkit.h 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include "file_toolkit.h" 10 | 11 | 12 | int check_prefix(char* path, char* prefix_list) 13 | { 14 | char* c = prefix_list; 15 | int i = 0; 16 | int result = 1; 17 | for(; *c != 0; c++,i++){ 18 | if (result && *c == ' ') { 19 | return 1; 20 | } else if (*c == ' ' ) { 21 | i = -1; 22 | result = 1; 23 | } else if (*c != path[i]) { 24 | i = -1; 25 | result = 0; 26 | } 27 | } 28 | return result; 29 | } 30 | 31 | int check_prefix_dir(char* path, char* prefix_list) 32 | { 33 | char* c = prefix_list; 34 | int i = 0; 35 | int result = 1; 36 | int num = 0; 37 | for(; *c != 0; c++,i++){ 38 | if (result && *c == ' ') { 39 | return num; 40 | } else if (*c == ' ' ) { 41 | i = -1; 42 | result = 1; 43 | num = 0; 44 | } else if (*c != path[i]) { 45 | i = -1; 46 | result = 0; 47 | num = 0; 48 | } else if (result && path[i] == '/') { 49 | num++; 50 | } 51 | } 52 | return num; 53 | } 54 | 55 | char* get_nth_dir(char* path, int n) 56 | { 57 | if(n <= 0) 58 | return 0; 59 | 60 | int num = 0; 61 | char* result = path; 62 | while(*result != 0){ 63 | if(*result == '/'){ 64 | num++; 65 | if(num == n) 66 | return result; 67 | } 68 | result++; 69 | } 70 | return result; 71 | } 72 | 73 | int create_nth_dir(char* dir, int n, uid_t owner, gid_t group, mode_t mod) 74 | { 75 | if(n < 1) 76 | return -1; 77 | int i,len; 78 | int result = -1; 79 | len = strlen(dir); 80 | char str[len + 1]; 81 | strcpy(str, dir); 82 | int level = -1; 83 | for (i=0; i 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "ptraceaux.h" 10 | 11 | int ptrace_attach(pid_t pid) 12 | { 13 | return ptrace(PTRACE_ATTACH, pid, NULL, NULL); 14 | } 15 | 16 | int ptrace_detach(pid_t pid) 17 | { 18 | return ptrace(PTRACE_DETACH, pid, NULL, NULL); 19 | } 20 | 21 | void ptrace_setopt(pid_t pid, int opt) 22 | { 23 | ptrace(PTRACE_SETOPTIONS, pid, NULL, (void *)opt); 24 | } 25 | 26 | void ptrace_cont(pid_t pid) 27 | { 28 | ptrace(PTRACE_SYSCALL, pid, NULL, NULL); 29 | } 30 | 31 | #ifdef SANDBOX_ARCH_ARM 32 | #include "arm/ptraceaux_more.c" 33 | #endif /* ARM */ 34 | 35 | #ifdef SANDBOX_ARCH_X86 36 | #include "x86/ptraceaux_more.c" 37 | #endif /* x86 */ 38 | 39 | -------------------------------------------------------------------------------- /jni/ptraceaux.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ptraceaux.h 3 | * Provide platform-neural access to the ptrace system call 4 | */ 5 | 6 | #ifndef PTRACEAUX_H_ 7 | #define PTRACEAUX_H_ 8 | 9 | #include 10 | 11 | /* from the man page of ptrace */ 12 | #define IS_FORK_EVENT(status) (status>>8 == (SIGTRAP | (PTRACE_EVENT_FORK<<8))) 13 | #define IS_VFORK_EVENT(status) (status>>8 == (SIGTRAP | (PTRACE_EVENT_VFORK<<8))) 14 | #define IS_CLONE_EVENT(status) (status>>8 == (SIGTRAP | (PTRACE_EVENT_CLONE<<8))) 15 | #define IS_SYSCALL_EVENT(status) (WIFSTOPPED(status) && WSTOPSIG(status) & 0x80) 16 | /* #define IS_FORK_EVENT(status) (status>>16 == PTRACE_EVENT_FORK) */ 17 | /* #define IS_CLONE_EVENT(status) (status>>16 == PTRACE_EVENT_CLONE) */ 18 | 19 | /* TODO: imagine a 64-bit tracer tracing a 32-bit tracee */ 20 | typedef void *tracee_ptr_t; 21 | /* Linux boxes follow LP64, i.e., long and pointers are 64-bit, int is 32-bit 22 | * Windows boxes follow LLP64, i.e. long long and pointers are 64-bit, int and long are 32-bit 23 | * */ 24 | typedef unsigned long tracer_word_t; 25 | 26 | #define TRACER_WORD_SIZE (sizeof(tracer_word_t)) 27 | 28 | /** 29 | * Attach to a running process 30 | */ 31 | extern int ptrace_attach(pid_t pid); 32 | 33 | /** 34 | * Detach a ptraced process 35 | */ 36 | extern int ptrace_detach(pid_t pid); 37 | 38 | /** 39 | * Set the option for a ptraced process 40 | */ 41 | extern void ptrace_setopt(pid_t pid, int opt); 42 | 43 | /** 44 | * Continue the execution of tracee 45 | */ 46 | extern void ptrace_cont(pid_t pid); 47 | 48 | /* Architecture dependent */ 49 | extern void ptrace_read_data (pid_t pid, void *buf, tracee_ptr_t addr, int nbytes); 50 | extern int ptrace_strlen (pid_t pid, tracee_ptr_t addr); 51 | extern void ptrace_write_data (pid_t pid, void *buf, tracee_ptr_t addr, int nbytes); 52 | extern long ptrace_get_syscall_nr (pid_t pid); 53 | extern long ptrace_get_syscall_arg (pid_t pid, int n); 54 | 55 | #endif /* PTRACEAUX_H_ */ 56 | 57 | -------------------------------------------------------------------------------- /jni/sandbox_helper.c: -------------------------------------------------------------------------------- 1 | /* 2 | * process_helper.c 3 | * Implementation of process_helper.h 4 | */ 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "config.h" 14 | #include "sandbox_helper.h" 15 | #include "file_toolkit.h" 16 | #include "ptraceaux.h" 17 | #include "binder_helper.h" 18 | 19 | #define IS_WRITE(oflag) ((oflag & O_WRONLY) != 0 || (oflag & O_RDWR) != 0) 20 | #define DEV_BINDER "/dev/binder" 21 | 22 | //common file syscall handler 23 | void syscall_common_handler(pid_t pid, char* syscall, int flag, uid_t uid, gid_t gid); 24 | 25 | //open syscall handler 26 | void syscall_open_handler(pid_t pid, int *binder_pid, int flag, uid_t uid, gid_t gid); 27 | 28 | //ioctl syscall handler 29 | void syscall_ioctl_handler(pid_t pid, pid_t binder_pid, int flag); 30 | 31 | //setuid/gid syscall handler 32 | //return: 33 | // 0 -- do not need to trace this process 34 | // 1 -- need to trace 35 | //and the arg will be set to the argument of this syscall 36 | int syscall_setuid_gid_handler(pid_t pid, pid_t target, int is_gid, long* arg); 37 | 38 | //default syscall handler 39 | void syscall_default_handler(pid_t pid); 40 | 41 | pid_t ptrace_app_process(pid_t process_pid, int flag) 42 | { 43 | /* 44 | if (ptrace_attach(pid)) { 45 | return -1; 46 | } 47 | */ 48 | pid_t pid = process_pid; 49 | printf("%d tracing process %d\n", getpid(), process_pid); 50 | 51 | ptrace_setopt(process_pid, PTRACE_O_TRACEFORK | PTRACE_O_TRACECLONE | PTRACE_O_TRACESYSGOOD); 52 | 53 | int binder_fd = -1; 54 | int status = 0; 55 | uid_t uid; 56 | gid_t gid; 57 | 58 | 59 | /* ptrace(PTRACE_SYSCALL, pid, NULL, NULL); */ 60 | /* pid = waitpid(-1, &status, __WALL); */ 61 | /* ptrace(PTRACE_SYSCALL, pid, NULL, NULL); */ 62 | /* pid = waitpid(-1, &status, __WALL); */ 63 | while(pid > 0){ 64 | if(IS_FORK_EVENT(status) || IS_CLONE_EVENT(status)){ 65 | pid_t newpid; 66 | ptrace(PTRACE_GETEVENTMSG, pid, NULL, &newpid); 67 | /* ptrace(PTRACE_SYSCALL, newpid, NULL, NULL); */ 68 | printf("new thread %d .\n", newpid); 69 | ptrace_setopt(newpid, PTRACE_O_TRACEFORK | PTRACE_O_TRACECLONE | PTRACE_O_TRACESYSGOOD); 70 | ptrace(PTRACE_SYSCALL, pid, NULL, NULL); 71 | } else if(IS_SYSCALL_EVENT(status)){ 72 | //syscall enter 73 | long syscall_no = ptrace_get_syscall_nr(pid); 74 | switch(syscall_no) { 75 | case __NR_setuid32: 76 | if (syscall_setuid_gid_handler(pid, process_pid, 0, (long *)&uid) == 0) { 77 | printf("%d exit\n", getpid()); 78 | return -1; 79 | } else { 80 | break; 81 | } 82 | case __NR_setgid32: 83 | if (syscall_setuid_gid_handler(pid, process_pid, 1, (long *)&gid) == 0) { 84 | printf("%d exit\n", getpid()); 85 | return -1; 86 | } else { 87 | break; 88 | } 89 | case __NR_stat: 90 | syscall_common_handler(pid, "stat", flag, uid, gid); 91 | break; 92 | case __NR_stat64: 93 | syscall_common_handler(pid, "stat64", flag, uid, gid); 94 | break; 95 | /* case __NR_newstat: */ 96 | /* syscall_common_handler(pid, "newstat", flag, uid, gid); */ 97 | /* break; */ 98 | case __NR_lstat: 99 | syscall_common_handler(pid, "lstat", flag, uid, gid); 100 | break; 101 | case __NR_lstat64: 102 | syscall_common_handler(pid, "lstat64", flag, uid, gid); 103 | break; 104 | /* case __NR_newlstat: */ 105 | /* syscall_common_handler(pid, "newlstat", flag, uid, gid); */ 106 | /* break; */ 107 | case __NR_readlink: 108 | syscall_common_handler(pid, "readlink", flag, uid, gid); 109 | break; 110 | case __NR_statfs: 111 | syscall_common_handler(pid, "statfs", flag, uid, gid); 112 | break; 113 | case __NR_statfs64: 114 | syscall_common_handler(pid, "statfs64", flag, uid, gid); 115 | break; 116 | case __NR_truncate: 117 | syscall_common_handler(pid, "truncate", flag, uid, gid); 118 | break; 119 | case __NR_truncate64: 120 | syscall_common_handler(pid, "truncate64", flag, uid, gid); 121 | break; 122 | /* case __NR_utime: */ 123 | /* syscall_common_handler(pid, "utime", flag, uid, gid); */ 124 | /* break; */ 125 | case __NR_utimes: 126 | syscall_common_handler(pid, "utimes", flag, uid, gid); 127 | break; 128 | case __NR_access: 129 | syscall_common_handler(pid, "access", flag, uid, gid); 130 | break; 131 | case __NR_chdir: 132 | syscall_common_handler(pid, "chdir", flag, uid, gid); 133 | break; 134 | case __NR_chroot: 135 | syscall_common_handler(pid, "chroot", flag, uid, gid); 136 | break; 137 | case __NR_chmod: 138 | syscall_common_handler(pid, "chmod", flag, uid, gid); 139 | break; 140 | case __NR_chown: 141 | syscall_common_handler(pid, "chown", flag, uid, gid); 142 | break; 143 | case __NR_chown32: 144 | syscall_common_handler(pid, "chown32", flag, uid, gid); 145 | break; 146 | case __NR_lchown: 147 | syscall_common_handler(pid, "lchown", flag, uid, gid); 148 | break; 149 | case __NR_lchown32: 150 | syscall_common_handler(pid, "lchown32", flag, uid, gid); 151 | break; 152 | case __NR_open: 153 | syscall_open_handler(pid, &binder_fd, flag, uid, gid); 154 | break; 155 | case __NR_creat: 156 | syscall_common_handler(pid, "creat", flag, uid, gid); 157 | break; 158 | case __NR_mknod: 159 | syscall_common_handler(pid, "mknod", flag, uid, gid); 160 | break; 161 | case __NR_mkdir: 162 | syscall_common_handler(pid, "mkdir", flag, uid, gid); 163 | break; 164 | case __NR_rmdir: 165 | syscall_common_handler(pid, "rmdir", flag, uid, gid); 166 | break; 167 | case __NR_acct: 168 | syscall_common_handler(pid, "acct", flag, uid, gid); 169 | break; 170 | case __NR_uselib: 171 | syscall_common_handler(pid, "uselib", flag, uid, gid); 172 | break; 173 | //TODO: link syscall handler 174 | case __NR_unlink: 175 | syscall_common_handler(pid, "unlink", flag, uid, gid); 176 | case __NR_ioctl: 177 | syscall_ioctl_handler(pid, binder_fd, flag); 178 | break; 179 | default: 180 | ptrace(PTRACE_SYSCALL, pid, NULL, NULL); 181 | break; 182 | } 183 | 184 | } else { 185 | ptrace(PTRACE_SYSCALL, pid, NULL, NULL); 186 | } 187 | pid = waitpid(-1, &status, __WALL); 188 | } 189 | /* ptrace_detach(pid); */ 190 | printf("%d exit\n", getpid()); 191 | return -1; 192 | } 193 | 194 | 195 | /** 196 | * Handle syscalls that take a path as the first parameter 197 | */ 198 | void syscall_common_handler(pid_t pid, char* syscall, int flag, uid_t uid, gid_t gid) 199 | { 200 | tracee_ptr_t arg0 = (tracee_ptr_t) ptrace_get_syscall_arg(pid, 0); 201 | 202 | int len = ptrace_strlen(pid, arg0); 203 | char path[len + 1]; 204 | //first arg of open is path addr 205 | ptrace_read_data(pid, path, arg0, len + 1); 206 | 207 | int nth_dir; 208 | 209 | if ((flag & SANDBOX_FLAG) && FILE_SANDBOX_ENABLED && (nth_dir = check_prefix_dir(path,SANDBOX_PATH_INTERNAL)) > 0) { 210 | //internal file storage sandbox 211 | char* sub_dir = get_nth_dir(path, nth_dir + 2); 212 | if (!check_prefix(sub_dir, SANDBOX_PATH_INTERNAL_EXCLUDE)) { 213 | char new_path[len + 1]; 214 | //replace dir in path with LINK_PREFIX 215 | char* second_dir = get_nth_dir(path, nth_dir + 1); 216 | strcpy(new_path, SANDBOX_LINK); 217 | strcat(new_path, second_dir); 218 | ptrace_write_data(pid, new_path, arg0, len + 1); 219 | // create require folder 220 | create_nth_dir(new_path, 3, uid, gid, 0751); 221 | printf("pid %d %s: %s ==> new path: %s", pid, syscall, path, new_path); 222 | 223 | // return from open syscall, reset the path 224 | ptrace(PTRACE_SYSCALL, pid, NULL, NULL); 225 | pid = waitpid(pid, NULL, __WALL); 226 | 227 | ptrace_write_data(pid, path, arg0, len + 1); 228 | long result = ptrace_get_syscall_arg(pid, 0); 229 | printf(" = %ld\n", result); 230 | 231 | ptrace(PTRACE_SYSCALL, pid, NULL, NULL); 232 | return; 233 | } 234 | /* } else if ((flag & SANDBOX_FLAG) && FILE_SANDBOX_ENABLED && (nth_dir = check_prefix_dir(path,SANDBOX_PATH_EXTERNAL)) > 0) { */ 235 | /* //external file storage sandbox */ 236 | /* char new_path[len + 1]; */ 237 | /* //replace dir in path with LINK_PREFIX */ 238 | /* char* second_dir = get_nth_dir(path, nth_dir + 1); */ 239 | /* strcpy(new_path, SANDBOX_LINK); */ 240 | /* strcat(new_path, second_dir); */ 241 | /* ptrace_write_data(pid, new_path, arg0, len + 1); */ 242 | /* printf("pid %d %s: %s\n ==> new path: %s\n", pid, syscall, path, new_path); */ 243 | 244 | /* // return from open syscall, reset the path */ 245 | /* ptrace(PTRACE_SYSCALL, pid, NULL, NULL); */ 246 | /* pid = waitpid(pid, NULL, __WALL); */ 247 | 248 | /* ptrace_write_data(pid, path, arg0, len + 1); */ 249 | 250 | /* ptrace(PTRACE_SYSCALL, pid, NULL, NULL); */ 251 | /* return; */ 252 | } 253 | //default 254 | printf("pid %d %s: %s\n", pid, syscall, path); 255 | syscall_default_handler(pid); 256 | } 257 | 258 | 259 | void syscall_open_handler(pid_t pid, int *binder_fd, int flag, uid_t uid, gid_t gid) 260 | { 261 | tracee_ptr_t arg0 = (tracee_ptr_t) ptrace_get_syscall_arg(pid, 0); 262 | //arg1 is oflag 263 | long arg1 = ptrace_get_syscall_arg(pid, 1); 264 | 265 | int len = ptrace_strlen(pid, arg0); 266 | char path[len + 1]; 267 | //first arg of open is path addr 268 | ptrace_read_data(pid, path, arg0, len + 1); 269 | 270 | if (strcmp(path, DEV_BINDER) == 0) { 271 | // return from open syscall, read the result fd 272 | ptrace(PTRACE_SYSCALL, pid, NULL, NULL); 273 | pid = waitpid(pid, NULL, __WALL); 274 | 275 | // reg0 will be the result of open 276 | *binder_fd = (int) ptrace_get_syscall_arg(pid , 0); 277 | printf("pid %d open binder: %d\n", pid, *binder_fd); 278 | 279 | ptrace(PTRACE_SYSCALL, pid, NULL, NULL); 280 | return; 281 | 282 | } else { 283 | syscall_common_handler(pid, "open", flag, uid, gid); 284 | return; 285 | 286 | } 287 | } 288 | 289 | 290 | void syscall_ioctl_handler(pid_t pid, int binder_fd, int flag) 291 | { 292 | /* printf("ioctl from %d\n", pid); */ 293 | if(binder_fd < 0) { 294 | ptrace(PTRACE_SYSCALL, pid, NULL, NULL); 295 | } 296 | 297 | // arg0 will be the file description 298 | long arg0 = ptrace_get_syscall_arg(pid, 0); 299 | 300 | if((int)arg0 == binder_fd) { 301 | binder_ioctl_handler(pid); 302 | ptrace(PTRACE_SYSCALL, pid, NULL, NULL); 303 | } else { 304 | ptrace(PTRACE_SYSCALL, pid, NULL, NULL); 305 | } 306 | } 307 | 308 | int syscall_setuid_gid_handler(pid_t pid, pid_t target, int is_gid, long* arg) 309 | { 310 | //arg0 will be the uid/gid 311 | long arg0 = ptrace_get_syscall_arg(pid, 0); 312 | *arg = arg0; 313 | if(!PROCESS_FILTER_ENABLED || pid != target){ 314 | syscall_default_handler(pid); 315 | return 1; 316 | } 317 | FILE *filter_file; 318 | if((filter_file = fopen(PROCESS_FILTER_PATH,"r")) == NULL){ 319 | printf("Error: failed to open process filter file"); 320 | syscall_default_handler(pid); 321 | return 1; 322 | } 323 | long uid,gid; 324 | int result = 0; 325 | while(!feof(filter_file)){ 326 | fscanf(filter_file, "%ld %ld", &uid, &gid); 327 | if(is_gid && gid == arg0){ 328 | result = 1; 329 | break; 330 | } else if(!is_gid && uid == arg0){ 331 | result = 1; 332 | break; 333 | } 334 | } 335 | fclose(filter_file); 336 | syscall_default_handler(pid); 337 | 338 | return result; 339 | } 340 | 341 | void syscall_default_handler(pid_t pid) 342 | { 343 | ptrace(PTRACE_SYSCALL, pid, NULL, NULL); 344 | pid = waitpid(pid, NULL, __WALL); 345 | //syscall return 346 | ptrace(PTRACE_SYSCALL, pid, NULL, NULL); 347 | } 348 | -------------------------------------------------------------------------------- /jni/sandbox_helper.h: -------------------------------------------------------------------------------- 1 | /* 2 | * process_helper.h 3 | * The helper functions for communicating with the app process 4 | */ 5 | 6 | #ifndef PROCESS_HELPER_H_ 7 | #define PROCESS_HELPER_H_ 8 | 9 | #include 10 | 11 | #define SANDBOX_FLAG 0x00000001 12 | 13 | /** 14 | * Ptrace the app process until it forks a new process 15 | */ 16 | extern pid_t ptrace_app_process(pid_t pid, int flag); 17 | 18 | #endif /* PROCESS_HELPER_H_ */ 19 | 20 | -------------------------------------------------------------------------------- /jni/test.c: -------------------------------------------------------------------------------- 1 | /* 2 | * test.c 3 | * For unit test 4 | */ 5 | 6 | #include "config.h" 7 | #include "zygote_helper.h" 8 | #include "ptraceaux.h" 9 | #include "sandbox_helper.h" 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #define APP_FLAG "app" 17 | #define ZYGOTE_FLAG "zygote" 18 | 19 | int main(int argc, char *argv[]) 20 | { 21 | /* init_ptrace_tool(ARCH_ARM); */ 22 | if(create_link(SANDBOX_STORAGE_PATH, SANDBOX_LINK) < 0) { 23 | printf("warnning: link existed\n"); 24 | } 25 | /* printf("%d\n",argc); */ 26 | if(fork() == 0) { 27 | pid_t pid = ptrace_zygote(zygote_find_process()); 28 | if(pid > 0) { 29 | ptrace_app_process(pid, SANDBOX_ENABLED); 30 | } 31 | } else { 32 | printf("press [Ctrl - c] to stop sandboxing\n"); 33 | while(1) { 34 | waitpid(-1, NULL, __WALL); 35 | } 36 | } 37 | return 0; 38 | } 39 | 40 | void blind_cont(pid_t pid) { 41 | int status; 42 | ptrace_setopt(pid, 0); 43 | while (1) { 44 | /* wait for all child threads/processes */ 45 | int pid = waitpid(-1, &status, __WALL); 46 | printf("app pid=%d, status %x\n", pid, status); 47 | ptrace(PTRACE_CONT, pid, NULL, NULL); 48 | ptrace_detach(pid); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /jni/uchar.c: -------------------------------------------------------------------------------- 1 | #include "uchar.h" 2 | #include 3 | #include 4 | 5 | int strcmp12(char16_t* str1, char* str2) 6 | { 7 | int i; 8 | for(i = 0; str1[i] != 0 && str2[i] != 0; i++) { 9 | if(str1[i] > (unsigned short)str2[i]) { 10 | return 1; 11 | } else if (str1[i] < (unsigned short)str2[i]) { 12 | return -1; 13 | } 14 | } 15 | if(str1[i] == 0 && str2[i] == 0) { 16 | return 0; 17 | } else if(str1[i] != 0) { 18 | return 1; 19 | } else { 20 | return -1; 21 | } 22 | } 23 | 24 | int strcmp16(char16_t* str1, char16_t* str2) 25 | { 26 | int i; 27 | for(i = 0; str1[i] != 0 && str2[i] != 0; i++) { 28 | if(str1[i] > str2[i]) { 29 | return 1; 30 | } else if (str1[i] < str2[i]) { 31 | return -1; 32 | } 33 | } 34 | if(str1[i] == 0 && str2[i] == 0) { 35 | return 0; 36 | } else if(str1[i] != 0) { 37 | return 1; 38 | } else { 39 | return -1; 40 | } 41 | 42 | } 43 | 44 | int strpre12(char16_t* str1, char* str2) 45 | { 46 | int i; 47 | for(i = 0; str1[i] != 0 && str2[i] != 0; i++) { 48 | if(str1[i] != (unsigned short)str2[i]) { 49 | return -1; 50 | } 51 | } 52 | if(str1[i] == 0 && str2[i] != 0) { 53 | return -1; 54 | } 55 | return 0; 56 | } 57 | 58 | int strpreg12(char16_t* str1, char* strg2) 59 | { 60 | int len = strlen(strg2); 61 | char tmp[len + 1]; 62 | strcpy(tmp, strg2); 63 | char* current = tmp; 64 | while(current < tmp + len + 1) { 65 | char* last = current; 66 | for(;*last != 0 && *last != ' '; last++) {} 67 | *last = 0; 68 | if(strpre12(str1, current) == 0) { 69 | return 0; 70 | } 71 | current = last + 1; 72 | } 73 | return -1; 74 | } 75 | 76 | void strchpre12(char16_t* str1, char* str2) 77 | { 78 | int i; 79 | for(i = 0; str1[i] != 0 && str2[i] != 0; i++) { 80 | str1[i] = (unsigned short) str2[i]; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /jni/uchar.h: -------------------------------------------------------------------------------- 1 | #ifndef UCHAR_H_ 2 | #define UCHAR_H_ 3 | 4 | typedef unsigned short char16_t; 5 | 6 | int strcmp12(char16_t* str1, char* str2); 7 | 8 | int strcmp16(char16_t* str1, char16_t* str2); 9 | 10 | int strpre12(char16_t* str1, char* str2); 11 | 12 | int strpreg12(char16_t* str1, char* strg2); 13 | 14 | void strchpre12(char16_t* str1, char* str2); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /jni/zygote_helper.c: -------------------------------------------------------------------------------- 1 | /* 2 | * zygote_finder.c 3 | * Implementation of zygote_finder.h 4 | */ 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "zygote_helper.h" 12 | #include "ptraceaux.h" 13 | 14 | #define DEFAULT_ZYGOTE_PID 37 15 | 16 | pid_t zygote_find_process(void) 17 | { 18 | char filepath[128]; 19 | char buf[512], *p; 20 | FILE *f; 21 | pid_t pid = DEFAULT_ZYGOTE_PID; 22 | snprintf(filepath, 128, "/proc/%d/status", pid); 23 | f = fopen(filepath, "r"); 24 | if (!f) { 25 | return -1; 26 | } 27 | /* first line is enough */ 28 | fgets(buf, 512, f); 29 | fclose(f); 30 | if (strncmp(buf, "Name:", 5)) { 31 | return -1; 32 | } 33 | /* retrieve the name */ 34 | *(strchr(buf, '\n')) = '\0'; 35 | for (p = &buf[5]; *p != '\0'&& (*p == ' ' || *p == '\t'); ++p) ; 36 | if (!strncmp(p, "zygote", 6)) { 37 | return pid; 38 | } 39 | /* TODO: should be a loop for all processes in the /proc/ */ 40 | return pid; 41 | } 42 | 43 | 44 | pid_t ptrace_zygote(pid_t zygote_pid) 45 | { 46 | /** 47 | * Zygote's behaivor is well understood. It calls fork() to make a new app process. 48 | * The child app process then triggers the DalvikVM loading, etc. 49 | */ 50 | int status, ev; 51 | 52 | /* keep an eye on zygote */ 53 | printf("zygote pid:%d\n",zygote_pid); 54 | if (ptrace_attach(zygote_pid)) { 55 | printf("Error: ptrace zygote failed\n"); 56 | return -1; 57 | } 58 | 59 | /* use this option to automatically attach to the child forked by zygote */ 60 | ptrace_setopt(zygote_pid, PTRACE_O_TRACEFORK | PTRACE_O_TRACECLONE | PTRACE_O_TRACESYSGOOD); 61 | 62 | while (1) { 63 | /* wait until zygote is trapped by a ptrace stop */ 64 | /* int pid = waitpid(zygote_pid, &status, __WALL); */ 65 | int pid = waitpid(-1, &status, __WALL); 66 | /* check if waitpid fails */ 67 | if (pid == -1) { 68 | ptrace_detach(zygote_pid); 69 | printf("Error: ptrace zygote waitpid failed\n"); 70 | return -1; 71 | } 72 | /* assert(zygote_pid == pid); */ 73 | printf("pid: %d, status %x\n", pid, status); 74 | /* check if the fork() event happens */ 75 | if (IS_FORK_EVENT(status)) { 76 | pid_t newpid; 77 | /* get the forked child pid from the msg */ 78 | ptrace(PTRACE_GETEVENTMSG, zygote_pid, NULL, &newpid); 79 | /* the child is already ptraced since we have PTRACE_O_TRACEFORK */ 80 | printf("zygote forks %d\n", newpid); 81 | /* let zygote continue and go */ 82 | ptrace_detach(zygote_pid); 83 | if(fork() == 0) { 84 | if(ptrace_attach(zygote_pid)) { 85 | printf("Error: ptrace zygote failed\n"); 86 | return -1; 87 | } 88 | ptrace_setopt(zygote_pid, PTRACE_O_TRACEFORK | PTRACE_O_TRACECLONE | PTRACE_O_TRACESYSGOOD); 89 | continue; 90 | } else { 91 | return newpid; 92 | } 93 | /* ptrace(PTRACE_GETEVENTMSG, pid, NULL, &newpid); */ 94 | /* printf("%d forks %d\n", pid, newpid); */ 95 | } 96 | /* if zygote pauses of no reason, let it continue */ 97 | ptrace(PTRACE_CONT, pid, NULL, NULL); 98 | } 99 | return -1; 100 | } 101 | 102 | 103 | -------------------------------------------------------------------------------- /jni/zygote_helper.h: -------------------------------------------------------------------------------- 1 | /* 2 | * zygote_helper.h 3 | * The helper functions for communicating with the zygote process 4 | */ 5 | 6 | #ifndef ZYGOTE_HELPER_H_ 7 | #define ZYGOTE_HELPER_H_ 8 | 9 | #include 10 | 11 | /** 12 | * Find the zygote process pid from the OS 13 | */ 14 | extern pid_t zygote_find_process(void); 15 | 16 | /** 17 | * Ptrace the zygote process until it forks a new process 18 | */ 19 | extern pid_t ptrace_zygote(pid_t zygote_pid); 20 | 21 | #endif /* ZYGOTE_HELPER_H_ */ 22 | -------------------------------------------------------------------------------- /run.bat: -------------------------------------------------------------------------------- 1 | adb shell mkdir /data/appfence 2 | adb push libs/armeabi/appfence /data/appfence/appfence 3 | adb shell chmod 777 /data/appfence/appfence 4 | adb shell /data/appfence/appfence --------------------------------------------------------------------------------