Mach-O文件格式

Mach-O文件結構

Mach-O(Mach Object)是一種基于Mach內核的文件格式。iOS系統(tǒng)生成的可執(zhí)行程序或者動態(tài)庫文件的存儲布局格式被稱之為mach-o格式。Mach-O可以有一個或多個架構。多個架構的稱為FAT文件。Mach-O文件結構包括

  1. Mach-O header 文件的目標基本信息,包含架構例如PPC,PPC64,IA-32或x86-64等信息
  2. Load Command 文件的邏輯結構和文件在虛擬內存中的布局??梢愿鶕?jù)他找到相關的Section 原始數(shù)據(jù)。mach-o文件由諸多的load command組成,,每個load command所代表的是一種數(shù)據(jù)類型。每種load command都是結構體struct load_command的擴展結構體。
  3. Section 節(jié):每個段則由多個節(jié)(Section)組成。節(jié)是內容分類的最小管理單元。每個節(jié)的描述信息是一個稱之為:struct section的結構體。每個節(jié)有一個唯一的名稱用來標識這個節(jié)。
image

ASLR技術

ASLR,全稱是Address Spce Layout Randomization,地址空間布局隨機化,是一種針對緩沖區(qū)溢出的安全保護技術,通過對堆、棧、共享庫映射等線性區(qū)布局的隨機化,增加了攻擊者預測目的地址的難度,防止攻擊者直接定位代碼位置,阻止溢出攻擊。這種技術會使得每個程序或者庫每次運行加載到內存中時的基地址都不是固定而是隨機的,這種機制會增加黑客的破解難度。

iOS中,Mach-O文件 load Commonds 中LC_DYLD_INFO或者LC_DYLD_INFO_ONLY 就是用來記錄所有需要進行地址調整的位置。這樣當程序被加載到內存時,加載器就會將需要調整的地址分別進行調整處理,以便轉化為真實的內存地址。這個過程稱之為基地址重定向(rebase)。

Header

mach-o/loader.h 。使用otool -h -v 命令查看Mach-O文件頭。

$ otool -h -v  TestMachO
Mach header
      magic cputype cpusubtype  caps    filetype ncmds sizeofcmds      flags
MH_MAGIC_64  X86_64        ALL  0x00     EXECUTE    40       5256   NOUNDEFS DYLDLINK TWOLEVEL WEAK_DEFINES BINDS_TO_WEAK PIE

對于FAT文件。Fat文件的header,最前面時FatHeader, 接著是各架構的arch

struct fat_header {
    unsigned long   magic;      /* FAT_MAGIC */
    unsigned long   nfat_arch;  /* number of structs that follow */
};

struct fat_arch {
    cpu_type_t  cputype;    /* cpu specifier (int) */
    cpu_subtype_t   cpusubtype; /* machine specifier (int) */
    unsigned long   offset;     /* file offset to this object file */
    unsigned long   size;       /* size of this object file */
    unsigned long   align;      /* alignment as a power of 2 */
};

單架構的 Mach-O header的定義

struct mach_header_64 {
    uint32_t    magic;      /* mach magic number identifier */
    cpu_type_t  cputype;    /* cup 架構 cpu specifier */
    cpu_subtype_t   cpusubtype; /*  machine specifier */
    // 文件類型常見有的MH_OBJECT(目標文件)、MH_EXECUTABLE(可執(zhí)行二進制文件)、MH_DYLIB (動態(tài)庫)。
    uint32_t    filetype;   /* 文件類型  type of file */
    uint32_t    ncmds;      /* 加載命令數(shù)量 number of load commands */
    uint32_t    sizeofcmds; /* 所有加載命令的大小 the size of all the load commands */
    uint32_t    flags;      /* 位的標記 flags */
    uint32_t    reserved;   /* reserved */
};
mach-o Header.png

Load Command

Load Command告訴操作系統(tǒng)應當如何加載文件中的數(shù)據(jù),對系統(tǒng)內核加載器和動態(tài)鏈接器起指導作用。使用MachOView查看LoadCommand

mach-o load commands.png
常見的Segment
  1. LC_SEGMENT_64: 64 位segment 的映射。64-bit segment of this file to be mapped.

  2. LC_DYLD_INF0_0NLY:記錄了有關鏈接的重要信息,包括在_LINKEDIT中動態(tài)鏈接相關信息的具體偏移和大小。ONLY表示這個加載指令是程序運行所必需的。

  3. LC_SYMTAB:為文件定義符號表和字符串表。在鏈接文件時被鏈接器使用,同時也用于調試器映射符號到源文件。符號表定義的本地符號僅用于調試,而已定義和未定義的 external符號被鏈接器使用。

  4. LC_DYSYMTAB:將符號表中給出符號的額外符號信息提供給動態(tài)鏈接器。

  5. LC_LOAD_DYLINKER:默認的加載器路徑。

  6. LC.UUID:用于標識Mach-0文件的ID,也用于崩潰堆棧和符號文件的對應解析。

  7. LC_VERSION_MIN_IPHONEOS:系統(tǒng)要求的最低版本。

  8. LC.SOURCE.VERSION:構建二進制文件的源代碼版本號。

  9. LC.MAIN:程序的入口。dykl獲取該地址,然后跳轉到該處執(zhí)行。

  10. LC_ENCRYPTION_INFO_64:文件是否加密的標志,加密內容的偏移和大小。

  11. LC_LOADJDYLIB:依賴的動態(tài)庫,包括動態(tài)庫名稱、當前版本號、兼容版本號。可以使用 “otool-Lxxx”命令查看。

$ otool -L TestMachO
SDSAD:
    /System/Library/Frameworks/Foundation.framework/Foundation (compatibility version 300.0.0, current version 1751.108.0)
    /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1292.0.0)
    ...
  1. LC_RPATH: Runpath Search Paths, @rpath
  2. LC_FUNCTION_STARTS:函數(shù)起始地址表,使調試器和其他程序能很容易地看到一個地
    址是否在函數(shù)內。
  3. LC_DATA_IN_CODE:定義在代碼段內的非指令的表。 ? LC_CODE_SIGNATURE:代碼簽名信息。
LC_Segment_64

segment 的結構定義:

struct segment_command_64 { /* for 64-bit architectures */
    uint32_t    cmd;        /* LoadCommand類型 */
    uint32_t    cmdsize;    /* LoadCommand結構的大小  */
    char        segname[16];    /* segment name */
    uint64_t    vmaddr;     /* 對應section的起始地址 。映射到虛擬地址的偏移 */
    uint64_t    vmsize;     /* 映射到虛擬地址的大小 */
    uint64_t    fileoff;    /* 對應于當前架構文件的偏移(注意:是當前架構文件,不是整個FAT文件) */
    uint64_t    filesize;   /* 文件的大小 */
    vm_prot_t   maxprot;    /* 段頁面的最高內存保護 */
    vm_prot_t   initprot;   /* 初始內存保護。 */
    uint32_t    nsects;     /* 包含section 的個數(shù) */
    uint32_t    flags;      /* flags 頁面標志 */
};

系統(tǒng)將fileoff偏移處filesize大小的內容加載到虛擬內存的vmaddr處,大小為vmsize,Segment頁面的權限由initprot進行初始化。它的權限可以動態(tài)改變,但是不能超過maxprot的值,例如 _TEXT初始化和最大權限都是可讀/可執(zhí)行/不可寫。
Segment 的分類

  • _PAGEZERO:空指針陷阱段,映射到虛擬內存空間的第1頁,用于捕捉對 的引用。
  • _TEXT:代碼段/只讀數(shù)據(jù)段。
  • _DATA_CONST:常量數(shù)據(jù)的段
  • _DATA:讀取和寫入數(shù)據(jù)的段。
  • _LINKEDIT:動態(tài)鏈接器需要使用的信息,包括重定位信息、綁定信息、懶加載信息等。

每一個 Segment 對應著0到多個Section 的數(shù)據(jù)。LC_Senment_64 的后面位置則存儲著 Section64 數(shù)據(jù)(找到對應的section 原始數(shù)據(jù)的偏移,大小等)。

Section64

struct section_64 { /* for 64-bit architectures */
    char        sectname[16];   /* name of this section */
    char        segname[16];    /* 對應Segment 的名稱 */
    uint64_t    addr;       /* 映射到虛擬地址的偏移 */
    uint64_t    size;       /* size in bytes of this section */
    uint32_t    offset;     /* file offset of this section */
    uint32_t    align;      /* 字節(jié)對其大小 (power of 2) */
    uint32_t    reloff;     /* file offset of relocation entries */
    uint32_t    nreloc;     /*  重定位入口的個數(shù)。 */
    uint32_t    flags;      /* flags (section type and attributes)*/
    uint32_t    reserved1;  /* 保留位 (for offset or index) */
    uint32_t    reserved2;  /* reserved (for count or sizeof) */
    uint32_t    reserved3;  /* reserved */
};
Segment _TEXT
  • 程序可執(zhí)行的代碼區(qū)域。
  • __stubs:間接符號存根,跳轉到懶加載指針表。
  • __stub_helper:幫助解決懶加載符號加載的輔助函數(shù)。
  • __objc一methname:方法名。
  • __objc_classname:類名。
  • __objc_methtype:方法簽名。
  • __cstring:只讀的C風格字符串,包含0C的部分字符串和屬性名。
Segment _DATA
  • __nl_symboLptr:非懶加載指針表,在dyld加載時會立即綁定值。
  • _la_symbol_ptr:懶加載指針表,第1次調用時才會綁定值。
  • __got:非懶加載全局指針表。
  • __objc_classrefs:被引用的類列表。
  • __mod一 init一 func: constructor函數(shù)
  • __mod_term_func: destructor函數(shù)。
  • __cfstring: 0C字符串。
  • __objc_classlist:程序中類的列表。
  • __objc_nlclslist:程序中自己實現(xiàn)了+load方法的類。
  • __objc_protolist:協(xié)議的列表。
用于分析Mach-O的工具
  • /usr/bin/lipo :可以創(chuàng)建和分析包含用于多個體系結構的映像的二進制文件。這種二進制文件的一個示例是通用二進制文件。通用二進制文件可以在基于PowerPC和基于Intel的Macintosh計算機中使用。另一個示例是PPC / PPC64二進制文件,可以在基于32位PowerPC和基于64位PowerPC的Macintosh計算機中使用。
  • /usr/bin/file:顯示文件的類型。對于多體系結構文件,它顯示構成檔案的每個圖像的類型。
  • /usr/bin/otool:可以列出了Mach-O文件中特定節(jié)和段的內容。它包括每種受支持體系結構的符號反匯編程序,并且知道如何格式化許多常見節(jié)類型的內容。
  • /usr/bin/pagestuff:顯示組成圖像的每個邏輯頁面上的信息,包括各部分的名稱和每個頁面中包含的符號。該工具不適用于包含多個架構的圖像的二進制文件。
  • /usr/bin/nm:可以查看目標文件的符號表的內容。
  • MachoView:可以查看mach-o文件內容
// 通過file命令查看文件信息
$ file TestMachO
SDSAD: Mach-O 64-bit executable x86_64

相關鏈接

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容