├── .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 |
56 |
57 |
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
--------------------------------------------------------------------------------