├── README.md └── jni ├── Android.mk ├── Application.mk └── inject.c /README.md: -------------------------------------------------------------------------------- 1 | # arm64inject 2 | -------------------------------------------------------------------------------- /jni/Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH := $(call my-dir) 2 | 3 | include $(CLEAR_VARS) 4 | 5 | LOCAL_MULTILIB := both 6 | LOCAL_MODULE := inject 7 | LOCAL_SRC_FILES := inject.c 8 | 9 | #shellcode.s 10 | 11 | LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog 12 | 13 | #LOCAL_FORCE_STATIC_EXECUTABLE := true 14 | 15 | include $(BUILD_EXECUTABLE) -------------------------------------------------------------------------------- /jni/Application.mk: -------------------------------------------------------------------------------- 1 | # The ARMv7 is significanly faster due to the use of the hardware FPU 2 | APP_ABI := armeabi arm64-v8a 3 | APP_PLATFORM := android-14 4 | -------------------------------------------------------------------------------- /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 | #include 14 | #include 15 | 16 | #if defined(__i386__) 17 | #define pt_regs user_regs_struct 18 | #elif defined(__aarch64__) 19 | #define pt_regs user_pt_regs 20 | #define uregs regs 21 | #define ARM_pc pc 22 | #define ARM_sp sp 23 | #define ARM_cpsr pstate 24 | #define ARM_lr regs[30] 25 | #define ARM_r0 regs[0] 26 | #define PTRACE_GETREGS PTRACE_GETREGSET 27 | #define PTRACE_SETREGS PTRACE_SETREGSET 28 | #endif 29 | 30 | #define ENABLE_DEBUG 1 31 | 32 | #if ENABLE_DEBUG 33 | #define LOG_TAG "INJECT" 34 | #define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG, fmt, ##args) 35 | #define DEBUG_PRINT(format,args...) \ 36 | LOGD(format, ##args) 37 | #else 38 | #define DEBUG_PRINT(format,args...) 39 | #endif 40 | 41 | #define CPSR_T_MASK ( 1u << 5 ) 42 | 43 | #if defined(__aarch64__) 44 | const char *libc_path = "/system/lib64/libc.so"; 45 | const char *linker_path = "/system/bin/linker64"; 46 | #else 47 | const char *libc_path = "/system/lib/libc.so"; 48 | const char *linker_path = "/system/bin/linker"; 49 | #endif 50 | 51 | int ptrace_readdata(pid_t pid, uint8_t *src, uint8_t *buf, size_t size) 52 | { 53 | long i, j, remain; 54 | uint8_t *laddr; 55 | size_t bytes_width = sizeof(long); 56 | 57 | union u { 58 | long val; 59 | char chars[bytes_width]; 60 | } d; 61 | 62 | j = size / bytes_width; 63 | remain = size % bytes_width; 64 | 65 | laddr = buf; 66 | 67 | for (i = 0; i < j; i ++) { 68 | d.val = ptrace(PTRACE_PEEKTEXT, pid, src, 0); 69 | memcpy(laddr, d.chars, bytes_width); 70 | src += bytes_width; 71 | laddr += bytes_width; 72 | } 73 | 74 | if (remain > 0) { 75 | d.val = ptrace(PTRACE_PEEKTEXT, pid, src, 0); 76 | memcpy(laddr, d.chars, remain); 77 | } 78 | 79 | return 0; 80 | } 81 | 82 | int ptrace_writedata(pid_t pid, uint8_t *dest, uint8_t *data, size_t size) 83 | { 84 | long i, j, remain; 85 | uint8_t *laddr; 86 | size_t bytes_width = sizeof(long); 87 | 88 | union u { 89 | long val; 90 | char chars[sizeof(long)]; 91 | } d; 92 | 93 | j = size / bytes_width; 94 | remain = size % bytes_width; 95 | 96 | laddr = data; 97 | 98 | for (i = 0; i < j; i ++) { 99 | memcpy(d.chars, laddr, bytes_width); 100 | ptrace(PTRACE_POKETEXT, pid, dest, d.val); 101 | 102 | dest += bytes_width; 103 | laddr += bytes_width; 104 | } 105 | 106 | if (remain > 0) { 107 | d.val = ptrace(PTRACE_PEEKTEXT, pid, dest, 0); 108 | for (i = 0; i < remain; i ++) { 109 | d.chars[i] = *laddr ++; 110 | } 111 | 112 | ptrace(PTRACE_POKETEXT, pid, dest, d.val); 113 | } 114 | 115 | return 0; 116 | } 117 | 118 | #if defined(__arm__) || defined(__aarch64__) 119 | int ptrace_call(pid_t pid, uintptr_t addr, long *params, int num_params, struct pt_regs* regs) 120 | { 121 | int i; 122 | #if defined(__arm__) 123 | int num_param_registers = 4; 124 | #elif defined(__aarch64__) 125 | int num_param_registers = 8; 126 | #endif 127 | 128 | for (i = 0; i < num_params && i < num_param_registers; i ++) { 129 | regs->uregs[i] = params[i]; 130 | } 131 | 132 | // 133 | // push remained params onto stack 134 | // 135 | if (i < num_params) { 136 | regs->ARM_sp -= (num_params - i) * sizeof(long) ; 137 | ptrace_writedata(pid, (void *)regs->ARM_sp, (uint8_t *)¶ms[i], (num_params - i) * sizeof(long)); 138 | } 139 | 140 | regs->ARM_pc = addr; 141 | if (regs->ARM_pc & 1) { 142 | /* thumb */ 143 | regs->ARM_pc &= (~1u); 144 | regs->ARM_cpsr |= CPSR_T_MASK; 145 | } else { 146 | /* arm */ 147 | regs->ARM_cpsr &= ~CPSR_T_MASK; 148 | } 149 | 150 | regs->ARM_lr = 0; 151 | 152 | if (ptrace_setregs(pid, regs) == -1 153 | || ptrace_continue(pid) == -1) { 154 | printf("error\n"); 155 | return -1; 156 | } 157 | 158 | int stat = 0; 159 | waitpid(pid, &stat, WUNTRACED); 160 | while (stat != 0xb7f) { 161 | if (ptrace_continue(pid) == -1) { 162 | printf("error\n"); 163 | return -1; 164 | } 165 | waitpid(pid, &stat, WUNTRACED); 166 | } 167 | 168 | return 0; 169 | } 170 | 171 | #elif defined(__i386__) 172 | long ptrace_call(pid_t pid, uintptr_t addr, long *params, int num_params, struct user_regs_struct * regs) 173 | { 174 | regs->esp -= (num_params) * sizeof(long) ; 175 | ptrace_writedata(pid, (void *)regs->esp, (uint8_t *)params, (num_params) * sizeof(long)); 176 | 177 | long tmp_addr = 0x00; 178 | regs->esp -= sizeof(long); 179 | ptrace_writedata(pid, regs->esp, (char *)&tmp_addr, sizeof(tmp_addr)); 180 | 181 | regs->eip = addr; 182 | 183 | if (ptrace_setregs(pid, regs) == -1 184 | || ptrace_continue( pid) == -1) { 185 | printf("error\n"); 186 | return -1; 187 | } 188 | 189 | int stat = 0; 190 | waitpid(pid, &stat, WUNTRACED); 191 | while (stat != 0xb7f) { 192 | if (ptrace_continue(pid) == -1) { 193 | printf("error\n"); 194 | return -1; 195 | } 196 | waitpid(pid, &stat, WUNTRACED); 197 | } 198 | 199 | return 0; 200 | } 201 | #else 202 | #error "Not supported" 203 | #endif 204 | 205 | int ptrace_getregs(pid_t pid, struct pt_regs * regs) 206 | { 207 | #if defined (__aarch64__) 208 | int regset = NT_PRSTATUS; 209 | struct iovec ioVec; 210 | 211 | ioVec.iov_base = regs; 212 | ioVec.iov_len = sizeof(*regs); 213 | if (ptrace(PTRACE_GETREGSET, pid, (void*)regset, &ioVec) < 0) { 214 | perror("ptrace_getregs: Can not get register values"); 215 | printf(" io %llx, %d", ioVec.iov_base, ioVec.iov_len); 216 | return -1; 217 | } 218 | 219 | return 0; 220 | #else 221 | if (ptrace(PTRACE_GETREGS, pid, NULL, regs) < 0) { 222 | perror("ptrace_getregs: Can not get register values"); 223 | return -1; 224 | } 225 | 226 | return 0; 227 | #endif 228 | } 229 | 230 | int ptrace_setregs(pid_t pid, struct pt_regs * regs) 231 | { 232 | #if defined (__aarch64__) 233 | int regset = NT_PRSTATUS; 234 | struct iovec ioVec; 235 | 236 | ioVec.iov_base = regs; 237 | ioVec.iov_len = sizeof(*regs); 238 | if (ptrace(PTRACE_SETREGSET, pid, (void*)regset, &ioVec) < 0) { 239 | perror("ptrace_setregs: Can not get register values"); 240 | return -1; 241 | } 242 | 243 | return 0; 244 | #else 245 | if (ptrace(PTRACE_SETREGS, pid, NULL, regs) < 0) { 246 | perror("ptrace_setregs: Can not set register values"); 247 | return -1; 248 | } 249 | 250 | return 0; 251 | #endif 252 | } 253 | 254 | int ptrace_continue(pid_t pid) 255 | { 256 | if (ptrace(PTRACE_CONT, pid, NULL, 0) < 0) { 257 | perror("ptrace_cont"); 258 | return -1; 259 | } 260 | 261 | return 0; 262 | } 263 | 264 | int ptrace_attach(pid_t pid) 265 | { 266 | if (ptrace(PTRACE_ATTACH, pid, NULL, 0) < 0) { 267 | perror("ptrace_attach"); 268 | return -1; 269 | } 270 | 271 | int status = 0; 272 | waitpid(pid, &status , WUNTRACED); 273 | 274 | return 0; 275 | } 276 | 277 | int ptrace_detach(pid_t pid) 278 | { 279 | if (ptrace(PTRACE_DETACH, pid, NULL, 0) < 0) { 280 | perror("ptrace_detach"); 281 | return -1; 282 | } 283 | 284 | return 0; 285 | } 286 | 287 | void* get_module_base(pid_t pid, const char* module_name) 288 | { 289 | FILE *fp; 290 | long addr = 0; 291 | char *pch; 292 | char filename[32]; 293 | char line[1024]; 294 | 295 | if (pid < 0) { 296 | /* self process */ 297 | snprintf(filename, sizeof(filename), "/proc/self/maps", pid); 298 | } else { 299 | snprintf(filename, sizeof(filename), "/proc/%d/maps", pid); 300 | } 301 | 302 | fp = fopen(filename, "r"); 303 | 304 | if (fp != NULL) { 305 | while (fgets(line, sizeof(line), fp)) { 306 | if (strstr(line, module_name)) { 307 | pch = strtok( line, "-" ); 308 | addr = strtoull( pch, NULL, 16 ); 309 | 310 | if (addr == 0x8000) 311 | addr = 0; 312 | 313 | break; 314 | } 315 | } 316 | 317 | fclose(fp) ; 318 | } 319 | 320 | return (void *)addr; 321 | } 322 | 323 | void* get_remote_addr(pid_t target_pid, const char* module_name, void* local_addr) 324 | { 325 | void* local_handle, *remote_handle; 326 | 327 | local_handle = get_module_base(-1, module_name); 328 | remote_handle = get_module_base(target_pid, module_name); 329 | 330 | DEBUG_PRINT("[+] get_remote_addr: local[%llx], remote[%llx]\n", local_handle, remote_handle); 331 | 332 | void * ret_addr = (void *)((uintptr_t)local_addr + (uintptr_t)remote_handle - (uintptr_t)local_handle); 333 | 334 | #if defined(__i386__) 335 | if (!strcmp(module_name, libc_path)) { 336 | ret_addr += 2; 337 | } 338 | #endif 339 | return ret_addr; 340 | } 341 | 342 | int find_pid_of(const char *process_name) 343 | { 344 | int id; 345 | pid_t pid = -1; 346 | DIR* dir; 347 | FILE *fp; 348 | char filename[32]; 349 | char cmdline[256]; 350 | 351 | struct dirent * entry; 352 | 353 | if (process_name == NULL) 354 | return -1; 355 | 356 | dir = opendir("/proc"); 357 | if (dir == NULL) 358 | return -1; 359 | 360 | while((entry = readdir(dir)) != NULL) { 361 | id = atoi(entry->d_name); 362 | if (id != 0) { 363 | sprintf(filename, "/proc/%d/cmdline", id); 364 | fp = fopen(filename, "r"); 365 | if (fp) { 366 | fgets(cmdline, sizeof(cmdline), fp); 367 | fclose(fp); 368 | 369 | if (strcmp(process_name, cmdline) == 0) { 370 | /* process found */ 371 | pid = id; 372 | break; 373 | } 374 | } 375 | } 376 | } 377 | 378 | closedir(dir); 379 | return pid; 380 | } 381 | 382 | uint64_t ptrace_retval(struct pt_regs * regs) 383 | { 384 | #if defined(__arm__) || defined(__aarch64__) 385 | return regs->ARM_r0; 386 | #elif defined(__i386__) 387 | return regs->eax; 388 | #else 389 | #error "Not supported" 390 | #endif 391 | } 392 | 393 | uint64_t ptrace_ip(struct pt_regs * regs) 394 | { 395 | #if defined(__arm__) || defined(__aarch64__) 396 | return regs->ARM_pc; 397 | #elif defined(__i386__) 398 | return regs->eip; 399 | #else 400 | #error "Not supported" 401 | #endif 402 | } 403 | 404 | int ptrace_call_wrapper(pid_t target_pid, const char * func_name, void * func_addr, long * parameters, int param_num, struct pt_regs * regs) 405 | { 406 | DEBUG_PRINT("[+] Calling %s in target process.\n", func_name); 407 | if (ptrace_call(target_pid, (uintptr_t)func_addr, parameters, param_num, regs) == -1) 408 | return -1; 409 | 410 | if (ptrace_getregs(target_pid, regs) == -1) 411 | return -1; 412 | DEBUG_PRINT("[+] Target process returned from %s, return value=%llx, pc=%llx \n", 413 | func_name, ptrace_retval(regs), ptrace_ip(regs)); 414 | return 0; 415 | } 416 | 417 | int inject_remote_process(pid_t target_pid, const char *library_path, const char *function_name, const char *param, size_t param_size) 418 | { 419 | int ret = -1; 420 | void *mmap_addr, *dlopen_addr, *dlsym_addr, *dlclose_addr, *dlerror_addr; 421 | void *local_handle, *remote_handle, *dlhandle; 422 | uint8_t *map_base = 0; 423 | uint8_t *dlopen_param1_ptr, *dlsym_param2_ptr, *saved_r0_pc_ptr, *inject_param_ptr, *remote_code_ptr, *local_code_ptr; 424 | 425 | struct pt_regs regs, original_regs; 426 | long parameters[10]; 427 | 428 | DEBUG_PRINT("[+] Injecting process: %d\n", target_pid); 429 | 430 | if (ptrace_attach(target_pid) == -1) 431 | goto exit; 432 | 433 | if (ptrace_getregs(target_pid, ®s) == -1) 434 | goto exit; 435 | 436 | /* save original registers */ 437 | memcpy(&original_regs, ®s, sizeof(regs)); 438 | 439 | mmap_addr = get_remote_addr(target_pid, libc_path, (void *)mmap); 440 | DEBUG_PRINT("[+] Remote mmap address: %llx\n", mmap_addr); 441 | 442 | /* call mmap */ 443 | parameters[0] = 0; // addr 444 | parameters[1] = 0x4000; // size 445 | parameters[2] = PROT_READ | PROT_WRITE | PROT_EXEC; // prot 446 | parameters[3] = MAP_ANONYMOUS | MAP_PRIVATE; // flags 447 | parameters[4] = 0; //fd 448 | parameters[5] = 0; //offset 449 | 450 | if (ptrace_call_wrapper(target_pid, "mmap", mmap_addr, parameters, 6, ®s) == -1) 451 | goto exit; 452 | 453 | map_base = ptrace_retval(®s); 454 | 455 | dlopen_addr = get_remote_addr( target_pid, linker_path, (void *)dlopen ); 456 | dlsym_addr = get_remote_addr( target_pid, linker_path, (void *)dlsym ); 457 | dlclose_addr = get_remote_addr( target_pid, linker_path, (void *)dlclose ); 458 | dlerror_addr = get_remote_addr( target_pid, linker_path, (void *)dlerror ); 459 | 460 | DEBUG_PRINT("[+] Get imports: dlopen: %llx, dlsym: %llx, dlclose: %llx, dlerror: %llx\n", 461 | dlopen_addr, dlsym_addr, dlclose_addr, dlerror_addr); 462 | 463 | printf("library path = %s\n", library_path); 464 | ptrace_writedata(target_pid, map_base, library_path, strlen(library_path) + 1); 465 | 466 | parameters[0] = map_base; 467 | parameters[1] = RTLD_NOW| RTLD_GLOBAL; 468 | 469 | if (ptrace_call_wrapper(target_pid, "dlopen", dlopen_addr, parameters, 2, ®s) == -1) 470 | goto exit; 471 | 472 | void * sohandle = ptrace_retval(®s); 473 | if(!sohandle) { 474 | if (ptrace_call_wrapper(target_pid, "dlerror", dlerror_addr, 0, 0, ®s) == -1) 475 | goto exit; 476 | 477 | uint8_t *errret = ptrace_retval(®s); 478 | uint8_t errbuf[100]; 479 | ptrace_readdata(target_pid, errret, errbuf, 100); 480 | } 481 | 482 | 483 | #define FUNCTION_NAME_ADDR_OFFSET 0x100 484 | ptrace_writedata(target_pid, map_base + FUNCTION_NAME_ADDR_OFFSET, function_name, strlen(function_name) + 1); 485 | parameters[0] = sohandle; 486 | parameters[1] = map_base + FUNCTION_NAME_ADDR_OFFSET; 487 | 488 | if (ptrace_call_wrapper(target_pid, "dlsym", dlsym_addr, parameters, 2, ®s) == -1) 489 | goto exit; 490 | 491 | void * hook_entry_addr = ptrace_retval(®s); 492 | DEBUG_PRINT("hook_entry_addr = %p\n", hook_entry_addr); 493 | 494 | #define FUNCTION_PARAM_ADDR_OFFSET 0x200 495 | ptrace_writedata(target_pid, map_base + FUNCTION_PARAM_ADDR_OFFSET, param, strlen(param) + 1); 496 | parameters[0] = map_base + FUNCTION_PARAM_ADDR_OFFSET; 497 | 498 | if (ptrace_call_wrapper(target_pid, "hook_entry", hook_entry_addr, parameters, 1, ®s) == -1) 499 | goto exit; 500 | 501 | printf("Press enter to dlclose and detach\n"); 502 | getchar(); 503 | parameters[0] = sohandle; 504 | 505 | if (ptrace_call_wrapper(target_pid, "dlclose", dlclose, parameters, 1, ®s) == -1) 506 | goto exit; 507 | 508 | /* restore */ 509 | ptrace_setregs(target_pid, &original_regs); 510 | ptrace_detach(target_pid); 511 | ret = 0; 512 | 513 | exit: 514 | return ret; 515 | } 516 | 517 | int main(int argc, char** argv) { 518 | pid_t target_pid; 519 | target_pid = find_pid_of("system_server"); 520 | if (-1 == target_pid) { 521 | printf("Can't find the process\n"); 522 | return -1; 523 | } 524 | //target_pid = find_pid_of("/data/test"); 525 | inject_remote_process(target_pid, "/data/libhello.so", "hook_entry", "I'm parameter!", strlen("I'm parameter!")); 526 | return 0; 527 | } --------------------------------------------------------------------------------