android so hook原理,Android so注入(inject)和Hook技术学习(二)——Got表hook之导入表hook...

全局符号表(GOT表)hook实际是通过解析SO文件,将待hook函数在got表的地址替换为自己函数的入口地址,这样目标进程每次调用待hook函数时,实际上是执行了我们自己的函数。

GOT表其实包含了导入表和导出表,导出表指将当前动态库的一些函数符号保留,供外部调用,导入表中的函数实际是在该动态库中调用外部的导出函数。

这里有几个关键点要说明一下:

(1) so文件的绝对路径和加载到内存中的基址是可以通过 /proc/[pid]/maps 获取到的。

(2) 修改导入表的函数地址的时候需要修改页的权限,增加写权限即可。

(3) 一般的导入表Hook是基于注入操作的,即把自己的代码注入到目标程序,本次实例重点讲述Hook的实现,注入代码采用上节所有代码inject.c。

导入表的hook有两种方法,以hook fopen函数为例。

方法一:

通过解析elf格式,找出静态的.got表的位置,并在内存中找到相应的.got表位置,这个时候内存中.got表保存着导入函数的地址,读取目标函数地址,与.got表每一项函数入口地址进行匹配,找到的话就直接替换新的函数地址,这样就完成了一次导入表的Hook操作了。

hook流程如下图所示:

49191bf7239ca2864a4ae5dd17587d79.png

图1 导入表Hook流程图

具体代码实现如下:

entry.c:

2f7861b5d7c10e0703d045abf136f168.png1 #include   2 #include   3 #include   4 #include   5 #include   6 #include   7 #include   8 #include   9 #include  10  11 #define LOG_TAG "INJECT" 12 #define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) 13  14 //FILE *fopen(const char *filename, const char *modes) 15 FILE* (*old_fopen)(const char *filename, const char *modes); 16 FILE* new_fopen(const char *filename, const char *modes){ 17     LOGD("[+] New call fopen.\n"); 18     if(old_fopen == -1){ 19         LOGD("error.\n"); 20     } 21     return old_fopen(filename, modes); 22 } 23  24 void* get_module_base(pid_t pid, const char* module_name){ 25     FILE* fp; 26     long addr = 0; 27     char* pch; 28     char filename[32]; 29     char line[1024]; 30      31     // 格式化字符串得到 "/proc/pid/maps" 32     if(pid 

2f7861b5d7c10e0703d045abf136f168.png

运行ndk-build编译,得到libentry.so,push到/data/local/tmp目录下,运行上节所得到的inject程序,得到如下结果,表明hook成功:

3365eca8973fd469f35c38704603911c.png

图2.

方法二

通过分析program header table查找got表。导入表对应在动态链接段.got.plt(DT_PLTGOT)指向处,但是每项的信息是和GOT表中的表项对应的,因此,在解析动态链接段时,需要解析DT_JMPREL、DT_SYMTAB,前者指向了每一个导入表表项的偏移地址和相关信息,包括在GOT表中偏移,后者为GOT表。

具体代码如下:

2f7861b5d7c10e0703d045abf136f168.png1 #include   2 #include   3 #include   4 #include   5 #include   6 #include   7 #include   8 #include   9 #include  10  11 #define LOG_TAG "INJECT" 12 #define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) 13  14  15 //FILE *fopen(const char *filename, const char *modes) 16 FILE* (*old_fopen)(const char *filename, const char *modes); 17 FILE* new_fopen(const char *filename, const char *modes){ 18     LOGD("[+] New call fopen.\n"); 19     if(old_fopen == -1){ 20         LOGD("error.\n"); 21     } 22     return old_fopen(filename, modes); 23 } 24  25 void* get_module_base(pid_t pid, const char* module_name){ 26     FILE* fp; 27     long addr = 0; 28     char* pch; 29     char filename[32]; 30     char line[1024]; 31      32     // 格式化字符串得到 "/proc/pid/maps" 33     if(pid e_ident, "\177ELF", 4) != 0) { 77         return 0; 78     } 79  80     Elf32_Phdr* phdr_table = (Elf32_Phdr*)(base_addr + header->e_phoff); 81     if (phdr_table == 0) 82     { 83         LOGD("[+] phdr_table address : 0"); 84         return 0; 85     } 86     size_t phdr_count = header->e_phnum; 87     LOGD("[+] phdr_count : %d", phdr_count); 88  89  90     //遍历program header table,ptype等于PT_DYNAMIC即为dynameic,获取到p_offset 91     unsigned long dynamicAddr = 0; 92     unsigned int dynamicSize = 0; 93     int j = 0; 94     for (j = 0; j > 8) & 0xffffff;150         Elf32_Sym* symTableIndex = (Elf32_Sym*)(number*16 + symTabOff + base_addr);151         char* funcName = (char*)(symTableIndex->st_name + strTabOff + base_addr);152         //LOGD("[+] Func Name : %s",funcName);153         if(memcmp(funcName, "fopen", 5) == 0)154         {155             // 获取当前内存分页的大小156             uint32_t page_size = getpagesize();157             // 获取内存分页的起始地址(需要内存对齐)158             uint32_t mem_page_start = (uint32_t)(((Elf32_Addr)rel_table[i].r_offset + base_addr)) & (~(page_size - 1));159             LOGD("[+] mem_page_start = %lx, page size = %lx\n", mem_page_start, page_size);160             //void* pstart = (void*)MEM_PAGE_START(((Elf32_Addr)rel_table[i].r_offset + base_addr));161             mprotect((uint32_t)mem_page_start, page_size, PROT_READ | PROT_WRITE | PROT_EXEC);162             LOGD("[+] r_off : %x",rel_table[i].r_offset + base_addr);163             LOGD("[+] new_fopen : %x",new_fopen);164             *(unsigned int*)(rel_table[i].r_offset + base_addr) = new_fopen;165         }166     }167 168     return 0;169 }170 171 int hook_entry(char* a){172     LOGD("[+] Start hooking.\n");173     hook_fopen();174     return 0;175 }

2f7861b5d7c10e0703d045abf136f168.png

运行后的结果为:

b4fdfaee2068ef1d2259a7696e0b0596.png

图3

参考文章:

打开App,阅读手记

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值