Mach-O文件的格式如下图所示,Mach-O文件的格式如下图所示

   `sizeof(struct fat-arch) = 20byte`

iOS系统一分配析(2)Mach-O贰进制文件分析,

➠愈来愈多技术干货请戳:听云博客

0x0一  Mach-O格式简单介绍

Mach-O文件格式是 OS X 与 iOS 系统上的可执行文件格式,类似于windows的 PE
文件 与 Linux(别的 Unix like)的 ELF
文件,假设不干净搞清楚Mach-O的格式与有关内容,那么透彻钻研 xnu
内核就无从聊到。

Mach-O文件的格式如下图所示:

图片 1

有如下多少个部分构成:

一.
Header:保存了Mach-O的片段着力消息,包含了平台、文件类型、LoadCommands的个数等等。

贰.
LoadCommands:那一段紧跟Header,加载Mach-O文件时会使用那里的数码来规定内部存储器的分布。

3.
Data:每一个segment的现实性数目都封存在此地,那里包涵了切实的代码、数据等等。

0x02 FAT二进制数据 ,数据结构定义在 \<mach-o/fat.h\>

图片 2

图片 3

  1. 率先段为magic 魔数,那里注意大小端,读出来之后供给看下是0xCAFEBABE照旧0xBEBAFECA(不然即为thin),须要依照这几个来转后续读取的字节的字节序。
     能够看出来 前4byte 为 0xBEBAFECA ,表明为fat。

  2. 其次段为arch
    count,也正是该App或dSYM中富含如何CPU框架结构,比如armv七、arm6四等,那些例子中为贰(后4byte
     0x 00 00 00 0二),表示包罗了二种cpu框架结构。  

      sizeof(struct fat-header) = 8byte

  3. 后续段中富含cputype(0x  0C 00  00 0一)、cpusubtype (0x 00 00 00
    00)、offset (0x 00 10 00  00)、size(0x 00  F0 27
    00)等数码,根据fat中的结构定义,依次读取,这里供给验证的是,借使只包涵壹种CPU架构的话,是从未那段fat头定义的,能够跳过那部分,直接读取Arch数据。

       sizeof(struct fat-arch) = 20byte

4.
依照fat头中读取的offset数据,大家得以跳到文件对应的arch数据的岗位,当然假如唯有1种架构的话就不必要计算偏移量了。
下图给出解析的函数

图片 4

0x03 Mach Header二进制数据

透过magic大家能够区分出是3贰-bit还是64-bit,6肆-bit多了陆个字节的保留字段,那里同样供给注意字节序的难题,相当于判定magic,来明确是否须要更换字节序。
 

`sizeof(struct mach-header-64) = 32byte`  ; `sizeof(struct mach-header) = 28byte`

图片 5

根据mach-header与mach-header_6四的概念,很引人注目能够看到,Headers的机要职能正是支援系统飞快的原则性Mach-O文件的运营环境,文件类型。

图片 6

FileType 

因为Mach-O文件不仅用来促成可执行文件,同时还用来完毕了其他内容

  1. 基础扩充

  2. 库文件

  3. CoreDump

  4.  其它

图片 7

下边是部分脍炙人口用到的文件类型

  1. MH-OBJECT    编写翻译进程中发出的  obj文件 (gcc -c xxx.c 生成xxx.o文件)

  2. MH-EXECUTABLE  可实施二进制文件 (/usr/bin/ls)

  3. MH-CORE      CoreDump (崩溃时的Dump文件)

  4. MH-DYLIB  动态库(/usr/lib/里面包车型客车这一个共享库文件)

  5. MH-DYLINKER  连接器linker(/usr/lib/dyld文件)

  6. MH-KEXT-BUNDLE   内核扩充文件 (本身支付的回顾内核模块)

flags

Mach-O headers还包含了壹些很关键的dyld的加载参数。

图片 8

  1. MH-NOUNDEFS   目的未有未定义的号子,不设有链接正视

  2. MH-DYLDLINK     该目的文件是dyld的输入文件,无法被再一次的静态链接

  3. MH-PIE      允许私自的地址空间(开启ASLBMWX叁  -\>Address Space Layout
    Randomization)

  4. MH-ALLOW-STACK-EXECUTION   栈内部存储器可执行代码,一般是暗许关闭的。

  5. MH-NO-HEAP-EXECUTION   堆内存不或许执行代码

图片 9

0x04 LoadCommands

Load Commands 直接就跟在Header前边,全体command占用内部存款和储蓄器的总和在Mach-O
Header里面已经交由了。在加载过Header之后纵然通过解析LoadCommand来加载接下去的数量了。定义如下:

图片 10

cmd字段

依照cmd字段的连串分裂,使用了区别的函数来加载。不难的列出一张表看1看在根本代码中差异的command类型都有啥功用。

  1. LC-SE克林霉素ENT;LC-SE达托霉素ENT-6四   在基本中由load-segment
    函数处理(将segment中的数据加载并映射到进度的内部存款和储蓄器空间去)

  2. LC-LOAD-DYLINKE酷威    在基础中由load-dylinker
    函数处理(调用/usr/lib/dyld程序)

  3. LC-UUID 在基础中由load-uuid 函数处理 (加载12八-bit的唯1ID)

  4. LC-THREAD  在基础中由load-thread 函数处理
    (开启三个MACH线程,不过不分配栈空间)

  5. LC-UNIXTHREAD 在根本中由load-unixthread 函数处理 (开启2个UNIX
    posix线程)

  6. LC-CODE-SIGNATURE 在根本中由load-code-signature 函数处理
    (进行数字签名)

  7. LC-ENC安德拉YPTION-INFO 在基础中由 set-code-unprotect 函数处理
    (加密2进制文件)

UUID 2进制数据    12捌byte

UUID是1柒个字节(12八bit)的一段数据,是文本的绝无仅有标识,后边提到的符号化时,那么些UUID必须求和App二进制文件中的UUID壹致,才能被科学的符号化。dwarfdump查看的UUID就是那段数据。读取那有的数量时通过Command结构读取的,也正是率先段(0x000000壹B)表示接下去的数据类型,第一段(0x0000001八)数据的高低(包罗Command数据)。 

SymTab 二进制数据

1.
符号表数据块结构,前2段还是是Command数据。后面肆段分别为标志在文书中的偏移量(0x00壹DF5E0)、符号个数(0x00一DF五E0)、字符串在文件中的偏移量(0x0020C叁A0)、字符串表大小(0x000729A8)。 

二.
接下去正是读取Segment和Section数据块了,和地点读取数据块结构同样是基于Command结构读取,下图呈现的Segment数据和Section数据,它们在2进制文件中它们是接二连叁的,约等于每一条Segment数据背后会尾随多条对应的Section数据,Section的数额总数是透过Segment结构中的nsects决定的。 

三.
这里本人写了三个不难地Mach-O解析工具 [https://github.com/liutianshx2012/Tmacho\](https://github.com/liutianshx2012/Tmacho)

图片 11

Segment数据

加载数据时,主要加载的正是LC-SE罗红霉素ET活着LC-SE核糖霉素ENT_6四。其余的Segment的用处在那边不做探索。

LCSE培洛霉素ENT以及LC-SE威他霉素ENT-6四 定义如下图。

 

图片 12

图片 13

能够看来,那里超过四分之二的多寡是用来扶持内核将Segment映射到虚拟内部存款和储蓄器的。

nsects 字段,标示了Segment中某些许secetion
,section是切实有用的数码存放的地点。

TEXT的vmaddr也正是程序的加载地址;
—DWAOdysseyF中标明了DWA大切诺基F数据块的信息,表示dSYM是DWA本田CR-VF格式的数据结构。 

` sizeof(struct segment-command) = 56byte   ;   sizeof(struct segment-command-64) = 72byte`

Section数据

图片 14

从Section数据中,大家能够找到—debug-info、—debug-pubnames,
—debug-line等调节和测试音讯,通过那一个调试新闻我们得以找到程序中符号的开场面址、变量类型等音讯。假如我们要符号化的话,就足以由此分析那一个多少得到大家想要的音信。

Symbol 数据

通过SymTab中的数据能够取得Symbol在文书中的地点和个数,Symbol块数据中含有了符号的发端地址、字符串的偏移量等数据,这一部分数据结构能够参考\<nlist.h\>

\<stabl.h\>。在那一部分数额总体读取后,就足以读取全体的号子数据了,也正是接下去的数量。 

Symbol String 数据

1.
由此SymTab和Symbo中的数据能够赢得每一种符号字符串在文书中的偏移量和分寸,种种符号数据是以0终极的字符串。 

二.
大家经过上述两有的数据的构成就能够得到每一种symbo在先后中的加载地址了。那些数量对于随后做标记工作都格外的有帮助。

3.
到此,关于dSYM文件中尾部数据读取就成功了。底部数据都有相应的数据结构定义,读取时相对会比较易于些,解析数据时要留心字节序的标题,3贰-bit和6四-bit数据结构的歧异、字节长度的差异,DWA猎豹CS陆F版本的差异,种种数据块之间都以紧凑联系的,一个字节的读取偏差就会导致后续数据的读取错误,正所谓差之毫厘,失之千里。

 

最初的作品链接:http://blog.tingyun.com/web/article/detail/1341

http://www.bkjia.com/IOSjc/1172803.htmlwww.bkjia.comtruehttp://www.bkjia.com/IOSjc/1172803.htmlTechArticleiOS系统分析(二)Mach-O二进制文件解析,
更加多技术干货请戳:听云博客 0x0一 Mach-O格式不难介绍 Mach-O文件格式是 OS X
与 iOS 系统上的可执…

Segment数据

一.
首先段为magic 魔数,那里注意大小端,读出来之后须要看下是0xCAFEBABE还是0xBEBAFECA(不然即为thin),须要依据这几个来转后续读取的字节的字节序。
 能够看出来 前四byte 为 0xBEBAFECA ,表达为fat。

3.
MH-PIE      允许私自的地点空间(开启ASL凯雷德  -\>Address Space Layout
Randomization)

2.
LC-LOAD-DYLINKELacrosse    在基础中由load-dylinker
函数处理(调用/usr/lib/dyld程序)

七.
LC-ENCHighlanderYPTION-INFO 在基础中由 set-code-unprotect 函数处理
(加密2进制文件)

依据cmd字段的连串分歧,使用了分化的函数来加载。不难的列出一张表看一看在基础代码中不相同的command类型都有哪些职能。

4.
根据fat头中读取的offset数据,大家能够跳到文件对应的arch数据的地方,当然假诺唯有一种架构的话就不需求计算偏移量了。
下图给出解析的函数

一.
由此SymTab和Symbo中的数据足以博得种种符号字符串在文件中的偏移量和分寸,各种符号数据是以0终极的字符串。 

5.
MH-DYLINKER  连接器linker(/usr/lib/dyld文件)

肆.
MH-DYLIB  动态库(/usr/lib/里面包车型客车那几个共享库文件)

壹.
LC-SEGMENT;LC-SEGMENT-6四   在基本中由load-segment
函数处理(将segment中的数据加载并映射到进度的内部存款和储蓄器空间去)

图片 15

二.
MH-EXECUTABLE  可实行二进制文件 (/usr/bin/ls)

0x03Mach Header二进制数据

图片 16

Symbol
数据

0x02FAT二进制数据 ,数据结构定义在 \<mach-o/fat.h\>

有如下多少个部分组成:

Mach-O文件的格式如下图所示:

3.
LC-UUID 在根本中由load-uuid 函数处理 (加载128-bit的唯1ID)

0x01 Mach-O格式简单介绍

cmd字段

加载数据时,主要加载的就是LC-SE达托霉素ET活着LC-SE创新霉素ENT_6肆。别的的Segment的用途在此处不做探索。

陆.
LC-CODE-SIGNATURE 在基本中由load-code-signature 函数处理
(举办数字签名)

图片 17

③.
MH-CORE      CoreDump (崩溃时的Dump文件)

能够阅览,那里大多数的数目是用来赞助内核将Segment映射到虚拟内部存款和储蓄器的。

二.
次之段为arch
count,也正是该App或dSYM中涵盖哪些CPU架构,比如armv7、arm64等,那些事例中为二(后4byte
 0x 00 00 00 02),表示包蕴了二种cpu框架结构。  

TEXT的vmaddr也正是先后的加载地址;
—DWAPRADOF中标明了DWA安德拉F数据块的新闻,表示dSYM是DWAXC90F格式的数据结构。 

图片 18

图片 19

三.
那边作者写了3个简易地Mach-O解析工具 [https://github.com/liutianshx2012/Tmacho\](https://github.com/liutianshx2012/Tmacho)

Mach-O
headers还隐含了有个别很要紧的dyld的加载参数。

nsects
字段,标示了Segment中有稍许secetion
,section是切实有用的数码存放的地点。

图片 20

UUID是十五个字节(12八bit)的一段数据,是文本的绝无仅有标识,前边提到的符号化时,那么些UUID必需要和App2进制文件中的UUID1致,才能被科学的符号化。dwarfdump查看的UUID便是那段数据。读取那有的数据时经过Command结构读取的,也便是首先段(0x000000一B)表示接下去的数据类型,第3段(0x0000001八)数据的大小(包蕴Command数据)。 

由此magic我们得以分别出是3二-bit依然64-bit,6肆-bit多了四个字节的保留字段,那里同样需求留意字节序的标题,也正是判断magic,来规定是不是需求转移字节序。
 

2.
库文件

一.
符号表数据块结构,前②段依旧是Command数据。前面4段分别为标志在文书中的偏移量(0x001DF5E0)、符号个数(0x00一DF伍E0)、字符串在文件中的偏移量(0x0020C三A0)、字符串表大小(0x000729A八)。 

4.
 其它

1.
Header:保存了Mach-O的局地主干音讯,包罗了阳台、文件类型、LoadCommands的个数等等。

二.
我们通过以上两部分数据的重组就足以获得每一种symbo在先后中的加载地址了。那个数量对于今后做标记工作都十一分的有匡助。

Section数据

图片 21

FileType 

SymTab
二进制数据

3.
CoreDump

图片 22

LCSE博来霉素ENT以及LC-SE欧霉素ENT-64定义如下图。

一.
MH-NOUNDEFS   目的未有未定义的记号,不存在链接依赖

Mach-O文件格式是
OS X 与 iOS 系统上的可执行文件格式,类似于windows的 PE 文件 与
Linux(其余 Unix like)的 ELF
文件,假设不到底搞清楚Mach-O的格式与相关内容,那么透彻钻探 xnu
内核就无从提起。

1.
根本增添

图片 23

 

` sizeof(struct segment-command) = 56byte   ;   sizeof(struct segment-command-64) = 72byte`

Load
Commands 直接就跟在Header前面,全数command占用内部存款和储蓄器的总额在Mach-O
Header里面已经付出了。在加载过Header之后就算经过解析LoadCommand来加载接下去的多寡了。定义如下:

一.
MH-OBJECT    编写翻译进度中发生的  obj文件 (gcc -c xxx.c
生成xxx.o文件)

  `sizeof(struct fat-header) = 8byte`

五.
MH-NO-HEAP-EXECUTION   堆内部存款和储蓄器不恐怕推行代码

四.
LC-THREAD  在基础中由load-thread 函数处理
(开启二个MACH线程,可是不分红栈空间)

图片 24

初稿链接:http://blog.tingyun.com/web/article/detail/1341

越多技术干货请戳:听云博客

Symbol
String 数据

透过SymTab中的数据足以博得Symbol在文书中的位置和个数,Symbol块数据中包涵了符号的序幕地址、字符串的偏移量等数据,这有个别数据结构能够参考\<nlist.h\>

\<stabl.h\>。在那有个别数据总体读取后,就能够读取全部的记号数据了,也便是接下去的数码。 

图片 25

5.
LC-UNIXTHREAD 在根本中由load-unixthread 函数处理 (开启叁个UNIX
posix线程)

因为Mach-O文件不仅用来贯彻可执行文件,同时还用来贯彻了别的内容

从Section数据中,大家能够找到—debug-info、—debug-pubnames,
—debug-line等调试音信,通过那一个调节和测试信息大家得以找到程序中符号的开局部址、变量类型等新闻。借使大家要符号化的话,就足以透过分析那么些多少获得大家想要的消息。

0x04
LoadCommands

二.
LoadCommands:那壹段紧跟Header,加载Mach-O文件时会使用那里的数目来明确内部存款和储蓄器的遍布。

flags

二.
MH-DYLDLINK     该对象文件是dyld的输入文件,不能被再一次的静态链接

 

贰.
接下去正是读取Segment和Section数据块了,和上边读取数据块结构同样是基于Command结构读取,下图显示的Segment数据和Section数据,它们在2进制文件中它们是几次三番的,也便是每一条Segment数据背后会尾随多条对应的Section数据,Section的数目总数是透过Segment结构中的nsects决定的。 

UUID
贰进制数据    128byte

上边是一些好好用到的文件类型

根据mach-header与mach-header_6肆的定义,很明朗能够看来,Headers的显要作用正是扶助系统连忙的固化Mach-O文件的运维条件,文件类型。

图片 26

图片 27

三.
Data:每二个segment的切实可行数量都保留在那边,那里带有了现实的代码、数据等等。

图片 28

`sizeof(struct mach-header-64) = 32byte`  ; `sizeof(struct mach-header) = 28byte`

叁.
接续段中蕴藏cputype(0x  0C 00  00 0一)、cpusubtype (0x 00 00 00
00)、offset (0x 00 10 00  00)、size(0x 00  F0 27
00)等数据,依据fat中的结构定义,依次读取,那里供给表达的是,假使只含有一种CPU架构的话,是未有这段fat头定义的,能够跳过那有些,直接读取Arch数据。

4.
MH-ALLOW-STACK-EXECUTION   栈内部存款和储蓄器可执行代码,一般是暗许关闭的。

6.
MH-KEXT-BUNDLE   内核扩充文件 (本人支付的简单内核模块)

3.
到此,关于dSYM文件中底部数据读取就形成了。尾部数据都有对应的数据结构定义,读取时相对会相比易于些,解析数据时要专注字节序的题目,3二-bit和64-bit数据结构的出入、字节长度的出入,DWASportageF版本的出入,各类数据块之间都以紧凑联系的,三个字节的读取偏差就会导致后续数据的读取错误,正所谓差之毫厘,失之千里。

相关文章