MachO文件详解

什么是Macho文件?

  苹果开发者对它一定不陌生,特别是喜欢逆向的同学,对它的研究更是必不可少。在可安装的每一个.app包中,都有一个与app同名的可执行文件,它可能长这样:(如果你碰到显示为白色的MachO文件,说明当前用户对其没有可执行权限)

MachO文件详解_第1张图片

Macho的全称是Mach Object,是在Mac以及IOS上可执行的一种文件格式,它包括但不限于可执行文件(.out .o),动态库,静态库,dyld,目标文件, 官方文档中为(loader.h   https://opensource.apple.com/source/xnu/xnu-1456.1.26/EXTERNAL_HEADERS/mach-o/loader.h)

MachO文件详解_第2张图片

它类似于Windows上的PE、Linux上的ELF格式。

MachO的内部结构是什么样子的?

MachO文件详解_第3张图片

MachO文件详解_第4张图片

一:header(https://opensource.apple.com/source/xnu/xnu-1456.1.26/EXTERNAL_HEADERS/mach-o/loader.h)

用于快速确认该文件的CPU类型、文件类型等信息。

除了使用MachOView能查看machO文件信息,还可以通过otool命令查看,我们通过otool命令来查看:

1⃣️magic:MachO文件的魔数,用来确定其属于64位(0xfeedfacf)还是32位(0xfeedface)

2⃣️cputype和cupsubtype代表的是cpu的类型和其子类型

MachO文件详解_第5张图片

3⃣️:filetype:2,代表可执行的文件 (第一张图中的宏)

4⃣️:ncmds:加载命令(load commands)的数量。

5⃣️:sizeofcmds表示总个数个load commands的总字节大小,load commands区域是紧接着header区域的

6⃣️:fiags:标识二进制文件支持的功能,主要与系统的加载、链接有关。

二:LoadCommands(加载命令)

用于告诉loader如何设置并加载二进制数据。

otool查看

Load command 1
      cmd LC_SEGMENT_64         // cmd 是load command的类型,LC_SEGMENT_64的含义是将这个64位的段映射到进程地址空间,即加载命令                      
  cmdsize 712                   // 代表load command的大小
  segname __TEXT                // 16字节的段名字 __TEXT
   vmaddr 0x0000000100000000    // 段的虚拟内存起始地址
   vmsize 0x00000000036a4000    // 段的虚拟内存大小
  fileoff 0                     // 段在文件中的偏移量
 filesize 57294848              // 段在文件中的大小
  maxprot 0x00000005            // 段页面所需要的最高内存保护(4=r,2=w,1=x)
 initprot 0x00000005            // 段页面初始的内存保护
   nsects 8                     // 段中包含section的数量
    flags 0x0                   // 其他杂项标志位
Section
  sectname __text               // 第一个是__text ,就是主程序代码
   segname __TEXT               // 该section所属的 segment名,第一个是__TEXT
      addr 0x0000000100006110   // 该section在内存的启始位置,0x100006110
      size 0x000000000358a268   // size 该section的大小,0x358a268
    offset 24848                // 24848 0x6110
     align 2^4 (16)             // 字节大小对齐,16
    reloff 0                    // 重定位入口的文件偏移 0
    nreloc 0                    // 需要重定位的入口数量 0
     flags 0x80000400           // 包含section的type和attributes
 reserved1 0                    // ...保留用
 reserved2 0                    // ...保留用

segment_command 和section(可以到苹果的官方文档中查看)

最常见的加载命令:

MachO文件详解_第6张图片

  • LC_SEGMENT_64: 将该段(64位)映射到进程地址空间中
  • LC_DYLD_INFO_ONLY:加载动态链接库信息(重定向地址、弱引用绑定、懒加载绑定、开放函数等的偏移值等信息)
  • LC_SYMTAB:载入符号表地址
  • LC_DYSYMTAB:载入动态符号表地址
  • LC_LOAD_DYLINKER:加载动态加载库,可以看出示例使用的是/usr/lib/dyld
  • LC_UUID:确定文件的唯一标识,crash解析中也会有这个,去检测dysm文件和crash文件是否匹配
  • LC_VERSION_MIN_MACOSX/LC_VERSION_MIN_IPHONEOS:确定二进制文件要求的最低操作系统版本
  • LC_SOURCE_VERSION:构建该二进制文件使用的源代码版本
  • LC_MAIN:设置程序主线程的入口地址和栈大小
  • LC_ENCRYPTION_INFO_64:获取加密信息
  • LC_LOAD_DYLIB:加载额外的动态库
  • LC_FUNCTION_STARTS:定义一个函数起始地址表,使调试器和其他程序易于看到一个地址是否在函数内
  • LC_DATA_IN_CODE:定义在代码段内的非指令的表
  • LC_CODE_SIGNATURE:获取应用签名信息

 

三:Data(数据段segment)

 1 存放数据:代码,字符常量,类,方法等

 2 可以拥有多个segment,每个segment可以有零到多个section。每个段都有一段虚拟地址映射到进程的地址空间

如果说前面两部分的主要作用,是让kern内核知道如何读取MachO文件,并指定MachO文件的动态链接器(dyly)用来完成后续的动态库加载,然后设置好程序入口等一些列程序启动前的信息,那么Data和链接信息部分,就相当于当程序运行起来后,为每一个映射到虚拟内存中的指令操作提供真实的物理地址支持。

四:Loader info(链接信息)

一个完整的用户级MachO文件的末端是一系列链接信息。其中包含了动态加载器用来链接可执行文件或者依赖所需使用的符号表、字符串表等 。

 

参考:https://juejin.im/post/5c67e7efe51d45164c75993b

你可能感兴趣的:(IOS)