我们编写的C、C++、swift、OC,最终编译链接生成Mach-O可执行文件,它不仅仅代表可执行文件,还有很多。
Mach-O是Mach object的缩写,是Mac\iOS上用于存储程序、库的标准格式。
那么哪些文件的类型是属于Mach-O格式呢?
总共有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文件类型
1、验证.o就是Mach-O类型:自己写个c文件,clang -c test.c
编译下,就是.o目标文件,file test.o
验证。
进入Mac中有静态库的地方,find . -name "*.a"
筛选出静态库,file libltdl.a
验证。
2、验证:可执行文件是Mach-O类型
3、验证:动态库(.dylib和.framework/xx)是Mach-O类型
进入有动态库的文件夹cd /usr/lib
,筛选find . -name "*.dylib"
,验证file libmx.dylib
。
之前抽取出来的armv7s动态库:
4、验证:动态链接编辑器是Mach-O类型
去哪里找动态链接编辑器呢?iFunBox打开手机端/usr/lib/dyld
5、验证:存储着二进制文件符号信息的文件 是Mach-O类型
在哪里找这个文件呢?
.dSYM/Contents/Resources/DWARF/xx(常用于分析APP的崩溃信息)
用XCode的release模式编译打包,这样会产生dSYM文件。
复制到桌面
上面说的这些类型(除了动态链接编辑器)都可以通过XCode来生成,在Xcode中查看target的Mach-O类型:
Universal Binary
下图,编译好的JailbreakTest可执行文件拖拽到Hopper,Hopper会告诉你这是:胖二进制,支持armv7构架、arm64构架。(所谓胖二进制文件,也就是里面有多个构架)
Mach-O的基本结构
1、基本结构
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] <object file> ...
-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 <routine name> start dissassemble from routine name
-s <segname> <sectname> 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
2.4 用终端看Mach-O这些信息很麻烦,推荐一款GUI工具
MachOView(https://github.com/gdbinit/MachOView)
github上的这个MachOView可能会奔溃,因为少了些判断,建议用MJ打包好的那个。
下载,打开,运行,解决报错
unable to find sdk 'macosx10.9' (in target 'MachOView'),说明当初创建MachOView项目的时候是macosx10.9,而现在本机的系统是10.13,偏高了。在XCode中设置下MachOView项目,两种解决办法:
解决一:
解决二:当前所用
运行,出来一个程序,点击程序图标,顶部状态栏出现菜单,点击File->Open,选中《暴走漫画app》的Mach-O:BaoManReader。
在MachOView和终端上,对比BaoManReader的Mach-O的头文件信息,MachOView更方便看、更详细些:
看看MachOView的其他部分:
之前用的class-dump、otool,也都是读取了Mach-O文件中的信息。
用MachOView工具就可以方便的看前面说到的几种Mach-O格式的头文件信息。
dyld
如何验证dyld这个Mach-O加载上面3种Mach-O呢?——看源码
通过load函数来加载。一层一层往下调
从目前来说,我们知道了iOS的动态库、可执行文件都由dyld这个库(位置:/usr/lib/dyld)负责加载的。
至于将可执行文件是如何加载进内存,或载进内存是如何分布的呢,或者载进内存后是怎么一步步执行到main函数的呢,且听下回分解。