09_Mach-O文件解析

2020-08-04  本文已影响0人  伶俐ll
Macho-O 是什么

Mach-O 是 Mach object 文件格式的缩写,它是一种用于记录可执行文件、对象代码、共享库、动态加载代码和内存转储的文件格式。

大多数基于 Mach 内核的操作系统都使用 Mach-O,如NeXTSTEP、OS X 和 iOS 。

Universal Binary

Universal Binary:通用二进制文件,也称胖二进制文件,是将支持不同架构的Mach-O打包在一起,再在文件起始位置加上Fat Header来说明所包含的Mach-O文件支持的架构和偏移地址信息。


Snip20200814_24.png

Mach-O文件格式

image.png

官方描述:
https://developer.apple.com/library/content/documentation/DeveloperTools/Conceptual/MachOTopics/0-Introduction/introduction.html

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

Mach-O文件的数据主体可分为三个部分:

下面将分别对每一部分进行介绍

一、Header

查看xnu源码我们可以得知,定义Header的结构体如下:

struct mach_header {
    uint32_t magic;
    cpu_type_t cputype;
    cpu_subtype_t cpusubtype;
    uint32_t filetype;
    uint32_t ncmds;
    uint32_t sizeofcmds;
    uint32_t flags;
};
struct mach_header_64 {
    uint32_t magic;
    cpu_type_t cputype;
    cpu_subtype_t cpusubtype;
    uint32_t filetype;
    uint32_t ncmds;
    uint32_t sizeofcmds;
    uint32_t flags;
    uint32_t reserved;
};

1、 magic

Mach-O的魔数,很多类型的文件,其起始的几个字节的内容是固定的,根据这几个字节的内容就可以确定文件类型,因此这几个字节的内容被称为魔数。在这里用于标示文件架构类型,也就是说判断是x86、x64、armv7、arm64。

//fat.h
//胖二进制文件
#define FAT_MAGIC   0xcafebabe
#define FAT_CIGAM   0xbebafeca
//loader.h
//非64bit架构文件
#define MH_MAGIC    0xfeedface  
#define MH_CIGAM    0xcefaedfe
//loader.h
//64bit架构文件
#define MH_MAGIC_64 0xfeedfacf 
#define MH_CIGAM_64 0xcffaedfe

2、 cputype与cpusubtype

定义了Mach-o所能支持的所有CPU类型,x86和arm的如下。

#define CPU_ARCH_ABI64  0x01000000      /* 64 bit ABI */
#define CPU_TYPE_X86        ((cpu_type_t) 7)
#define CPU_TYPE_I386       CPU_TYPE_X86   
#define CPU_TYPE_X86_64     (CPU_TYPE_X86 | CPU_ARCH_ABI64)
#define CPU_TYPE_ARM        ((cpu_type_t) 12)
#define CPU_TYPE_ARM64          (CPU_TYPE_ARM | CPU_ARCH_ABI64)

3、ncmds和sizeofcmds

这个cmd就是加载命令,ncmds就是加载命令的个数,而sizeofcmds就是加载命令的字节数。

4、flags

程序的标识位

5、 reserved

64bit的保留字段。

6、filetype

用于判断程序的文件类型,在mach-o/loader.h中定义一组宏可以很直观的明白该位的意义。

#define    MH_OBJECT   0x1     /* relocatable object file */
#define    MH_EXECUTE  0x2     /* demand paged executable file */
#define    MH_FVMLIB   0x3     /* fixed VM shared library file */
#define    MH_CORE     0x4     /* core file */
#define    MH_PRELOAD  0x5     /* preloaded executable file */
#define    MH_DYLIB    0x6     /* dynamically bound shared library */
#define    MH_DYLINKER 0x7     /* dynamic link editor */
#define    MH_BUNDLE   0x8     /* dynamically bound bundle file */
#define    MH_DYLIB_STUB   0x9     /* shared library stub for static */
                /*  linking only, no section contents */
#define    MH_DSYM     0xa     /* companion file with only debug */
                /*  sections */
#define    MH_KEXT_BUNDLE  0xb     /* x86_64 kexts */

其中,常见的Mach-O文件类型有:

MH_OBJECT :
MH_EXECUTE

可执行文件

```
 lingli@bogon 逆向 % clang -o test2 test.c
 lingli@bogon 逆向 % file test2
 test2: Mach-O 64-bit executable x86_64
 ```
MH_DYLIB:动态库文件
zhanglingli@bogon 逆向 % cd /usr/lib           
zhanglingli@bogon lib % file libssl.44.dylib 
libssl.44.dylib: Mach-O 64-bit dynamically linked shared 
library x86_64
MH_DYLINKER

动态链接编辑器

zhanglingli@bogon 逆向 % file dyld 
dyld: Mach-O universal binary with 2 architectures: 
[arm_v7s:Mach-O dynamic linker arm_v7s] [arm64:Mach-O 
64-bit dynamic linker arm64]
dyld (for architecture armv7s):   Mach-O dynamic linker 
arm_v7s
dyld (for architecture arm64):    Mach-O 64-bit dynamic 
linker arm64
MH_DSYM

存储着二进制文件符号信息的文件,.dSYM/Contents/Resources/DWARF/xx(常用于分析APP的崩溃信息)

zhanglingli@bogon 逆向 % file weather                                          
weather: Mach-O universal binary with 2 architectures: 
[arm_v7:Mach-O dSYM companion file arm_v7] [arm64]
weather (for architecture armv7):    Mach-O dSYM 
companion file arm_v7
weather (for architecture arm64):    Mach-O 64-bit dSYM 
companion file arm64
MH_CORE0

程序Crash之后产生的Core文件

MH_BUNDLE0

Xcode里面可以创建bundle的Target,编译之后在bundle后缀名的文件夹下面可以找到

在Xcode中查看target的Mach-O类型
image.png

二、Load commands

在mach-o/loader.h中可以看到对Load Command的定义。

struct load_command {
    uint32_t cmd;
    uint32_t cmdsize;
};

加载命令,上面头部中的数据已经说明了整个Mach-O文件的基本信息,但整个Mach-O中最重要的还要数加载命令。这些加载命令在Mach-O文件加载解析时,被内核加载器或者动态链接器调用,指导如何设置加载对应的二进制数据段。

Snip20200814_28.png Snip20200814_27.png

由上表可知

可以使用size -l -m -x来查看Mach-O的内存分布
zhanglingli@bogon 逆向mySelf % size -l -m -x daf 
daf (for architecture armv7):
Segment __PAGEZERO: 0x4000 (vmaddr 0x0 fileoff 0)
Segment __TEXT: 0xc000 (vmaddr 0x4000 fileoff 0)
    Section __text: 0x1db4 (addr 0xbcc8 offset 31944)
    Section __picsymbolstub4: 0x3b0 (addr 0xda7c offset 39548)
    Section __stub_helper: 0x2e8 (addr 0xde2c offset 40492)
    Section __objc_methname: 0xf60 (addr 0xe114 offset 41236)
    Section __cstring: 0x419 (addr 0xf074 offset 45172)
    Section __objc_classname: 0xb8 (addr 0xf48d offset 46221)
    Section __objc_methtype: 0xab9 (addr 0xf545 offset 46405)
    total 0x4336
Segment __DATA: 0x4000 (vmaddr 0x10000 fileoff 49152)
    Section __nl_symbol_ptr: 0x48 (addr 0x10000 offset 49152)
    Section __la_symbol_ptr: 0xec (addr 0x10048 offset 49224)
    Section __cfstring: 0x30 (addr 0x10134 offset 49460)
    Section __objc_classlist: 0xc (addr 0x10164 offset 49508)
    Section __objc_nlclslist: 0x4 (addr 0x10170 offset 49520)
    Section __objc_protolist: 0x18 (addr 0x10174 offset 49524)
    Section __objc_imageinfo: 0x8 (addr 0x1018c offset 49548)
    Section __objc_const: 0xae8 (addr 0x10194 offset 49556)
    Section __objc_selrefs: 0x94 (addr 0x10c7c offset 52348)
    Section __objc_protorefs: 0x8 (addr 0x10d10 offset 52496)
    Section __objc_classrefs: 0xc (addr 0x10d18 offset 52504)
    Section __objc_superrefs: 0x4 (addr 0x10d24 offset 52516)
    Section __objc_ivar: 0x8 (addr 0x10d28 offset 52520)
    Section __objc_data: 0xa0 (addr 0x10d30 offset 52528)
    Section __data: 0x168 (addr 0x10dd0 offset 52688)
    Section __bss: 0x140 (addr 0x10f38 offset 0)
    total 0x1078
Segment __LINKEDIT: 0x8000 (vmaddr 0x14000 fileoff 65536)
total 0x1c000

三、Raw segment data

在Load commands中定义的Segment的最原始的编译数据,是Mach-O文件中最大的一部分,包含了Load Command中所需的数据以及在虚存地址偏移量和大小;一般Mach-O文件有多个段(Segement),段每个段有不同的功能,一般包括:

dyld和Mach-O

APP的可执行文件、动态库都是由dyld负责加载的,dyld用于加载以下类型的Mach-O文件

上一篇下一篇

猜你喜欢

热点阅读