最后介绍的这种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. 泡泡一分钟:Teaching Robots to Draw

    Teaching Robots to Draw 教会机器人画画https://h2r.cs.brown.edu/wp-content/uploads/kotani19.pdf Atsunobu Kot ...

  2. STM32F405的内部ADC采集

    1. ADC的初始化部分基本一致,下面是引脚复用配置 void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc) { GPIO_InitTypeDef GPIO_Ini ...

  3. linux:使用python脚本监控某个进程是否存在(不使用crontab)

    背景: 需要每天定时去检测crontab进程是否启动,所以不能用crontab来启动检测脚本了,直接使用while 循环和sleep方式实现定时检测 # coding:utf-8 import os ...

  4. 测试报告ExtentReport改进

    具体步骤Step-1:在pom.xml文件中添加 Maven 依赖包 <?xml version="1.0" encoding="UTF-8"?> ...

  5. 在ensp上利用单臂路由实验VLAN间路由

    我们为什么要设置单臂路由? 因为我们要解决不同vlan,不同网络的PC机间的通信问题~ 那它为啥叫单臂路由嘞? 单臂路由的原理时通过一台路由器,使vlan间互通数据通过路由器进行三层转发,如果在路由器 ...

  6. 用vue实现列表分页和按钮操作

    为中华之崛起而读书 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> < ...

  7. HSRP 实验

    一.环境准备 1. 软件:GNS3 2. 路由:c7200 二.实验操作 实验要求: 1.理解HSRP的工作原理. 2.掌握HSRP配置方法. 3.理解HSRP的抢占与跟踪作用. 实验拓扑: 实验过程 ...

  8. 什么是渐进式Web App(PWA)?为什么值得关注?

    转载自:https://blog.csdn.net/mogoweb/article/details/79029651 在开始PWA这个话题之前,我们先来看看Internet现状. 截至2017年1月, ...

  9. # Java类链接模型

    动态链接和解析 每一个class都有一个常量池, 保存它自己的所有的符号引用. 每一个已经被加载的class, interface都另外有一个内部版本的常量池, 叫做runtime constant ...

  10. 在iis中部署网站出现的错误

    第一次错误: 解决的方案:点击网站新建一个同名的应用池,选择网站的基本设置,选中同名的应用池 接下来可能会有第二个错误 错误摘要HTTP 错误 500.21 - Internal Server Err ...