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