七、Mach-O

我们编写的C、C++、swift、OC,最终编译链接生成Mach-O可执行文件,它不仅仅代表可执行文件,还有很多。

Mach-O是Mach object的缩写,是Mac\iOS上用于存储程序、库的标准格式。

那么哪些文件的类型是属于Mach-O格式呢?

七、Mach-O_第1张图片

总共有11种。

可以在xnu源码中,查看到Mach-O格式的详细定义(https://opensource.apple.com/tarballs/xnu/)

  • EXTERNAL_HEADERS/mach-o/fat.h
  • EXTERNAL_HEADERS/mach-o/loader.h

xnu:Mac系统的内核

课后了解:FreeBSD Unix Linux XNU Darwin MacOSX这些技术概念的联系

常见的Mach-O文件类型

七、Mach-O_第2张图片
常见的Mach-O文件类型

1、验证.o就是Mach-O类型:自己写个c文件,clang -c test.c编译下,就是.o目标文件,file test.o验证。

七、Mach-O_第3张图片
.C文件内容
七、Mach-O_第4张图片
验证.o目标文件是Mach-O类型(MH_OBJECT)
七、Mach-O_第5张图片
验证.a静态库是Mach-O类型(MH_OBJECT)

进入Mac中有静态库的地方,find . -name "*.a"筛选出静态库,file libltdl.a验证。

七、Mach-O_第6张图片
疑惑:这里的.a静态库没显示Mach-O类型

2、验证:可执行文件是Mach-O类型

七、Mach-O_第7张图片
验证可执行文件是Mach-O类型

3、验证:动态库(.dylib和.framework/xx)是Mach-O类型
进入有动态库的文件夹cd /usr/lib,筛选find . -name "*.dylib",验证file libmx.dylib

动态库dylib

之前抽取出来的armv7s动态库:

七、Mach-O_第8张图片
动态库.framework/xx

4、验证:动态链接编辑器是Mach-O类型

去哪里找动态链接编辑器呢?iFunBox打开手机端/usr/lib/dyld

七、Mach-O_第9张图片
七、Mach-O_第10张图片
验证:Mach-O

5、验证:存储着二进制文件符号信息的文件 是Mach-O类型

在哪里找这个文件呢?
.dSYM/Contents/Resources/DWARF/xx(常用于分析APP的崩溃信息)

用XCode的release模式编译打包,这样会产生dSYM文件。

七、Mach-O_第11张图片
release模式生成dSYM文件,其实这是个文件夹
七、Mach-O_第12张图片
显示包内容,找到符号文件

复制到桌面

验证dSYM的类型:Mach-O

上面说的这些类型(除了动态链接编辑器)都可以通过XCode来生成,在Xcode中查看target的Mach-O类型:

七、Mach-O_第13张图片


Universal Binary

七、Mach-O_第14张图片
XCode打包app的构架设置
file验证

下图,编译好的JailbreakTest可执行文件拖拽到Hopper,Hopper会告诉你这是:胖二进制,支持armv7构架、arm64构架。(所谓胖二进制文件,也就是里面有多个构架)

七、Mach-O_第15张图片
Hopper也会告诉当前Mach-O文件的所有信息
七、Mach-O_第16张图片
简述
七、Mach-O_第17张图片
胖二进制文件瘦身


Mach-O的基本结构

1、基本结构

七、Mach-O_第18张图片
苹果文档对Mach-O的描述
七、Mach-O_第19张图片
Mach-O的基本结构
2、拿到一个Mach-O,怎么去分析呢,如何查看Mach-O的段。
otool:查看Mach-O特定部分和段的内容

只有充分了解了Mach-O段的相关信息,才能在它内存中改些东西。知道了数据段在哪里,也就知道了可以修改的地方在哪里。

使用otool查看《下厨房app》例子:

2.1 终端中敲otool,看怎么使用,有哪些用法:

FengdeMacBook-Pro:ipa fengluo$ otool
Usage: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/otool [-arch arch_type] [-fahlLDtdorSTMRIHGvVcXmqQjCP] [-mcpu=arg] [--version]  ...
    -f print the fat headers
    -a print the archive header
    -h print the mach header
    -l print the load commands
    -L print shared libraries used
    -D print shared library id name
    -t print the text section (disassemble with -v)
    -p   start dissassemble from routine name
    -s   print contents of section
    -d print the data section
    -o print the Objective-C segment
    -r print the relocation entries
    -S print the table of contents of a library (obsolete)
    -T print the table of contents of a dynamic shared library (obsolete)
    -M print the module table of a dynamic shared library (obsolete)
    -R print the reference table of a dynamic shared library (obsolete)
    -I print the indirect symbol table
    -H print the two-level hints table (obsolete)
    -G print the data in code table
    -v print verbosely (symbolically) when possible
    -V print disassembled operands symbolically
    -c print argument strings of a core file
    -X print no leading addresses or headers
    -m don't use archive(member) syntax
    -B force Thumb disassembly (ARM objects only)
    -q use llvm's disassembler (the default)
    -Q use otool(1)'s disassembler
    -mcpu=arg use `arg' as the cpu for disassembly
    -j print opcode bytes
    -P print the info plist section as strings
    -C print linker optimization hints
    --version print the version of /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/otool
 
 

2.2 使用otool看下《下厨房app》的Mach-O文件中,都用了哪些动态库

FengdeMacBook-Pro:ipa fengluo$ otool -L recipe
recipe:
    /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 400.9.4)
    /usr/lib/libicucore.A.dylib (compatibility version 1.0.0, current version 62.1.0)
    /usr/lib/libresolv.9.dylib (compatibility version 1.0.0, current version 1.0.0)
    /usr/lib/libsqlite3.dylib (compatibility version 9.0.0, current version 274.20.0)
    /usr/lib/libxml2.2.dylib (compatibility version 10.0.0, current version 10.9.0)
    /usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.11)
    。。。。。。。。。。。。。省略

2.3 打印下头信息

FengdeMacBook-Pro:ipa fengluo$ otool -h recipe
Mach header
      magic cputype cpusubtype  caps    filetype ncmds sizeofcmds      flags
 0xfeedfacf 16777228          0  0x00           2    67       7664 0x00218085
七、Mach-O_第20张图片

2.4 用终端看Mach-O这些信息很麻烦,推荐一款GUI工具

MachOView(https://github.com/gdbinit/MachOView)
github上的这个MachOView可能会奔溃,因为少了些判断,建议用MJ打包好的那个。

下载,打开,运行,解决报错

七、Mach-O_第21张图片
Snip20181127_93.png

unable to find sdk 'macosx10.9' (in target 'MachOView'),说明当初创建MachOView项目的时候是macosx10.9,而现在本机的系统是10.13,偏高了。在XCode中设置下MachOView项目,两种解决办法:

解决一:

七、Mach-O_第22张图片

解决二:当前所用

七、Mach-O_第23张图片
1
七、Mach-O_第24张图片
2
七、Mach-O_第25张图片
3

运行,出来一个程序,点击程序图标,顶部状态栏出现菜单,点击File->Open,选中《暴走漫画app》的Mach-O:BaoManReader。

在MachOView和终端上,对比BaoManReader的Mach-O的头文件信息,MachOView更方便看、更详细些:

七、Mach-O_第26张图片

看看MachOView的其他部分:

七、Mach-O_第27张图片
Load Commands
七、Mach-O_第28张图片

之前用的class-dump、otool,也都是读取了Mach-O文件中的信息。

用MachOView工具就可以方便的看前面说到的几种Mach-O格式的头文件信息。


dyld

七、Mach-O_第29张图片

如何验证dyld这个Mach-O加载上面3种Mach-O呢?——看源码

通过load函数来加载。一层一层往下调

七、Mach-O_第30张图片

从目前来说,我们知道了iOS的动态库、可执行文件都由dyld这个库(位置:/usr/lib/dyld)负责加载的。
至于将可执行文件是如何加载进内存,或载进内存是如何分布的呢,或者载进内存后是怎么一步步执行到main函数的呢,且听下回分解。

你可能感兴趣的:(七、Mach-O)