文章目录

  • 前言
  • 一、函数拦截需要的几个参数
  • 二、插桩前先保存实际函数入口 6 字节数据
  • 三、在插桩的函数入口写入跳转指令 | 构造拼接桩函数

前言

【Android 逆向】函数拦截实例 ( 函数拦截流程 | ① 定位动态库及函数位置 ) 博客中简单介绍了 hook 函数 ( 函数拦截 ) 的流程 , 本篇博客开始介绍函数拦截实例 ;

拦截 clock_gettime 函数 ;

#include <time.h>
int clock_gettime(clockid_t clk_id,struct timespec *tp);

一、函数拦截需要的几个参数


定义 hook_func 函数 , 执行 C/C++ 函数的 hook 操作 ;

void hook_func(uint8_t* pApi, uint8_t* pUser, uint8_t* pStub, size_t size)

上述函数的 444 个参数含义如下 :

  • uint8_t* pApi 参数 : 要拦截的实际函数 , int clock_gettime(clockid_t clk_id,struct timespec *tp); 函数 ;
  • uint8_t* pUser 参数 : 拦截函数后 , 跳转到的 dn_clock_gettime 函数 ;
  • uint8_t* pStub 参数 : 定义的 do_clock_gettime 桩代码 , 将 pApi 函数的前 6 字节拷贝到该 pStub 函数入口 , 然后跳转到 pApi 函数的第 666 字节开始执行 , 相当于调用了 uint8_t* pApi 参数对应的实际函数 , 即 int clock_gettime(clockid_t clk_id,struct timespec *tp); 函数 ;
  • size_t size 参数 : 跳转指令占 0xE9,0,0,0,0 555 字节 , 这里 将函数入口前 666 字节保存下来 ;

函数调用实例 :

/* 这是 hook 标准库中的 clock_gettime 函数的入口方法 , 跳转到自定义的 dn_clock_gettime 方法中 */
hook_func((uint8_t*)clock_gettime, (uint8_t*)dn_clock_gettime, (uint8_t*)do_clock_gettime, 6);

二、插桩前先保存实际函数入口 6 字节数据


插桩前先 保存函数的入口 6 字节数据 , 因为之后插桩 , 会使用跳转代码 0xE9,0,0,0,0 覆盖函数入口内存 , 被破坏的实际函数 最终还是要执行 , 需要拷贝一下 , 供之后实际函数调用使用 ;

 unsigned char code[64] = { 0 };/* 插桩前先保存函数的入口 6 字节数据 , 因为之后插桩 , * 会使用跳转代码 0xE9,0,0,0,0 覆盖函数入口内存* 该函数最终还是要执行 , 需要拷贝一下 , 供之后实际函数调用使用 */memcpy(code, pApi, size);

三、在插桩的函数入口写入跳转指令 | 构造拼接桩函数


这里执行了 222 次插桩操作 :

  • 第一次是实际函数跳转 : 函数插桩 , pApi 是实际函数 , pUser 是插桩后跳转到的拦截函数 ; 该情况是在 clock_gettime 函数的入口处插入跳转代码 , 跳转到 dn_clock_gettime 函数位置 ;
  • 第二次是构造桩函数 ( 构造拼接桩函数 ) : 在自定义的 dn_clock_gettime 函数中 , 需要调用实际的 clock_gettime 函数 , 这里将 do_clock_gettime 函数构造成 clock_gettime 函数 ;

构造拼接桩函数 : 前 6 字节是保存下来的 clock_gettime 函数的前 6 字节指令 , 执行到第 6 字节时 , 直接跳转到 clock_gettime 函数 执行 , 这样执行拼接的函数 等同于执行 clock_gettime 函数 ;

do_clock_gettime 函数构造成 clock_gettime 函数流程 : 执行 do_clock_gettime 方法的第 6 字节的指令时 , 跳转到 clock_gettime 函数的第 6 字节指令位置 , do_clock_gettime 的 0 ~ 6 字节指令是 clock_gettime 实际函数的前 6 字节 , 之所以这么定义 , 是因为 clock_gettime 的前 6 个字节被覆盖为 跳转指令了 ;

调用 do_clock_gettime 方法 , 就相当于调用了 clock_gettime 方法 ;

 /* 函数插桩 , pApi 是实际函数 , pUser 是插桩后跳转到的拦截函数 */write_code(pApi, pUser);/* 执行 size + pStub 位置的指令时 , 直接跳转到 size + pApi 位置如 : 执行 do_clock_gettime 方法的第 6 字节的指令时 , 跳转到 clock_gettime 函数的第 6 字节指令位置   do_clock_gettime 的 0 ~ 6 字节指令是 clock_gettime 实际函数的前 6 字节 , 之所以这么定义 , 是因为 clock_gettime 的前 6 个字节被覆盖为 跳转指令了调用 do_clock_gettime 方法 , 就相当于调用了 clock_gettime 方法 ; */write_code(size + pStub, size + pApi);/* 将复制的 6 字节 代码存放到 pStub 函数中的 0 ~ 6 字节位置 */memcpy(pStub, code, size);

函数插桩的具体细节在之前的

  • 【Android 逆向】函数拦截 ( 修改内存页属性 | x86 架构插桩拦截 )
  • 【Android 逆向】函数拦截 ( ARM 架构下的插桩拦截 | 完整代码示例 )

博客中有详细的说明 , 先修改内存页属性 , 然后直接修改内存 , 写入跳转汇编指令对应的二进制机器码数据 ;

代码示例 :

/** unsigned char* pFunc* unsigned char* pStub* 上述两个参数分别是两个函数指针* * 注意 : 写完之后要刷新 CPU 高速缓存 , 调用 cache_flush 系统调用函数*/
int write_code(unsigned char* pFunc, unsigned char* pStub) {/* 获取 pFunc 函数入口 , 先获取该函数所在内存页地址 */void* pBase = (void*)(0xFFFFF000 & (int)pFunc);/* 修改整个内存页属性 , 修改为 可读 | 可写 | 可执行 , * 避免因为内存访问权限问题导致操作失败* mprotect 函数只能对整个页内存的属性进行修改 * 每个 内存页 大小都是 4KB */int ret = mprotect(pBase, 0x1000, PROT_WRITE | PROT_READ | PROT_EXEC);/* 修改内存页属性失败的情况 */if (ret == -1) {perror("mprotect:");return -1;}
#if defined(__i386__) // arm 情况处理/* E9 是 JMP 无条件跳转指令 , 后面 4 字节是跳转的地址 */unsigned char code[] = { 0xE9,0,0,0,0 };/* 计算 pStub 函数跳转地址 , 目标函数 pStub 地址 - 当前函数 pFunc 地址 - 5 * 跳转指令 跳转的是 偏移量 , 不是绝对地址值*/*(unsigned*)(code + 1) = pStub - pFunc - 5;/* 将跳转代码拷贝到 pFunc 地址处 , 这是 pFunc 函数的入口地址 */memcpy(pFunc, code, sizeof(code));
#else // arm 情况处理/* B 无条件跳转指令 */unsigned char code[] = { 0x04,0xF0,0x1F,0xE5,0x00,0x00,0x00,0x00 };/* arm 的跳转是绝对地址跳转 , 传入 pStub 函数指针即可 */*(unsigned*)(code + 4) = (unsigned)pStub;/* 将机器码复制到函数开始位置 */memcpy(pFunc, code, sizeof(code));
#endifreturn 0;
}

【Android 逆向】函数拦截实例 ( ② 插桩操作 | 保存实际函数入口 6 字节数据 | 在插桩的函数入口写入跳转指令 | 构造拼接桩函数 )相关推荐

  1. 【Android 逆向】函数拦截实例 ( ③ 刷新 CPU 高速缓存 | ④ 处理拦截函数 | ⑤ 返回特定结果 )

    文章目录 前言 一.刷新 CPU 高速缓存 二.处理拦截函数 1.桩函数 2.处理拦截函数 三.返回特定结果 四.相关完整代码 前言 [Android 逆向]函数拦截实例 ( 函数拦截流程 | ① 定 ...

  2. 【Android 逆向】函数拦截实例 ( 函数拦截流程 | ① 定位动态库及函数位置 )

    文章目录 一.函数拦截流程 二.定位动态库及函数位置 一.函数拦截流程 函数拦截流程 : 定位动态库及函数位置 : 获取该动态库在内存中的位置 , 以便于 查找函数位置 ; 插桩 : 在函数的入口处插 ...

  3. 【Android 逆向】函数拦截 ( 使用 cache_flush 系统函数刷新 CPU 高速缓存 | 刷新 CPU 高速缓存弊端 | 函数拦截推荐时机 )

    文章目录 一.使用 cache_flush 系统函数刷新 CPU 高速缓存 二.使用 cache_flush 系统函数刷新 CPU 高速缓存的弊端 三.函数拦截推荐时机 一.使用 cache_flus ...

  4. 【Groovy】MOP 元对象协议与元编程 ( 使用 Groovy 元编程进行函数拦截 | 重写 MetaClass#invokeMethod 方法实现函数拦截 | 实现函数调用转发 )

    文章目录 一.重写 MetaClass#invokeMethod 方法实现函数拦截 二.在 MetaClass#invokeMethod 方法中调用对象的其它方法 三.完整代码示例 一.重写 Meta ...

  5. 小七新Android逆向,小七Android逆向脱壳课程

    [视频目录] [小七新Android逆向脱壳课程]脱壳1.Java环境配置与各种逆向工具安装配置介绍 [小七新Android逆向脱壳课程]脱壳2.Android手机端配置及必要软件安装 [小七新And ...

  6. 【Android 逆向】函数拦截 ( ARM 架构下的插桩拦截 | 完整代码示例 )

    文章目录 一.ARM 架构下的插桩拦截 二.完整代码示例 一.ARM 架构下的插桩拦截 ARM 架构下的跳转指令 : 下面的二进制数都是十六进制数 ; 323232 位指令 ; 04 F0 1F E5 ...

  7. 【Android 逆向】函数拦截 ( GOT 表拦截 与 插桩拦截 | 插桩拦截简介 | 插桩拦截涉及的 ARM 和 x86 中的跳转指令 )

    文章目录 一.GOT 表拦截与插桩拦截 二.插桩拦截简介 三.插桩拦截涉及的 ARM 和 x86 中的跳转指令 一.GOT 表拦截与插桩拦截 函数拦截有 222 种方式 : 使用 GOT 表进行函数拦 ...

  8. 【Android 逆向】函数拦截 ( 修改内存页属性 | x86 架构插桩拦截 )

    文章目录 一.修改内存页属性 二.x86 架构下的插桩拦截 一.修改内存页属性 实际函数 的 函数指针为 unsigned char* pFunc , 拦截函数 的函数指针为 unsigned cha ...

  9. 【Android 逆向】函数拦截 ( CPU 高速缓存机制 | CPU 高速缓存机制 导致 函数拦截失败 )

    文章目录 一.CPU 高速缓存机制 二.CPU 高速缓存机制 导致 函数拦截失败 一.CPU 高速缓存机制 CPU 架构模型中 , 指令 在开始时 , 存放在内存中 , 如 : /proc/pid/m ...

最新文章

  1. “猜画小歌”的一些细节和思考
  2. springboot多数据源配置_SpringBoot-配置多数据源
  3. ElasticSearch学习笔记(二)—结构了解和索引文档增删改
  4. Mybatis源码之(TypeAliasRegistry)TypeAlias别名实现机制
  5. 美化type=file控件
  6. 暴力破解(一)——python脚本暴力破解 加密的zip压缩文件
  7. 网络编程:UDP的socket编程(Linux)
  8. Google Earth Engine ——LANDSAT8——TOA系列数据
  9. 乌鲁木齐市谷歌高清卫星地图下载
  10. npm/cnpm install 报错 platform unsupported
  11. 在salesforce中实现鼠标悬停显示提示框效果,并对显示框内容进行微缩页面布局
  12. 关于电脑连不上WiFi,但可以连上网线的解决办法
  13. centos6 安装 nscd 清除DNS缓存
  14. Android 从网页中跳转到APP
  15. 五、C语言创建桌面程序:画笔和画刷
  16. Bert-whitening 向量降维及使用
  17. 房子场景模型如何建造?看3D建模教程:3ds max、zbrush制作房子
  18. ssm+JSP计算机毕业设计基于java的信访管理系统64esx【源码、程序、数据库、部署】
  19. 福昕阅读器软件foxit设置快…
  20. 南阳《建筑业企业施工劳务资质备案申请表》填写说明

热门文章

  1. java多线程 ThreadPoolExecutor 策略的坑
  2. Python天天美味(13) - struct.unpack
  3. SCSM 2012Orchestrator 2012 虚拟机自动交付测试
  4. TypePerf收集服务器性能
  5. TCP和UDP和IP和HTTP和socket
  6. BZOJ3709: [PA2014]Bohater
  7. editplus替换空白行的正则表达式
  8. 【FAQ】使用 LOAD 載入外部中文字檔 *.TXT, 中文字卻成為亂碼之解決
  9. php+ tinymce粘贴word
  10. JAVA中文字符串编码--GBK转UTF-8