Mach-o 分析
组成
Mach-O通常有三部分组成
头部 (Header): Mach-O文件的架构 比如Mac的 PPC, PPC64, IA-32, x86-64,ios的arm系列.
加载命令(Load commands): .
原始段数据(Raw segment data)*:可以拥有多个段(segment),每个段可以拥有零个或多个区域(section)。每一个段(segment)都拥有一段虚拟地址映射到进程的地址空间。
官方给的图如下:
mach-o
准备工作
我们创建一个工程,mach-o
#include <stdio.h>
int main(int argc, const char * argv[]) {
printf("Hello, World!\n");
return 0;
}
打开终端cd 到该工程的main所在目录执行下列命令gcc main.m -g -o test.out 会生成 test.out 文件。我们就分析这个文件
Mach-O 分析
通常一个iOS App应用会安装在/var/mobile/Applications,系统的原生App会安装在/Applications目录下,大部分情况下,xxx.app/xxx文件并不是Mach-O格式文件,由于现在需要支持不同CPU架构的iOS设备,所以我们编译打包出来的执行文件是一个Universal Binary格式文件(通用二进制文件,也称胖二进制文件),实际上Universal Binary只不过将支持不同架构的Mach-O打包在一起,再在文件起始位置加上Fat Header来说明所包含的Mach-O文件支持的架构和偏移地址信息。
Universal Binary
我们可以通过otool 工具查看头
otool - f test (上面的test.out 通过该命令是没有输出结果的,因为是no fat文件,这里的test必须是 多个结构体在一起的才可以)
Fat headers
fat_magic 0xcafebabe
nfat_arch 2
architecture 0
cputype 12
cpusubtype 9
capabilities 0x0
offset 16384
size 37933760
align 2^14 (16384)
architecture 1
cputype 16777228
cpusubtype 0
capabilities 0x0
offset 37961728
size 43561328
align 2^14 (16384)
胖二进制文件定义在 /usr/include/mach-o/fat.h,
#define FAT_MAGIC 0xcafebabe
#define FAT_CIGAM 0xbebafeca /* NXSwapLong(FAT_MAGIC) */
struct fat_header {
uint32_t magic; /* FAT_MAGIC or FAT_MAGIC_64 */
uint32_t nfat_arch; /* number of structs that follow */
};
struct fat_arch {
cpu_type_t cputype; /* cpu specifier (int) */
cpu_subtype_t cpusubtype; /* machine specifier (int) */
uint32_t offset; /* file offset to this object file */
uint32_t size; /* size of this object file */
uint32_t align; /* alignment as a power of 2 */
};
/*
* The support for the 64-bit fat file format described here is a work in
* progress and not yet fully supported in all the Apple Developer Tools.
*
* When a slice is greater than 4mb or an offset to a slice is greater than 4mb
* then the 64-bit fat file format is used.
*/
#define FAT_MAGIC_64 0xcafebabf
#define FAT_CIGAM_64 0xbfbafeca /* NXSwapLong(FAT_MAGIC_64) */
struct fat_arch_64 {
cpu_type_t cputype; /* cpu specifier (int) */
cpu_subtype_t cpusubtype; /* machine specifier (int) */
uint64_t offset; /* file offset to this object file */
uint64_t size; /* size of this object file */
uint32_t align; /* alignment as a power of 2 */
uint32_t reserved; /* reserved */
};
-
magic字段就是我们常说的魔数(就是文件结构),加载器通过这个魔数值来判断这是什么样的文件。在32 位和64 位 上magic 不一样。
32 位是0xcafebabe ,64位是0xcafebabf -
nfat_arch字段是指当前的胖二进制文件包含了多少个不同架构的Mach-O文件;
fat_header后会跟着fat_arch,有多少个不同架构的Mach-O文件,就有多少个fat_arch,用于说明对应Mach-O文件大小、支持的CPU架构、偏移地址等;
mach-o header
mach-o 的头定义在在 /usr/include/mach-o/loader.h,
/*
* The 32-bit mach header appears at the very beginning of the object file for
* 32-bit architectures.
*/
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 */
};
/* Constant for the magic field of the mach_header (32-bit architectures) */
#define MH_MAGIC 0xfeedface /* the mach magic number */
#define MH_CIGAM 0xcefaedfe /* NXSwapInt(MH_MAGIC) */
/*
* The 64-bit mach header appears at the very beginning of object files for
* 64-bit architectures.
*/
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 */
};
/* Constant for the magic field of the mach_header_64 (64-bit architectures) */
#define MH_MAGIC_64 0xfeedfacf /* the 64-bit mach magic number */
#define MH_CIGAM_64 0xcffaedfe /* NXSwapInt(MH_MAGIC_64) */
我们可以通过otool -h test.out查看 mach-o header信息
magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
0xfeedfacf 16777223 3 0x80 2 15 1280 0x00200085
分析头信息
1.magic,可以看到文件中的内容最开始部分,是以 cafe babe开头的对于一个 二进制文件 来讲,每个类型都可以在文件最初几个字节来标识出来,即“魔数”。不同类型的 二进制文件,都有自己独特的"魔数"。OS X上,可执行文件的标识有这样几个魔数(不同的魔数代表不同的可执行文件类型)是mach-o文件的魔数,0xfeedface代表的是32位,0xfeedfacf代表64位,cafebabe是跨处理器架构的通用格式。
2.cputype和cupsubtype代表的是cpu的类型和其子类型。
3.接着是filetype,2,代表可执行的文件
* Constants for the filetype field of the mach_header
*/
#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 */
4.ncmds 指的是加载命令(load commands)的数量,例子中一共15个,编号0-14
5.sizeofcmds 表示load commands 的bytes, load commands区域是紧接着header区域的。
6.最后个flags,例子中是0x00218085,可以按文档分析之。
这个就是标志位。
#define MH_PIE 0x200000 /* When this bit is set, the OS will load the main executable at a random address. Only used in MH_EXECUTE filetypes. */
#define MH_BINDS_TO_WEAK 0x10000 /* the final linked image uses weak symbols */
#define MH_WEAK_DEFINES 0x8000 /* the final linked image contains external weak symbols */
#define MH_TWOLEVEL 0x80 /* the image is using two-level name space bindings */
#define MH_DYLDLINK 0x4 /* the object file is input for the dynamic linker and can't be staticly link edited again */
#define MH_NOUNDEFS 0x1 /* the object file has no undefined references */
这里我们可以借助也UE程序MachOView,MachOView是Mac上查看Mach-O结构的工具查看结构
image.pngLoad commands
load commmand直接跟在 header 部分的后面,结构定义在文件/usr/include/mach-o/loader.h中。
结构定义如下
/*
* The load commands directly follow the mach_header. The total size of all
* of the commands is given by the sizeofcmds field in the mach_header. All
* load commands must have as their first two fields cmd and cmdsize. The cmd
* field is filled in with a constant for that command type. Each command type
* has a structure specifically for it. The cmdsize field is the size in bytes
* of the particular load command structure plus anything that follows it that
* is a part of the load command (i.e. section structures, strings, etc.). To
* advance to the next load command the cmdsize can be added to the offset or
* pointer of the current load command. The cmdsize for 32-bit architectures
* MUST be a multiple of 4 bytes and for 64-bit architectures MUST be a multiple
* of 8 bytes (these are forever the maximum alignment of any load commands).
* The padded bytes must be zero. All tables in the object file must also
* follow these rules so the file can be memory mapped. Otherwise the pointers
* to these tables will not work well or at all on some machines. With all
* padding zeroed like objects will compare byte for byte.
*/
struct load_command {
uint32_t cmd; /* type of load command */
uint32_t cmdsize; /* total size of command in bytes */
};
这里的注释很清楚
1.load commands 在mach_header 后面。
2.sizeofcmds 指定了load commands 的大小
3.每个command 有cmd 和cmdsize 组成。
4.cmd 代表类型。每种类型都有常量标示
5.cmdsize 是大小
6.cmdSize 32位必须是4字节的倍数。 64位就是b字节的倍数
这些加载命令在Mach-O文件加载解析时,被内核加载器或者动态链接器调用,指导如何设置加载对应的二进制数据段。
cmd 类型很多都在 /usr/include/mach-o/loader.h中可以自己查看。
具体可以通过下面命令查看(test文件名)
otool -v -l test.out | open -f
段数据(Segments)
Segments包含了很多segment,每一个segment定义了一些Mach-O文件的数据、地址和内存保护属性,这些数据在动态链接器加载程序时被映射到了虚拟内存中。每个段都有不同的功能。
一般包含下列功能
- 1). __PAGEZERO: 空指针陷阱段,映射到虚拟内存空间的第一页,用于捕捉对NULL指针的引用;
- 2). __TEXT: 包含了执行代码以及其他只读数据。 为了让内核将它 直接从可执行文件映射到共享内存, 静态连接器设置该段的虚拟内存权限为不允许写。当这个段被映射到内存后,可以被所有进程共享。(这主要用在frameworks, bundles和共享库等程序中,也可以为同一个可执行文件的多个进程拷贝使用)
- 3). __DATA: 包含了程序数据,该段可写;
- 4). __LINKEDIT: 含有为动态链接库使用的原始数据,比如符号,字符串,重定位表条目等等。
一般的段又会按不同的功能划分为几个区(section),即段所有字母大小,加两个下横线作为前缀,而区则为小写,同样加两个下横线作为前缀
下面列出段中可能包含的section:
__TEXT段:
__text, __cstring, __picsymbol_stub, __symbol_stub, __const, __litera14, __litera18;
__DATA段:
__data, __la_symbol_ptr, __nl_symbol_ptr, __dyld, __const, __mod_init_func, __mod_term_func, __bss, __commom;
__IMPORT段
__jump_table, __pointers;
其中__TEXT段中的__text是实际上的代码部分;__DATA段的__data是实际的初始数据
可以通过otool –s查看某segment的某个section。(test是文件名)
otool -s __TEXT __text test.out
或者
otool -t test.out
想查看汇编
otool -t -v test.out
segment_command
接下来我们看 数据段 segment_command
/*
* The segment load command indicates that a part of this file is to be
* mapped into the task's address space. The size of this segment in memory,
* vmsize, maybe equal to or larger than the amount to map from this file,
* filesize. The file is mapped starting at fileoff to the beginning of
* the segment in memory, vmaddr. The rest of the memory of the segment,
* if any, is allocated zero fill on demand. The segment's maximum virtual
* memory protection and initial virtual memory protection are specified
* by the maxprot and initprot fields. If the segment has sections then the
* section structures directly follow the segment command and their size is
* reflected in cmdsize.
*/
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 */
};
/*
* The 64-bit segment load command indicates that a part of this file is to be
* mapped into a 64-bit task's address space. If the 64-bit segment has
* sections then section_64 structures directly follow the 64-bit segment
* command and their size is reflected in cmdsize.
*/
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 */
};
这里我们看看结构体的每个成员变量代表什么
1.cmd 32位是个常量 LC_SEGMENT 64 常量LC_SEGMENT_64
2.cmdsize 该区域大小
3.segname[16] 名字
4.vmaddr segment 的内存地址。
5.vmsize segment的内存大小
6.fileoff 文件偏移量
- filesize 在文件中的大小
8.maxprot 页面所需要的最高内存保护(4=r,2=w,1=x)
9.initprot 页面初始的内存保护
10.nsects sections的多少
11.flags 指示器。标记该segment 如何操作
#define SG_HIGHVM 0x1 /* the file contents for this segment is forthe high part of the VM space, the low part is zero filled (for stacks in core files) */ 不足的部分用0 充满
#define SG_FVMLIB 0x2 /* this segment is the VM that is allocated by a fixed VM library, for overlap checking in the link editor */ 这部分重新连接vm library
#define SG_NORELOC 0x4 /* this segment has nothing that was relocated in it and nothing relocated to it, that is it maybe safely replaced without relocation*/
#define SG_PROTECTED_VERSION_1 0x8 /* This segment is protected. If the=segment starts at file offset 0, the
first page of the segment is not
protected. All other pages of the
segment are protected. */
下面是section 部分
/*
* A segment is made up of zero or more sections. Non-MH_OBJECT files have
* all of their segments with the proper sections in each, and padded to the
* specified segment alignment when produced by the link editor. The first
* segment of a MH_EXECUTE and MH_FVMLIB format file contains the mach_header
* and load commands of the object file before its first section. The zero
* fill sections are always last in their segment (in all formats). This
* allows the zeroed segment padding to be mapped into memory where zero fill
* sections might be. The gigabyte zero fill sections, those with the section
* type S_GB_ZEROFILL, can only be in a segment with sections of this type.
* These segments are then placed after all other segments.
*
* The MH_OBJECT format has all of its sections in one segment for
* compactness. There is no padding to a specified segment boundary and the
* mach_header and load commands are not part of the segment.
*
* Sections with the same section name, sectname, going into the same segment,
* segname, are combined by the link editor. The resulting section is aligned
* to the maximum alignment of the combined sections and is the new section's
* alignment. The combined sections are aligned to their original alignment in
* the combined section. Any padded bytes to get the specified alignment are
* zeroed.
*
* The format of the relocation entries referenced by the reloff and nreloc
* fields of the section structure for mach object files is described in the
* header file <reloc.h>.
*/
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.sectname 第一个是__text ,就是主程序代码
2.segname 该section所属的 segment名,第一个是__TEXT
3.addr 该section在内存的启始位置
4.size 该section的大小
5.offset 该section的文件偏移
6.align 字节大小对齐 ,
- reloff 重定位入口的文件偏移,
8.nreloc 需要重定位的入口数量,
9.flags 包含section的type和attributes
这里还有点东西需要看看
/* The currently known segment names and the section names in those segments */
#define SEG_PAGEZERO "__PAGEZERO" /* the pagezero segment which has no */
/* protections and catches NULL */
/* references for MH_EXECUTE files */
#define SEG_TEXT "__TEXT" /* the tradition UNIX text segment */
#define SECT_TEXT "__text" /* the real text part of the text */
/* section no headers, and no padding */
#define SECT_FVMLIB_INIT0 "__fvmlib_init0" /* the fvmlib initialization */
/* section */
#define SECT_FVMLIB_INIT1 "__fvmlib_init1" /* the section following the */
/* fvmlib initialization */
/* section */
#define SEG_DATA "__DATA" /* the tradition UNIX data segment */
#define SECT_DATA "__data" /* the real initialized data section */
/* no padding, no bss overlap */
#define SECT_BSS "__bss" /* the real uninitialized data section*/
/* no padding */
#define SECT_COMMON "__common" /* the section common symbols are */
/* allocated in by the link editor */
#define SEG_OBJC "__OBJC" /* objective-C runtime segment */
#define SECT_OBJC_SYMBOLS "__symbol_table" /* symbol table */
#define SECT_OBJC_MODULES "__module_info" /* module information */
#define SECT_OBJC_STRINGS "__selector_strs" /* string table */
#define SECT_OBJC_REFS "__selector_refs" /* string table */
#define SEG_ICON "__ICON" /* the icon segment */
#define SECT_ICON_HEADER "__header" /* the icon headers */
#define SECT_ICON_TIFF "__tiff" /* the icons in tiff format */
#define SEG_LINKEDIT "__LINKEDIT" /* the segment containing all structs */
/* created and maintained by the link */
/* editor. Created with -seglinkedit */
/* option to ld(1) for MH_EXECUTE and */
/* FVMLIB file types only */
#define SEG_UNIXSTACK "__UNIXSTACK" /* the unix stack segment */
#define SEG_IMPORT "__IMPORT" /* the segment for the self (dyld) */
/* modifing code stubs that has read, */
/* write and execute permissions */
看到这里据我估计读者也很懵,其实我也很懵现在。现在需要把上面零散的至少汇总起来了。
汇总
这里我写的demo名字叫mach-o-parse。只解析出来了部分功能。不过这让我彻底搞懂了这个mach-o 的结构
源代码
#import "ViewController.h"
@interface ViewController ()
@end
typedef struct mach_new_header {
uint32_t magic; /* mach magic number identifier */
uint32_t cputype; /* cpu specifier */
uint16_t cpusubtype; /* machine specifier */
uint8_t zhanwei;
uint8_t caps;
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;
} Mach_O_Header;
void printHeader(Mach_O_Header header){
NSLog(@"header magic 0x%0x",header.magic);
NSLog(@"header cputype %d",header.cputype);
NSLog(@"header cpusubtype %d",header.cpusubtype);
NSLog(@"header caps 0x%x",header.caps);
NSLog(@"header filetype %d",header.filetype);
NSLog(@"header ncmds %d",header.ncmds);
NSLog(@"header sizeofcmds %d",header.sizeofcmds);
NSLog(@"header flags 0x%0x",header.flags);
}
typedef struct {
uint32_t cmd; /* type of load command */
uint32_t cmdsize; /* total size of command in bytes */
}Mach_O_load_command;
void printLoadCommand(Mach_O_load_command loadCommand){
NSLog(@"loadCommand cmd 0x%0x",loadCommand.cmd);
NSLog(@"loadCommand cmdsize %0d",loadCommand.cmdsize);
}
typedef struct { /* for 64-bit architectures */
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 */
uint32_t maxprot; /* maximum VM protection */
uint32_t initprot; /* initial VM protection */
uint32_t nsects; /* number of sections in segment */
uint32_t flags; /* flags */
}Mach_O_segment_command;
void printSegment_command(Mach_O_segment_command segmentCommand){
NSLog(@"segmentCommand segname %s",segmentCommand.segname);
NSLog(@"segmentCommand vmaddr 0x%llx",segmentCommand.vmaddr);
NSLog(@"segmentCommand vmsize %llu",segmentCommand.vmsize);
NSLog(@"segmentCommand fileoff 0x%llx",segmentCommand.fileoff);
NSLog(@"segmentCommand filesize %llu",segmentCommand.filesize);
NSLog(@"segmentCommand maxprot 0x%x",segmentCommand.maxprot);
NSLog(@"segmentCommand initprot 0x%x",segmentCommand.initprot);
NSLog(@"segmentCommand nsects %d",segmentCommand.nsects);
NSLog(@"segmentCommand flags 0x%x",segmentCommand.flags);
}
typedef struct { /* 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 */
}Mach_O_section;
void printSection_command(Mach_O_section sectionCommand){
NSLog(@"sectionCommand secname %s",sectionCommand.sectname);
NSLog(@"sectionCommand segname %s",sectionCommand.segname);
NSLog(@"sectionCommand addr 0x%llx",sectionCommand.addr);
NSLog(@"sectionCommand size %llu",sectionCommand.size);
NSLog(@"sectionCommand offset %d",sectionCommand.offset);
NSLog(@"sectionCommand align %d",sectionCommand.align);
NSLog(@"sectionCommand reloff %d",sectionCommand.reloff);
NSLog(@"sectionCommand nreloc %d",sectionCommand.nreloc);
NSLog(@"sectionCommand flags %d",sectionCommand.flags);
}
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSData *mach = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"test" ofType:@"out"]];
static int location =0;
Mach_O_Header header ;
[mach getBytes:&header range:NSMakeRange(0, sizeof(Mach_O_Header))];
location =sizeof(Mach_O_Header);
printHeader(header);
for (int i=0; i<header.ncmds; i++) {
Mach_O_load_command loadCommand;
Mach_O_segment_command segment;
[mach getBytes:&loadCommand range:NSMakeRange(location, sizeof(Mach_O_load_command))];
location+=sizeof(Mach_O_load_command);
printLoadCommand(loadCommand);
NSUInteger length = loadCommand.cmdsize;
///减去loadCommand 的长度
length-=8;
///获取Mach_O_segment_command 的数据
[mach getBytes:&segment range:NSMakeRange(location, sizeof(Mach_O_segment_command))];
location+=sizeof(Mach_O_segment_command);
printSegment_command(segment);
length-=sizeof(Mach_O_segment_command);
if (length>0) {
Mach_O_section section ;
[mach getBytes:§ion range:NSMakeRange(location, sizeof(Mach_O_section))];
location+=sizeof(Mach_O_section);
printSection_command(section);
length-=sizeof(Mach_O_section);
}
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
测试结果截取了一部分
2018-04-19 17:43:34.811420+0800 Mach-o-parse[58332:11931902] 64 8 8696
2018-04-19 17:43:34.811548+0800 Mach-o-parse[58332:11931902] header magic 0xfeedfacf
2018-04-19 17:43:34.811656+0800 Mach-o-parse[58332:11931902] header cputype 16777223
2018-04-19 17:43:34.811752+0800 Mach-o-parse[58332:11931902] header cpusubtype 3
2018-04-19 17:43:34.811886+0800 Mach-o-parse[58332:11931902] header caps 0x80
2018-04-19 17:43:34.811982+0800 Mach-o-parse[58332:11931902] header filetype 2
2018-04-19 17:43:34.812071+0800 Mach-o-parse[58332:11931902] header ncmds 15
2018-04-19 17:43:34.812128+0800 Mach-o-parse[58332:11931902] header sizeofcmds 1280
2018-04-19 17:43:34.812171+0800 Mach-o-parse[58332:11931902] header flags 0x200085
2018-04-19 17:43:34.812228+0800 Mach-o-parse[58332:11931902] loadCommand cmd 0x19
2018-04-19 17:43:34.812310+0800 Mach-o-parse[58332:11931902] loadCommand cmdsize 72
2018-04-19 17:43:44.179138+0800 Mach-o-parse[58332:11931902] segmentCommand segname __PAGEZERO
2018-04-19 17:43:44.179337+0800 Mach-o-parse[58332:11931902] segmentCommand vmaddr 0x0
2018-04-19 17:43:44.179672+0800 Mach-o-parse[58332:11931902] segmentCommand vmsize 4294967296
2018-04-19 17:43:44.180009+0800 Mach-o-parse[58332:11931902] segmentCommand fileoff 0x0
2018-04-19 17:43:44.180212+0800 Mach-o-parse[58332:11931902] segmentCommand filesize 0
2018-04-19 17:43:44.180323+0800 Mach-o-parse[58332:11931902] segmentCommand maxprot 0x0
2018-04-19 17:43:44.180489+0800 Mach-o-parse[58332:11931902] segmentCommand initprot 0x0
2018-04-19 17:43:44.180610+0800 Mach-o-parse[58332:11931902] segmentCommand nsects 0
2018-04-19 17:43:44.180709+0800 Mach-o-parse[58332:11931902] segmentCommand flags 0x0
2018-04-19 17:43:44.180803+0800 Mach-o-parse[58332:11931902] loadCommand cmd 0x19
2018-04-19 17:43:44.181155+0800 Mach-o-parse[58332:11931902] loadCommand cmdsize 472
2018-04-19 17:43:44.181445+0800 Mach-o-parse[58332:11931902] segmentCommand segname __TEXT
2018-04-19 17:43:44.181628+0800 Mach-o-parse[58332:11931902] segmentCommand vmaddr 0x100000000
2018-04-19 17:43:44.181898+0800 Mach-o-parse[58332:11931902] segmentCommand vmsize 4096
2018-04-19 17:43:44.182053+0800 Mach-o-parse[58332:11931902] segmentCommand fileoff 0x0
2018-04-19 17:43:44.182541+0800 Mach-o-parse[58332:11931902] segmentCommand filesize 4096
2018-04-19 17:43:44.183243+0800 Mach-o-parse[58332:11931902] segmentCommand maxprot 0x7
2018-04-19 17:43:44.183394+0800 Mach-o-parse[58332:11931902] segmentCommand initprot 0x5
2018-04-19 17:43:44.184954+0800 Mach-o-parse[58332:11931902] segmentCommand nsects 5
2018-04-19 17:43:44.185290+0800 Mach-o-parse[58332:11931902] segmentCommand flags 0x0
2018-04-19 17:43:44.185609+0800 Mach-o-parse[58332:11931902] sectionCommand secname __text
2018-04-19 17:43:44.185923+0800 Mach-o-parse[58332:11931902] sectionCommand segname __TEXT
2018-04-19 17:43:44.187436+0800 Mach-o-parse[58332:11931902] sectionCommand addr 0x100000f50
2018-04-19 17:43:44.187659+0800 Mach-o-parse[58332:11931902] sectionCommand size 52
2018-04-19 17:43:44.187749+0800 Mach-o-parse[58332:11931902] sectionCommand offset 3920
2018-04-19 17:43:44.187854+0800 Mach-o-parse[58332:11931902] sectionCommand align 4
2018-04-19 17:43:44.188435+0800 Mach-o-parse[58332:11931902] sectionCommand reloff 0
2018-04-19 17:43:44.207834+0800 Mach-o-parse[58332:11931902] sectionCommand nreloc 0
2018-04-19 17:43:44.208121+0800 Mach-o-parse[58332:11931902] sectionCommand flags -2147482624
2018-04-19 17:43:44.208212+0800 Mach-o-parse[58332:11931902] loadCommand cmd 0x74735f5f
2018-04-19 17:43:44.208903+0800 Mach-o-parse[58332:11931902] loadCommand cmdsize 7561845
2018-04-19 17:43:44.209102+0800 Mach-o-parse[58332:11931902] segmentCommand segname
2018-04-19 17:43:44.209186+0800 Mach-o-parse[58332:11931902] segmentCommand vmaddr 0x0
2018-04-19 17:43:44.209262+0800 Mach-o-parse[58332:11931902] segmentCommand vmsize 4294971268
2018-04-19 17:43:44.209351+0800 Mach-o-parse[58332:11931902] segmentCommand fileoff 0x6
2018-04-19 17:43:44.209532+0800 Mach-o-parse[58332:11931902] segmentCommand filesize 4294971268
2018-04-19 17:43:44.209662+0800 Mach-o-parse[58332:11931902] segmentCommand maxprot 0x0
2018-04-19 17:43:44.210690+0800 Mach-o-parse[58332:11931902] segmentCommand initprot 0x0
2018-04-19 17:43:44.211320+0800 Mach-o-parse[58332:11931902] segmentCommand nsects -2147482616
2018-04-19 17:43:44.214560+0800 Mach-o-parse[58332:11931902] segmentCommand flags 0x0
2018-04-19 17:43:44.214699+0800 Mach-o-parse[58332:11931902] sectionCommand secname \^F
2018-04-19 17:43:44.214795+0800 Mach-o-parse[58332:11931902] sectionCommand segname elper
2018-04-19 17:43:44.214890+0800 Mach-o-parse[58332:11931902] sectionCommand addr 0x0
2018-04-19 17:43:44.214979+0800 Mach-o-parse[58332:11931902] sectionCommand size 4294971276
2018-04-19 17:43:44.215061+0800 Mach-o-parse[58332:11931902] sectionCommand offset 26
2018-04-19 17:43:44.215160+0800 Mach-o-parse[58332:11931902] sectionCommand align 0
2018-04-19 17:43:44.215322+0800 Mach-o-parse[58332:11931902] sectionCommand reloff 3980
2018-04-19 17:43:44.215412+0800 Mach-o-parse[58332:11931902] sectionCommand nreloc 2
2018-04-19 17:43:44.215526+0800 Mach-o-parse[58332:11931902] sectionCommand flags 0
2018-04-19 17:43:44.215612+0800 Mach-o-parse[58332:11931902] loadCommand cmd 0x0
2018-04-19 17:43:44.251678+0800 Mach-o-parse[58332:11931902] loadCommand cmdsize 0
2018-04-19 17:43:44.252740+0800 Mach-o-parse[58332:11931902] segmentCommand segname __cstring
2018-04-19 17:43:44.253046+0800 Mach-o-parse[58332:11931902] segmentCommand vmaddr 0x545845545f5f
2018-04-19 17:43:44.253541+0800 Mach-o-parse[58332:11931902] segmentCommand vmsize 0
2018-04-19 17:43:44.254023+0800 Mach-o-parse[58332:11931902] segmentCommand fileoff 0x100000fa6
2018-04-19 17:43:44.254421+0800 Mach-o-parse[58332:11931902] segmentCommand filesize 15
2018-04-19 17:43:44.254554+0800 Mach-o-parse[58332:11931902] segmentCommand maxprot 0xfa6
2018-04-19 17:43:44.255075+0800 Mach-o-parse[58332:11931902] segmentCommand initprot 0x0
2018-04-19 17:43:44.255257+0800 Mach-o-parse[58332:11931902] segmentCommand nsects 0
2018-04-19 17:43:44.255360+0800 Mach-o-parse[58332:11931902] segmentCommand flags 0x0
2018-04-19 17:43:44.255604+0800 Mach-o-parse[58332:11931902] sectionCommand secname \^B
2018-04-19 17:43:44.255800+0800 Mach-o-parse[58332:11931902] sectionCommand segname __unwind_info
2018-04-19 17:43:44.255909+0800 Mach-o-parse[58332:11931902] sectionCommand addr 0x545845545f5f
2018-04-19 17:43:44.256104+0800 Mach-o-parse[58332:11931902] sectionCommand size 0
2018-04-19 17:43:44.256408+0800 Mach-o-parse[58332:11931902] sectionCommand offset 4024
2018-04-19 17:43:44.256492+0800 Mach-o-parse[58332:11931902] sectionCommand align 1
2018-04-19 17:43:44.256590+0800 Mach-o-parse[58332:11931902] sectionCommand reloff 72
2018-04-19 17:43:44.256680+0800 Mach-o-parse[58332:11931902] sectionCommand nreloc 0
2018-04-19 17:43:44.256771+0800 Mach-o-parse[58332:11931902] sectionCommand flags 4024
....
从测试代码终于看出了mach-o 的结构
mach-o结构从测试代码看不出 loadCommand 与section 是不连续的
我们通过machoView 看出来的
截图如下
图1
图2
我们从图1 看loadCommand 的最后地址是0x00000f1c。
从图2 看section的首地址是0x00000F50。
图3
从图3 中我们发现0x00000F50又出现了。这个地址就是指向的需要连接的section地址。
到此为止,mach-o 的具体结构我们弄懂了。
图4
这里还有个知识点就是maxprot 和initprot 。看图就明白了。
今天终于把mach-o 文件分析完毕了。
注意 segment 有很多种。所有的定义都在 loader.h 文件中。是根据loadCommand 中的cmd 参数变化更改下面的segment 的。