MachO文件分析

2021-05-20  本文已影响0人  忻凯同学

MachO文件

Mach-O是Mach Object文件格式的缩写,是mac以及iOS上可执行文件的格式。是一种用于可执行文件、目标代码、动态库的文件格式。作为a.out格式的替代,Mach-O提供了更强的扩展性。
类似于windows上的PE格式 (Portable Executable ),linux上的elf格式 (Executable and Linking Format)

Mach-O文件格式

实际开发中,MatchO文件有很多不同的类型,可以通过在Xcode上指定。
TargetsBuild SettingsLinkingMach-O Type

通用二进制文件

在Xcode编译可以指定生成哪些架构的Match-O文件,同时也可以添加其他架构
TargetsBuild SettingsArchitecturesArchitectures

设备的CPU架构(指令集)

Mach-O架构拆分、合并

  1. lipo工具

$lipo -info 'MachO文件'

$lipo 'MachO文件' –thin '架构名' –output '目标MachO文件'

$lipo -create '第一个MachO文件' '第二个MachO文件 -output '目标MachO文件'

  1. file指令:查看文件信息

$file 文件路径

MachO文件结构

Mach-O 的组成结构如图所示,主要包括三个部分:Header、Load commands、Data

Header

包含二进制文件的一般信息,架构类型、字节顺序、加载指令的数量等。

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:定位结构是64位还是32位 (e.g. MH_MAGIC_64)
cputype:CPU类型 (e.g. CPU_TYPE_ARM64)
cpusubtype:CPU具体类型 (e.g. CPU_SUBTYPE_ARM64_ALL)
filetype:文件类型 (e.g. MH_EXECUTE)
ncmds:Load Commands条数
sizeofcmds:Load Commands大小
flags:标志位。标识二进制文件支持的功能,主要和系统加载、链接有关
reserved:预留区(只有64位才有)

Load Commands

包含区域的位置、符号表、动态符号表等。描述了文件中数据的具体组织结构,不同的数据类型使用不同的加载命令表示。

Data

由 Segment 段和 Section 节组成。存放具体数据:代码、数据、字符串常量、类、方法等。

  1. Segment 组成
#define SEG_PAGEZERO    "__PAGEZERO" /* 当时 MH_EXECUTE 文件时,捕获到空指针 */
#define SEG_TEXT    "__TEXT" /* 代码/只读数据段 */
#define SEG_DATA    "__DATA" /* 数据段 */
#define SEG_OBJC    "__OBJC" /* Objective-C runtime 段 */
#define SEG_LINKEDIT    "__LINKEDIT" /* 包含需要被动态链接器使用的符号和其他表,包括符号表、字符串表等 */
  1. Segment 的数据结构
struct segment_command_64 { 
    uint32_t    cmd;        /* LC_SEGMENT_64 */
    uint32_t    cmdsize;    /* section_64 结构体所需要的空间 */
    char        segname[16];    /* segment 名字,上述宏中的定义 */
    uint64_t    vmaddr;     /* 所描述段的虚拟内存地址 */
    uint64_t    vmsize;     /* 为当前段分配的虚拟内存大小 */
    uint64_t    fileoff;    /* 当前段在文件中的偏移量 */
    uint64_t    filesize;   /* 当前段在文件中占用的字节 */
    vm_prot_t   maxprot;    /* 段所在页所需要的最高内存保护,用八进制表示 */
    vm_prot_t   initprot;   /* 段所在页原始内存保护 */
    uint32_t    nsects;     /* 段中 Section 数量 */
    uint32_t    flags;      /* 标识符 */
};
  1. Section 数据结构
    部分的 Segment (主要指的 __TEXT 和 __DATA)进一步分解为 Section。
struct section_64 { 
    char        sectname[16];   /* Section 名字 */
    char        segname[16];    /* Section 所在的 Segment 名称 */
    uint64_t    addr;       /* Section 所在的内存地址 */
    uint64_t    size;       /* Section 的大小 */
    uint32_t    offset;     /* Section 所在的文件偏移 */
    uint32_t    align;      /* Section 的内存对齐边界 (2 的次幂) */
    uint32_t    reloff;     /* 重定位信息的文件偏移 */
    uint32_t    nreloc;     /* 重定位条目的数目 */
    uint32_t    flags;      /* 标志属性 */
    uint32_t    reserved1;  /* 保留字段1 (for offset or index) */
    uint32_t    reserved2;  /* 保留字段2 (for count or sizeof) */
    uint32_t    reserved3;  /* 保留字段3 */
};

以下列举一些常见的 Section:

__TEXT,__text: 主程序代码
__TEXT,__stubs / __stub_helper: 用于动态链接的桩
__TEXT,__objc_methname: OC方法名称
__TEXT,__objc_classname: OC类名
__TEXT,__objc_methtype: OC方法类型
__TEXT,__cstring: 程序中c语言字符串
__DATA,__got: 非懒加载符号表
__DATA,__la_symbol_ptr: 懒加载符号表
__DATA,__objc_classlist: OC类列表
__DATA,__objc_protollist: OC原型列表
__DATA,__objc_imageinfo: OC镜像信息
__DATA,__objc_const: OC常量
__DATA,__objc_selfrefs: OC类自引用(self)
__DATA,__objc_superrefs: OC类超类引用(super)
__DATA,__objc_protolrefs: OC原型引用
__DATA,__objc_data / __data: OC代码数据
Dynamic Loader Info: 动态链接器所需要使用的信息 (重定向,符号绑定,懒加载绑定等..)
Function Starts: 方法的起始位置
Symbol Table: 符号表
Dynamic Symbol Table: 动态符号表
String Table: 字符串表
Code Signature: 代码签名信息

上一篇下一篇

猜你喜欢

热点阅读