敢说敢作敢为, 无怨无恨无悔。这篇文章主要讲述Android Exception Hook相关的知识,希望能为你提供帮助。
承接上一篇文章Android Inline Hook,接下来我们看一下android系统中基于异常的hook方式,这种方式与inline hook相比实现较为简单,但执行效率是它的短板。
exception hook的执行流程大致如下:
文章图片
如图所示,在hook过程中需要多次对hook点指令和hook点的下一条指令进行修改,由此造成在执行效率上的损耗。
首先我们需要将hook点指令替换为一条不合法的异常指令,当程序执行到该位置时进程会接收到信号SIGILL(illegal instruction),然后进入到我们注册的SIgnal Handler中,在信号处理函里我们需要做两件事,一是执行我们的hook逻辑(如修改寄存器的值),二是恢复hook点指令并将hook点指令的下一条指令替换为异常指令,再恢复程序的运行。当程序运行到hook点的下一条指令时会再次触发异常进入信号处理函数,这一次我们需要在信号处理函数中将hook点指令再次替换为异常指令,然后恢复hook点的下一条指令,最后恢复程序运行。
由此可见,我们在信号处理函数中需要对异常的发生位置进行判断,对hook点跟hook点的下一条指令进行区分。当然最重要的是理解Linux系统中的信号机制。
void signal_handler(int signum, siginfo_t *Ssiginfo, void *context) { //信号处理函数
ucontext_t *uc = context;
struct sigcontext *sigc = & uc-> uc_mcontext; } struct sigaction sig; //initialize the signal set sigemptyset(& sig.sa_mask); //make sigaction.sa_sigaction specifies the //signal-handling function for signum sig.sa_flags = SA_SIGINFO; //attach our handler sig.sa_sigaction = signal_handler; sigaction(SIGILL, & sig, NULL);
通过sigaction函数对信号进行注册后我们便可以在信号处理函数中对其进行处理。Linux用户手册中对该函数进行了详细的说明,可参阅:Linux Programmer\'s Manual SIGACTION(2)
在信号处理函数中我们可以通过结构体sigcontext获取异常发生时各个寄存器的信息,其定义如下:
struct sigcontext { unsigned long trap_no; unsigned long error_code; unsigned long oldmask; unsigned long arm_r0; unsigned long arm_r1; unsigned long arm_r2; unsigned long arm_r3; unsigned long arm_r4; unsigned long arm_r5; unsigned long arm_r6; unsigned long arm_r7; unsigned long arm_r8; unsigned long arm_r9; unsigned long arm_r10; unsigned long arm_fp; unsigned long arm_ip; unsigned long arm_sp; unsigned long arm_lr; unsigned long arm_pc; unsigned long arm_cpsr; unsigned long fault_address; };
例如我们可以通过pc寄存器的值确定程序执行的位置。
完整程序如下:
1 #include < assert.h> 2 #include < unistd.h> 3 #include < stdlib.h> 4 #include < stdio.h> 5 #include < signal.h> 6 #include < ucontext.h> 7 #include < sys/mman.h> 8 9 int g_code_type; 10 long g_code_address; 11 uint32_t g_code_origin; 12 uint32_t g_code_next; 13 14 long get_module_addr(pid_t pid, const char *module_name) 15 { 16FILE *fp; 17char file_path[256]; 18char file_line[512]; 19if (pid < 0) { 20snprintf(file_path, sizeof(file_path), "/proc/self/maps"); 21} else { 22snprintf(file_path, sizeof(file_path), "/proc/%d/maps", pid); 23} 24fp = fopen(file_path, "r"); 25if (fp == NULL) { 26return -1; 27} 28long addr_start = -1, addr_end = 0; 29while (fgets(file_line, sizeof(file_line), fp)) { 30if (strstr(file_line, module_name)) { 31if (2 == sscanf(file_line, "%8lx-%8lx", & addr_start, & addr_end)) { 32break; 33} 34} 35} 36fclose(fp); 37return addr_start; 38 } 39 40 bool change_addr_attr(long address, bool writable) { 41//根据内存页大小对齐 42long page_size = sysconf(_SC_PAGESIZE); 43long page_start = address & (~(page_size - 1)); 44if (writable == true) { 45return mprotect((void*)page_start, page_size, PROT_READ | PROT_WRITE | PROT_EXEC) != -1; 46} else { 47return mprotect((void*)page_start, page_size, PROT_READ | PROT_EXEC) != -1; 48} 49 } 50 51 bool write_code(long address, uint32_t data) 52 { 53if (change_addr_attr(address, true) == false) { 54return false; 55} 56if (g_code_type == IS_THUMB) { 57*((uint16_t*)address) = (uint16_t)data; 58} else { 59*((uint32_t*)address) = data; 60} 61return change_addr_attr(address, false); 62 } 63 64 bool write_ill_instruction(long address, uint32_t *save) 65 { 66if (g_code_type == IS_THUMB) { 67*save = *((uint16_t*)address); 68} else if (g_code_type == IS_ARM) { 69*save = *((uint32_t*)address); 70} 71return write_code(address, 0xFFFFFFFF); 72 } 73 74 static void signal_handler(int signum, siginfo_t *Ssiginfo, void *context) 75 { 76ucontext_t *uc = context; 77struct sigcontext *sigc = & uc-> uc_mcontext; 78 79long next_address = g_code_address + (IS_ARM ? 4 : 2); 80 81if (sigc-> arm_pc == g_code_address) { 82//恢复hook点指令 83write_code(g_code_address, g_code_origin); 84//将hook点下一条指令改为异常指令 85write_ill_instruction(next_address, & g_code_next); 86} else if (sigc-> arm_pc == next_address){ 87//恢复hook点下一条指令 88write_code(next_address, g_code_next); 89//将hook点指令改为异常指令 90write_ill_instruction(g_code_address, & g_code_origin); 91} else { 92exit(EXIT_FAILURE); 93} 94 } 95 96 bool hook_exception_make(const char *library, long address, enum code_type type) 97 { 98g_code_type = type; 99 100struct sigaction sig; 101sigemptyset(& sig.sa_mask); 102sig.sa_flags = SA_SIGINFO; 103sig.sa_sigaction = signal_handler; 104sigaction(SIGILL, & sig, NULL); 105 106long target_address = get_module_addr(-1, library); 107g_code_address = target_address + address; 108return write_ill_instruction(g_code_address, & g_code_origin); 109 }
【Android Exception Hook】
推荐阅读
- GradleGradle Wrapper与Android Plugin for Gradle
- Mapped Statements collection does not contain value for
- LINQ to SQL(DBML文件)
- LINQ到列表/集合
- LINQ转字符串数组
- Android驱动学习-灯光系统总体框架
- Android Studio移动鼠标显示悬浮提示的设置方法
- ●UVA 10652 Board Wrapping
- android inline hook