Mach-O文件解析

579 阅读4分钟

1、什么是Mach-O文件

  • Mach-OMach Object 文件格式的缩写,它是一种用于 目标代码内核转储 等的文件格式.作为a.out格式的替代, Mach-O 提供了更强的扩展性,并提升了 符号表 中信息的访问速度.苹果系统中常用于可执行文件动态库.o的目标文件.a.framework的静态库以及动态连接器dyld

2、Mach-O结构

  • Mach-O 是一个以数据块分组的二进制字节流,这些数据块包含元信息,比如 字节顺序CPU类型数据块大小

2.1、ASLR

  • ASLR ,全称是Address Spce Layout Randomization,翻译过来就是地址空间布局随机化,是一种针对缓冲区溢出的安全保护技术,通过对堆、栈、共享库映射等线性区布局的随机化,增加了攻击者预测目的地址的难度,防止攻击者直接定位代码位置,阻止溢出攻击
    • 未使用ASLR时Mach-O载入内存情况: image.png
    • 使用ASLR时Mach-O载入内存情况: image.png
  • 虚拟内存中的真正地址 = ASLR偏移量 + PAGEZERO的大小 + Mach-O中的偏移量 (其中PAGEZERO的大小就是VM Size,Mach-O中的偏移量就是Offset,因为PAGEZERO到内存中才会展开,所以要加上PAGEZERO的大小)

2.2、Header

  • 保存 Mach-O 的一些基本信息 image.png
  1. Magic Number(模数): 表示该二进制所支持的CPU位数,用于校验

    • MH_MAGIC : 0xFEEDFACE //32位
    • MH_MAGIC_64 : 0xFEEDFACF //64位
  2. CPU TypeCPU SubType:CPU架构及子版本

  3. File Type:文件类型

    • MH_EXECUTABLE : 可执行二进制文件
    • MH_OBJECT : 目标文件
    • MH_DYLIB : 动态库
  4. Number of Load Commands:加载命令的数量

  5. Size of load Commands:所有加载命令的大小

  6. Flags(文件状态信息)包含一些状态位.(dyld加载需要的一些标记,20多种宏定义,需要查看源码)

    • MH_DYLDLINK : 该二进制不能再静态链接
    • MH_PIE : 启用 ASLR 地址空间布局随机化
  7. reserved:64位保留字段

2.3、Load Commands(加载指令)

  • 紧跟 Header,加载 Mach-O 文件时会使用这部分数据确定内存分布,对系统内核加载器动态连接器起指导作用

  • load_commands 展开后的数目与总大小已经在 Header 中有记录,所有加载指令都是以 CommandCommand Size起头。Command Size 字段以字节为单位,主要记录偏移量load command 指针进入下一条加载指令,32位架构的 load command 是以4字节的倍数,64位结构的 load command 是以8字节的倍数(加载指令永远是这样对齐),不够用0填充字节,这样就可以被映射到内存

  • VM Address、VM Size记录这此段在虚拟内存的位置和大小

  • File Offset、File Size记录着此段在Mach-O中的位置和大小

  • 结构如图所示: image.png

指令分析
  • Load Commands 指令如下: image.png
    1. LC_SEGMENT_64 : 加载段

      • 源码中数据结构: image.png
      • 4种主要 LC_SEGMENT_64 类型: __PAGEZERO__TEXT__DATA__LINKEDIT image.png
    2. LC_DYLD_INFO_ONLY :动态链接相关信息

    3. LC_SYMTAB:加载符号地址

    4. LC_DYSYMTAB:加载动态符号表地址

    5. LC_LOAD_DYLINKER :加载动态链接器dyld,用于后续加载动态库 image.png

    6. LC_UUID :加载二进制的UUID,唯一标识,常用于解析crash堆栈。 image.png

    7. LC_VERSION_MIN_MACOSX :加载该二进制支持的最小操作系统版本,对应于工程配置中的 Deployment Target

    8. LC_SOURCE_VERSION : 源代码版本

    9. LC_MAIN :加载main函数

    10. LC_DYLIB :加载动态库,外挂如WeChatPlugin,会增加一条这样的指令,用于加载自定义的动态库 image.png

    11. LC_RPATH :加载@rpath,对应于工程配置中的 Runpath Search Paths image.png

    12. LC_FUNCTION_STARTS :加载函数入口信息。

    13. LC_DATA_IN_CODE :定义在代码段内的非指令的表

    14. LC_CODE_SIGNATURE :加载签名,用于校验,外挂如WeChatPlugin,会删掉这条指令 image.png

2.4、Section64(节)

  • Load Commands 区域下来接着就是 DATA 区域,展开 Load Commands 下的 LC_SEGMENT_64 可以看到多个 Section64 ,各个Section的具体信息可以在 DATA 区查看,它们是一一对应的: image.png

  • DATA: Load Commands 中每个segment的具体数据保存在这里,包含具体的代码、数据等 image.png

  • section 节已经是最小的分类,大部分内容集中在 __TEXT, __DATA 这两段中,部分内容如下 image.png image.png

3、符号表:Symbol Table

  • 方法的名称称为符号,存在于Symbols这项中 image.png

  • 上架时会剔除符号表,只保留动态符号表 ,因为编译完成后地址就已经确定了,如果还留着符号表只是为别人Hook你的内容提供便利

参考文档