首页
学习
活动
专区
工具
TVP
发布

Swift的高级技巧-动态注入和更改代码

虽然Xcode为lldb命令提供了几个可视化抽象,例如通过单击代码行添加断点并通过单击播放按钮来运行,但lldb提供了一些Xcode UI中不存在的有用命令。这可以是从即时创建方法到甚至更改CPU的寄存器以强制应用程序上的特定流而无需重新编译它,并且了解它们可以极大地改善您的调试体验。

并非所有Swift都是在Xcode中开发的 - 像Swift编译器或Apple的SourceKit-LSP这样的东西通过其他方式更好地工作,这些方法通常最终会让你手动使用lldb如果没有Xcode来帮助您,其中一些技巧可能会阻止您再次编译应用程序以测试某些更改。

注入属性和方法

您可能已经知道(“打印对象”的缩写) - 通常用于打印属性内容的友好命令:

然而,比这更强大 - 尽管名称暗示它打印的东西,是一个别名,更原始(或只是)命令的论证版本,使输出更加开放:

因为它是别名,所以可以做任何事情。用于评估表达式表达式的范围可以从打印属性到更改其值,甚至可以定义新类。作为一个简单的用法,我们可以在代码中更改属性的值以强制新流而无需重新编译代码:

除此之外,如果你单独写,你将能够编写这样的多线表达式。我们可以使用它在我们的调试会话中创建全新的方法和类:

(这里使用美元符号表示这些属性和方法属于lldb,而不是实际代码。)

前面的例子允许我直接从lldb 调用,这将在我的“我无法处理这个bug”计数器上加1。

这样做的能力可以与lldb导入插件的能力相结合,这可以大大增强您的调试体验。一个很好的例子就是Chisel,这是一个由Facebook制作的工具,它包含许多lldb插件 - 就像命令一样,它增加了一个明亮的边框,这样你就可以在屏幕上快速定位它们,并且它们都通过巧妙的用法来实现。/ 。

然后,您可以使用lldb的断点操作在命中断点时自动触发这些方法。结合的属性更改功能,您可以创建特殊的断点,这些断点将改变您尝试执行的测试的应用流程。

通常,所有高级断点命令都非常痛苦地在lldb中手动编写(这就是为什么我会在本文中避免它们),但幸运的是,您可以轻松地在Xcode中设置断点操作:

- 避免动态

如果你已经使用了一段时间,你可能在过去看到过这样一个神秘的错误信息:

这是因为通过编译来评估您的代码,不幸的是,即使您尝试访问的代码是正确的,仍然存在可能出错的情况。

如果你正在处理不需要评估的东西(比如静态属性而不是方法或闭包),你可以使用命令(简称)作为打印的替代,以便立即获取内容。宾语。

- 打破内存地址以更改其内容

注意:以下命令仅在极端情况下有用。你不会在这里学习一个新的Swift技巧,但你可能会学到一些有趣的软件工程!

我通过使用越狱的iPad来使用流行的应用程序进入逆向工程,当你这样做时,你没有选择重新编译代码 - 你需要动态地改变它。例如,如果我无法重新编译代码,即使我没有订阅,如何强制以下方法进入条件?

我们可以通过使用应用程序的内存来解决 - 在任何堆栈框架内,您可以调用该命令来查看该堆栈的完整指令集:

这里整洁的东西不是命令本身,而是你可以用这些信息做些什么。我们习惯在Xcode中设置断点到代码行和特定选择器,但在lldb的控制台中你也可以使用断点特定的内存地址。

我们需要知道一些汇编来解决这个问题:如果我的代码包含一个,那么该代码的结果汇编肯定会有一个跳转指令。在这种情况下,跳转指令将跳转到存储器地址,如果寄存器(在前一条指令中设置)不等于零(那么,为真)。由于我没有订阅,肯定会为零,这将阻止该指令被触发。

要看到这种情况发生并修复它,让我们首先断点并将应用程序放在指令处:

如果我再次运行,小箭头将显示我们在正确的内存地址处开始操作。

有两种方法可以解决这个问题:

方法1:更改CPU寄存器的内容

该和命令由LLDB提供,让您检查和修改的CPU寄存器的内容,并解决这个问题的第一种方式是简单地改变的内容。

通过定位指令,将返回以下内容:

因为为零,指令不会触发,从而使代码输出。但是,这是一个简单的修复 - 我们可以通过运行和恢复应用程序设置为不为零的东西:

在日常的iOS开发中,可以用来替换代码中的整个对象。如果某个方法要返回你不想要的东西,你可以在lldb中创建一个新对象,获取其内存地址并将其注入所需的寄存器。

方法2:更改指令本身

解决这个问题的第二种也可能是最疯狂的方法是实时重写应用程序本身

就像寄存器一样,lldb提供并允许您更改应用程序使用的任何内存地址的内容。这可以用作动态更改属性内容的替代方法,但在这种情况下,我们可以使用它来更改指令本身。

这里可以做两件事:如果我们想要反转if指令的逻辑,我们可以改为(所以它检查一个条件),或者(跳空不是)to (跳空,或)。我发现后者更容易,所以这就是我要遵循的。如果我们阅读该指令的内容,我们会看到如下内容:

这看起来很疯狂,但我们不需要了解所有这些 - 我们只需要知道指令的OPCODE对应于开头的两位(75)。按照这个图表,我们可以看到OPCODE for 是74,所以如果我们想要成为,我们需要将前两位与74交换。

为此,我们可以使用与该地址完全相同的内容,但前两位更改为74。

现在,运行应用程序将导致打印。

结论

虽然拆解和写入内存对于日常开发来说可能过于极端,但您可以使用一些更高级的lldb技巧来提高工作效率。更改属性,定义辅助方法并将它们与断点操作混合将允许您更快地导航和测试代码,而无需重新编译它。

原文作者:Bruno Rocha

原文地址:https://swiftrocks.com/using-lldb-manually-xcode-console-tricks.html

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20190820A02PDD00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券