很好,既然你不小心点进来了,那么只要你不小心看完这篇文章,那么你将不小心的学会如下技能:(1)分析 Swift 类的底层原理;(2)逆向 Swift;(3)使用 ιldb 脚本;(4)使用 xcrun swift-demangle 工具;(5)ChaCha20Poly1305 算法在 Swift 中的应用;Swift 源码地址 Mems 工具下载地址笔者将从 Swift String 的底层原理切入,循序渐进地带大家走进 Swift 逆向的世界,逐步理解其核心逻辑与实践思路。首先打开 XCode 创建一个 Swift 项目,然后在入口类的构造函数中添加如下代码,并且点击 序号 15 打上断点随后点击运行,会自动卡在断点处,然后点击步过随后可以看到 Swift String 的内部结构了。接下来打开 Swift 源码可以看到 String 结构体的构造函数中接收了一个 _StringGuts 对象,继续跟进 _StringGuts 结构体阅读源码后可以发现 _StringGuts 结构体的构造函数接收了一个 _StringObject 对象,并且这个 _StringObject 对象是通过传入 empty 参数进行构造的,所以等会可以检索 "init(empty" 来定位 _StringObject 的构造函数该私有构造函数中,根据不同平台的指针位宽(64/32/16 位)适配空字符串的底层内存布局,保证空字符串在所有平台下的内存表示一致。(3.1)_pointerBitWidth 编译条件_pointerBitWidth(_64):Swift 编译器内置的私有编译标记,判断当前平台是否为 64 位架构(如 arm64/iOS、x86_64/macOS);_pointerBitWidth(_32)/_16:对应 32 位 / 16 位架构(极少用,如老旧的 armv7 设备、嵌入式平台);(3.2)64 位下的代码逻辑先明确 Swift String 的底层核心字段_countAndFlagsBits = 0:空字符串长度为 0,所有标志位清零;Builtin.valueToBridgeObject:Swift 内置(Builtin)函数,将「空字符串的静态内存地址」转换为桥接对象指针(_object);Nibbles.emptyString:Swift 标准库中预定义的「空字符串常量」(全局唯一,避免重复创建空字符串实例,类比 C++ 的 std::string::empty() 优化)。Nibbles 是个枚举,源码中给它加了多个extension。进一步查看源码可以看到 Nibbles.emptyString,调用方法:small(isASCII: Bool)通过调试也可以发现存储的地址是 0xe00000000000000064 位平台设计逻辑空字符串无需动态分配内存,直接复用全局唯一的 emptyString 静态地址,_object 指向该地址,_countAndFlagsBits 置 0,实现极致的内存效率(无堆分配)。(3.3)32 位下的代码逻辑在 StringObject.swift 文件下检索 init(count:,可以看到 32 位下调用的构造函数,因为通常是 64位,故 32位不做分析,感兴趣的可以自行了解。经过上面的分析,可以知道一个字符串变量至少占用了16字节。用 MemoryLayout 工具进行验证也确实是16个字节。已知字符串变量至少占用 16个字节,那么在内存中是什么样的呢?首先前往 [Mems] 下载 或者直接从 Mems.zip 中解压得到 Mems.swift 文件,然后导入到项目中,最后键入下面的代码上面的程序运行后可以得到下面的结果空字符串的_object = 0xe000000000000000,字符串 "1" 的_object = 0xe100000000000000,据此可合理推测,e后四位的十六进制数值用于存储小字符串的长度,接下来将对此展开进一步验证。查看字符串 "123" 的内存查看字符串 "0123456789ABCDE" 的内存查看字符串 "0123456789ABCDEF" 的内存字符串长度小于 16 时,e 后的4位用于表示字符串长度,并且字符串内容存储在另外 15 个字节中。通过对比 "0123456789ABCDEFG" 与 "0123456789ABCDEF" 的内存数据可推测,字符串长度不再存储于_object 中,而是由_countAndFlagsBits 字段存储;而_object 中记录的地址偏移 0x20 后,即为字符串的实际内存地址。查看字符串 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" 的内存查看字符串 "泥嚎,我正在分析 swift string!" 的内存大字符串的 _object 存储的是字符串的内存地址,偏移 0x20 就可以读取到字符串内容测试环境分为 [ Swift 源码 ]、 [ 项目源码 ] 和 一个 [ IPA 文件 ],Swift 源码和项目源码用来理解 Swift 底层结构,ipa 文件用来辅助分析。[SwiftDemo.zip]连接上 iPhone,打开 爱思助手,然后按照下面的步骤操作。当然,如果你有巨魔,就可以跳过这个地方了。IDA 中 Swift 函数符号是经过特殊处理的,形如 _$s10Foundation4UUIDV10uuidStringSSvg 和 _$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC 这种,前者看起来还相对明了,后者看起来就稍微费劲点,此时可以使用 xcrun swift-demangle 命令进行函数符号还原即可。首先了解一下什么是 xcrun。xcrun 是 macOS 下 Xcode 提供的工具链调度工具,用于定位和执行 Xcode 安装的各种开发工具(如 swiftc、lldb、clang、nm、swift-demangle 等)。所以 xcrun swift-demangle 是 macOS 下通过 xcrun 调度的 Swift 符号还原工具,核心作用是将 Swift 编译后生成的「名字重整(Mangled)符号」(晦涩的乱码式字符串)还原为可读的 Swift 函数 / 类 / 属性名。使用方法如下可能遇见的问题如下,解决方法就是使用单引号将函数符号括起来首先拟定核心目标:找到 ChaCha20 算法的明文、密钥、nonceData 及密文。明确方向后,第一步需先了解 Swift 中 ChaCha20 算法的使用方式,你可通过 AI 自行查询,也可直接参考下文的 encryptWithChaCha20Poly1305 函数;下面是 [ 项目源码 ] 中的 encryptWithChaCha20Poly1305(message:keyHex:nonceHex:) 函数 的具体实现。因为这里是知道 encryptWithChaCha20Poly1305 函数传入
...(已截断)
---
来源: 看雪论坛
原文链接: https://bbs.kanxue.com/thread-289504.htm
[原创] Swift 逆向 之 授人以鱼不如授人以渔
175 浏览
12 回复
感谢分享
感谢,先收藏。
感谢分享
tql
点赞
大佬 多发 爱看 学习 牛子 支持
蜕无痕
大佬 多发 爱看 学习 牛子 支持
痕哥别这样,我害怕
大佬 多发 爱看 学习 牛子 支持
痕哥别这样,我害怕
很6,一下小心学会了
好
大佬,你也太强了,能否来篇oc逆向呢?oc逆向也不多。
artake
大佬,你也太强了,能否来篇oc逆向呢?oc逆向也不多。
oc 挺多的啊,而且不需要像 Swift 这样分析,直接使用 lldb 的 po 或者 frida 的 Objc.Object 都可以解析出数据的
大佬,你也太强了,能否来篇oc逆向呢?oc逆向也不多。
oc 挺多的啊,而且不需要像 Swift 这样分析,直接使用 lldb 的 po 或者 frida 的 Objc.Object 都可以解析出数据的
感谢分享