写给 iOS 开发者的 Hopper + lldb 简介(写给女朋友的检讨书)

网友投稿 819 2022-09-24

本站部分文章、图片属于网络上可搜索到的公开信息,均用于学习和交流用途,不能代表睿象云的观点、立场或意见。我们接受网民的监督,如发现任何违法内容或侵犯了您的权益,请第一时间联系小编邮箱jiasou666@gmail.com 处理。

写给 iOS 开发者的 Hopper + lldb 简介(写给女朋友的检讨书)

你是否曾经疑惑,别人是怎么获取下图所示的私有 API伪代码的?这实际上很简单,而且是找出 UIkit中那些烦人错误的好方法。使用 Hopper 这样的工具后,只需要点几下鼠标,就能得到伪代码。更酷的还在后头。有了 Obj-C runtime 和 lldb,即使不能提高伪代码的语法正确性,也一定能提高伪代码的可读性!让我们深入探讨一下吧!

Decompilation of a method in UIKit. 在 UIKit 中反编译一个方法。

什么是 Hopper?

摘自 Hopper 主页的定义:“Hopper 是一种适用于 OS X 和 Linux 的逆向工程工具,可以用于反汇编、反编译和调试 32位/64位英特尔处理器的 Mac、Linux、Windows 和 iOS 可执行程序!”用更简洁的话来说,这代表我们可以用一个编译二进制(你的 iOS app,UIKit 二进制等等)生成你之前看到的伪代码!

反汇编 vs 反编译

开篇

注意 x86(32位) 和 x86(64位)两种文件的存在。

首先是左侧操作面板中的“Labels”和“Strings”。“Labels”会向你展示二进制文件中包含的所有类和方法(你还会看到其他文件,不过本教程中只需要关注方法签名)。

下拉查看所有的方法!

检查你自己的 app,确保没有对任何你不想让别人看到的东西硬编码!

做好准备

搜索方法名称和类。

如果你不了解汇编指令,这个界面就没有太大帮助,请查看界面右上角,注意那个带有代码的按钮。这个按钮可以开启反编译过程,并产生伪代码。点下去吧!

没那么难用,对吧??

在调试第三方 SDK 或者查看自己的 app 时,这个工具效果非常好。

一般笔者在查找程序错误时会采用以下步骤:

在代码中找出自认为导致问题的那个文件,然后打开 Hopper 搜索那个类和方法名称,然后进行反编译 通过反编译,我可以很容易就能收集方法签名,并在 lldb 中设置它们的断点(参见 lldb 部分)。

以上就是全部操作,完全没有一点删减。如果你不想再看,可以到此为止,不过笔者在工作流程中添加了 lldb 操作来对伪代码进行更进一步的清理!

lldb

在私有方法中设置断点

好了,一般来说,Hopper 产生的伪代码就已经能满足你的需求了,不过有时候它会比较难懂,需要进行一些清理工作。这就到了 Obj-C runtime 和 lldb 大显身手的时候了。

首先,在模拟器中打开示范代码,通过调试暂停程序执行。暂停后,代码会转存到 lldb中,在这里,你可以给选定的任何方法签名设置断点。输入“b -[UIPopoverPresentationController dimmingViewWasTapped:]”,给“-[UIPopoverPresentationController dimmingViewWasTapped:]”设置断点,然后按回车键。调试控制台界面与下图类似:

b 是设置断点的简称。

现在继续程序执行,一旦启动“-[UIPopoverPresentationController dimmingViewWasTapped:]”,就会启动你所设置的断点。遵循示例项目中的操作指令(双击黄色区域)。

就是感觉挺累的,这段时间,总之,想请假,觉得坐在这里,也没很大的意义。到了这一步,你可能会因为不了解汇编而有些担心,但是笔者要告诉你,你真的不需要懂。只要有一点儿直觉,加上反复尝试,你就可以完成任务了。换句话说,我们现在所要做的就是让反编译过程稍微简单一些(替换寄存器等等)。这样产生的伪代码会好懂一些,不过如果你遇到伪代码难懂的情况,可以采用同样的理念对伪代码进行清理。

好了,现在该左右对照反汇编和反编译了。笔者常用的做法是寻找反编译的关键点,比如说调用 if 语句或者方法的时候。这些关键点对应的编译指令很容易猜到,只需要逐行浏览编译。如果你的关键点是一个 if 语句,就去找测试或 cmp(compare)指令。

在本文中,笔者选的是反编译中的第一个 if 语句,并在 Xcode 的反编译结果中搜寻测试或 cmp(compare)指令。如下图所示,笔者找到了一个测试指令。

可能需要尝试几次,要有耐心!

现在在那个内存地址(你的地址可能不同)用“b 0x148b95c”设置一个断点。

继续程序执行,期待你的断点被启动。

下一步就会见证 lldb 和 Obj-C runtime 的神奇之处。我们要清理反编译结果中大部分艰涩难懂的部分。如果你不熟悉反编译过程中的 eax、edi、和 esiare,它们就是 x86 CPU 寄存器,我们可以把它们转存到 lldb 中。如果你看到 r0、r1、r16等等,那些是 ARM 框架。如果这些你全都看不懂,别担心,只要把它们和伪代码匹配就好了。

在 lldb 提示框中输入“register read”,按回车键。

CPU 寄存器。根据你所用的不同框架,显示不同名字。

显示出来的是 CPU 寄存器及其内容值。现在你可以用 lldb 中显示的值替代反编译结果中的寄存器。

不要盲目地更换反编译的 esi、edi 和其他寄存器,因为在执行不同代码时,它们可能代表不同的值。这就回到了明智选择关键点的重要性。笔者的操作步骤如下:

在一个关键点设置断点,继续程序执行 转储寄存器 用 lldb 生成的内容值替换反编译结果中关键点以上的缓存器

举个例子,我们的关键点是 dimmingViewWasTapped 方法中的第一个 if 语句,一旦断点被启动,转储寄存器,替换伪代码中 if 语句以上的缓存器。如果你跟踪伪代码,发现关键点之后的缓存器未重置,那就更新这些内容值。

如果你进行这个操作,就会发现 edi 包含委托选择器,但是 esi 寄存器包含一个 hex 值。这就更加费解了,不过幸好我们可以利用 Obj-C runtime来搞清楚 esi 到底是什么。

复制 esi 的内存地址,输入“po [0x78657dd0 class]”,然后按回车键。

Very nice!

太棒了!

啦啦啦,现在我们知道 esi 是什么了,并且可以利用这个值来提升反编译效果。

笔者发现反编译说“esi = self”,你们可能已经推断出esi = UIPopoverPresentationController,但是这个推断不一定总是成立。而且,如果还不明显,你可以尝试“po [0x78657dd0 anyMethodThatThisClassImplements]”。如果你对某个对象的内部很感兴趣,这个操作效果超好。

其他问题

有 Hopper 的替代工具吗?- 有的,就是 IDA Pro(HexRays 是他们的反编译器),不过除非你想一掷千金,不然 Hopper 就是你最好的选择。他们还提供免费版本,不过只有反汇编器。

我的反编译和反汇编结果的缓存器显示的是 r,不是 e- 你反编译或者反汇编了 x86 64位文件。

上一篇:智能告警 Cloud Alert云平台系统如何接入?(智能告警英文)
下一篇:AIOps智能化运维带来哪些便捷服务?(aiops运维决策时间)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~