最后介绍的这种hook方式原理比较简单,只需要将GOT表中的目标函数地址替换为我们自己的函数地址即可,但它的缺点是只能对导入函数进行hook,还需要对elf文件的结构有所了解。

一、获取到GOT表在内存中的地址

要得到GOT表在内存中的地址首先要解析elf文件,获取其在文件中的偏移地址,内存地址就等于基地址加上文件偏移。

在elf的section header table中名为.got的节头记录着GOT表在文件中的偏移,所以第一件事就是获取到.got节头中的信息。

1、获取到section header table的入口地址

 Elf32_Ehdr elf_header;
memset(&elf_header, , sizeof(elf_header));
fseek(fp, , SEEK_SET);
fread(&elf_header, sizeof(elf_header), , fp);

文件指针fp对应打开的elf文件。结构体Elf32_Ehdr对应elf文件头,Elf32_Ehdr.e_shoff记录着节区头部表(section header table)在文件中的偏移。

2、获取字符串表

获取到section header table的起始地址后要通过名字来判断出哪一项为.got节头,这时就要用到字符串表。

 char* parse_string_table(FILE *fp)
{
Elf32_Ehdr elf_header;
Elf32_Shdr elf_setion_header;
memset(&elf_header, , sizeof(elf_header));
memset(&elf_setion_header, , sizeof(elf_setion_header));
  //读取elf头
fseek(fp, , SEEK_SET);
fread(&elf_header, sizeof(elf_header), , fp);
//字符串表头在节区头部表的第Elf32_Ehdr.e_shstrndx项
//通过节区头部表偏移和每个节区头的大小可以算出字符串表节头的地址
fseek(fp, elf_header.e_shoff + elf_header.e_shstrndx * elf_header.e_shentsize, SEEK_SET);
fread(&elf_setion_header, sizeof(elf_setion_header), , fp);
int size_string_table = elf_setion_header.sh_size;
char *buffer = malloc(size_string_table);
//通过字符串表节区头中记录的偏移地址读取字符串表
fseek(fp, elf_setion_header.sh_offset, SEEK_SET);
fread(buffer, size_string_table, , fp);
return buffer;
}

3、遍历节区头部表

遍历整个节区头部表,获取.got节区头,获取GOT表在文件中的偏移地址。

 void parse_got_table(FILE *fp, long *addr_got_table, long *size_got_table)
{
Elf32_Ehdr elf_header;
Elf32_Shdr elf_secion_header;
memset(&elf_header, , sizeof(elf_header));
memset(&elf_secion_header, , sizeof(elf_secion_header));
//读取elf头
fseek(fp, , SEEK_SET);
fread(&elf_header, sizeof(elf_header), , fp);
//获取字符串表
char *string_table = parse_string_table(fp);
fseek(fp, elf_header.e_shoff, SEEK_SET);
//遍历节区头部表
for (int i = ; i < elf_header.e_shnum; ++i) {
fread(&elf_secion_header, elf_header.e_shentsize, , fp);
if (elf_secion_header.sh_type == SHT_PROGBITS
&& == strcmp(".got", string_table + elf_secion_header.sh_name)) {
//返回GOT表偏移及大小
*addr_got_table = elf_secion_header.sh_addr;
*size_got_table = elf_secion_header.sh_size;
}
}
free(string_table);
}

4、获取elf文件在内存中的基址

在Linux系统中可以通过读取/proc/pid/maps来获取各个elf文件在内存中的加载基址。在之前的文章中已经反复用到,这里就不再重复了。

最后可以得到:GOT表内存地址 = elf文件内存基址 + GOT表文件偏移

二、修改GOT表中存放的导入函数的地址

知道GOT表在内存中的地址后我们就可以着手对其修改了,里边存放的全是外部符号地址(前三项有特殊作用,这里不做讨论),很显然每个表项占4个字节。接下来一个问题是我们怎么知道需要替换哪一个表项呢?如果我们知道需要hook的函数地址,就可以跟表里的地址进行逐一比对。如果是系统库中的函数,我们可以直接获取到函数地址,但如果是第三方库中的函数呢?我们可以借助dlsym函数。

void hook_got_make(const char *elf, const char *symbol, const char *library, void *func, void **old_func)
{
FILE *file = fopen(elf, "rb");
long addr_got_table;
long size_got_table;
parse_got_table(file, &addr_got_table, &size_got_table);
fclose(file);
void *handle = dlopen(library, RTLD_LAZY);
void *target = dlsym(handle, symbol);
dlclose(handle);
long addr_base = get_module_addr(-, elf);
for (int i = ; i < size_got_table; i += ) {
if (*(uint32_t *)(addr_base + addr_got_table + i) == (uint32_t)target) {
*old_func = target;
write_code(addr_base + addr_got_table + i, (uint32_t)func);
}
}
}

首先通过dlopen加载symbol(目标函数名)所在的可执行文件,当然这个文件肯定之前就已经加载到内存中了。然后通过dlsym获取symbol对应的函数地址。

获取到地址后首先保存到old_func中,然后用我们的新地址覆盖GOT表中的原地址。注意在更改GOT表的内容时首先要将所在内存地址的属性设为可写。

Android GOT Hook的更多相关文章

  1. 使用cydia substrate 来进行android native hook

      cydia不仅可以hook java代码,同样可以hook native代码,下面举一个例子来进行android native hook 我是在网上找到的supermathhook这个项目,在他基 ...

  2. Android Exception Hook

    承接上一篇文章Android Inline Hook,接下来我们看一下android系统中基于异常的hook方式,这种方式与inline hook相比实现较为简单,但执行效率是它的短板. except ...

  3. Android Xpose Hook(一)

    实验环境:     Droid4x模拟器 (目前Android版本4.2.2)     Android Studio 1.下载相关工具 XposedInstaller下载 http://repo.xp ...

  4. android inline hook

    最近终于沉下心来对着书把hook跟注入方面的代码敲了一遍,打算写几个博客把它们记录下来. 第一次介绍一下我感觉难度最大的inline hook,实现代码参考了腾讯GAD的游戏安全入门. inline ...

  5. android ART hook

    0x00 前言 之前一直都是在Dalvik 虚拟机上在折腾,从Android 4.4开始开始引入ART,到5.0已经成为默认选择.而且最近看到阿里开源的 Dexposed 框架,已经提供了对于andr ...

  6. Android Native Hook技术(二)

    Hook技术应用 已经介绍了安卓 Native hook 原理,这里介绍 hook 技术的应用,及 Cyida Substrate 框架. 分析某APP,发现其POST请求数据经过加密,我们希望还原其 ...

  7. Android Native Hook技术(一)

    原理分析 ADBI是一个著名的安卓平台hook框架,基于 动态库注入 与 inline hook 技术实现.该框架主要由2个模块构成:1)hijack负责将so注入到目标进程空间,2)libbase是 ...

  8. android的hook方面知识点

    android hook分为另种: native层hook---理解ELF文件 java层---虚拟机特性和Java上的反射的作用 注入代码: 存放在哪? 用mmap函数分配临时内存来完成代码存放,对 ...

  9. Android逆向进阶(7)——揭开Hook的神秘面纱

    本文作者:i春秋作家——HAI_ 0×00 前言 HAI_逆向使用手册(想尝试一下新的写法) 其他 Android逆向进阶 系列课程 <<<<<<< 人物说明 ...

随机推荐

  1. IDEA使用Git出现push to origin/master was rejected错误解决方案

    在IDEA中配置码云的URL,如下图 切换到自己项目所在的目录,右键选择GIT BASH Here 在terminl窗口中依次输入命令: git pull git pull origin master ...

  2. 【ARM-Linux开发】【CUDA开发】【视频开发】关于Linux下利用GPU对视频进行硬件加速转码的方案

    最近一直在研究Linux下利用GPU进行硬件加速转码的方案,折腾了很久,至今没有找到比较理想的硬加速转码方案.似乎网上讨论这一方案的文章也特别少,这个过程中也进行了各种尝试,遇到很多具体问题,以下便对 ...

  3. [转帖]helm模板文件chart编写语法详解

    helm模板文件chart编写语法详解 https://blog.51cto.com/qujunorz/2421328 需要学习一下. charts编写介绍 开始 快速创建一个chart模板,helm ...

  4. [转帖]Chrome用户请尽快更新:谷歌发现两个严重的零日漏洞

    Chrome用户请尽快更新:谷歌发现两个严重的零日漏洞 https://news.cnblogs.com/n/647075/ 强烈建议:Chrome 用户请尽快升级浏览器!在谷歌今天发布的紧急补丁程序 ...

  5. (四)linux 学习 --使用命令

    The Linux Command Line 读书笔记 - 部分内容来自 http://billie66.github.io/TLCL/book/chap06.html 文章目录 什么是命令 是哪一种 ...

  6. 简单的python爬虫教程:批量爬取图片

    python编程语言,可以说是新型语言,也是这两年来发展比较快的一种语言,而且不管是少儿还是成年人都可以学习这个新型编程语言,今天南京小码王python培训机构变为大家分享了一个python爬虫教程. ...

  7. SpringCloud之Zuul网关简介、映射vs过滤配置使用

    目的: Zuul路由网关简介及基本使用 Zuul路由映射配置 Zuul请求过滤配置 Zuul路由网关简介及基本使用 Zuul简介: Zuul是从设备和网站到Netflix流应用程序后端的所有请求的前门 ...

  8. Create your first Java application

    参考链接 -[IntelliJ IDEA] https://www.jetbrains.com/help/idea/creating-and-running-your-first-java-appli ...

  9. Luogu4233 射命丸文的笔记 DP、多项式求逆

    传送门 注意到总共有\(\frac{n!}{n}\)条本质不同的哈密顿回路,每一条哈密顿回路恰好会出现在\(2^{\binom{n}{2} - n}\)个图中,所以我们实际上要算的是强连通有向竞赛图的 ...

  10. The Day Two 找到一个具有最大和的连续子数组,返回其最大和

    """ 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和. 示例: 输入: [-2,1,-3,4,-1,2,1,-5, ...