iOS Mach-O文件

什么是Mach-O

        Mach-O格式是全称为Mach Object的文件格式的缩写,是OSX/iOS系统上的可执行文件格式,类似于Windows上的PE格式 (Portable Executable )和 Linux上的elf格式 (Executable and Linking Format)。

Mach-O格式文件类型

1、Executable:应用的主要二进制

2、Dylib Library:动态链接库(又称DSO或DLL)

3、Static Library:静态链接库

4、Bundle:不能被链接的Dylib,只能在运行时使用dlopen方法加载,可当插件使用

5、Relocatable Object File :可重定向文件类型

什么是FatFile/FatBinary

        各种不同架构(arm64、X86)的Mach-O合成的集合体,可以运行于多个架构。

Mach-O文件图解

目前流行的Mach-O文件的查看软件是MachOView

MachOView下载地址:http://sourceforge.net/projects/machoview/

MachOView源码地址:https://github.com/gdbinit/MachOView


 

Mach-O文件格式主要由三部分组成:Header、Load Commands和Data

Header部分描述当前Mach-O文件的基本信息 ,主要是包括CPU类型、CPU具体类型、文件类型、加载命令数量和大小等

Load commands部分主要包括Mach-O文件中在虚拟内存中空间的分配,起始结束内存地址以及不同的段在Mach-O文件中的位置与大小的分布

Data部分主要描述内存分配内容,包括__TEXT和 __DATA字段

Mach Header

        Mach header 根据CPU架构不同,分为两种 ,32位和64位的数据结构,具体如下所示

// 32位
struct mach_header {
    uint32_t    magic;      /* mach magic number identifier */
    cpu_type_t  cputype;    /* cpu specifier */
    cpu_subtype_t   cpusubtype; /* machine specifier */
    uint32_t    filetype;   /* type of file */
    uint32_t    ncmds;      /* number of load commands */
    uint32_t    sizeofcmds; /* the size of all the load commands */
    uint32_t    flags;      /* flags */
};
// 64位
 struct mach_header_64 {
    uint32_t    magic;      /* mach magic number identifier */
    cpu_type_t  cputype;    /* cpu specifier */
    cpu_subtype_t   cpusubtype; /* machine specifier */
    uint32_t    filetype;   /* type of file */
    uint32_t    ncmds;      /* number of load commands */
    uint32_t    sizeofcmds; /* the size of all the load commands */
    uint32_t    flags;      /* flags */
    uint32_t    reserved;   /* reserved */
};

字段含义解释如下

magic:确定Mach-O文件运行框架,如64位/32位
cputype:CPU类型,如arm
cpusubtype:对应CPU类型的具体型号
filetype:文件类型
ncmds:加载命令条数
sizeofcmds:所有加载命令的大小
flags:标志位
reserved:保留字段

LoadCommands

        LoadCommand主要是指令类型和指令内容长度,结构如下

 struct load_command {
    uint32_t cmd;       /* type of load command */
    uint32_t cmdsize;   /* total size of command in bytes */
};

Command的指令说明

  • LC_SEGMENT/LC_SEGMENNT_64 :将对应段中的数据加载并映射到进程的内存空间

  • LC_SEGMENT_TEXT :代码段,其中_stub_helper用于关联函数bind/rebind

  • LC_SEGMENT_DATA :可读/可写的数据段,函数指针,其中_la_symbol_ptr动态函数个数,及相对动态符号表的偏移量

  • LC_SEGMENT_LINKEDIT :动态链接加载指令,支持动态链接dyld,该段长度覆盖符号表等数据(计算链接时程序的基址),符号表,动态符号表,字符串表段中定义的offset偏移量都是基于_LINKEDIT的vm_add

  • LC_SYMTAB :符号表信息,解析函数名

  • LC_DYSYMTAB :动态符号表信息,地址值为动态函数相对符号表的索引,_la_symbol_ptr对应的cmd可以换算出第一个动态函数对应动态符号表的初始地址,其次存储是连续,结构长度固定的,可以通过遍历获取所有动态函数的对应的符号表索引

Data部分

        Data部分是由很多Segment组成的,每一个Segment定义了一些Mach-O文件的数据、地址和内存保护属性,这些数据在动态链接器加载程序时被映射到了虚拟内存中,不同的段有不同的功能。

Segment功能划分

  • __PAGEZERO: 空指针陷阱段,映射到虚拟内存空间的第一页,用于捕捉对NULL指针的引用
  • __TEXT: 包含了执行代码以及其他只读数据。 内核将该段从可执行文件映射到共享内存, 静态连接器设置该段的虚拟内存权限为不允许写。当这个段被映射到内存后,可以被所有进程共享。(这主要用在frameworks, bundles和共享库等程序中,也可以为同一个可执行文件的多个进程拷贝使用)
  • __DATA: 包含了程序数据,可读可写
  • __LINKEDIT: 包含动态链接库使用的原始数据,比如符号,字符串,重定位表条目等。

注意*:一般Segment又会按不同的功能划分为几个区(Section),Segment和Section都以两个下划线为前缀,段所有字母大写,而区则是所有字母小写。

Segment结构体:

struct segment_command { /* for 32-bit architectures */
    uint32_t    cmd;        /* LC_SEGMENT */
    uint32_t    cmdsize;    /* includes sizeof section structs */
    char        segname[16];    /* segment name */
    uint32_t    vmaddr;     /* memory address of this segment */
    uint32_t    vmsize;     /* memory size of this segment */
    uint32_t    fileoff;    /* file offset of this segment */
    uint32_t    filesize;   /* amount to map from the file */
    vm_prot_t   maxprot;    /* maximum VM protection */
    vm_prot_t   initprot;   /* initial VM protection */
    uint32_t    nsects;     /* number of sections in segment */
    uint32_t    flags;      /* flags */
};


struct segment_command_64 { /* for 64-bit architectures */
    uint32_t    cmd;        /* LC_SEGMENT_64 */
    uint32_t    cmdsize;    /* includes sizeof section_64 structs */
    char        segname[16];    /* segment name */
    uint64_t    vmaddr;     /* memory address of this segment */
    uint64_t    vmsize;     /* memory size of this segment */
    uint64_t    fileoff;    /* file offset of this segment */
    uint64_t    filesize;   /* amount to map from the file */
    vm_prot_t   maxprot;    /* maximum VM protection */
    vm_prot_t   initprot;   /* initial VM protection */
    uint32_t    nsects;     /* number of sections in segment */
    uint32_t    flags;      /* flags */
};

Section结构体:

struct section { /* for 32-bit architectures */
    char        sectname[16];   /* name of this section */
    char        segname[16];    /* segment this section goes in */
    uint32_t    addr;       /* memory address of this section */
    uint32_t    size;       /* size in bytes of this section */
    uint32_t    offset;     /* file offset of this section */
    uint32_t    align;      /* section alignment (power of 2) */
    uint32_t    reloff;     /* file offset of relocation entries */
    uint32_t    nreloc;     /* number of relocation entries */
    uint32_t    flags;      /* flags (section type and attributes)*/
    uint32_t    reserved1;  /* reserved (for offset or index) */
    uint32_t    reserved2;  /* reserved (for count or sizeof) */
};

struct section_64 { /* for 64-bit architectures */
    char        sectname[16];   /* name of this section */
    char        segname[16];    /* segment this section goes in */
    uint64_t    addr;       /* memory address of this section */
    uint64_t    size;       /* size in bytes of this section */
    uint32_t    offset;     /* file offset of this section */
    uint32_t    align;      /* section alignment (power of 2) */
    uint32_t    reloff;     /* file offset of relocation entries */
    uint32_t    nreloc;     /* number of relocation entries */
    uint32_t    flags;      /* flags (section type and attributes)*/
    uint32_t    reserved1;  /* reserved (for offset or index) */
    uint32_t    reserved2;  /* reserved (for count or sizeof) */
    uint32_t    reserved3;  /* reserved */
};

未完待续......

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值