作者:郝连福,业界资深计算机技术专家,现任声网Agora 首席前端架构师。先后担任过 Principal Engineer/Engineering Director(UTStarcom)、Sr. architect(Intel)、T4 architect(YY)等职,曾设计开发电信核心网专用操作系统、高性能TCP/IP协议栈、以及声网SDK架构重构等重大项目。

引言

本文是声网Agora 与 RTC 开发者社区共同发起的 Dev for Dev(Developer for Developer)互动创新实践活动的开篇,同时也是开源技术爱好者在一线工作中的真实记录。文中遇到的情况颇具代表性,特整理分享出来以飨读者。


通常在 iOS 中实现应用 Hook 的方式有以下三种:

1.Method Swizzling:利用 OC(Objective C)的 Runtime 特性,动态改变 SEL(方法编号)IMP(方法实现)的对应关系,达到 OC 方法调用流程改变的目的,只适用于动态的 OC 方法;

2.Fishhook:FaceBook(现更名为 Meta)提供的一个动态修改链接 Mach-O 文件的工具,利用 Mach-O 文件加载原理,通过修改懒加载和非懒加载两个表的指针实现 C 函数 HOOK 的效果;适用于静态的 C 方法;

3.Cydia Substrate:原名为 Mobile Substrate,是一个强大的框架,它的主要作用是针对 OC 方法、C 函数以及函数地址进行 HOOK 操作,适用于 OC 方法、C 函数以及函数地址,亦适用于 Android 平台。

Fishhook 是一个由 Meta 公司开源的第三方框架,它能够在模拟器和设备上动态地重新绑定运行在 iOS/macOS 上的 Mach-O 二进制文件的符号,从而实现动态修改 C 语言函数,常用于应用的调试/追踪。这个框架只包含两个核心文件:fishhook.c 以及 fishhook.h 所以非常轻量,在许多企业级应用中颇受青睐。然而这个以精练著称的开源项目中,却埋藏着一个不易察觉的问题……

随着 iOS 15 Beta 版的发布,许多开发者发现了普遍的应用程序崩溃──这通常由系统兼容性问题引发,而随着排查过程的不断深入,我们发现问题并没有那么简单。起初,开发者把问题反馈到 Fishhook 之后,有不同的团体和个人贡献了好几个修复的PR,但都未能从根本上解决这个问题。在仔细分析了 iOS 和 macOS 的操作系统内核 XNU 源码后,我们最终定位到了问题的 RootCause。

对 Fishhook Crash 问题的溯源

为了定位问题,我们通常会根据现有的报错日志尝试对问题进行复现,通过调试追踪我们发现,在 iOS 15 或者 macOS 12的环境下 Fishhook 代码在重绑定符号时会100%地发生崩溃现象,正是这个崩溃导致集成了 Fishhook 的应用变的不可用。鉴于这个问题的影响很大,一些使用了fishhook项目的应用在发现问题后紧急移除了该组件以缓解其影响。

造成 fishhook 崩溃的根本原因

Fishhook 的工作原理需要 Hook 修改符号动态绑定数据段,这些数据段的默认权限一般是只读的,所以需要加上“写”权限才能修改,而问题恰好就出在这里──我们在排查过程中发现 Fishhook 里增加“写”权限的代码存在 Bug,问题相关代码如下:

这段代码里面有3个严重错误,为了便于阅读,我们分别以红绿蓝3个颜色的框将相关代码标识出来,对这些错误的具体解释如下:

1.首先,不能仅根据 __DATA_CONST 这个 segname 来判断是否需要增加“写”权限,因为从 iOS 14.5 甚至更早的版本开始,都需要 Hook 一个叫 __AUTH_CONST 的 segment,因此只Hook 一个 __DATA_CONST 字段是不够的

2.其次,获取当前的 vm prot 时,传错了地址,不应该是 rebindings,因为我们要写入的地址是 indirect_symbol_bindings

3.最后,XNU 内核的 C-O-W 机制与 Linux Kernel 不同,对于 RO 的 vm segment mapping 需要显式指定 VM_PROT_COPY 才能增加“写”权限,但是 XNU BSD 的 mprotect 系统调用根本就做不到这一点,故而这句 mprotect 系统调用形同虚设,相当于什么也没做!XNU MACH 关键代码逻辑如下:

Fishhook 代码存在的上述 3 个错误叠加在一起,最终导致在修改 indirect_symbol_bindings 所指向的数据时发生了**“写”保护错误**,进而发生的 Crash 影响了整个应用系统。

修复 Fishhook 崩溃的最佳方法

既然我们已经找到了 Bug 位置所在,修复的思路便只需对症下药即可:

  • 将原来写错的地址 rebindings 修改成 indirect_symbol_bindings
  • 将 mprotect 系统调用改成使用 vm_protect 系统调用,并增加 VM_PROT_COPY 选项;
  • 代码逻辑上修改为只有 vm_protect 系统调用执行成功时,才能去做“写”动作。

因此 Bug 修复的核心代码如下:

这里需注意,首先,为符号动态绑定的数据段增加“写”权限时一定要添加 VM_PROT_COPY 选项,否则写入操作会失败;其次,要在代码逻辑中添加“只有 vm_protect 系统调用返回成功”才能真正去执行“写”这些数据段的操作,否则就什么都不要做。

经过严格的测试和反复验证,我们彻底修复了这个 Bug,并在2021年的6月12日向 Fishhook 官方提交了 PR(https://github.com/facebook/fishhook/pull/87),Fishhook的维护团队在对比了多个修复方案后,最终选择 Merge 了我们的修复补丁并将其合并进主分支,至此该问题最终得以解决。

系统升温(级)使“冰封”的 Bug 得见天日

读者大概率会好奇,为什么在 iOS 15 或者 macOS 12 之前的版本没有这个问题呢?

事实上,在 iOS 15 或者 macOS 12 之前的操作系统自身也存在这个缺陷,对这些数据段的保护并不严谨,对应该“只读”的数据段并没有去掉“写”权限,我们调查到相关的证据如下:

在上述证据片段中,protection 数值 3 表示权限为“可读可写”,因此 Fishhook 代码里面做Hook动作的“写”操作在老版本的 iOS/macOS 中并没有任何问题。但是 iOS 15/macOS 12 新版本操作系统中对这些数据段的保护更加严格,对相应的权限做了一些调整──将本应赋予“只读”数据段的“可读可写”权限修正为“只读”,也就是说上述证据片段中 protection 的数值发生了变化,相关的证据如下:

上述代码片段中的 protection 数值1代表“只读” ──也理应如此。但正是这种“修正”与原来“不当”的配置产生了逻辑上的冲突,最终 Fishhook 的这个 Bug 在较新的 iOS 15/macOS 12 系统中暴露出来,导致了严重的崩溃问题。从代码的角度来看 Fishhook 的这个 Bug 显然是一直存在的,只是在早期的 iOS 和 macOS 版本中没有构成触发的条件,故而隐患一直被雪藏,直到相关的条件被改变。

总结

通常在应用开发过程中,本着不重复造轮子和快速上线、不断迭代的原则,我们经常会引入第三方模块,尤其是有着广泛应用的底层开源组件。但随着 IT 基础设施的变迁,系统环境会随着时间的推移不断增加新特性、抛弃旧实现,在这个过程中由于依赖问题我们的应用不可避免地会不断遭遇不可用的挑战。作为业务应用的开发者,我们必须不断提高向上游组件进行问题溯源的能力,秉持开发者的初心,取自开源、回馈开源。

Dev for Dev专栏介绍

Dev for Dev(Developer for Developer)是声网Agora 与 RTC 开发者社区共同发起的开发者互动创新实践活动。透过工程师视角的技术分享、交流碰撞、项目共建等多种形式,汇聚开发者的力量,挖掘和传递最具价值的技术内容和项目,全面释放技术的创造力。

被冰封的 Bug:Fishhook Crash 修复纪实相关推荐

  1. linux切换桌面环境bug,GNOME 3.32.2桌面环境发布,最新的bug和安全修复

    GNOME项目今天宣布发布GNOME 3.32 "Taipei"桌面环境的第二个也是最后一个版本的普遍可用性,适合于所有基于的Linux操作系统. 在第一个版本发布一个月之后,GN ...

  2. 游戏本自动掉帧_LOL官方割韭菜?“永恩上线就出问题,游戏掉帧商城BUG仍未修复”...

    前言:英雄联盟作为一款已经运营了十年之久的游戏,已经有了非常多的玩家和粉丝,随着游戏的不断发展,比赛机制的不断完善,这款游戏正在逐渐的走向世界.昨天的时候,英雄联盟的客户端就已经进行了更新,结果却没有 ...

  3. 携程再爆大数据杀熟,携程致歉信:程序 bug 已紧急修复,将赔偿用户

    3月10日,前360移动搜索负责人@陈利人在一篇名为<携程的牌坊塌了>的文章中爆料,日前在携程购买了一张机票,总价为17548元:当他发现没有选择报销凭证退回重选时,提示已无票,重新搜索价 ...

  4. 【Bug 调试】修复注册验证问题 第十三届蓝桥杯(Web 应用开发)线上模拟赛

    [Bug 调试]修复注册验证问题 考试需求: 解答: index.js: // " abc " ----> "abc " ----> "a ...

  5. woeusb 命令行 win10_微软认错!win10存在多个bug已承诺修复,可你还敢更新吗

    原标题:微软认错!win10存在多个bug已承诺修复,可你还敢更新吗 Win10没有最糟糕,只有更糟糕? 之前还在满心期待2020年win10大更新的大白菜,被5月更新之后的各种bug打击的支离破碎. ...

  6. iOS12 SKStoreViewController crash修复

    文章目录 一.前言 二.问题描述 三.分析问题 非法内存访问 四.解决问题 一.前言 SKStoreViewController在iOS 11上是正常没啥问题的,但到了iOS 12突然导致了大范围的闪 ...

  7. 现在的编译器还需要手动展开循环吗_一例 Go 编译器代码优化 bug 定位和修复解析...

    缘起 某日,一位友人在群里招呼我,"看到有人给 Go 提了个编译器的 bug,挺有意思,感觉还挺严重的,要不要来看看?"于是我打开了 issue 40367 .彼时,最新一条评论是 ...

  8. mysql表出现crash 修复_MySQL表索引损坏致Crash及修复过程实例

    --------------(大量相同的报错)---------------- 2017-08-31T11:11:04.291424Z 32394522 [ERROR] InnoDB: Record ...

  9. iOS 15.1即将上线,iPhone13的“苹果手表解锁”Bug已被修复

    整理 | 祝涛 出品 | CSDN(ID:CSDNnews) 据报道,苹果公司已经修复了iPhone 13上Apple Watch解锁功能失效的问题.Apple Watch解锁功能可以让戴着口罩的用户 ...

最新文章

  1. 计算机组成加减交替法被除数,计算机组成原第2章答案.doc
  2. python汉字长度_行中字符串的长度(Python)
  3. java 实现中文排序,Java自定义比较器实现中文排序
  4. c语言用链表对学生成绩排序,学生成绩排序和平均分计算利用c语言链表的创建插入删除.doc...
  5. pandas分组计算平均值_pandas索引,分组计算
  6. 10倍!微软开源深度学习优化库DeepSpeed,可训练1000亿参数模型
  7. Oracle数据库中dual是什么东西啊?
  8. C语言零基础——简单门票费程序
  9. Android游戏添加游戏动画,Android游戏中的动画制作
  10. 如何在小视频源码里实现边下边播
  11. kali 2.0 安装搜狗输入法 troubleshooting
  12. 怎样通过修改folder.htt来实现文件夹加密码
  13. 02 Python的自我介绍(数字、字符串、列表)
  14. PAT甲级 1027 Colors in Mars (20分)
  15. Python经典实验4-字典和集合的应用
  16. jenkins安装和配置(一):ubuntu 20.04 jenkins安装
  17. 微信小程序H5页面API红包代发接口
  18. ibm tivoli_在Tivoli Access Manager v6.1 / WebSEAL和Tivoli Integrated Portal v1.1.x之间配置单点登录
  19. java akka 实战_《Akka实战:快速构建高可用分布式应用》(杜云飞)【摘要 书评 试读】- 京东图书...
  20. 使用ssh挂载远程网络硬盘

热门文章

  1. 基于Java+Swing+mysql图书管理系统
  2. IDEA界面的主题风格-黑白界面修改
  3. zepto的使用方法
  4. 华兴数控g71外圆循环编程_用G71粗车循环的举例——数控车床编程实例
  5. 数字电子技术基础(七):加法器
  6. matlab与python语法区别(持续更新)
  7. 数模美赛如何找数据 | 2023年美赛数学建模必备数据库
  8. CC2541-修改蓝牙名称和mac地址
  9. 清理SONY D-NE10 的线控器
  10. matplotlib的学习4-设置坐标轴