iOS 逆向

Mach-O 介绍

2019-01-10  本文已影响0人  绿叶竹林

一、Mach-O 相关概念简介

1.概念描述

Mach-O 为 Mach Object 文件格式的缩写,它是一种用于可执行文件、目标代码、动态库、内核转储的文件格式。作为 a.out 格式的替代,Mach-O 提供了更强的扩展性,并提升了 符号表 中信息的访问速度。

通用二进制
通用二进制代码有两种基本类型:

多重架构二进制(胖二进制)
在 NeXTSTEP ,OPENSTEP 和 Mac OS X 中,可以将多个Mach-O文件组合进一个多重架构二进制(胖二进制)文件中,以用一个单独的二进制文件支持多种架构的指令集。例如,一个Mac OS X中的多重架构二进制可以包含32位和64位的PowerPC代码,或PowerPC和x86的32位代码,甚至包含32位的PowerPC代码,64位PowerPC代码,32位x86代码和64位x86代码。

2.对 Mach-O 文件进行操作

lipo <Mach-O> -thin <架构名> -output <输出文件路径>
lipo -create <Mach-O1> <Mach-O2> -output <输出文件路径>

二、查看可执行文件

1.使用 otool 命令查看 Mach-O 文件

otool -L WeChat
otool -h WeChat
otool -l WeChat | grep crypt
查看是否加密.png
cryptid 为 0 时表示无加密,即已砸壳;
cryptid 为 1 时表示有加密,即未砸壳。
otool -h DingTalk

2.使用 MachOView 软件查看

用 MachOView 打开可执行文件可以看到有胖二进制文件的结构如下图:


胖二进制.png

可以看到可执行文件包括三个部分:

三、Mach-O 文件结构

Mach-O.png
Mach-O主要分为三个部分:HeaderLoad commandsData

1. Header

头文件就是该可执行文件的信息概要

头部.png
该部分结构可以 打开 <macho-o/loader.h> 查看
/*
 * 64位结构头
 */
struct mach_header_64 {
    uint32_t    magic;      // Mach-O 文件的
    cpu_type_t  cputype;    // CPU 架构
    cpu_subtype_t   cpusubtype; // CPU 架构子版本
    uint32_t    filetype;   // 文件类型。常见的有 MH_OBJECT(目标文件)、MH_EXECUTE(可执行文件)、MH_DYLIB(动态库)、MH_DYLINKER(动态链接器)
    uint32_t    ncmds;      // 加载指令数量
    uint32_t    sizeofcmds; // 加载指令大小
    uint32_t    flags;      // dyld 加载需要的一些标记
    uint32_t    reserved;   // 64 位的保留字段
};

2. Load commands

Load commands 作用是让系统知道如何加载文件中的信息,对系统内核加载器和动态链接器起引导作用。

部分加载指令.png

从上图可以看到,Load command 包含以下部分:

3. Data

LC_SEGMENT_64 加载指令映射的就是 Data 中的数据偏移和大小,该文件组要包含四个段:

下面是 64 位 segment 段的数据结构

struct segment_command_64 { /* for 64-bit architectures */
    uint32_t    cmd;        // 指令类型
    uint32_t    cmdsize;    // 指令大小
    char        segname[16];// 段的名字
    uint64_t    vmaddr;     // 映射到虚拟地址的偏移
    uint64_t    vmsize;     // 映射到虚拟地址的大小
    uint64_t    fileoff;    // 对应当前架构文件的偏移
    uint64_t    filesize;   // 文件的大小
    vm_prot_t   maxprot;    // 段页面的最高内存保护
    vm_prot_t   initprot;   // 初始内存保护
    uint32_t    nsects;     // 包含的节的个数
    uint32_t    flags;      // 段页面的标志
};

段中包含的节的数据结构

struct section_64 { /* for 64-bit architectures */
    char        sectname[16];   // 节的名字
    char        segname[16];    // 所属段的名字
    uint64_t    addr;       // 映射到虚拟地址的偏移
    uint64_t    size;       // 节的大小
    uint32_t    offset;     // 节在当前架构文件中的偏移
    uint32_t    align;      // 节的字节对齐大小
    uint32_t    reloff;     // 重定位入口的文件偏移
    uint32_t    nreloc;     // 重定位入口的个性
    uint32_t    flags;      // 节的类型和属性
    uint32_t    reserved1;  // 保留位
    uint32_t    reserved2;  // 保留位
    uint32_t    reserved3;  // 保留位
};

__Text 段中包含的节

__Data 段中包含的节

上一篇下一篇

猜你喜欢

热点阅读