docs: clang 插件开发

This commit is contained in:
杭城小刘
2024-04-27 13:01:58 +08:00
parent 6e47061735
commit 851797d133
257 changed files with 9060 additions and 239 deletions

View File

@@ -1,6 +1,8 @@
# DYLD 及 Mach-O
DYLD 及 Mach-O
dynamic loader动态加载器。在 MacOS/iOS 中,是使用 `/usr/lib/dyld` 程序来加载动态库的。
dynamic loader动态加载器。在 MacOS/iOS 中,使用 `/usr/lib/dyld` 程序来加载动态库的。
## DYLDdyld shared cache 动态库共享缓存
@@ -18,6 +20,8 @@ ImageLoader* load(const char* path, const LoadContext& context, unsigned& cacheI
某个 App 被第一次打开时候, dyld 根据动态库的依赖,循环加载动态库到动态库共享缓存中(内存),后续其他 App 第一次打开发现使用了动态库A已经在动态库共享缓存中存在则不需要加载。这一步调用方法为 `findInSharedCacheImage`
## dyld 应用
窥探系统库底层实现的时候可能需要从动态库共享缓存中提取出某个 Framework比如 UIKit。这时候要么用第三方工具要么用 dyld 的能力。
@@ -63,6 +67,16 @@ int main(int argc, const char* argv[])
将编译后的产物复制到动态库共享缓存目录下去。然后执行命令`./dsc_extractor dyld_shared_cache_armv7s armv7s`,代表将动态库提取到 armv7s 目录下。
dyld 本身就是一种 MachO 文件MachO 文件类型为7是一种包含多种架构的结构如下图
<img src="./../assets/DyldStructure.png" style="zoom:25%">
可以加载以下类型的 Mach-O 文件MH_EXECUTE、MH_DYLIB、MH_BUNDLE
## Mach-O
Mach Object 的缩写,是 iOS/MacOS 上用于存储程序、库的标准格式
@@ -87,57 +101,66 @@ Mach Object 的缩写,是 iOS/MacOS 上用于存储程序、库的标准格式
#define MH_KEXT_BUNDLE 0xb /* x86_64 kexts */
```
### 常见的 Mach-O 文件类型
MH_OBJECT
- MH_OBJECT
- 目标文件(.o
- 静态库文件(.a静态库其实就是 N 个 `.o` 合并在一起
- 目标文件(.o
- MH_EXECUTE可执行文件
- 静态库文件(.a静态库其实就是 N 个 `.o` 合并在一起
MH_EXECUTE可执行文件
MH_DYLIB动态库文件
- dylib
- .framework
MY_DYLINKER动态链接编辑器 (/usr/lib/dyld)
MH_DSYM存储着二进制文件符号。`.dSYM/Contents/Resource/DWARF/xx` 常用于还原堆栈
- MH_DYLIB动态库文件
- dylib
- .framework
- MH_DYLINKER动态链接器 (/usr/lib/dyld)
- MH_DSYM存储着二进制文件符号。`.dSYM/Contents/Resource/DWARF/xx` 常用于还原堆栈
Xcode 中也可以查看 Mach-O 文件类型
![](https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/MachOFileType.png)
<img src="https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/MachOFileType.png" style="zoom:25%">
源代码比如c文件编译变为目标文件比如.o文件再经过链接变为可执行文件。
Tips`file` 命令可以查看文件类型。
<img src="./../assets/FileCommandToWatchFileType.png" style="zoom:45%">
`find . -name "*.c"` 比如在当前路径查找 .c 文件
### Universal Binary
通用二进制文件,可以同时适用于多种架构的二进制文件,包含多种不同架构的独立的二进制文件。
因为要存储多种架构的代码,所以通用二进制文件通常比单一平台的二进制程序更大
- 因为要存储多种架构的代码,所以通用二进制文件通常比单一平台的二进制程序更大
由于两种架构有共同的一些资源所以并不会达到单一版本的2倍多。
- 由于两种架构有共同的一些资源所以并不会达到单一版本的2倍多。
执行的过程中,只调用一部分代码,运行起来不需要额外的内存。
- 执行的过程中,只调用一部分代码,运行起来不需要额外的内存。
因为通用二进制文件比原来的大所以被成为“胖二进制文件”Fat Binary
因为通用二进制文件比原来的大所以被成为“胖二进制文件”Fat Binary,使用 Hopper 打开会显示 “FAT archive”
查看某可执行文件(Test)支持的架构指令集
信息查看:
`lipo -info Test`
- 查看某可执行文件(Test)支持的架构指令集 `lipo -info Test`
将某个指令集拆出来比如 arm64
- 将某个指令集拆出来比如 arm64`lipo Test -thin arm64 -o Test_arm64`
`lipo Test -thin arm64 -o Test_arm64`
- 也可以将多个指令集合并:`lipo -create Test_arm64 Test_armv7 -output Test_universal`
也可以将多个指令集合并
Xcode 中可以修改指令集。由 Build Settings 的2个配置决定 `Architectures->Architectures` `User-Defined->VALID_ARCHS`取2者的交集。
其中 `Architectures->Architectures` 的值 `$(ARCHS_STANDARD)` 是 Xcode 内置的环境变量,不同版本的 Xcode 值不一样,是通用的一些架构值。比如 Xcode9下`$(ARCHS_STANDARD)` 可能为 arm64、armv7。Xcode 4下`$(ARCHS_STANDARD)` 可能为 armv7
`lipo -create Test_arm64 Test_armv7 -output Test_universal`
## Mach-O 结构
![](https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/Mach-OStructure.png)
### Mach-O 结构
<img src="./../assets/Mach-OStructure.png" style="zoom:45%">
一个 Mach-O 文件包含3块
@@ -147,20 +170,26 @@ Xcode 中也可以查看 Mach-O 文件类型
- Raw segment data在 Load Commands 中定义的 segment 的原始数据
可以用 [GitHub - fangshufeng/MachOView: 分析Macho必备工具](https://github.com/fangshufeng/MachOView) 和系统自带的 atool 查看 Mach-O 信息
可以用 [MachOView:](https://github.com/fangshufeng/MachOView) 和系统自带的 atool 查看 Mach-O 信息
![](https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/otoolhelp.png)
<img src="./../assets/otoolhelp.png" style="zoom:25%">
比如我用 otool 查看我编写的一个 SwiftUIDemo 所依赖的共享缓存库
<img src="./../assets/SwiftUIDemoDependencyLibrary.png" style="zoom:25%">
用 MachOView 查看 DDD Mach-O 文件
![](https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/MachOPageZero.png)
<img src="./../assets/MachOPageZero.png" style="zoom:35%">
![](https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/MachOText.png)
<img src="./../assets/MachOText.png" style="zoom:35%">
可以看到在 Mach-O 文件上,`__PAGEZERO``VM Size` 有值,但是 File Size 为0也就是说 `__PAGEZERO` 在 Mach-O 中不占据内存,但是程序运行起来之后,会占据虚拟内存。所以代码段在 Mach-O 中 File Offset 为0如果前面的 `__PAGEZERO` 的 File size 有值,这里的 File Offset 就不为0
**在没有 ASLR 的时候__TEXT 代码段地址 = __PAGEZEROR 地址**
## ASLR
### 未使用 ASLR 的问题
@@ -173,29 +202,75 @@ Xcode 中也可以查看 Mach-O 文件类型
- 可执行文件 Header 的内存地址,就是 `LC_SEGMENT(__TEXT)` 中的 VM Address
- arm64 0x100000000
- arm64 `0x100000000`
- 非 arm640x4000
- 非 arm64`0x4000`
也可以使用 `size -l -m -x DDD` 指令来查看 Mach-O 的内存分布
![](https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/MachOInsepect.png)
<img src="./../assets/MachOInsepect.png" style="zoom:35%">
利用 MachOView 查看如下:
<img src="./../assets/MachOViewDemo1.png" style="zoom:25%">
<img src="./../assets/MachOViewDemo2.png" style="zoom:25%">
- _PAGEZERO
- VM Address0x0
- VM Size0x100000000
- _TEXT
- VM Address0x100000000
- VM Size0x4000
- _DATA_CONST:
- VM Address0x10004000
- VM Size0x4000
- _DATA
- VM Address0x10008000
- VM Size0x4000
- _LINKEDIT
- VM Address0x1000C000
- VM Size0x8000
<img src="./../assets/ASLRDemo.png" style="zoom:45%">
File Offset在 Mach-O 文件中的位置
File Size在 Mach-O 文件中的占据的大小
从下面的图可以看出,`_PAGEZERO` 在真实的 Mach-O 文件中不存在,不占据大小。只在虚拟内存中存在。
<img src="./../assets/MachOViewDemo1.png" style="zoom:25%">
![](https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/ASLRDemo.png)
我们会发现根据 Mach-O 文件中的信息File Size、File Offset、VM Address、VM Size 可以判断出 `__TEXT` 段内函数信息,这样子不够安全
### ASLR 诞生
Address Space Layout Randomization地址空间布局随机化。是一种针对缓冲区溢出的安全保护技术通过堆、栈、共享库映射等线性区布局的随机化通过增加攻击者预测目的地址的难度防止攻击者直接定位攻击代码的位置达到阻止溢出攻击目的的一种技术。在 iOS 4.3 引入。
![](https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/ASLROffset.png)
<img src="./../assets/ASLROffset.png" style="zoom:45%">
- LC_SEGMENT (__TEXT) 的 VM Address 0x10005000
- LC_SEGMENT (__TEXT) 的 VM Address `0x10005000`
- ASLR 随机偏移 0x5000也就是可执行文件的内存地址
在有 ASLR 的时候__TEXT 代码段地址 = __PAGEZEROR 地址
在有 ASLR 的时候__TEXT 代码段地址 = __`PAGEZEROR 地址`
在 Mach-O 文件中的地址是原始地址