AllHookInOne 中的hook基本流程
来源:互联网 发布:推荐系统算法 编辑:程序博客网 时间:2024/04/30 12:11
一、导入表(GOT表 HOOK)
熟悉 ELF 结构的读者都知道,SO引用外部函数的时候,在编译时会将外部函数的地址以Stub 的形式存放在.GOT表中,加载时 linker再进行重定位,即将真实的外部函数写到此 stub中。
HOOK 的思路就是:替换GOT表中的外部函数地址。可以理解为hook导入函数。
具体流程:
1.注入进程
2.可能有读者想到马上就是读取并解析 SO的结构,找到外部函数对应在GOT表中的存放地址。在 http://bbs.pediy.com/showthread.php?t=194053中已经讨论dlopen 返回的是solist,已经包含SO 信息。(直接通过SOLIST 实现替换HOOK,代码量就很小了)
导入表 HOOK 的实现是最简单的了,但也不难看出,导入表的HOOK 功能是很有限的。
例举两点:
1. 导入表 HOOK对进程通过 dlopen动态获得并调用外部符号是无效的。
2. 导入表 HOOK只能影响被注入进程。
二、AllHookInOne基本流程
主要原理:通过解析映射到内存中的elf的结构,解析出got,然后进行hook重定位替换。其中必须要基于执行视图(Execution View)进行符号解析;
ELF文件格式是基于链接视图(Linking View),链接视图是基于节(Section)对ELF进行解析的。然而动态链接库在加载的过程中,linker只关注ELF中的段(Segment)信息。因此ELF中的节信息被完全篡改或者甚至删除掉,并不会影响linker的加载过程,这样做可以防止静态分析工具(比如IDA,readelf等)对其进行分析,一般加过壳的ELF文件都会有这方面的处理。
对于这种ELF文件,如果要实现hook功能,则必须要基于执行视图(Execution View)进行符号解析;
AllHookInOne主要流程方法有:
1、从给定的so中获取基址,获取so句柄ElfHandle
ElfHandle* handle = openElfBySoname(soname);
2、从segment视图获取elf信息(即加载到内存的so)
getElfInfoBySegmentView(info, handle);
3、根据符号名寻找函数地址Sym
findSymByName(info, symbol, &sym, &symidx);
4、遍历链表,进行一次替换relplt表函数地址操作,其中需要使用mprotect修改访问内存,然后调用系统指令 清除缓存
replaceFunc(addr, replace_func, old_func)
5、遍历链表,进行一次替换reldyn表函数地址操作,其中需要使用mprotect修改访问内存,然后调用系统指令 清除缓存
replaceFunc(addr, replace_func, old_func))
6、释放资源,关闭elf句柄 closeElfBySoname(handle);
参考:https://github.com/boyliang/AllHookInOne
/* * elfhook.cpp * * Created on: 2014年10月9日 * Author: boyliang */#include <unistd.h>#include <stdio.h>#include <sys/mman.h>#include <assert.h>#include <errno.h>#include <string.h>#include <sys/syscall.h>#include "common.h"#include "elfutils.h"#include "elfio.h"#define PAGE_START(addr) (~(getpagesize() - 1) & (addr))//使用mprotect修改访问内存static int modifyMemAccess(void *addr, int prots){void *page_start_addr = (void *)PAGE_START((uint32_t)addr);return mprotect(page_start_addr, getpagesize(), prots);}//调用系统指令 清除缓存static int clearCache(void *addr, size_t len){void *end = (uint8_t *)addr + len;syscall(0xf0002, addr, end);}//替换函数地址。static int replaceFunc(void *addr, void *replace_func, void **old_func){int res = 0;if(*(void **)addr == replace_func){LOGW("addr %p had been replace.", addr);goto fails;}if(!*old_func){*old_func = *(void **)addr;}if(modifyMemAccess((void *)addr, PROT_EXEC|PROT_READ|PROT_WRITE)){LOGE("[-] modifymemAccess fails, error %s.", strerror(errno));res = 1;goto fails;}*(void **)addr = replace_func;clearCache(addr, getpagesize());LOGI("[+] old_func is %p, replace_func is %p, new_func %p.", *old_func, replace_func, *(uint32_t *)addr);fails:return res;}#define R_ARM_ABS32 0x02#define R_ARM_GLOB_DAT 0x15#define R_ARM_JUMP_SLOT 0x16//http://blog.csdn.net/L173864930/article/details/40507359int elfHook(const char *soname, const char *symbol, void *replace_func, void **old_func){assert(old_func);assert(replace_func);assert(symbol);//从给定的so中获取基址,获取so句柄ElfHandleElfHandle* handle = openElfBySoname(soname);ElfInfo info;//从segment视图获取elf信息(即加载到内存的so)getElfInfoBySegmentView(info, handle);Elf32_Sym *sym = NULL;int symidx = 0;//根据符号名寻找函数地址SymfindSymByName(info, symbol, &sym, &symidx);if(!sym){LOGE("[-] Could not find symbol %s", symbol);goto fails;}else{LOGI("[+] sym %p, symidx %d.", sym, symidx);}for (int i = 0; i < info.relpltsz; i++) {Elf32_Rel& rel = info.relplt[i];if (ELF32_R_SYM(rel.r_info) == symidx && ELF32_R_TYPE(rel.r_info) == R_ARM_JUMP_SLOT) {void *addr = (void *) (info.elf_base + rel.r_offset);//进行一次替换relplt表函数地址操作,其中需要使用mprotect修改访问内存,然后调用系统指令 清除缓存if (replaceFunc(addr, replace_func, old_func))goto fails;//only oncebreak;}}for (int i = 0; i < info.reldynsz; i++) {Elf32_Rel& rel = info.reldyn[i];if (ELF32_R_SYM(rel.r_info) == symidx &&(ELF32_R_TYPE(rel.r_info) == R_ARM_ABS32|| ELF32_R_TYPE(rel.r_info) == R_ARM_GLOB_DAT)) {void *addr = (void *) (info.elf_base + rel.r_offset);//进行一次替换reldyn表函数地址操作,其中需要使用mprotect修改访问内存,然后调用系统指令 清除缓存if (replaceFunc(addr, replace_func, old_func))goto fails;}}fails:closeElfBySoname(handle);//释放资源,关闭elf句柄return 0;}
- AllHookInOne 中的hook基本流程
- andfix中的java hook流程
- mysql中的基本操作流程
- 流程矩阵模型中的基本元素是什么?
- vb6中的hook技术
- MFC中的HOOK编程
- linux 中的hook
- MFC中的HOOK编程
- MFC中的HOOK编程
- Nova中的Hook机制
- libc中的hook机制
- Lua中的Hook机制
- 基本流程
- Android系统篇之----Hook系统的AMS服务实现应用启动的拦截功能----一、Hook系统剪切板服务流程回顾在之前的一篇文章中已经介绍了 Android中的应用启动流程,这个流程一定要理
- java读取文件夹中的文件夹和文件基本流程
- LCD 在uboot和Kernel中的基本流程
- wince中的hook(钩子)用法
- wince中的hook(钩子)用法
- 一个简易的Set容器
- "冒泡排序"算法-图文代码教你轻松简单理解-java编程
- 使用_CrtSetDbgFlag检测内存泄露
- 有趣的Linux命令
- Fedora openjdk 中文方框乱码
- AllHookInOne 中的hook基本流程
- Decorator和Factory设计模式的混搭
- 数据库2
- arm指令备注
- docker-py 文件传输put_archive
- 如何提升代码的逼格之设计模式
- Sqlserver查询数据库文件大小和剩余空间
- Linux各种发行版本概述(Redhat系 | Debian系)
- 一些集合的循环输出,从控制器(C)到视图页面(V)