欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[原创]初探Mach-O学习小记(附源码)

[原创]初探Mach-O学习小记(附源码)

近来在学习osx和ios方面的东西,简单熟悉了下oc的语法后打算学习下osx和ios下的文件格式。
--------------------------------------------------------------------------------------------


  • Header部分

结构体定义在mach-o/loader.h头文件中

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;

};


magic
用于判断程序的平台版本,也就是说判断是x86 or x64,在mach-o/loader.h中定义machheader与machheader64 结构的附近会看到两条宏,如果MHMAGIC的值是0xfeedface就说明是一个x86程序反之如果是0xfeedfacf 就是x64程序(以上理论基于osx,ios并未验证)。

#define MH_MAGIC 0xfeedface    /* the mach magic number */

#define MH_CIGAM 0xcefaedfe    /* NXSwapInt(MH_MAGIC) */

#define MH_MAGIC_64 0xfeedfacf /* the 64-bit mach magic number */

#define MH_CIGAM_64 0xcffaedfe /* NXSwapInt(MH_MAGIC_64) */


cputype与cpusubtype
用于判断CPU的平台与版本,在mach/machine.h头文件中可以看到两组宏定义CPUTYPE???和CPUSUBTYPE???,定义着各种各样的型号。
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 */


ncmds与sizeofcmds
ncmds代表Load Command的个数,sizeofcmds代表ncmds段Load Command的总字节数。
flags与reserved
flags表示dyld加载标志位,它的标识宏在mach-o/loader.h中格式为MH_???,reserved是x64的保留位,目前看了下基本是恒为0x00000000。

  • Load Command

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

struct load_command {

    uint32_t cmd;

    uint32_t cmdsize;

};


cmd与cmdsize
cmd该位的值表示其类型,这点最开始本以为只是标记,对照hex查看时发现结构对不上,在头文件中好好的看了下才发现自己认知错误。mach-o/loader.h中定义loadcommand结构体的下方有着一组宏(LC???)与注解,不同类型对应不同的的结构。cmdsize该位代表所占字节数。

segment_command          LC_SEGMENT

segment_command_64       LC_SEGMENT_64

fvmlib_command           LC_IDFVMLIB or LC_LOADFVMLIB

dylib_command            LC_ID_DYLIB, LC_LOAD_{,WEAK_}DYLIB, LC_REEXPORT_DYLIB`

sub_framework_command    LC_SUB_FRAMEWORK

sub_client_command       LC_SUB_CLIENT`

sub_umbrella_command     LC_SUB_UMBRELLA

sub_library_command      LC_SUB_LIBRARY

prebound_dylib_command   LC_PREBOUND_DYLIB

dylinker_command         LC_ID_DYLINKER, LC_LOAD_DYLINKER orLC_DYLD_ENVIRONMENT

thread_command           LC_THREAD or  LC_UNIXTHREAD

routines_command         LC_ROUTINES

symtab_command           LC_SYMTAB

dysymtab_command         LC_DYSYMTAB

twolevel_hints_command   LC_TWOLEVEL_HINTS

prebind_cksum_command    LC_PREBIND_CKSUM

uuid_command             LC_UUID

rpath_command            LC_RPATH

linkedit_data_command    LC_CODE_SIGNATURE,LC_SEGMENT_SPLIT_INFO,LC_FUNCTION_STARTS,  LC_DATA_IN_CODE, LC_DYLIB_CODE_SIGN_DRS or LC_LINKER_OPTIMIZATION_HINT.

encryption_info_command  LC_ENCRYPTION_INFO

version_min_command      LC_VERSION_MIN_MACOSX or LC_VERSION_MIN_IPHONEOS LC_VERSION_MIN_WATCHOS

dyld_info_command        LC_DYLD_INFO or LC_DYLD_INFO_ONLY

linker_option_command    LC_LINKER_OPTION

symseg_command           LC_SYMSEG

ident_command            LC_IDENT

fvmfile_command          LC_FVMFILE

entry_point_command      LC_MAIN

source_version_command   LC_SOURCE_VERSION


在写代码对macho进行解析的时候发现,LC_SEGMENT和LC_SEGMENT_64与其他的类型并不一样,结构体内有一个nsects项,该项的值代表这个Segment段存在多少个secetion子段。

  • Data

data段的数量就是Load Command中secetion的总数量,相应的数据与大小就是addr起始的size字节大小的数据。

struct section {

    char sectname[16];

    char segname[16];

    uint32_t addr;

    uint32_t size;

    uint32_t offset;

    uint32_t align;

    uint32_t reloff;

    uint32_t nreloc;

    uint32_t flags;

    uint32_t reserved1;

    uint32_t reserved2;

};

struct section_64 {

    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;

};


初学osx/ios如发现文章中有错误,请指出望不吝赐教。
这是一个简单的解析macho的控制台demo,代码很少。献给和我一样刚刚转向学习osx/ios的朋友。
StudyMachO.zip

上传的附件 StudyMachO.zip

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功