android的got表HOOK实现
概述
对于android的so文件的hook根据ELF文件特性分为:Got表hook、Sym表hook和inline hook等。
全局符号表(GOT表)hook,它是通过解析SO文件,将待hook函数在got表的地址替换为自己函数的入口地址,这样目标进程每次调用待hook函数时,实际上是执行了我们自己的函数。
Androd so注入和函数Hook(基于got表)的步骤:
1.ptrace附加目标pid进程;
2.在目标pid进程中,查找内存空间(用于存放被注入的so文件的路径和so中被调用的函数的名称或者shellcode);
3.调用目标pid进程中的dlopen、dlsym等函数,用于加载so文件实现Android so的注入和函数的Hook;
4.释放附加的目标pid进程和卸载注入的so文件。
具体代码实现
以下以fopen函数进行got hook为例。
//获取模块地址功能实现
void* getModuleBase(pid_t pid, const char* module_name){FILE* fp;long address = 0;char* pch;char filename[32];char line[1024];// 格式化字符串得到 "/proc/pid/maps"if(pid < 0){snprintf(filename, sizeof(filename), "/proc/self/maps");}else{snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);}// 打开文件/proc/pid/maps,获取指定pid进程加载的内存模块信息fp = fopen(filename, "r");if(fp != NULL){// 每次一行,读取文件 /proc/pid/maps中内容while(fgets(line, sizeof(line), fp)){// 查找指定的so模块if(strstr(line, module_name)){// 分割字符串pch = strtok(line, "-");// 字符串转长整形address = strtoul(pch, NULL, 16);}break;}}}fclose(fp);return (void*)address;
}
//hook fopen进行实现
//(libxxxx.so文件是ELF32文件)
#define LIBPATH "/data/app-lib/com.xxxx/libxxxx.so"int hookFopen(){// 获取目标pid中"/data/app-lib/com.xxxx/libxxxx.so"模块的加载地址void* base_addr = getModuleBase(getpid(), LIBPATH );// 保存Hook目标函数的原始调用地址old_fopen = fopen;int fd;// 用open打开内存模块文件"/data/app-lib/com.xxxx/libxxxx.so"fd = open(LIB_PATH, O_RDONLY);if(-1 == fd){return -1;}// elf32文件的文件头结构体Elf32_EhdrElf32_Ehdr ehdr;// 读取elf32格式的文件"/data/app-lib/com.xxxx/libxxxx.so"的文件头信息read(fd, &ehdr, sizeof(Elf32_Ehdr));// elf32文件中节区表信息结构的文件偏移unsigned long shdr_addr = ehdr.e_shoff;// elf32文件中节区表信息结构的数量int shnum = ehdr.e_shnum;// elf32文件中每个节区表信息结构中的单个信息结构的大小(描述每个节区的信息的结构体的大小)int shent_size = ehdr.e_shentsize;// elf32文件节区表中每个节区的名称存放的节区名称字符串表,在节区表中的序号indexunsigned long stridx = ehdr.e_shstrndx;Elf32_Shdr shdr;lseek(fd, shdr_addr + stridx * shent_size, SEEK_SET);// 读取elf32文件中的描述每个节区的信息的结构体(这里是保存elf32文件的每个节区的名称字符串的)read(fd, &shdr, shent_size);// 为保存elf32文件的所有的节区的名称字符串申请内存空间char * string_table = (char *)malloc(shdr.sh_size);// 定位到具体存放elf32文件的所有的节区的名称字符串的文件偏移处lseek(fd, shdr.sh_offset, SEEK_SET);read(fd, string_table, shdr.sh_size);lseek(fd, shdr_addr, SEEK_SET);int i;uint32_t out_addr = 0;uint32_t out_size = 0;uint32_t got_item = 0;int32_t got_found = 0;// 循环遍历elf32文件的节区表(描述每个节区的信息的结构体)for(i = 0; i<shnum; i++){// 依次读取节区表中每个描述节区的信息的结构体read(fd, &shdr, shent_size);// 判断当前节区描述结构体描述的节区是否是SHT_PROGBITS类型//类型为SHT_PROGBITS的.got节区包含全局偏移表if(shdr.sh_type == SHT_PROGBITS){// 获取节区的名称字符串在保存所有节区的名称字符串段.shstrtab中的序号int name_idx = shdr.sh_name;// 判断节区的名称是否为".got.plt"或者".got"if(strcmp(&(string_table[name_idx]), ".got.plt") == 0|| strcmp(&(string_table[name_idx]), ".got") == 0){// 获取节区".got"或者".got.plt"在内存中实际数据存放地址out_addr = base_addr + shdr.sh_addr;// 获取节区".got"或者".got.plt"的大小out_size = shdr.sh_size;int j = 0;// 遍历节区".got"或者".got.plt"获取保存的全局的函数调用地址for(j = 0; j<out_size; j += 4){// 获取节区".got"或者".got.plt"中的单个函数的调用地址got_item = *(uint32_t*)(out_addr + j);// 判断节区".got"或者".got.plt"中函数调用地址是否是将要被Hook的目标函数地址if(got_item == old_fopen){got_found = 1;// 获取当前内存分页的大小uint32_t page_size = getpagesize();// 获取内存分页的起始地址(需要内存对齐)uint32_t entry_page_start = (out_addr + j) & (~(page_size - 1));// 修改内存属性为可读可写可执行if(mprotect((uint32_t*)entry_page_start, page_size, PROT_READ | PROT_WRITE | PROT_EXEC) == -1){return -1;}// Hook的函数,是我们自己定义的函数got_item = new_fopen;// 进行恢复内存属性为可读可执行if(mprotect((uint32_t*)entry_page_start, page_size, PROT_READ | PROT_EXEC) == -1){return -1;}break;// 目标函数的调用地址已经被Hook了}else if(got_item == new_fopen){break;}}// 对目标函数HOOk成功,跳出循环if(got_found)break;}}}free(string_table);close(fd);
}
android的got表HOOK实现相关推荐
- Android so导入表,Android so注入(inject)和Hook技术学习(二)——Got表hook之导入表hook...
全局符号表(GOT表)hook实际是通过解析SO文件,将待hook函数在got表的地址替换为自己函数的入口地址,这样目标进程每次调用待hook函数时,实际上是执行了我们自己的函数. GOT表其实包含了 ...
- 【Android 插件化】Hook 插件化框架总结 ( 插件包管理 | Hook Activity 启动流程 | Hook 插件包资源加载 ) ★★★
Android 插件化系列文章目录 [Android 插件化]插件化简介 ( 组件化与插件化 ) [Android 插件化]插件化原理 ( JVM 内存数据 | 类加载流程 ) [Android 插件 ...
- 【Android 插件化】Hook 插件化框架 ( 使用 Hook 方式替换插件 Activity 的 mResources 成员变量 )
Android 插件化系列文章目录 [Android 插件化]插件化简介 ( 组件化与插件化 ) [Android 插件化]插件化原理 ( JVM 内存数据 | 类加载流程 ) [Android 插件 ...
- 【Android 插件化】Hook 插件化框架 ( 从源码角度分析加载资源流程 | Hook 点选择 | 资源冲突解决方案 )
Android 插件化系列文章目录 [Android 插件化]插件化简介 ( 组件化与插件化 ) [Android 插件化]插件化原理 ( JVM 内存数据 | 类加载流程 ) [Android 插件 ...
- 【Android 插件化】Hook 插件化框架 ( 加载插件包资源 )
Android 插件化系列文章目录 [Android 插件化]插件化简介 ( 组件化与插件化 ) [Android 插件化]插件化原理 ( JVM 内存数据 | 类加载流程 ) [Android 插件 ...
- 【Android 插件化】Hook 插件化框架 ( 反射工具类 | 反射常用操作整理 )
Android 插件化系列文章目录 [Android 插件化]插件化简介 ( 组件化与插件化 ) [Android 插件化]插件化原理 ( JVM 内存数据 | 类加载流程 ) [Android 插件 ...
- 【Android 插件化】Hook 插件化框架 ( Hook Activity 启动流程 | 主线程创建 Activity 实例之前使用插件 Activity 类替换占位的组件 )
Android 插件化系列文章目录 [Android 插件化]插件化简介 ( 组件化与插件化 ) [Android 插件化]插件化原理 ( JVM 内存数据 | 类加载流程 ) [Android 插件 ...
- 【Android 插件化】Hook 插件化框架 ( Hook Activity 启动流程 | AMS 启动前使用动态代理替换掉插件 Activity 类 )
Android 插件化系列文章目录 [Android 插件化]插件化简介 ( 组件化与插件化 ) [Android 插件化]插件化原理 ( JVM 内存数据 | 类加载流程 ) [Android 插件 ...
- 【Android 插件化】Hook 插件化框架 ( Hook Activity 启动流程 | 反射获取 IActivityManager 对象 )
Android 插件化系列文章目录 [Android 插件化]插件化简介 ( 组件化与插件化 ) [Android 插件化]插件化原理 ( JVM 内存数据 | 类加载流程 ) [Android 插件 ...
- 【Android 插件化】Hook 插件化框架 ( Hook Activity 启动流程 | Hook 点分析 )
Android 插件化系列文章目录 [Android 插件化]插件化简介 ( 组件化与插件化 ) [Android 插件化]插件化原理 ( JVM 内存数据 | 类加载流程 ) [Android 插件 ...
最新文章
- ISA Server***检测及配置
- ClassPool CtClass浅析
- 使用Magicodes.SwaggerUI快速配置SwaggerUI以及设置API分组
- 二分查找(一次查找多个相同的值)
- JDK 9中不推荐使用Java的Observer和Observable
- Windows Live Messenger 2011,离线安装、多开、去广告……
- 小熊派折叠开发板Docker编译烧录安装HAP
- 第二节:使用反射构建动态可扩展应用程序
- liunux中的 【ifconfig】 命令 查看系统IP。
- 汇桔网与分众传媒正式达成全面深度战略资本合作
- wepy集成colorui 样式框架
- de4dot命令 v2.0.3.3405 破解命令
- matlab 求obb,obb包围盒代码
- 计算机一级考试试题在线操作,计算机一级考试题库操作题
- 以程序员的方式解决武汉公积金用户注册页面无法点击下一步问题
- thrift文件服务器,Thrift功能和使用
- 【概率论与数理统计】1.4 条件概率
- 电商打折套路分析 —— Python数据分析练习
- 解读《Superhuman AI for multiplayer poker》
- 一代版本一代神,加密行业在新局势下充满机遇也面临挑战