├── .gitignore ├── README.md ├── ptrace-inject ├── jni │ ├── Android.mk │ ├── Application.mk │ ├── inject.c │ ├── inject.h │ ├── inject_so.c │ ├── log_marco.h │ ├── main.c │ ├── proc_tool.c │ └── proc_tool.h └── makefile └── shellcode-inject ├── jni ├── Android.mk ├── Application.mk ├── inject.c ├── inject.h ├── inject_so.c ├── log_marco.h ├── main.c ├── proc_tool.c └── proc_tool.h └── makefile /.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | .vscode/ 3 | /obj 4 | /libs 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Android-Inject 2 | ## ptrace-inject: 3 | - use ptrace-api inject arm/arm64 process 4 | #### how to build: 5 | - make sure have `ndk-build` in your PATH 6 | - type ndk-build at the command line 7 | - output at /libs 8 | #### how to use: 9 | ``` 10 | -rwxrwxrwx 1 shell shell 14312 2022-12-02 16:14 inject 11 | -rwxrwxrwx 1 root root 987604 2022-12-01 17:08 libc.so 12 | -rwxrwxrwx 1 shell shell 5976 2022-12-02 16:14 libtest.so 13 | blueline:/data/local/tmp # ./inject pid /data/local/tmp/libtest.so 14 | ``` 15 | 16 | ## shellcode-inject: 17 | - shellcode 18 | -------------------------------------------------------------------------------- /ptrace-inject/jni/Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH:= $(call my-dir) 2 | include $(CLEAR_VARS) 3 | 4 | LOCAL_MODULE := inject 5 | LOCAL_SRC_FILES := main.c proc_tool.c inject.c 6 | LOCAL_LDLIBS := -lc -llog 7 | include $(BUILD_EXECUTABLE) 8 | 9 | 10 | include $(CLEAR_VARS) 11 | LOCAL_MODULE := test 12 | LOCAL_SRC_FILES := inject_so.c 13 | include $(BUILD_SHARED_LIBRARY) -------------------------------------------------------------------------------- /ptrace-inject/jni/Application.mk: -------------------------------------------------------------------------------- 1 | APP_PLATFORM := android-21 2 | APP_ABI := armeabi-v7a arm64-v8a -------------------------------------------------------------------------------- /ptrace-inject/jni/inject.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "inject.h" 15 | #include "proc_tool.h" 16 | #include "log_marco.h" 17 | 18 | /** 19 | * is zygote process. 20 | */ 21 | static int is_zygote(pid_t pid) 22 | { 23 | char* name = proc_get_process_name(pid); 24 | if(name == NULL) return -1; 25 | return strcmp(name, ZYGOTE_NAME); 26 | } 27 | 28 | 29 | /** 30 | * connect zygote. 31 | */ 32 | static int socket_zygote() 33 | { 34 | int s = -1, len = 0; 35 | struct sockaddr_un un; 36 | 37 | sleep(1); 38 | 39 | if((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) return -1; 40 | 41 | un.sun_family = AF_UNIX; 42 | strcpy(un.sun_path, "/dev/socket/zygote"); 43 | len = strlen(un.sun_path) + offsetof(struct sockaddr_un, sun_path); 44 | if(connect(s, (struct sockaddr *) &un, len) == -1){ 45 | close(s); 46 | return -1; 47 | } 48 | close(s); 49 | return 0; 50 | } 51 | 52 | 53 | /** 54 | * use PTRACE_ATTACH attach target process. 55 | */ 56 | static int ptrace_attach_process(pid_t pid) 57 | { 58 | if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) return -1; 59 | waitpid(pid, NULL, WUNTRACED); 60 | 61 | if(is_zygote(pid) == 0){ 62 | if(socket_zygote() < 0) 63 | return -1; 64 | } 65 | 66 | /** 67 | * use PTRACE_SYSCALL restart target process, 68 | * target process will stop at next syscall. 69 | */ 70 | if (ptrace(PTRACE_SYSCALL, pid, NULL, 0) < 0) return -1; 71 | waitpid(pid, NULL, WUNTRACED); 72 | return 0; 73 | } 74 | 75 | 76 | /** 77 | * use PTRACE_GETREGS get regs value. 78 | */ 79 | static int ptrace_get_regs(pid_t pid, struct pt_regs* regs) 80 | { 81 | #if defined(__aarch64__) 82 | unsigned int expected_size; 83 | struct iovec iov; 84 | iov.iov_base = regs; 85 | iov.iov_len = expected_size = sizeof(struct pt_regs); 86 | if(ptrace(PTRACE_GETREGS, pid, (void*)NT_PRSTATUS, &iov) < 0) return -1; 87 | if (iov.iov_len != expected_size) return -1; 88 | return 0; 89 | #else 90 | if(ptrace(PTRACE_GETREGS, pid, NULL, regs) < 0) return -1; 91 | return 0; 92 | #endif 93 | } 94 | 95 | 96 | /** 97 | * use PTRACE_SETREGS set regs value. 98 | */ 99 | static int ptrace_set_regs(pid_t pid, struct pt_regs* regs) 100 | { 101 | #if defined(__aarch64__) 102 | struct iovec iov; 103 | iov.iov_base = regs; 104 | iov.iov_len = sizeof(struct pt_regs); 105 | if(ptrace(PTRACE_SETREGS, pid, (void*)NT_PRSTATUS, &iov) < 0) return -1; 106 | return 0; 107 | #else 108 | if(ptrace(PTRACE_SETREGS, pid, NULL, regs) < 0) return -1; 109 | return 0; 110 | #endif 111 | } 112 | 113 | 114 | /** 115 | * use PTRACE_CONT restart target process. 116 | */ 117 | static int ptrace_cont_process(pid_t pid) 118 | { 119 | if(ptrace(PTRACE_CONT, pid, NULL, NULL) < 0) return -1; 120 | return 0; 121 | } 122 | 123 | 124 | /** 125 | * use PTRACE_DETACH detach target process. 126 | */ 127 | static int ptrace_detach_process(pid_t pid, struct pt_regs* regs) 128 | { 129 | if(ptrace_set_regs(pid, regs) < 0) return -1; 130 | if(ptrace(PTRACE_DETACH, pid, NULL, NULL) < 0) return -1; 131 | return 0; 132 | } 133 | 134 | 135 | /** 136 | * use PTRACE_PEEKDATA remote read data. 137 | * pid: target process pid 138 | * src: target process addr 139 | * dst: buffer to save data 140 | * size: need read data size 141 | */ 142 | static void remote_read_data(pid_t pid, void* src, void* dst, int size) 143 | { 144 | int count = size / 4; 145 | int over_count = size % 4; 146 | int *dst_ptr = (int*)dst; 147 | int *src_ptr = (int*)src; 148 | char buf[4] = {0}; 149 | 150 | for (int i = 0; i < count; i++) { 151 | *dst_ptr = ptrace(PTRACE_PEEKDATA, pid, (void*)(src_ptr), NULL); 152 | //check 153 | dst_ptr++; 154 | src_ptr++; 155 | } 156 | 157 | if(over_count > 0){ 158 | *buf = ptrace(PTRACE_PEEKDATA, pid, (void*)(src_ptr), NULL); 159 | //check 160 | memcpy((void*)dst_ptr, (const void*)buf, over_count); 161 | } 162 | } 163 | 164 | 165 | /** 166 | * use PTRACE_POKEDATA remote write data. 167 | * pid: target process pid 168 | * src: target process addr 169 | * dst: the write data 170 | * size: the write data size 171 | */ 172 | static int remote_write_data(pid_t pid, void* dst, void* src, int size) 173 | { 174 | int count = size / 4; 175 | int over_count = size % 4; 176 | int *dst_ptr = (int*)dst; 177 | int *src_ptr = (int*)src; 178 | char buf[4] = {0}; 179 | 180 | for (int i = 0; i < count; i++) { 181 | if (ptrace(PTRACE_POKEDATA, pid, (void*)(dst_ptr), *src_ptr) < 0) 182 | return -1; 183 | dst_ptr++; 184 | src_ptr++; 185 | } 186 | 187 | if(over_count > 0){ 188 | *buf = ptrace(PTRACE_PEEKDATA, pid, (void*)(dst_ptr), NULL); 189 | for(int i = 0; i < over_count; i++){ 190 | buf[i] = *((char*)src_ptr + i); 191 | } 192 | 193 | if (ptrace(PTRACE_POKEDATA, pid, (void*)(dst_ptr), *buf) < 0) 194 | return -1; 195 | } 196 | return 0; 197 | } 198 | 199 | 200 | /** 201 | * remote write string 202 | */ 203 | static int remote_write_string(pid_t pid, void* dst, const char *str) 204 | { 205 | return remote_write_data(pid, dst, (void*)str, 256); 206 | } 207 | 208 | 209 | /** 210 | * call target process fun 211 | * pid -> target process pid 212 | * fun_addr -> target process fun addr 213 | * regs -> register 214 | * param_num -> the param count 215 | * ... 216 | */ 217 | static long remote_call_fun(pid_t pid, void* fun_addr, struct pt_regs* regs, int param_num, ...) 218 | { 219 | struct pt_regs new_regs = *regs; 220 | new_regs.ARM_pc = (long)fun_addr & ~1; 221 | new_regs.ARM_lr = 0; 222 | va_list arglist; 223 | 224 | if ((long)fun_addr & 1) { 225 | new_regs.ARM_cpsr |= 0x20; //thumb 0010 0000 226 | } 227 | else { 228 | new_regs.ARM_cpsr &= ~0x20; //arm 0000 0000 229 | } 230 | 231 | #if defined(__aarch64__) 232 | va_start(arglist, param_num); 233 | if(param_num < 9){ 234 | for(int i = 0; i < param_num; i++){ 235 | new_regs.uregs[i] = va_arg(arglist, long); 236 | } 237 | } 238 | else{ 239 | for(int i = 0; i < 8; i++){ 240 | new_regs.uregs[i] = va_arg(arglist, long); 241 | } 242 | 243 | int stack_num = param_num - 8; 244 | new_regs.ARM_sp -= stack_num * 8; 245 | int n = 0; 246 | for(int i = 0; i < stack_num; i++){ 247 | n = va_arg(arglist, long); 248 | if(remote_write_data(pid, (void*)(new_regs.ARM_sp + i * 8), (void*)&n, 8) < 0) 249 | return -1; 250 | } 251 | } 252 | va_end(arglist); 253 | #else 254 | va_start(arglist, param_num); 255 | if(param_num < 5){ 256 | for(int i = 0; i < param_num; i++){ 257 | new_regs.uregs[i] = va_arg(arglist, int); 258 | } 259 | } 260 | else{ 261 | for(int i = 0; i < 4; i++){ 262 | new_regs.uregs[i] = va_arg(arglist, int); 263 | } 264 | 265 | int stack_num = param_num - 4; 266 | new_regs.ARM_sp -= stack_num * 4; 267 | int n = 0; 268 | for(int i = 0; i < stack_num; i++){ 269 | n = va_arg(arglist, int); 270 | if(remote_write_data(pid, (void*)(new_regs.ARM_sp + i * 4), (void*)&n, 4) < 0) 271 | return -1; 272 | } 273 | } 274 | va_end(arglist); 275 | #endif 276 | 277 | if(ptrace_set_regs(pid, &new_regs) < 0) return -1; 278 | if(ptrace_cont_process(pid) < 0) return -1; 279 | waitpid( pid, NULL, WUNTRACED); 280 | if(ptrace_get_regs(pid, &new_regs) < 0)return -1; 281 | return new_regs.ARM_r0; 282 | } 283 | 284 | 285 | /** 286 | * inject 287 | */ 288 | int start_inject(pid_t pid, const char *so_path){ 289 | void* mmap_addr = NULL; 290 | void* mmap_result = NULL; 291 | void* dlopen_addr = NULL; 292 | void* handle = NULL; 293 | void* dlerror_addr = NULL; 294 | long dlerror_data = 0; 295 | struct pt_regs old_regs = {0}; 296 | struct pt_regs new_regs = {0}; 297 | char errbuf[MAX_LENGTH] = {0}; 298 | 299 | #define fatal(fmt, args...) do {printf(fmt, ##args); goto ERR_EXIT;} while(0) 300 | 301 | //attach target process 302 | if(ptrace_attach_process(pid) < 0) { 303 | printf("[-] PTRACE_ATTACH FAILED:[%s]\n", strerror(errno)); 304 | return -1; 305 | } 306 | printf("[+] PTRACE_ATTACH OK\n"); 307 | 308 | if(ptrace_get_regs(pid, &old_regs) < 0) { 309 | printf("[-] PTRACE_GETREGS FAILED:[%s]\n", strerror(errno)); 310 | return -1; 311 | } 312 | printf("[+] PTRACE_GETREGS OK\n"); 313 | new_regs = old_regs; 314 | 315 | // get target process mmap addr 316 | mmap_addr = proc_get_remote_fun_addr(pid, "libc.so", (void*)mmap); 317 | if(mmap_addr == NULL) 318 | fatal("[-] GET_MMAP_FUN FAILED\n"); 319 | printf("[+] MMAP_FUN = %p\n", mmap_addr); 320 | mmap_result = (void*)remote_call_fun(pid, mmap_addr, &new_regs, 6, 321 | NULL, 322 | 0x4000, 323 | PROT_EXEC | PROT_READ | PROT_WRITE, 324 | MAP_PRIVATE | MAP_ANONYMOUS, 325 | 0, 326 | 0); 327 | if(mmap_result == MAP_FAILED) 328 | fatal("[-] REMOTE_CALL_MMAP FAILED:[%s]\n", strerror(errno)); 329 | printf("[+] MMAP_RESULT = %p\n", mmap_result); 330 | 331 | //write inject_so path 332 | if(remote_write_string(pid, mmap_result, so_path) < 0) 333 | fatal("[-] REMOTE_WRITE FAILED:[%s]\n", strerror(errno)); 334 | printf("[+] REMOTE_WRITE OK\n"); 335 | 336 | /** 337 | * get dlopen addr 338 | * ANDROID 10.0 /libdl.so -> dlopen 339 | * */ 340 | dlopen_addr = proc_get_remote_fun_addr(pid, "/libdl.so", (void*)dlopen); 341 | if(dlopen_addr == NULL) 342 | fatal("[-] GET_DLOPEN_FUN FAILED\n"); 343 | printf("[+] DLOPEN_FUN = %p\n", dlopen_addr); 344 | handle = (void*)remote_call_fun(pid, dlopen_addr, &new_regs, 2, mmap_result, RTLD_NOW); 345 | 346 | if(handle == NULL){ 347 | //if dlopen failed, get dlerror 348 | dlerror_addr = proc_get_remote_fun_addr(pid, "/libdl.so", (void*)dlerror); 349 | if(dlerror_addr == NULL) 350 | fatal("[-] GET_DLERROR_FUN FAILED\n"); 351 | printf("[+] DLERROR_FUN = %p\n", dlerror_addr); 352 | 353 | dlerror_data = remote_call_fun(pid, dlerror_addr, &new_regs, 0); 354 | if(dlerror_data <= 0) 355 | fatal("[-] REMOTE_CALL_DLERROR FAILED\n"); 356 | remote_read_data(pid, (void*)dlerror_data, (void*)errbuf, MAX_LENGTH); 357 | printf("[+] DLERROR_RESULT = %s\n", errbuf); 358 | 359 | }else{ 360 | printf("[+] DLOPEN_RESULT = %p\n", handle); 361 | } 362 | 363 | #undef fatal 364 | if(ptrace_detach_process(pid, &old_regs) < 0) return -1; 365 | return 0; 366 | 367 | ERR_EXIT: 368 | if(ptrace_detach_process(pid, &old_regs) < 0) return -1; 369 | return -1; 370 | } 371 | -------------------------------------------------------------------------------- /ptrace-inject/jni/inject.h: -------------------------------------------------------------------------------- 1 | #ifndef INJECT_H 2 | #define INJECT_H 3 | 4 | #include 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | #if defined(__aarch64__) 11 | #define ZYGOTE_NAME "zygote64" 12 | #define PTRACE_GETREGS PTRACE_GETREGSET 13 | #define PTRACE_SETREGS PTRACE_SETREGSET 14 | #define pt_regs user_pt_regs 15 | #define uregs regs 16 | #define ARM_pc pc 17 | #define ARM_sp sp 18 | #define ARM_cpsr pstate 19 | #define ARM_lr regs[30] 20 | #define ARM_r0 regs[0] 21 | #else 22 | #define ZYGOTE_NAME "zygote" 23 | #endif 24 | 25 | int start_inject(pid_t pid, const char *so_path); 26 | 27 | #ifdef __cplusplus 28 | } 29 | #endif 30 | 31 | #endif //INJECT_H -------------------------------------------------------------------------------- /ptrace-inject/jni/inject_so.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | __attribute__((constructor)) void my_inject() 5 | { 6 | printf("inject ok!\n"); 7 | fflush(stdout); 8 | } 9 | -------------------------------------------------------------------------------- /ptrace-inject/jni/log_marco.h: -------------------------------------------------------------------------------- 1 | #ifndef LOG_UTILS_H 2 | #define LOG_UTILS_H 3 | 4 | #include 5 | 6 | #define TAG "PTRACE_INJECT" 7 | #define INJECT_DEBUG 1 8 | 9 | #ifdef INJECT_DEBUG 10 | #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__) 11 | #else 12 | #define LOGD(...) 13 | #endif // INJECT_DEBUG 14 | #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__) 15 | #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__) 16 | #define LOGW(...) __android_log_print(ANDROID_LOG_WARN, TAG, __VA_ARGS__) 17 | 18 | #ifndef PAGE_SIZE 19 | #define PAGE_SIZE 4096 20 | #endif 21 | 22 | #define PAGE_START(addr) (~(PAGE_SIZE - 1) & (addr)) 23 | #define PAGE_END(addr) (PAGE_START(addr + sizeof(uintptr_t) - 1) + PAGE_SIZE) 24 | #define PAGE_COVER(addr) (PAGE_END(addr) - PAGE_START(addr)) 25 | 26 | #define SET_BIT0(addr) (addr | 1) 27 | #define CLEAR_BIT0(addr) (addr & 0xFFFFFFFE) 28 | #define TEST_BIT0(addr) (addr & 1) 29 | 30 | #endif //LOG_UTILS_H -------------------------------------------------------------------------------- /ptrace-inject/jni/main.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "proc_tool.h" 11 | #include "inject.h" 12 | 13 | 14 | int main(int argc, char* argv[]) 15 | { 16 | pid_t pid = 0; 17 | char* so_name = NULL; 18 | char cmd[256] = {0}; 19 | if(argc < 3){ 20 | printf("[-] missing command line arguments.\n"); 21 | return 0; 22 | } 23 | 24 | pid = atoi(argv[1]); 25 | so_name = argv[2]; 26 | printf("[+] start inject [%s] to [pid:%d] process\n", so_name, pid); 27 | system("su -c setenforce 0"); 28 | 29 | // #if defined(__aarch64__) 30 | // system("mount -o rw,remount /"); 31 | // system("mount -o rw,remount /system"); 32 | // snprintf(cmd, sizeof(cmd), "cp %s /system/lib64/libtest.so", so_name); 33 | // system(cmd); 34 | // system("chmod 777 /system/lib64/libtest.so"); 35 | // system("chcon u:object_r:system_file:s0 /system/lib64/libtest.so"); 36 | // if(start_inject(pid, so_name) < 0){ 37 | // printf("[-] inject failed\n"); 38 | // }else{ 39 | // printf("[+] inject ok\n"); 40 | // } 41 | // #else 42 | // if(start_inject(pid, so_name) < 0){ 43 | // printf("[-] inject failed\n"); 44 | // }else{ 45 | // printf("[+] inject ok\n"); 46 | // } 47 | // #endif 48 | 49 | if(start_inject(pid, so_name) < 0){ 50 | printf("[-] inject failed\n"); 51 | }else{ 52 | printf("[+] inject ok\n"); 53 | } 54 | fflush(stdout); 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /ptrace-inject/jni/proc_tool.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "proc_tool.h" 7 | #include "log_marco.h" 8 | 9 | /** 10 | * get target process name. 11 | * pid = -1, get self 12 | * pid != -1, get target process 13 | * return: process_name 14 | */ 15 | char* proc_get_process_name(pid_t pid) 16 | { 17 | FILE* fp = NULL; 18 | char path[MAX_LENGTH] = {0}; 19 | static char buffer[MAX_LENGTH] = {0}; 20 | 21 | #define fatal(fmt, args...) do {LOGE(fmt, ##args); goto ERR_EXIT;} while(0) 22 | 23 | if(0 > pid){ 24 | snprintf(path, sizeof(path), "/proc/self/cmdline"); 25 | } 26 | else{ 27 | snprintf(path, sizeof(path), "/proc/%d/cmdline", pid); 28 | } 29 | 30 | fp = fopen(path, "r"); 31 | if(NULL == fp) fatal("[-] fopen:[%s], errno:[%s]", path, strerror(errno)); 32 | if(NULL == fgets(buffer, sizeof(buffer), fp)) fatal("[-] fgets errno:[%s]", strerror(errno)); 33 | 34 | #undef fatal 35 | fclose(fp); 36 | return buffer; 37 | 38 | ERR_EXIT: 39 | if(NULL != fp) fclose(fp); 40 | return NULL; 41 | } 42 | 43 | /** 44 | * get moduleBase from /proc/pid/maps 45 | * pid = -1, get self 46 | * pid != -1, get target process 47 | * moduleName -> module name 48 | * return base_addr 49 | */ 50 | void* proc_get_module_base(pid_t pid, const char* module_name) 51 | { 52 | FILE* fp = NULL; 53 | void* base_addr = NULL; 54 | char perm[5]; 55 | char path[MAX_LENGTH] = {0}; 56 | char buff[MAX_LENGTH] = {0}; 57 | 58 | #define fatal(fmt, args...) do {LOGE(fmt, ##args); goto ERR_EXIT;} while(0) 59 | 60 | if(NULL == module_name) return NULL; 61 | 62 | if(pid < 0){ 63 | snprintf(path, sizeof(path), "/proc/self/maps"); 64 | } 65 | else{ 66 | snprintf(path, sizeof(path), "/proc/%d/maps", pid); 67 | } 68 | 69 | fp = fopen(path, "r"); 70 | if(NULL == fp) fatal("[-] fopen:[%s], errno:[%s]", path, strerror(errno)); 71 | while(fgets(buff, sizeof(buff), fp)){ 72 | if(sscanf(buff, "%p-%*p %4s", &base_addr, perm) != 2) continue; 73 | if (perm[3] != 'p') continue; 74 | if (perm[0] == '-' && perm[1] == '-' && perm[2] == '-') continue; 75 | #if defined(__aarch64__) 76 | if (NULL == strstr(buff, "lib64")) continue; 77 | #endif 78 | if (NULL != strstr(buff, module_name)) { 79 | break; 80 | } 81 | } 82 | 83 | #undef fatal 84 | fclose(fp); 85 | return base_addr; 86 | 87 | ERR_EXIT: 88 | if(NULL != fp) fclose(fp); 89 | return NULL; 90 | } 91 | 92 | /** 93 | * get target process fun addr 94 | * pid: target process pid 95 | * module_name: target module name 96 | * local_addr: local fun addr 97 | * return remote_addr 98 | */ 99 | void* proc_get_remote_fun_addr(pid_t pid, const char* module_name, void* local_addr) 100 | { 101 | void* local_module_base = NULL; 102 | void* remote_module_base = NULL; 103 | char* remote_addr = NULL; 104 | 105 | #define fatal(fmt, args...) do {LOGE(fmt, ##args); goto ERR_EXIT;} while(0) 106 | 107 | local_module_base = proc_get_module_base(-1, module_name); 108 | if(NULL == local_module_base) fatal("[-] get local module base failed"); 109 | remote_module_base = proc_get_module_base(pid, module_name); 110 | if(NULL == remote_module_base) fatal("[-] get remote module base failed"); 111 | remote_addr = (char*)remote_module_base + ((char*)local_addr - (char*)local_module_base); 112 | 113 | #undef fatal 114 | return (void*)remote_addr; 115 | 116 | ERR_EXIT: 117 | return NULL; 118 | } 119 | -------------------------------------------------------------------------------- /ptrace-inject/jni/proc_tool.h: -------------------------------------------------------------------------------- 1 | #ifndef PROC_TOOL_H 2 | #define PROC_TOOL_H 3 | 4 | #include 5 | 6 | #ifndef MAX_LENGTH 7 | #define MAX_LENGTH 1024 8 | #endif //MAX_LENGTH 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | char* proc_get_process_name(pid_t pid); 15 | void* proc_get_module_base(pid_t pid, const char* module_name); 16 | void* proc_get_remote_fun_addr(pid_t pid, const char* module_name, void* local_addr); 17 | 18 | #ifdef __cplusplus 19 | } 20 | #endif 21 | 22 | #endif //PROC_TOOL_H 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ptrace-inject/makefile: -------------------------------------------------------------------------------- 1 | 2 | 3 | all: 4 | adb push ./libs/armeabi-v7a/inject /data/local/tmp/inject 5 | adb push ./libs/armeabi-v7a/libtest.so /data/local/tmp/ 6 | adb shell chmod 777 /data/local/tmp/inject 7 | adb shell chmod 777 /data/local/tmp/libtest.so 8 | adb shell /data/local/tmp/inject 9 | 10 | arm64: 11 | adb push ./libs/arm64-v8a/inject /data/local/tmp/inject 12 | adb push ./libs/arm64-v8a/libtest.so /data/local/tmp/ 13 | adb shell chmod 777 /data/local/tmp/inject 14 | adb shell chmod 777 /data/local/tmp/libtest.so 15 | adb shell /data/local/tmp/inject 16 | 17 | clean: 18 | rm -rf obj 19 | rm -rf libs 20 | -------------------------------------------------------------------------------- /shellcode-inject/jni/Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH:= $(call my-dir) 2 | include $(CLEAR_VARS) 3 | 4 | LOCAL_MODULE := inject 5 | LOCAL_SRC_FILES := main.c proc_tool.c inject.c 6 | LOCAL_LDLIBS := -lc -llog 7 | include $(BUILD_EXECUTABLE) 8 | 9 | 10 | include $(CLEAR_VARS) 11 | LOCAL_MODULE := test 12 | LOCAL_SRC_FILES := inject_so.c 13 | include $(BUILD_SHARED_LIBRARY) -------------------------------------------------------------------------------- /shellcode-inject/jni/Application.mk: -------------------------------------------------------------------------------- 1 | APP_PLATFORM := android-21 2 | APP_ABI := armeabi-v7a arm64-v8a -------------------------------------------------------------------------------- /shellcode-inject/jni/inject.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "inject.h" 15 | #include "proc_tool.h" 16 | #include "log_marco.h" 17 | 18 | /** 19 | * is zygote process. 20 | */ 21 | static int is_zygote(pid_t pid) 22 | { 23 | char* name = proc_get_process_name(pid); 24 | if(name == NULL) return -1; 25 | return strcmp(name, ZYGOTE_NAME); 26 | } 27 | 28 | 29 | /** 30 | * connect zygote. 31 | */ 32 | static int socket_zygote() 33 | { 34 | int s = -1, len = 0; 35 | struct sockaddr_un un; 36 | 37 | sleep(1); 38 | 39 | if((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) return -1; 40 | 41 | un.sun_family = AF_UNIX; 42 | strcpy(un.sun_path, "/dev/socket/zygote"); 43 | len = strlen(un.sun_path) + offsetof(struct sockaddr_un, sun_path); 44 | if(connect(s, (struct sockaddr *) &un, len) == -1){ 45 | close(s); 46 | return -1; 47 | } 48 | close(s); 49 | return 0; 50 | } 51 | 52 | 53 | /** 54 | * use PTRACE_ATTACH attach target process. 55 | */ 56 | static int ptrace_attach_process(pid_t pid) 57 | { 58 | if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) return -1; 59 | waitpid(pid, NULL, WUNTRACED); 60 | 61 | if(is_zygote(pid) == 0){ 62 | if(socket_zygote() < 0) 63 | return -1; 64 | } 65 | 66 | /** 67 | * use PTRACE_SYSCALL restart target process, 68 | * target process will stop at next syscall. 69 | */ 70 | if (ptrace(PTRACE_SYSCALL, pid, NULL, 0) < 0) return -1; 71 | waitpid(pid, NULL, WUNTRACED); 72 | return 0; 73 | } 74 | 75 | 76 | /** 77 | * use PTRACE_GETREGS get regs value. 78 | */ 79 | static int ptrace_get_regs(pid_t pid, struct pt_regs* regs) 80 | { 81 | #if defined(__aarch64__) 82 | unsigned int expected_size; 83 | struct iovec iov; 84 | iov.iov_base = regs; 85 | iov.iov_len = expected_size = sizeof(struct pt_regs); 86 | if(ptrace(PTRACE_GETREGS, pid, (void*)NT_PRSTATUS, &iov) < 0) return -1; 87 | if (iov.iov_len != expected_size) return -1; 88 | return 0; 89 | #else 90 | if(ptrace(PTRACE_GETREGS, pid, NULL, regs) < 0) return -1; 91 | return 0; 92 | #endif 93 | } 94 | 95 | 96 | /** 97 | * use PTRACE_SETREGS set regs value. 98 | */ 99 | static int ptrace_set_regs(pid_t pid, struct pt_regs* regs) 100 | { 101 | #if defined(__aarch64__) 102 | struct iovec iov; 103 | iov.iov_base = regs; 104 | iov.iov_len = sizeof(struct pt_regs); 105 | if(ptrace(PTRACE_SETREGS, pid, (void*)NT_PRSTATUS, &iov) < 0) return -1; 106 | return 0; 107 | #else 108 | if(ptrace(PTRACE_SETREGS, pid, NULL, regs) < 0) return -1; 109 | return 0; 110 | #endif 111 | } 112 | 113 | 114 | /** 115 | * use PTRACE_CONT restart target process. 116 | */ 117 | static int ptrace_cont_process(pid_t pid) 118 | { 119 | if(ptrace(PTRACE_CONT, pid, NULL, NULL) < 0) return -1; 120 | return 0; 121 | } 122 | 123 | 124 | /** 125 | * use PTRACE_DETACH detach target process. 126 | */ 127 | static int ptrace_detach_process(pid_t pid, struct pt_regs* regs) 128 | { 129 | if(ptrace_set_regs(pid, regs) < 0) return -1; 130 | if(ptrace(PTRACE_DETACH, pid, NULL, NULL) < 0) return -1; 131 | return 0; 132 | } 133 | 134 | 135 | /** 136 | * use PTRACE_PEEKDATA remote read data. 137 | * pid: target process pid 138 | * src: target process addr 139 | * dst: buffer to save data 140 | * size: need read data size 141 | */ 142 | static void remote_read_data(pid_t pid, void* src, void* dst, int size) 143 | { 144 | int count = size / 4; 145 | int over_count = size % 4; 146 | int *dst_ptr = (int*)dst; 147 | int *src_ptr = (int*)src; 148 | char buf[4] = {0}; 149 | 150 | for (int i = 0; i < count; i++) { 151 | *dst_ptr = ptrace(PTRACE_PEEKDATA, pid, (void*)(src_ptr), NULL); 152 | //check 153 | dst_ptr++; 154 | src_ptr++; 155 | } 156 | 157 | if(over_count > 0){ 158 | *buf = ptrace(PTRACE_PEEKDATA, pid, (void*)(src_ptr), NULL); 159 | //check 160 | memcpy((void*)dst_ptr, (const void*)buf, over_count); 161 | } 162 | } 163 | 164 | 165 | /** 166 | * use PTRACE_POKEDATA remote write data. 167 | * pid: target process pid 168 | * src: target process addr 169 | * dst: the write data 170 | * size: the write data size 171 | */ 172 | static int remote_write_data(pid_t pid, void* dst, void* src, int size) 173 | { 174 | int count = size / 4; 175 | int over_count = size % 4; 176 | int *dst_ptr = (int*)dst; 177 | int *src_ptr = (int*)src; 178 | char buf[4] = {0}; 179 | 180 | for (int i = 0; i < count; i++) { 181 | if (ptrace(PTRACE_POKEDATA, pid, (void*)(dst_ptr), *src_ptr) < 0) 182 | return -1; 183 | dst_ptr++; 184 | src_ptr++; 185 | } 186 | 187 | if(over_count > 0){ 188 | *buf = ptrace(PTRACE_PEEKDATA, pid, (void*)(dst_ptr), NULL); 189 | for(int i = 0; i < over_count; i++){ 190 | buf[i] = *((char*)src_ptr + i); 191 | } 192 | 193 | if (ptrace(PTRACE_POKEDATA, pid, (void*)(dst_ptr), *buf) < 0) 194 | return -1; 195 | } 196 | return 0; 197 | } 198 | 199 | 200 | /** 201 | * remote write string 202 | */ 203 | static int remote_write_string(pid_t pid, void* dst, const char *str) 204 | { 205 | return remote_write_data(pid, dst, (void*)str, 256); 206 | } 207 | 208 | 209 | /** 210 | * call target process fun 211 | * pid -> target process pid 212 | * fun_addr -> target process fun addr 213 | * regs -> register 214 | * param_num -> the param count 215 | * ... 216 | */ 217 | static long remote_call_fun(pid_t pid, void* fun_addr, struct pt_regs* regs, int param_num, ...) 218 | { 219 | struct pt_regs new_regs = *regs; 220 | new_regs.ARM_pc = (long)fun_addr & ~1; 221 | new_regs.ARM_lr = 0; 222 | va_list arglist; 223 | 224 | if ((long)fun_addr & 1) { 225 | new_regs.ARM_cpsr |= 0x20; //thumb 0010 0000 226 | } 227 | else { 228 | new_regs.ARM_cpsr &= ~0x20; //arm 0000 0000 229 | } 230 | 231 | #if defined(__aarch64__) 232 | va_start(arglist, param_num); 233 | if(param_num < 9){ 234 | for(int i = 0; i < param_num; i++){ 235 | new_regs.uregs[i] = va_arg(arglist, long); 236 | } 237 | } 238 | else{ 239 | for(int i = 0; i < 8; i++){ 240 | new_regs.uregs[i] = va_arg(arglist, long); 241 | } 242 | 243 | int stack_num = param_num - 8; 244 | new_regs.ARM_sp -= stack_num * 8; 245 | int n = 0; 246 | for(int i = 0; i < stack_num; i++){ 247 | n = va_arg(arglist, long); 248 | if(remote_write_data(pid, (void*)(new_regs.ARM_sp + i * 8), (void*)&n, 8) < 0) 249 | return -1; 250 | } 251 | } 252 | va_end(arglist); 253 | #else 254 | va_start(arglist, param_num); 255 | if(param_num < 5){ 256 | for(int i = 0; i < param_num; i++){ 257 | new_regs.uregs[i] = va_arg(arglist, int); 258 | } 259 | } 260 | else{ 261 | for(int i = 0; i < 4; i++){ 262 | new_regs.uregs[i] = va_arg(arglist, int); 263 | } 264 | 265 | int stack_num = param_num - 4; 266 | new_regs.ARM_sp -= stack_num * 4; 267 | int n = 0; 268 | for(int i = 0; i < stack_num; i++){ 269 | n = va_arg(arglist, int); 270 | if(remote_write_data(pid, (void*)(new_regs.ARM_sp + i * 4), (void*)&n, 4) < 0) 271 | return -1; 272 | } 273 | } 274 | va_end(arglist); 275 | #endif 276 | 277 | if(ptrace_set_regs(pid, &new_regs) < 0) return -1; 278 | if(ptrace_cont_process(pid) < 0) return -1; 279 | waitpid( pid, NULL, WUNTRACED); 280 | if(ptrace_get_regs(pid, &new_regs) < 0)return -1; 281 | return new_regs.ARM_r0; 282 | } 283 | 284 | 285 | unsigned int shell_code_arm[] = 286 | { 287 | 0xe59f0040, //0 +0 ldr r0, [pc, #64] ; 48 <.text+0x48> 288 | 0xe3a01000, //1 +4 mov r1, #0 ; 0x0 289 | 0xe1a0e00f, //2 +8 mov lr, pc 290 | 0xe59ff038, //3 +c ldr pc, [pc, #56] ; 4c <.text+0x4c> 291 | 0xe59fd02c, //4 +10 ldr sp, [pc, #44] ; 44 <.text+0x44> 292 | 0xe59f0010, //5 +14 ldr r0, [pc, #16] ; 30 <.text+0x30> 293 | 0xe59f1010, //6 +18 ldr r1, [pc, #16] ; 34 <.text+0x34> 294 | 0xe59f2010, //7 +1c ldr r2, [pc, #16] ; 38 <.text+0x38> 295 | 0xe59f3010, //8 +20 ldr r3, [pc, #16] ; 3c <.text+0x3c> 296 | 0xe59fe010, //9 +24 ldr lr, [pc, #16] ; 40 <.text+0x40> 297 | 0xe59ff010, //10 +28 ldr pc, [pc, #16] ; 44 <.text+0x44> 298 | 0xe1a00000, //11 +2c nop r0 299 | 0xe1a00000, //12 +30 nop r1 300 | 0xe1a00000, //13 +34 nop r2 301 | 0xe1a00000, //14 +38 nop r3 302 | 0xe1a00000, //15 +3c nop lr 303 | 0xe1a00000, //16 +40 nop pc 304 | 0xe1a00000, //17 +44 nop sp 305 | 0xe1a00000, //18 +48 nop addr of libname 306 | 0xe1a00000, //19 +4c nop dlopenaddr 307 | }; 308 | 309 | 310 | /** 311 | * inject 312 | */ 313 | int start_inject(pid_t pid, const char *so_path) 314 | { 315 | void* dlopen_addr = NULL; 316 | void* mprotect_addr = NULL; 317 | void* sopath_addr = NULL; 318 | size_t inject_path_len = 0; 319 | struct pt_regs old_regs = {0}; 320 | struct pt_regs new_regs = {0}; 321 | 322 | 323 | #define fatal(fmt, args...) do {printf(fmt, ##args); goto ERR_EXIT;} while(0) 324 | 325 | //attach target process 326 | if(ptrace_attach_process(pid) < 0) { 327 | printf("[-] PTRACE_ATTACH FAILED:[%s]\n", strerror(errno)); 328 | return -1; 329 | } 330 | printf("[+] PTRACE_ATTACH OK\n"); 331 | 332 | if(ptrace_get_regs(pid, &old_regs) < 0) { 333 | printf("[-] PTRACE_GETREGS FAILED:[%s]\n", strerror(errno)); 334 | return -1; 335 | } 336 | printf("[+] PTRACE_GETREGS OK\n"); 337 | new_regs = old_regs; 338 | 339 | /** 340 | * get dlopen addr 341 | * ANDROID 10.0 /libdl.so -> dlopen 342 | * */ 343 | dlopen_addr = proc_get_remote_fun_addr(pid, "/libdl.so", (void*)dlopen); 344 | if(dlopen_addr == NULL) 345 | fatal("[-] GET_DLOPEN_FUN FAILED\n"); 346 | printf("[+] DLOPEN_FUN = %p\n", dlopen_addr); 347 | 348 | //get mprotect addr 349 | mprotect_addr = proc_get_remote_fun_addr(pid, "/libc.so", (void*)mprotect); 350 | if(mprotect_addr == NULL) 351 | fatal("[-] GET_MPROTECT_FUN FAILED\n"); 352 | printf("[+] MPROTECT_FUN = %p\n", mprotect_addr); 353 | 354 | shell_code_arm[11] = new_regs.uregs[0]; 355 | shell_code_arm[12] = new_regs.uregs[1]; 356 | shell_code_arm[13] = new_regs.uregs[2]; 357 | shell_code_arm[14] = new_regs.uregs[3]; 358 | shell_code_arm[15] = new_regs.ARM_lr; 359 | shell_code_arm[16] = new_regs.ARM_pc; 360 | shell_code_arm[17] = new_regs.ARM_sp; 361 | shell_code_arm[19] = (size_t)dlopen_addr; // ldr fix T 362 | 363 | inject_path_len = strlen(so_path) + 1; 364 | inject_path_len = inject_path_len / 4 + (inject_path_len % 4 ? 1 : 0); 365 | sopath_addr = (void*)(new_regs.ARM_sp - (inject_path_len * 4) - sizeof(shell_code_arm)); 366 | shell_code_arm[18] = (size_t)sopath_addr; 367 | new_regs.ARM_sp = new_regs.ARM_sp - (inject_path_len * 4) - sizeof(shell_code_arm); 368 | 369 | //write inject_so path 370 | if(remote_write_data(pid, sopath_addr, (void*)so_path, strlen(so_path) + 1) < 0) 371 | fatal("[-] REMOTE_WRITE_PATH FAILED:[%s]\n", strerror(errno)); 372 | printf("[+] REMOTE_WRITE_PATH OK\n"); 373 | 374 | //write code to stack 375 | if(remote_write_data(pid, (void*)(new_regs.ARM_sp - sizeof(shell_code_arm)), (void*)shell_code_arm, sizeof(shell_code_arm)) < 0) 376 | fatal("[-] REMOTE_WRITE_CODE FAILED:[%s]\n", strerror(errno)); 377 | printf("[+] REMOTE_WRITE_CODE OK\n"); 378 | 379 | // todo 380 | // mprotect 381 | // new_regs.uregs[0] = (size_t)PAGE_START(new_regs.ARM_sp - sizeof(shell_code_arm)) & ~0xfff; 382 | // new_regs.uregs[1] = 0x1000; 383 | // new_regs.uregs[2] = PROT_EXEC | PROT_READ | PROT_WRITE; 384 | // new_regs.ARM_lr = (size_t)(new_regs.ARM_sp - sizeof(shell_code_arm)); // arm ? thumb ? 385 | // new_regs.ARM_pc = (size_t)mprotect_addr & ~1; // arm ? thumb ? 386 | // if ((size_t)mprotect_addr & 1) { 387 | // new_regs.ARM_cpsr |= 0x20; //thumb 0010 0000 388 | // } 389 | // else { 390 | // new_regs.ARM_cpsr &= ~0x20; //arm 0000 0000 391 | // } 392 | 393 | // printf("old_regs.ARM_lr=%p\n", old_regs.ARM_lr); 394 | // printf("old_regs.ARM_pc=%p\n", old_regs.ARM_pc); 395 | // printf("old_regs.ARM_sp=%p\n", old_regs.ARM_sp); 396 | // printf("old_regs.ARM_cpsr=%p\n", old_regs.ARM_cpsr); 397 | // printf("codeaddr=%p\n", (new_regs.ARM_sp - sizeof(shell_code_arm))); 398 | // printf("new_regs.ARM_0=%p\n", new_regs.uregs[0]); 399 | // printf("new_regs.ARM_1=%p\n", new_regs.uregs[1]); 400 | // printf("new_regs.ARM_2=%p\n", new_regs.uregs[2]); 401 | // printf("new_regs.ARM_sp=%p\n", new_regs.ARM_sp); 402 | // printf("new_regs.ARM_lr=%p\n", new_regs.ARM_lr); 403 | // printf("new_regs.ARM_pc=%p\n", new_regs.ARM_pc); 404 | 405 | #undef fatal 406 | if(ptrace_detach_process(pid, &new_regs) < 0) return -1; 407 | return 0; 408 | 409 | ERR_EXIT: 410 | if(ptrace_detach_process(pid, &old_regs) < 0) return -1; 411 | return -1; 412 | } 413 | -------------------------------------------------------------------------------- /shellcode-inject/jni/inject.h: -------------------------------------------------------------------------------- 1 | #ifndef INJECT_H 2 | #define INJECT_H 3 | 4 | #include 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | #if defined(__aarch64__) 11 | #define ZYGOTE_NAME "zygote64" 12 | #define PTRACE_GETREGS PTRACE_GETREGSET 13 | #define PTRACE_SETREGS PTRACE_SETREGSET 14 | #define pt_regs user_pt_regs 15 | #define uregs regs 16 | #define ARM_pc pc 17 | #define ARM_sp sp 18 | #define ARM_cpsr pstate 19 | #define ARM_lr regs[30] 20 | #define ARM_r0 regs[0] 21 | #else 22 | #define ZYGOTE_NAME "zygote" 23 | #endif 24 | 25 | int start_inject(pid_t pid, const char *so_path); 26 | 27 | #ifdef __cplusplus 28 | } 29 | #endif 30 | 31 | #endif //INJECT_H -------------------------------------------------------------------------------- /shellcode-inject/jni/inject_so.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | __attribute__((constructor)) void my_inject() 5 | { 6 | printf("inject ok!\n"); 7 | fflush(stdout); 8 | } 9 | -------------------------------------------------------------------------------- /shellcode-inject/jni/log_marco.h: -------------------------------------------------------------------------------- 1 | #ifndef LOG_UTILS_H 2 | #define LOG_UTILS_H 3 | 4 | #include 5 | 6 | #define TAG "PTRACE_INJECT" 7 | #define INJECT_DEBUG 1 8 | 9 | #ifdef INJECT_DEBUG 10 | #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__) 11 | #else 12 | #define LOGD(...) 13 | #endif // INJECT_DEBUG 14 | #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__) 15 | #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__) 16 | #define LOGW(...) __android_log_print(ANDROID_LOG_WARN, TAG, __VA_ARGS__) 17 | 18 | #ifndef PAGE_SIZE 19 | #define PAGE_SIZE 4096 20 | #endif 21 | 22 | #define PAGE_START(addr) (~(PAGE_SIZE - 1) & (addr)) 23 | #define PAGE_END(addr) (PAGE_START(addr + sizeof(uintptr_t) - 1) + PAGE_SIZE) 24 | #define PAGE_COVER(addr) (PAGE_END(addr) - PAGE_START(addr)) 25 | 26 | #define SET_BIT0(addr) (addr | 1) 27 | #define CLEAR_BIT0(addr) (addr & 0xFFFFFFFE) 28 | #define TEST_BIT0(addr) (addr & 1) 29 | 30 | #endif //LOG_UTILS_H -------------------------------------------------------------------------------- /shellcode-inject/jni/main.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "proc_tool.h" 11 | #include "inject.h" 12 | 13 | 14 | int main(int argc, char* argv[]) 15 | { 16 | pid_t pid = 0; 17 | char* so_name = NULL; 18 | char cmd[256] = {0}; 19 | if(argc < 3){ 20 | printf("[-] missing command line arguments.\n"); 21 | return 0; 22 | } 23 | 24 | pid = atoi(argv[1]); 25 | so_name = argv[2]; 26 | printf("[+] start inject [%s] to [pid:%d] process\n", so_name, pid); 27 | fflush(stdout); 28 | system("su -c setenforce 0"); 29 | 30 | if(start_inject(pid, so_name) < 0){ 31 | printf("[-] inject failed\n"); 32 | }else{ 33 | printf("[+] inject ok\n"); 34 | } 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /shellcode-inject/jni/proc_tool.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "proc_tool.h" 7 | #include "log_marco.h" 8 | 9 | /** 10 | * get target process name. 11 | * pid = -1, get self 12 | * pid != -1, get target process 13 | * return: process_name 14 | */ 15 | char* proc_get_process_name(pid_t pid) 16 | { 17 | FILE* fp = NULL; 18 | char path[MAX_LENGTH] = {0}; 19 | static char buffer[MAX_LENGTH] = {0}; 20 | 21 | #define fatal(fmt, args...) do {LOGE(fmt, ##args); goto ERR_EXIT;} while(0) 22 | 23 | if(0 > pid){ 24 | snprintf(path, sizeof(path), "/proc/self/cmdline"); 25 | } 26 | else{ 27 | snprintf(path, sizeof(path), "/proc/%d/cmdline", pid); 28 | } 29 | 30 | fp = fopen(path, "r"); 31 | if(NULL == fp) fatal("[-] fopen:[%s], errno:[%s]", path, strerror(errno)); 32 | if(NULL == fgets(buffer, sizeof(buffer), fp)) fatal("[-] fgets errno:[%s]", strerror(errno)); 33 | 34 | #undef fatal 35 | fclose(fp); 36 | return buffer; 37 | 38 | ERR_EXIT: 39 | if(NULL != fp) fclose(fp); 40 | return NULL; 41 | } 42 | 43 | /** 44 | * get moduleBase from /proc/pid/maps 45 | * pid = -1, get self 46 | * pid != -1, get target process 47 | * moduleName -> module name 48 | * return base_addr 49 | */ 50 | void* proc_get_module_base(pid_t pid, const char* module_name) 51 | { 52 | FILE* fp = NULL; 53 | void* base_addr = NULL; 54 | char perm[5]; 55 | char path[MAX_LENGTH] = {0}; 56 | char buff[MAX_LENGTH] = {0}; 57 | 58 | #define fatal(fmt, args...) do {LOGE(fmt, ##args); goto ERR_EXIT;} while(0) 59 | 60 | if(NULL == module_name) return NULL; 61 | 62 | if(pid < 0){ 63 | snprintf(path, sizeof(path), "/proc/self/maps"); 64 | } 65 | else{ 66 | snprintf(path, sizeof(path), "/proc/%d/maps", pid); 67 | } 68 | 69 | fp = fopen(path, "r"); 70 | if(NULL == fp) fatal("[-] fopen:[%s], errno:[%s]", path, strerror(errno)); 71 | while(fgets(buff, sizeof(buff), fp)){ 72 | if(sscanf(buff, "%p-%*p %4s", &base_addr, perm) != 2) continue; 73 | if (perm[3] != 'p') continue; 74 | if (perm[0] == '-' && perm[1] == '-' && perm[2] == '-') continue; 75 | #if defined(__aarch64__) 76 | if (NULL == strstr(buff, "lib64")) continue; 77 | #endif 78 | if (NULL != strstr(buff, module_name)) { 79 | break; 80 | } 81 | } 82 | 83 | #undef fatal 84 | fclose(fp); 85 | return base_addr; 86 | 87 | ERR_EXIT: 88 | if(NULL != fp) fclose(fp); 89 | return NULL; 90 | } 91 | 92 | /** 93 | * get target process fun addr 94 | * pid: target process pid 95 | * module_name: target module name 96 | * local_addr: local fun addr 97 | * return remote_addr 98 | */ 99 | void* proc_get_remote_fun_addr(pid_t pid, const char* module_name, void* local_addr) 100 | { 101 | void* local_module_base = NULL; 102 | void* remote_module_base = NULL; 103 | char* remote_addr = NULL; 104 | 105 | #define fatal(fmt, args...) do {LOGE(fmt, ##args); goto ERR_EXIT;} while(0) 106 | 107 | local_module_base = proc_get_module_base(-1, module_name); 108 | if(NULL == local_module_base) fatal("[-] get local module base failed"); 109 | remote_module_base = proc_get_module_base(pid, module_name); 110 | if(NULL == remote_module_base) fatal("[-] get remote module base failed"); 111 | remote_addr = (char*)remote_module_base + ((char*)local_addr - (char*)local_module_base); 112 | 113 | #undef fatal 114 | return (void*)remote_addr; 115 | 116 | ERR_EXIT: 117 | return NULL; 118 | } 119 | -------------------------------------------------------------------------------- /shellcode-inject/jni/proc_tool.h: -------------------------------------------------------------------------------- 1 | #ifndef PROC_TOOL_H 2 | #define PROC_TOOL_H 3 | 4 | #include 5 | 6 | #ifndef MAX_LENGTH 7 | #define MAX_LENGTH 1024 8 | #endif //MAX_LENGTH 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | char* proc_get_process_name(pid_t pid); 15 | void* proc_get_module_base(pid_t pid, const char* module_name); 16 | void* proc_get_remote_fun_addr(pid_t pid, const char* module_name, void* local_addr); 17 | 18 | #ifdef __cplusplus 19 | } 20 | #endif 21 | 22 | #endif //PROC_TOOL_H 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /shellcode-inject/makefile: -------------------------------------------------------------------------------- 1 | 2 | 3 | all: 4 | adb push ./libs/armeabi-v7a/inject /data/local/tmp/inject 5 | adb push ./libs/armeabi-v7a/libtest.so /data/local/tmp/ 6 | adb shell chmod 777 /data/local/tmp/inject 7 | adb shell chmod 777 /data/local/tmp/libtest.so 8 | adb shell /data/local/tmp/inject 9 | 10 | arm64: 11 | adb push ./libs/arm64-v8a/inject /data/local/tmp/inject 12 | adb push ./libs/arm64-v8a/libtest.so /data/local/tmp/ 13 | adb shell chmod 777 /data/local/tmp/inject 14 | adb shell chmod 777 /data/local/tmp/libtest.so 15 | adb shell /data/local/tmp/inject 16 | 17 | clean: 18 | rm -rf obj 19 | rm -rf libs 20 | --------------------------------------------------------------------------------