MachOView源码解析

869 阅读3分钟

MachO

MachO是Mach Object文件格式(Mach Object File Format)的缩写,是Mac/iOS上可执行文件的格式,类似于 Linux 和大部分 UNIX 的原生格式 ELF(Extensible Firmware Interface)以及 Windows 上的 PE。 包括如下格式

  • 目标文件.o
  • .a
  • .dylib
  • .framework
  • 可执行文件 execute
  • dyld
  • .dsym

MachO 文件结构

image.png

  1. MachO Header: Mach-O 的 CPU 类型、文件类型、加载命令的数量和大小等
  2. Load Commands
  • 理解为书的目录,每个command对应后续代码和数据的具体组织结构,不同的数据类型使用不同的加载命令表示
  • Segment Load Command 指向Data区域的Segment(段)
    • PAGEZERO: 当设置一个指针变量的值为NULL时,其实就是将指针指向了__PAGEZERO段这块区域。
    • __TEXT: 代码段
    • __DATA_CONST 常量数据段
    • __DATA 其他数据段
    • __LINKEDIT 符号信息、代码签名等数据
  • 每个Segment由多个Section(节)组成
  1. Data : 存放各类的代码和数据了
  • Segments+Sections

MachOView

github.com/hefeijinbo/…

MachOView用于显示MachO文件的开源工具, 本文主要讲解MachOView的源码和MachO文件解析流程

读取Fat+Thin二进制信息

Mach-O 支持多架构在一个包中,如 armv7、arm64、x86-64等,俗称胖二进制/通用二进制(Fat)

  • 针对Fat二进制文件, 会解析Fat + 每个子架构的信息, 如果是单架构,只会解析单个架构的信息 image.png image.png
  • 当读取结束后, MachOView中显示了Fat+Thin的二进制信息节点(FatLayout+MachOLayout)
  • 这个可以理解为 RootNode, 每个架构一个 RootNode(Layout) image.png

子Node创建总体流程

针对每个架构(Layout/Node)循环执行 MainTasks(同步) > BackgroundTasks(异步) image.png

MainTask

创建每个架构的 MachO Header + Load Command + Sections + Relocations(.o,.a) Node image.png Load Command 有如下种类 image.png createLoadCommandNode执行完成后,所有的load command节点就创建完成了 image.png 创建每个Section的二进制内容节点, 作为后续的Background Task的父Node image.png

Backgroud Tasks

创建各个section的子Node, 来显示更多的代码/数据信息

// 后台异步任务
- (void)doBackgroundTasks
{
  NSBlockOperation * linkEditOperation = [NSBlockOperation blockOperationWithBlock:^
  {
      [dataController updateStatus:MVStatusTaskPendding :@"LinkEdit Parsing ..."]; // 通知UI刷新任务状态
      [self processLinkEdit64]; // 创建符号表 外部符号表 代码签名等节点
  }];
  
  NSBlockOperation * sectionRelocsOperation = [NSBlockOperation blockOperationWithBlock:^
  {
      [dataController updateStatus:MVStatusTaskPendding :@"Section relocations Parsing ..."];
      [self processSectionRelocs64]; // 针对.o .a 文件, 生成重定位Relocation节点信息
  }];
  
  NSBlockOperation * dyldInfoOperation = [NSBlockOperation blockOperationWithBlock:^
  {
       [dataController updateStatus:MVStatusTaskPendding :@"Dyld info  Parsing ..."];
      [self processDyldInfo]; // 生成dynamic loader信息节点
  }];
  
  NSBlockOperation * sectionOperation = [NSBlockOperation blockOperationWithBlock:^
  {
      [dataController updateStatus:MVStatusTaskPendding :@"Section contents Parsing ..."];
    // 解析Section64的二进制显示可读的信息节点
    // C String Literals、Floating Point Literals、Module、Symbol Stubs....
      [self processSections64]; 
  }];
  
  NSBlockOperation * EHFramesOperation = [NSBlockOperation blockOperationWithBlock:^
  {
      [dataController updateStatus:MVStatusTaskPendding :@" Exception Frames Parsing ..."];
      [self processEHFrames64]; // Exception Frames
  }];
  
  NSBlockOperation * LSDAsOperation = [NSBlockOperation blockOperationWithBlock:^
  {
      [dataController updateStatus:MVStatusTaskPendding :@" Lang Spec Data Areas  Parsing ..."];
      [self processLSDA64]; // Lang Spec Data Areas
  }];
  
  NSBlockOperation * objcSectionOperation = [NSBlockOperation blockOperationWithBlock:^
  {
      [dataController updateStatus:MVStatusTaskPendding :@" ObjC Section contents  Parsing ..."];
      [self processObjcSections64]; // 解析Section64 中的OC信息
  }];
  
  NSBlockOperation * codeSectionsOperation = [NSBlockOperation blockOperationWithBlock:^
  {
      [dataController updateStatus:MVStatusTaskPendding :@" Code sections Parsing ..."];
    [self processCodeSections64]; //解析Section Text端,反汇编
  }];
  
  // Block任务按顺序执行
  [sectionOperation       addDependency:linkEditOperation];
  [sectionRelocsOperation addDependency:sectionOperation];
  [dyldInfoOperation      addDependency:sectionRelocsOperation];
  [objcSectionOperation   addDependency:dyldInfoOperation];
  [codeSectionsOperation  addDependency:objcSectionOperation];
  [EHFramesOperation      addDependency:dyldInfoOperation];
  [LSDAsOperation         addDependency:EHFramesOperation];

  [dataController updateStatus:MVStatusTaskStarted];
  [oq   addOperations:[NSArray arrayWithObjects:linkEditOperation,
                                                sectionOperation,
                                                sectionRelocsOperation,
                                                dyldInfoOperation,
                                                EHFramesOperation,
                                                LSDAsOperation,
                                                objcSectionOperation,
                                                codeSectionsOperation,nil] 
    waitUntilFinished:YES]; // 在后台线程执行
  [dataController updateStatus:MVStatusTaskTerminated];//完成所有解析任务

  • Dynamic Loader Info+LinkEdit后的Node信息 image.png
  • processCodeSections : 解析__Text.__text Section, 显示汇编代码 image.png
  • processSections64 : 解析Section的二进制显示C String Literals、Floating Point Literals、Module、Pointer、Symbol Stubs.... image.png
  • processObjcSections64 : 解析Section的OC信息 CFString, Class, Category,protocol,Image.... image.png

更多信息

  • MachOView

github.com/hefeijinbo/…

  • 官网macho介绍

developer.apple.com/library/arc…

  • API参考

developer.apple.com/documentati…