macOS Universal binaries & Mach-O Format

从零开始学习AWS黑客技术,成为专家 htARTE(HackTricks AWS红队专家)

支持HackTricks的其他方式:

基本信息

Mac OS二进制文件通常被编译为通用二进制文件通用二进制文件可以在同一个文件中支持多种架构

这些二进制文件遵循Mach-O结构,基本上由以下部分组成:

  • 头部

  • 装载命令

  • 数据

https://alexdremov.me/content/images/2022/10/6XLCD.gif

Fat Header

使用以下命令搜索文件:mdfind fat.h | grep -i mach-o | grep -E "fat.h$"

头部包含魔数字节,后面是文件包含的架构数(nfat_arch),每个架构都将有一个fat_arch结构体。

使用以下命令检查:

或使用Mach-O View工具:

正如您可能想到的,通常为2种架构编译的通用二进制文件会使大小翻倍,而为单个架构编译的二进制文件。

Mach-O头部

头部包含有关文件的基本信息,例如用于识别其为Mach-O文件的魔数字节以及有关目标架构的信息。您可以在以下位置找到它:mdfind loader.h | grep -i mach-o | grep -E "loader.h$"

Mach-O 文件类型

有不同的文件类型,你可以在这里的源代码中找到它们的定义。最重要的类型包括:

  • MH_OBJECT:可重定位目标文件(编译的中间产品,还不是可执行文件)。

  • MH_EXECUTE:可执行文件。

  • MH_FVMLIB:固定虚拟内存库文件。

  • MH_CORE:代码转储。

  • MH_PRELOAD:预加载的可执行文件(在 XNU 中不再支持)。

  • MH_DYLIB:动态库。

  • MH_DYLINKER:动态链接器。

  • MH_BUNDLE:"插件文件"。使用 -bundle 在 gcc 中生成,并由 NSBundledlopen 显式加载。

  • MH_DYSM:配套的 .dSym 文件(带有用于调试的符号的文件)。

  • MH_KEXT_BUNDLE:内核扩展。

或者使用Mach-O View

Mach-O 标志

源代码还定义了几个对加载库有用的标志:

  • MH_NOUNDEFS: 没有未定义的引用(完全链接)

  • MH_DYLDLINK: Dyld 链接

  • MH_PREBOUND: 动态引用预绑定。

  • MH_SPLIT_SEGS: 文件分割为只读和读写段。

  • MH_WEAK_DEFINES: 二进制文件具有弱定义的符号

  • MH_BINDS_TO_WEAK: 二进制文件使用弱符号

  • MH_ALLOW_STACK_EXECUTION: 使堆栈可执行

  • MH_NO_REEXPORTED_DYLIBS: 库没有 LC_REEXPORT 命令

  • MH_PIE: 位置无关可执行文件

  • MH_HAS_TLV_DESCRIPTORS: 存在具有线程本地变量的部分

  • MH_NO_HEAP_EXECUTION: 堆/数据页面不执行

  • MH_HAS_OBJC: 二进制文件具有 Objective-C 部分

  • MH_SIM_SUPPORT: 模拟器支持

  • MH_DYLIB_IN_CACHE: 在共享库缓存中使用的 dylibs/frameworks。

Mach-O 加载命令

在这里指定了文件在内存中的布局,详细说明了符号表的位置,执行开始时主线程的上下文以及所需的共享库。提供了有关二进制文件加载到内存中的动态加载器 (dyld) 的指令。

使用了在上述提到的 loader.h 中定义的 load_command 结构。

有大约50种不同类型的加载命令,系统会以不同方式处理。最常见的是:LC_SEGMENT_64LC_LOAD_DYLINKERLC_MAINLC_LOAD_DYLIBLC_CODE_SIGNATURE

LC_SEGMENT/LC_SEGMENT_64

这些命令定义了在执行过程中映射到进程的虚拟内存空间中的段

有不同类型的段,比如**__TEXT段,保存程序的可执行代码,以及__DATA段,包含进程使用的数据。这些段位于Mach-O文件的数据部分**中。

每个段可以进一步划分为多个区块。加载命令结构包含了关于各自段内的这些区块的信息

在头部首先找到段头

段头的示例:

此头部定义了在其后出现的区块头的数量

章节标题示例

如果您将节偏移量(0x37DC)与arch开始的偏移量相加,在本例中为0x18000 --> 0x37DC + 0x18000 = 0x1B7DC

还可以通过命令行获取头部信息

LC_CODE_SIGNATURE

包含有关 Mach-O 文件的代码签名的信息。它只包含一个指向签名 blob偏移量。这通常位于文件的末尾。 但是,您可以在此博客文章和这个gists中找到关于此部分的一些信息。

LC_ENCRYPTION_INFO[_64]

支持二进制加密。但是,当然,如果攻击者设法 compromise 进程,他将能够以未加密的方式 dump 内存。

LC_LOAD_DYLINKER

包含动态链接器可执行文件的路径,将共享库映射到进程地址空间。值始终设置为 /usr/lib/dyld。重要的是要注意,在 macOS 中,dylib 映射发生在用户模式,而不是内核模式。

LC_IDENT

已过时,但当配置为在 panic 时生成 dumps 时,将创建一个 Mach-O 核心 dump,并在 LC_IDENT 命令中设置内核版本。

LC_UUID

随机 UUID。它本身对任何直接用途都没有用,但 XNU 会将其与进程信息的其余部分一起缓存。它可用于崩溃报告。

LC_DYLD_ENVIRONMENT

允许在进程执行之前指定 dyld 的环境变量。这可能非常危险,因为它可以允许在进程内部执行任意代码,因此此加载命令仅在使用 #define SUPPORT_LC_DYLD_ENVIRONMENT 构建的 dyld 中使用,并进一步限制处理仅限于形式为 DYLD_..._PATH 的变量,指定加载路径。

LC_LOAD_DYLIB

此加载命令描述了动态库依赖项,指示加载器(dyld)加载和链接该库。Mach-O 二进制文件所需的每个库都有一个 LC_LOAD_DYLIB 加载命令。

  • 此加载命令是**dylib_command**类型的结构(其中包含一个描述实际依赖动态库的 struct dylib):

您也可以通过以下命令行获取此信息:

一些潜在的与恶意软件相关的库包括:

  • DiskArbitration:监控 USB 驱动器

  • AVFoundation:捕获音频和视频

  • CoreWLAN:Wifi 扫描。

一个 Mach-O 二进制文件可以包含一个或多个构造函数,这些函数将在LC_MAIN 中指定的地址之前执行。 任何构造函数的偏移量都保存在**__DATA_CONST** 段的**__mod_init_func** 部分中。

Mach-O 数据

文件的核心是数据区域,由加载命令区域中定义的几个段组成。每个段中可以包含各种数据部分,每个部分包含特定类型的代码或数据

https://www.oreilly.com/api/v2/epubs/9781785883378/files/graphics/B05055_02_38.jpg

这包括:

  • 函数表:包含有关程序函数的信息。

  • 符号表:包含有关二进制文件使用的外部函数的信息

  • 还可以包含内部函数、变量名称等等。

要检查它,您可以使用Mach-O View工具:

或者从命令行界面:

从零开始学习AWS黑客技术,成为专家 htARTE(HackTricks AWS Red Team Expert)

其他支持HackTricks的方式:

最后更新于