关闭

Android中的so注入(inject)和挂钩(hook) - For both x86 and arm

524人阅读 评论(0) 收藏 举报

对于Android for arm上的so注入(inject)和挂钩(hook),网上已有牛人给出了代码-libinject(http://bbs.pediy.com/showthread.php?t=141355)。由于实现中的ptrace函数是依赖于平台的,所以不经改动只能用于arm平台。本文将之扩展了一下,使它能够通用于Android的x86和arm平台。Arm平台部分基本重用了libinject中的代码,其中因为汇编不好移植且容易出错,所以把shellcode.s用ptrace_call替换掉了,另外保留了mmap,用来传字符串参数,当然也可以通过栈来传,但栈里和其它东西混一起,一弄不好就会隔儿了,所以还是保险点好。最后注意设备要root。

首先创建目录及文件:

jni
    inject.c
    Android.mk
    Application.mk

inject.c:

  1. #include <stdio.h>    
  2. #include <stdlib.h>    
  3. #include <asm/user.h>    
  4. #include <asm/ptrace.h>    
  5. #include <sys/ptrace.h>    
  6. #include <sys/wait.h>    
  7. #include <sys/mman.h>    
  8. #include <dlfcn.h>    
  9. #include <dirent.h>    
  10. #include <unistd.h>    
  11. #include <string.h>    
  12. #include <elf.h>    
  13. #include <android/log.h>    
  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 *)&params[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, &regs) == -1)    
  386.         goto exit;    
  387.     
  388.     /* save original registers */    
  389.     memcpy(&original_regs, &regs, 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, &regs) == -1)    
  403.         goto exit;    
  404.     
  405.     map_base = ptrace_retval(&regs);    
  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, &regs) == -1)    
  422.         goto exit;    
  423.     
  424.     void * sohandle = ptrace_retval(&regs);    
  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, &regs) == -1)    
  432.         goto exit;    
  433.     
  434.     void * hook_entry_addr = ptrace_retval(&regs);    
  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, &regs) == -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, &regs) == -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. }    
注意上面的/system/bin/surfaceflinger进程我随手写的,你的设备上不一定有。没有的话挑其它的也行,前提是ps命令里能找到。

Android.mk:
[plain] view plain copy
 print?
  1. LOCAL_PATH := $(call my-dir)  
  2.   
  3. include $(CLEAR_VARS)  
  4. LOCAL_MODULE := inject   
  5. LOCAL_SRC_FILES := inject.c   
  6.   
  7. #shellcode.s  
  8.   
  9. LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog  
  10.   
  11. #LOCAL_FORCE_STATIC_EXECUTABLE := true  
  12.   
  13. include $(BUILD_EXECUTABLE)  
Application.mk:
[plain] view plain copy
 print?
  1. APP_ABI := x86 armeabi-v7a  

运行nkd-build编译成生x86和arm平台下的可执行文件:

[plain] view plain copy
 print?
  1. jzj@jzj-laptop:~/workspace/inject_hook/inject_jni$ ndk-build  
  2. Install        : inject => libs/x86/inject  
  3. Install        : inject => libs/armeabi-v7a/inject  

再来生成要注入的so,创建目录及文件:

jni
    hello.c
    Android.mk
    Application.mk

hello.c:

  1. #include <unistd.h>  
  2. #include <stdio.h>  
  3. #include <stdlib.h>  
  4. #include <android/log.h>  
  5. #include <elf.h>  
  6. #include <fcntl.h>  
  7.   
  8. #define LOG_TAG "DEBUG"  
  9. #define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args)    
  10.   
  11. int hook_entry(char * a){  
  12.     LOGD("Hook success, pid = %d\n", getpid());  
  13.     LOGD("Hello %s\n", a);  
  14.     return 0;  
  15. }  
Android.mk:
  1. LOCAL_PATH := $(call my-dir)  
  2.   
  3. include $(CLEAR_VARS)  
  4.   
  5. LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog   
  6. #LOCAL_ARM_MODE := arm  
  7. LOCAL_MODULE    := hello  
  8. LOCAL_SRC_FILES := hello.c  
  9. include $(BUILD_SHARED_LIBRARY)  

Application.mk:
  1. APP_ABI := x86 armeabi-v7a  
运行nkd-build编译成生x86和arm平台下的so:
  1. jzj@jzj-laptop:~/workspace/inject_hook/hook_so_simple$ ndk-build   
  2. Install        : libhello.so => libs/x86/libhello.so  
  3. Install        : libhello.so => libs/armeabi-v7a/libhello.so  

然后就可以跑起来试试了,连接root过的Android设备或者打开模拟器。将inject和libhello.so拷入设备,设执行权限,执行:


先看看被注入进程(surfaceflinger)的mmap,可以看到我们的so已经被加载了,紧接着的那一块就是我们mmap出来的:

从logcat中也可以看到so注入成功,并且以被注入进程的身份执行了so中的代码:


简单的注入成功,现在我们再来做一个实验,就是应用这套机制来截获surfaceflinger中的eglSwapBuffers调用,然后用我们自己的函数来替换掉原来的eglSwapBuffers调用。关于截系统中的函数调用网上有例子http://bbs.pediy.com/showthread.php?t=157419,这里依葫芦画瓢。首先将hello.c改下:

  1. #include <unistd.h>  
  2. #include <stdio.h>  
  3. #include <stdlib.h>  
  4. #include <android/log.h>  
  5. #include <EGL/egl.h>  
  6. #include <GLES/gl.h>  
  7. #include <elf.h>  
  8. #include <fcntl.h>  
  9. #include <sys/mman.h>  
  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. }  

其实这种查找方法有点简单粗暴,要是正式应用的话可以在动态符号表中查找这个符号的got地址。

接着Android.mk改为:

[plain] view plain copy
 print?
  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)  

Application.mk :

[plain] view plain copy
 print?
  1. APP_ABI := x86 armeabi-v7a    
  2. APP_PLATFORM := android-14  

运行ndk-build编译:

[plain] view plain copy
 print?
  1. jzj@jzj-laptop:~/workspace/inject_hook/hook_so$ ndk-build   
  2. Install        : libhello.so => libs/x86/libhello.so  
  3. Install        : libhello.so => libs/armeabi-v7a/libhello.so  

和上面一样运行,查看logcat,我们可以看到surfaceflinger中调用eglSwapBuffers的地址已被替换成我们的版本:

[plain] view plain copy
 print?
  1. D/INJECT  ( 2231): [+] Injecting process: 1728  
  2. D/INJECT  ( 2231): [+] get_remote_addr: local[b7e4f000], remote[b7e73000]  
  3. D/INJECT  ( 2231): [+] Remote mmap address: b7e9fe32  
  4. D/INJECT  ( 2231): [+] Calling mmap in target process.  
  5. D/INJECT  ( 2231): [+] Target process returned from mmap, return value=b4f1c000, pc=0   
  6. D/INJECT  ( 2231): [+] get_remote_addr: local[b7f00000], remote[b7f7e000]  
  7. D/INJECT  ( 2231): [+] get_remote_addr: local[b7f00000], remote[b7f7e000]  
  8. D/INJECT  ( 2231): [+] get_remote_addr: local[b7f00000], remote[b7f7e000]  
  9. D/INJECT  ( 2231): [+] get_remote_addr: local[b7f00000], remote[b7f7e000]  
  10. D/INJECT  ( 2231): [+] Get imports: dlopen: b7f84f50, dlsym: b7f84fd0, dlclose: b7f84de0, dlerror: b7f84dc0  
  11. D/INJECT  ( 2231): [+] Calling dlopen in target process.  
  12. D/INJECT  ( 2231): [+] Target process returned from dlopen, return value=b7f995ec, pc=0   
  13. D/INJECT  ( 2231): [+] Calling dlsym in target process.  
  14. D/INJECT  ( 2231): [+] Target process returned from dlsym, return value=b4f17e10, pc=0   
  15. D/INJECT  ( 2231): hook_entry_addr = 0xb4f17e10  
  16. D/DEBUG   ( 1728): Hook success  
  17. D/DEBUG   ( 1728): Start hooking  
  18. D/DEBUG   ( 1728): Orig eglSwapBuffers = 0xb7d4a9c0  
  19. D/DEBUG   ( 1728): libsurfaceflinger.so address = 0xb7f22000  
  20. D/DEBUG   ( 1728): out_addr = b7f7aff4, out_size = 624  
  21. D/DEBUG   ( 1728): Found eglSwapBuffers in got  
  22. ...  
  23. D/DEBUG   ( 1728): New eglSwapBuffers  
  24. D/DEBUG   ( 1728): New eglSwapBuffers  
  25. D/DEBUG   ( 1728): New eglSwapBuffers  
  26. ...  


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:454025次
    • 积分:5530
    • 等级:
    • 排名:第4978名
    • 原创:400篇
    • 转载:411篇
    • 译文:0篇
    • 评论:49条
    文章分类
    最新评论