`

dyld 加载 Mach-O

    博客分类:
  • ios
ios 
阅读更多

原文出自【听云技术博客】:http://blog.tingyun.com/web/article/detail/1346

前言

最近看 ObjC的runtime 是怎么实现 +load 钩子函数的实现。进而引申分析了 dyld 处理 Mach-O 的这部分机制。

1.简单分析 Mach-O 在dyld 中是如何被加载到内存中的;

2.分析了 +load 的 特殊加载时机;

+ load

1.png

上图的调用栈告诉我们哪些函数被调用了。

dyld 是Apple 的动态链接器;在 xnu 内核为程序启动做好准备后,就会将 PC 控制权交给 dyld 负责剩下的工作 (dyld 是运行在 用户态的, 这里由 内核态 切到了用户态)。

每当有新的镜像加载之后,都会执行 load-images 方法进行回调,这里的回调是在整个ObjC runtime 初始化时 -objc-init 注册的 :

二.png

有新的镜像被 map 到 runtime 时,调用 load-images 方法,并传入最新镜像的信息列表 infoList:

三.png

这里的镜像就是 一些 System framework 的二进制。

进入 下图函数 load-images-nolock 查找 load 函数

四.png

调用 prepare-load-methods 对 load 方法的调用进行准备(将需要调用 load 方法的类添加到一个列表中)

五.png

调用 -getObjc2NonlazyClassList 获取所有的类的列表之后,会通过 remapClass 获取类对应的指针,然后调用 schedule-class-load 递归地 将当前类和没有调用 + load 父类进入列表。

六.png

在执行 add-class-to-loadable-list(cls) 将当前类加入加载列表之前,会先把父类加入待加载的列表,保证父类在子类前调用 load 方法。

在将镜像加载到运行时、对 load 方法的准备就绪,执行 call-load-methods,开始调用 load 方法:

七.png

其中 call-class-loads 会从一个待加载的类列表 loadable-classes 中寻找对应的类,然后找到 @selector(load) 的实现并执行。

八.png

分析到这里,已经能得知 load 函数是如何被调用的。

九.png

接下来分析 dyld 这部分怎么加载镜像的

1.1 数据结构

mach-o 文件头 操作。 

1.png

1.2 ImageLoader

2.png

每一个加载的 Mach-O 文件都会存在这样一个ImageLoader 的 实例,上图可以看出 这里ImageLoader是一个抽象类,每一种具体的Mach-O 文件都会继承 ImageLoader类, 继承关系 如下图:

16.png

 在加载时会根据Mach-O的格式不同选择生成不用的实例。

1.3 -main

4.png

在调用-main 函数之后,做了一下几件事情:

  1. 选择运行环境(iOS 模拟器)

  2. 初始化数据、设置全局变量、上下文信息

  3. 检查文件是否Restricted

走完这些流程,就会调用 instantiateFromLoadedImage 函数,开始加载Mach-O 并且实例化 为 ImageLoader。

1.4 instantiateFromLoadedImage

5.png

这个函数做了三件事情: 

  1. 检查Mach-O 文件是否合法 

  2. 初始化 ImageLoader 实例 

  3. 调用addImage 函数添加 初始化后的实例到管理模块中

1.5 isCompatibleMachO

6.png

Mach-O 文件的合法性检查: 

  1. mach-header 中的 cputype与当前运行的CPU 版本是否支持

  2. mach-header 中的 subtype 在该CPU 架构下的所有版本都可以支持

cputype 就是CPU 平台, x86,ARM ,POWERPC 等, 而subtype 就是同一个平台下的不同版本, 例如:arm7,arm7.

1.6 ImageLoaderMachO: : instantiateMainExecutable

7.png

该函数主要通过 sniffLoadCommands 函数来判断 Mach-O 文件是否是压缩过的,然后分别 选择不同的 子类实例化。 

17.png

1.7 sniffLoadCommands

这个函数主要做两件事情 

  1. 判断Mach-O文件是classic的还是compressed的。 

  2. 获取mach-O文件的segment的数量。

7-1.png

8.PNG

9.PNG

10.PNG

1.8 ImageLoaderMachOClassic: :instantiateMainExecutable

classic 与 compressed 的初始化大同小异,先分析Classic 的实现 

11.png

可以看到加载的核心代码 还在 instantiateStart 函数中

1.9 instantiateStart

12.png

这里仍然没有出现加载的核心代码,只是根据之前获得的数据申请分配了内存,并计算 segments的 指针。 ImageLoaderMachOClassic 的构造函数才是加载 的核心逻辑。

2.0 ImageLoaderMachOClassic

13.png

14.png

根据Mach-O 文件 segments 将数据加载到 内存中, 任何返回 调用 addImage 函数。

2.1 addImage

15.png

这个函数只是做了数据更新 

  1. 将image 添加到管理容器中

  2. 更新了内存分布的信息

end

整个加载过程基本分为三个步骤:

  1. 合法加测

  2. 解析Mach-O文件头信息,将segments 的具体信息 构建到image 的实例中

  3. 添加image 到管理容器

根据 dyld的源代码的粗略分析, 更多信息需要分析 xnu 内核代码。

参考

ObjC runtime 源代码

dyld 源代码

《Mac OSX and iOS Internals》

0
0
分享到:
评论

相关推荐

    程序员移动开发中的iOS安全攻防知识分享

    fishhook是Facebook开源的一个动态修改链接Mach-O文件的工具,利用dyld加载Mach-O文件的原理,通过修改懒加载和非懒加载两个表的指针达到hook系统动态库函数的目的。 二、LLDB命令 LLDB是一个命令行调试工具,提供...

    MachOview查看Mach-O文件结构.zip

    Mach-O(Mach Object)文件是Apple操作系统,包括macOS和iOS,使用的二进制文件格式。这种格式包含了可执行代码、库、符号表等关键元素,使得开发者能够构建和运行应用程序。MachOview是一款强大的开源工具,它允许...

    swift-通过Mach-O文件NonlazyClassList构建动态库进行iOSload方法耗时检测

    在Mach-O文件的加载命令中,`LC_LOAD_DYLIB`和`LC_LOAD_WEAK_DYLIB`用于引入动态库,而`NonlazyClassList`则是一个包含了所有未懒加载类的列表。 当iOS系统加载动态库时,会按照`NonlazyClassList`中的顺序逐个调用...

    strongarm:Mach-O分析库:flexed_biceps:

    强壮有力的手臂 strongarm是功能齐全的跨平台ARM64 Mach-O分析库。...insert_dylib :将加载命令添加到Mach-O dsc_symbolicate :给定dyld_shared_cache,从嵌入式系统映像生成符号映射 nm :列出Mach-O的符号表 l

    Injector:将DyLib注入现有的Mach-O文件

    DyLib则是Mach-O文件中的动态链接库,允许程序在运行时加载和使用外部功能。 C++是一种广泛使用的编程语言,尤其适用于系统级编程和构建高性能的应用。在这个场景中,C++可能被用来编写Injector工具,它能够将DyLib...

    iOS开发底层源码学习,dyld源码

    2. **加载动态库**:dyld根据Mach-O头信息找到依赖的动态库,并将其加载到内存中。这个过程中,dyld会处理库的相对地址,使其适应当前进程的地址空间。 3. **符号绑定**:dyld负责解析和绑定所有符号引用,确保函数...

    WWDC session 406_optimizing_app_startup_time.pdf

    1. **理论部分**:涵盖了从`main()`函数执行前发生的所有事情,包括mach-o文件格式、虚拟内存基础知识以及mach-o二进制文件是如何被加载和准备的。 - **Mach-O格式**:Mach-O是一种目标文件格式,用于存储可执行...

    Mac OS X应用程序格式详解.docx

    在Mach-O格式中,一个应用程序或动态库包含了一系列的"load commands",这些命令定义了如何加载和解析二进制文件。当OS X执行一个应用程序时,系统会解析这些命令来确定程序的入口点、依赖的动态库以及如何进行内存...

    dyld_read:dyld加载流程分析

    - **加载命令解析**:dyld 会解析 Mach-O 文件的加载命令,以了解如何正确地加载和解析文件。 - **符号解析**:dyld_read 可能会参与到符号解析过程中,找出哪些符号需要被解析和绑定。 - **数据结构的初始化**:...

    dyld 源码(750.6)

    1. **可执行文件加载**:dyld接收由内核传递的可执行文件地址,并解析其Mach-O头信息,这包含了程序的加载命令,指示dyld如何处理内存映射。 2. **动态库搜索**:dyld根据可执行文件中的依赖信息寻找需要加载的动态...

    dyld_soucecode_analysis:dyld原始码分析,dyld加载一个程序的大致过程-源码程序

    dyld加载一个程序的过程可以分为以下几个关键步骤: 1. **初始化**:当一个程序启动时,dyld首先被加载到内存中,然后它会解析可执行文件的Mach-O头信息,以了解程序的依赖性。 2. **加载依赖库**:dyld会根据程序...

    HookCase:用于macOSOS X逆向工程的工具

    在macOS环境下,由于系统的特殊性,如Mach-O文件格式、Objective-C++语言的使用、内核模块和动态链接器dyld等,使得逆向工作相对复杂。HookCase则为这一过程提供了便利。 首先,让我们来了解一下Mach-O文件格式。...

    dyld:PureDarwin动态加载程序

    1. **启动过程**:当一个应用程序启动时,dyld首先读取可执行文件的Mach-O头信息,找出程序需要的动态库列表。 2. **库搜索**:dyld根据配置和环境变量,查找并加载这些库。在macOS中,常用的是`/usr/lib`和`/usr/...

    阿里数据iOS端启动速度优化心得

    其中,Load dylibs阶段dyld会分析应用依赖的dylib,找到其mach-o文件,打开和读取这些文件并验证其有效性。Rebase/Bind阶段dyld需要修正镜像内部的指针,指向正确的地址。为了优化dyld加载的过程,可以采取以下措施...

    iOS安全体系演进过程及漏洞分析.pdf

    正常执行流程中,内核加载主程序并将其控制权交给dyld,然后dyld加载动态链接库(dylib)。但是,如果主程序的MachO头被篡改,不加载dyld并直接执行恶意代码,就可能造成安全问题。 代码签名的实际校验涉及到内存页面...

    Objective C之Hook所有+load方法简单示例

    在Objective-C中,我们可以通过诸如`mach-o`工具或`objc/runtime.h`中的API来解析MachO文件,找出所有的类定义和Category信息。这样,我们就可以遍历这些信息,找到所有的`+load`方法。 Hook技术的核心是替换原始...

    fishhook_read:原始解析-源码解析

    fishhook的工作原理主要基于mach-o文件格式和dyld动态链接器。在iOS系统中,dyld负责加载和解析应用程序中的动态库,而fishhook则利用dyld的这一特性,在程序运行过程中找到目标函数的地址,并将其替换为我们自定义...

    ios 反编译工具

    它支持32位和64位的Mach-O文件(iOS应用程序的主要格式)的反编译,并且能够解析Objective-C和Swift代码。Hopper不仅提供了反汇编功能,还能进行静态分析,帮助开发者理解应用程序的工作原理。 Hopper的主要特性...

    Advanced.Apple.Debugging.&.Reverse.Engineering.v2.0[源码+PDF+EPUB]

    3. **二进制分析**:探讨如何分析可执行文件的格式,如Mach-O文件结构,以及如何解读符号表和加载命令,这对于理解程序的动态行为和定位问题很有帮助。 4. **内存管理**:讲解Objective-C的自动引用计数(ARC)和...

Global site tag (gtag.js) - Google Analytics