共享文件原理_fishhook 的实现原理浅析

c4965d3e43abafa0a907dc9f1ecee959.png

| 作者:小可长江,目前在 bilibili 做音视频研发,业余时间喜欢研究好的源码和逆向

打开姿势很重要

早些时候,iOS中一提到“黑魔法”、HOOK,很多人第一时间想到的就是 AOP RunTime MethodSwizzling 这些不明觉厉的东西,它们的基本用法其实都不难,真正难的是如何在合适的地方用好它们。

任何事物都有两面性,越强大其可能带来的隐患也越具有毁灭性。苹果提供的运行时机制固然大有用处,但如果在项目中滥用(更不是用来当做面试提升逼格的),很多时候只会适得其反,详细误区请参考 iOS界的毒瘤-MethodSwizzling

关于 MethodSwizzling 的用法在之前的文章中也有过讲解,请参考 MethodSwizzling的几种姿势。该方式更多的用于性能监测、 crash 的兼容和上报、反破解防护等一些工具的开发中,而在逆向中,在面对有相应安全防护措施的应用时,其用武之地比较有限。

无独有偶,“黑魔法”可不只有 RunTime ,今天我们来聊聊在逆向中常用的另一种HOOK方式:fishhook。

fishhook 背后的故事

(一)实现原理

fishhook 是 FaceBook 开源的可以动态修改 MachO 符号表的工具。fishhook 的强大之处在于它可以 HOOK 系统的静态 C 函数。

大家都知道 OC 的方法之所以可以 HOOK 是因为它的运行时特性,OC 的方法调用在底层都是 msg_send(id,SEL) 的形式,这为我们提供了交换方法实现(IMP)的机会,但 C 函数在编译链接时就确定了函数指针的地址偏移量(Offset),这个偏移量在编译好的可执行文件中是固定的,而可执行文件每次被重新装载到内存中时被系统分配的起始地址(在 lldb 中用命令 image List 获取)是不断变化的。运行中的静态函数指针地址其实就等于上述 Offset + Mach0 文件在内存中的首地址:

4411c1a51819ed55ce2b11244570add1.png

既然 C 函数的指针地址是相对固定且不可修改的,那么 fishhook 又是怎么实现 对 C 函数的 HOOK 呢?其实内部/自定义的 C 函数 fishhook 也 HOOK 不了,它只能HOOK Mach-O 外部(共享缓存库中)的函数。fishhook 利用了 MachO 的动态绑定机制(不清楚的同学看这里:MachO 文件结构详解dyld背后的故事&源码分析
):苹果的共享缓存库不会被编译进我们的 MachO 文件,而是在动态链接时才去重新绑定。苹果采用了 PIC(Position-independent code)技术成功让 C 的底层也能有动态的表现:

  • 编译时在 Mach-O 文件 _DATA 段的符号表中为每一个被引用的系统 C 函数建立一个指针(8字节的数据,放的全是0),这个指针用于动态绑定时重定位到共享库中的函数实现。

  • 在运行时当系统 C 函数被第一次调用时会动态绑定一次,然后将 Mach-O 中的 _DATA 段符号表中对应的指针,指向外部函数(其在共享库中的实际内存地址)。

fishhook 正是利用了 PIC 技术做了这么两个操作:

  • 将指向系统方法(外部函数)的指针重新进行绑定指向内部函数/自定义 C 函数。

  • 将内部函数的指针在动态链接时指向系统方法的地址。

这样就把系统方法与自己定义的方法进行了交换,达到 HOOK 系统 C 函数(共享库中的)的目的。

(二)用汇编解析过程

为了更好的理解 fishhook 是如何 HOOK 系统的 C 函数,我们以 HOOK NSLog 为例,从汇编着手来一步步去分析,为大家扒开 fishhook 实现 HOOK 系统 NSLog 的全过程。

注:对于非懒加载符号表,dyld 会在动态链接时就链接动态库
对于懒加载符号表,dyld 会在运行时函数第一次被调用时动态绑定一次
NSLog 在懒加载表中

1.验证系统的动态绑定:

新建一个空工程,写下这两行代码:

dee79ddb1c86c3b7488ba4c23e169f57.png

编译一下工程,在目录 Products 下将 .app 内的可执行文件拷出用 MachOView 打开:

020c9b8c185bc73490bd29f90236c73f.png

记下 0x3028 这个偏移值,这就是用于重定向到共享库中的那个指针相对于 MachO文件的偏移量。

在两个 NSLog 处分别加上断点,将工程 Run 起来,把 Debug -> Debug Workflow -> Always Show Disassembly 勾选上,用于查看汇编信息,断点断住后获取 MachO 在内存中的首地址:

62ae0761c84f47fc17e965ebdc6e7d6b.png

0x3028+0x000000010b0f7000 就是用于重定向到共享库中的那个指针的内存地址。此时我们查看该地址是否已经被重定向:

e17e28f3e697904c57db200625007f45.png

  1. 拿到该指针当前保存的值,iOS 的 CPU 是小端序,当前机型为 64 位 CPU,所以倒序读 8 个字节就是指针的值:0x010b0f89a0

  2. dis -s 是反汇编命令,我们发现此时该指针指向的函数正在调用系统动态绑定的函数

  3. 进一步查看调用函数详细信息:libdyld.dylib`dyld_stub_binder

这是在干嘛?没错,这就是第一次调用 NSLog 时系统去重新绑定位懒加载符号表中 NSLog 对应的指针所指向的位置。

接下来我们过掉第一次断点,让断点断在第二个 NSLog 处,再次查看符号表中该指针(依然是 0x3028+0x000000010b0f7000 这个地址)所指向的地址,

362e2435d8db74da2f04550e4c674aad.png

我们发现,它指向的地址由之前的 0x010b0f89a0 变为 0x010b491276 了,对应的函数也由之前的 dyld_stub_binder 变为 NSLog ,这意味着该函数的动态绑定已经完成。以上,我们验证了 iOS 的动态绑定全过程。

2.验证 fishhook 的重绑定:

我们将 fishhook文件拖入工程,并添加一个简单的绑定:

ed2bcc41476ade228940cc66537eb3ee.png

注意:修改文件后重新编译的 MachO 文件,符号表里的指针偏移值可能会改变,重新运行的程序内存首地址也会发生变化,需要你重新拿到它们计算得出指针新的内存地址。

我们运行起来之后点击屏幕进入上图所示断点,查看符号表中原本指向系统 NSLog 的指针指向:

4202eda37bbfc1072f186d29bb6d77db.png

此时该指针的指向被修改为我们自定义的函数 myNslog 了,而将系统重定位的外部函数地址保存到了另一个自定义函数指针 sys_nslog 中:

7b87cfd37467d0b4fda03fa2163409d1.png

以上,我们通过断点分析汇编信息,验证了 fishhook 实现 HOOK 系统外部函数的思路。接下来我们结合 fishhook 的官方说明看它是如何根据字符串(方法名)找到对应指针在符号表中的偏移值的。

(三)fishhook 是如何根据字符串找到对应指针在符号表中的偏移值的?

fishhook 官方给了这张图:

a13e8f81f98a275ecdbbbf97bbe7c523.png

这张图其实就是讲根据一个字符串(比如 "NSLog") 如何一步步找到其在 MachO 文件里对应指针的偏移值,大致步骤如下:

1) 在 String Table 中找到该字符串在 Symbols Table -> Symbols 中的位置:

680e109fd6c4fec8a9ad1b88616d5f20.png

用 0x4F9F-0x4F04 = 0x9B

2) 在 Symbols Table -> Symbols 中找到Data = 0x9B 的符号,其对应的 offset 值 122 (0x7A) 就是该符号在 Dynamic Symbols Table -> Indirect Symbols 表中的 Data 值

f06ab57ad3a7ad3cea6cd3e0fe38bf53.png

3) 在 Dynamic Symbols Table -> Indirect Symbols 表中找到 Data 值为 0x7A 的符号,其位于该表中的位置(第一个)就是它在懒加载表中对应的位置。

0457eda390594e30853f813178668ae9.png

4) 懒加载表中对应位置的 Offset 值就是该指针最终的偏移量:

5e39edf2249ae81e9b9912fe92fc4453.png

总结

今天我们结合 iOS 的共享缓存库中采用的 PIC 技术,介绍了 fishhook 对系统外部函数实现 HOOK 基本原理和具体过程,并通过反汇编命令一一验证了 iOS 的动态绑定过程和 fishhook 的重新绑定机制,最后把 fishhook 在符号表中查找指针偏移量的步骤做了演示。 愿你有所收获! 水平有限,请多指教~

文章链接

  • iOS界的毒瘤-MethodSwizzling
    https://juejin.im/entry/5a1fceddf265da43310d9985

  • MethodSwizzling的几种姿势 
    https://juejin.im/post/5c616552f265da2dd53fa4e7#heading-3

  • MachO--文件结构详解
    https://juejin.im/post/5c67e7efe51d45164c75993b

  • dyld背后的故事&源码分析
    https://juejin.im/post/5c727262e51d457139116208

15e50a7d4cdf429fb8adc339826a615d.png

推荐阅读

移动开发唱衰,iOS开发者如何涅槃重生?

Cocoapod 1.6 概览

看完这个你们团队的代码也很规范

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/567039.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ef power tools mysql_使用 EF Power Tool Code Frist 生成 Mysql 实体

使用 EF Power Tool Code Frist 生成 Mysql 实体1,在要生成的项目上右键2,3,4,5, 生成后的效果已知问题:1,在Mysql数据表中 tinyint(1) ,会被映射成为 C# bool ,这样造成一些数据信息的丢失。 这个问题应该是EF 工具的问题&#…

python数据可视化散点图案例_Python数据可视化—散点图_python 数据可视化

Python数据可视化—散点图 PS: 翻了翻草稿箱, 发现居然存了一篇去年2月的文章。。。虽然naive,还是发出来吧。。。 本文记录了Python中的数据可视化——散点图scatter, 令x作为数据(50个点,每个30维)&#…

python重复元素判定_30段极简Python代码:这些小技巧你都Get了么

选自 | towardsdatascience转自 | 机器之心Python 是机器学习最广泛采用的编程语言,它最重要的优势在于编程的易用性。如果读者对基本的 Python 语法已经有一些了解,那么这篇文章可能会给你一些启发。作者简单概览了 30 段代码,它们都是平常非…

mysql主从数据库同步问题_聊聊MySQL主从数据库同步的那些事儿

在linux服务器下测试:主(master)服务器IP:219.223.5.105(对应内网IP:192.168.1.75)从(slave)服务器IP:219.223.5.104(对应内网IP:192.168.1.74)一、修改主服务器master[mysqld]log-binmysql-bin //[必须]启用二进制日…

360浏览器广告太多怎么办_360浏览器如何关闭广告自动推送

点击蓝字关注我们大家是不是在用360浏览器上网的时候经常会跳出广告来,这些广告有些时候是很烦人的,然而这些广告是能够关闭的,现在我们针对360浏览器,介绍如果关闭自动推送的广告。首先在360浏览器的右上方找到三条杠的“大队长”…

代码合并工具_作为程序员你必须知道的几款代码比较工具

在程序开发的过程中,程序员会经常对源代码以及库文件进行代码对比,在这篇文章里我们向大家介绍几款程序员常用的代码比较工具。WinMergeWinMerge是一款运行于Windows系统下的文件比较和合并工具,使用它可以非常方便地比较多个文档内容&#x…

powershell设置了权限依旧无法运行脚本_Power Shell折腾记

更多内容可以关注公众号“编程学习杂谈(codingLearning)”或者访问我的博客微软昨天刚刚发布了最新的Terminal图标,对是图标不是软件。对这个最新版的终端个人期待值还是很高的,不仅颜值高而且更好用,不过正式在稳定Wi…

delphi中richedit中光标如何定位到最后_嵌入式开发之Linux系统中Vi编辑器的使用

请大家关注点赞&#xff0c;已经完成物联网相关开发&#xff0c;会从硬件层&#xff0c;硬件中间层&#xff0c;传输层&#xff0c;软件中间件(物联网云平台)&#xff0c;APP开发相关博文。首先从嵌入式开发博文开始&#xff01;上一节关于<>。本节关于Linux系统中Vi编辑…

什么是python自动化测试_python已经自动化了,大家一般用什么测试框架?

首先我们需要明白自动化测试框架更倾向于一种设计思想 &#xff0c;这种思想指导工具的使用或者自研开发&#xff0c;并且不是只能使用仅仅一种框架&#xff0c;结合被测系统本身特性一般是选择多种测试框架的组合&#xff0c;来满足测试和设计需求(开发、维护角度)。录制回放测…

nginx会将post请求转为get么_前端角度谈GET与POST的区别

GET与POST 参数&#xff1a;GET传递的参数只能带URL后面&#xff0c;文本格式QueryString&#xff0c;各浏览器一般有长度限制&#xff0c;一般认为是2083&#xff0c;如果有中文字符更短。提交到服务器端的数据量小。参考&#xff1a;https://www.XXX.com.cn/blog/20201021.ht…

js预览本地word文档_Github+docsify打造在线文档

效果图如下预览链接&#xff1a;https://a870439570.github.io/interview-docs快速开始首先先安装好npm和nodejs,这里就不做过多介绍了 自信安装即可 (https://blog.csdn.net/zimushuang/article/details/79715679)安装docsify 推荐安装 docsify-cli 工具&#xff0c;可以方便创…

python创建一个json_如何为Python选择一个更快的JSON库

使用JSON越多, 你就越有可能遇到JSON编码或解码瓶颈。Python的内置库也不错, 但是还有多个更快的JSON库可用: 如何选择使用哪一个呢?事实是&#xff0c;没有一个正确的答案&#xff0c;没有一个最快的JSON库来超越其他所有库:一个“快速的JSON库”对不同的人意味着不同的东西&…

python函数拟合不规则曲线_python 对任意数据和曲线进行拟合并求出函数表达式的三种解决方案...

第一种是进行多项式拟合&#xff0c;数学上可以证明&#xff0c;任意函数都可以表示为多项式形式。具体示例如下。 ###拟合年龄 import numpy as np import matplotlib.pyplot as plt #定义x、y散点坐标 x [10,20,30,40,50,60,70,80] x np.array(x) print(x is :\n,x) num […

python数据结构 树_Python数据结构——AVL树的实现

既然&#xff0c;我们已经证明&#xff0c;保持 AVL 树的平衡将会使性能得到很大的提升&#xff0c;那我们看看如何在程序中向树插入一个新的键值。因为所有的新键是作为叶节点插入树的&#xff0c;而新叶子的平衡因子为零&#xff0c;所以我们对新插入的节点不作调整。不过一旦…

python安装常见问题_Python常见问题

问题描述: 在linux环境下部署Python项目时常常报错无法找到自己编写的模块解决方案export PYTHONPATH项目路径问题描述:Scrapy防封之settings文件设置解决方案设置动态USER-AGENT安装scrapy-fake-useragent模块在settings.py中添加配置DOWNLOADER_MIDDLEWARES {scrapy.downloa…

设无向图g如图所示_阿里重磅发布大规模图神经网络平台 AliGraph,架构算法解读...

图神经网络 (GNN) 主要是利用神经网络处理复杂的图数据&#xff0c;它将图数据转换到低维空间&#xff0c;同时最大限度保留结构和属性信息&#xff0c;并构造一个用于训练和推理的神经网络。在实际应用中&#xff0c;为了加速 GNN 训练和新算法的快速迭代&#xff0c;设计一套…

mysql5.0.19_CentOS下升级MySQL5.0.19到5.5

系统环境&#xff1a;CentOS 5.5CentOS 5.5的源mysql目前还停留在5.0.19上&#xff0c;要做数据库主从的时候&#xff0c;必须升级到5.1以上。索性&#xff0c;直接到5.5吧1系统环境&#xff1a;CentOS 5.5CentOS 5.5的源mysql目前还停留在5.0.19上&#xff0c;要做数据库主从的…

基于点云的三维重建_香港科技大学王煜教授:深度学习在物体三维重建中的应用...

基于单幅图像的物体三维重建是计算机视觉领域的一个重要问题, 近十年来得到了广泛地关注. 随着深度学习的不断发展, 近年来逐渐成为一个新的学术研究热点问题.计算机视觉研究的主要目标之一是从二维图像复原三维结构. 二维图像是当今时代极易获取的数据形式, 互联网上每时每刻都…

ranger管mysql_添加Kafka的Ranger访问权限策略

设置Kafka管理员权限在首页中单击“Kafka”区域的组件插件名称&#xff0c;例如“Kafka”。选择“Policy Name”为“all - topic”的策略&#xff0c;单击按钮编辑策略。在“Allow Conditions”区域&#xff0c;单击“Select User”下选择框选择用户。单击“Add Permissions”&…

ubuntu安装python3.6_Ubuntu上安装python3.6以及多版本python管理 | SQN

这篇文章记录了如何在Ubuntu上安装python3.6以及将其设置为系统默认。 查看Ubuntu版本 由于python3.6在不同的Ubuntu版本中的安装是不一样的&#xff0c;这里我们先来看一下的Ubuntu的版本&#xff0c;在terminal中输入lsb_release -a即可查看&#xff0c;例如我的Ubuntu版本为…