/* * 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) */
#define MH_INCRLINK 0x2/* the object file is the output of an incremental link against a base file and can't be link edited again */ #define MH_DYLDLINK 0x4/* the object file is input for the dynamic linker and can't be staticly link edited again */ #define MH_BINDATLOAD 0x8/* the object file's undefined references are bound by the dynamic linker when loaded. */ #define MH_PREBOUND 0x10/* the file has its dynamic undefined references prebound. */ #define MH_SPLIT_SEGS 0x20/* the file has its read-only and read-write segments split */ #define MH_LAZY_INIT 0x40/* the shared library init routine is to be run lazily via catching memory faults to its writeable segments (obsolete) */ #define MH_TWOLEVEL 0x80/* the image is using two-level name space bindings */ ... //太长,有兴趣可以自己看源码 // EXTERNAL_HEADERS/mach-o/x86_64/loader.h
同样简单的介绍几个比较重要的。
Flag Type
含义
MH_NOUNDEFS
目标没有未定义的符号,不存在链接依赖
MH_DYLDLINK
该目标文件是dyld的输入文件,无法被再次的静态链接
MH_PIE
允许随机的地址空间
MH_ALLOW_STACK_EXECUTION
栈内存可执行代码,一般是默认关闭的。
MH_NO_HEAP_EXECUTION
堆内存无法执行代码
2.4 Headers小结
0x03 Load Commands
这是load_command的数据结构
1 2 3 4
struct load_command { uint32_t cmd; /* type of load command */ uint32_t cmdsize; /* total size of command in bytes */ };
/* * Loop through each of the load_commands indicated by the * Mach-O header; if an absurd value is provided, we just * run off the end of the reserved section by incrementing * the offset too far, so we are implicitly fail-safe. */ offset = mach_header_sz; ncmds = header->ncmds;
while (ncmds--) { /* * Get a pointer to the command. */ lcp = (struct load_command *)(addr + offset); //lcp设为当前要解析的cmd的地址 oldoffset = offset; //oldoffset是从macho文件内存开始的地方偏移到当前command的偏移量 offset += lcp->cmdsize; //重新计算offset,再加上当前command的长度,offset的值为文件内存起始地址到下一个command的偏移量 /* * Perform prevalidation of the struct load_command * before we attempt to use its contents. Invalid * values are ones which result in an overflow, or * which can not possibly be valid commands, or which * straddle or exist past the reserved section at the * start of the image. */ if (oldoffset > offset || lcp->cmdsize < sizeof(struct load_command) || offset > header->sizeofcmds + mach_header_sz) { ret = LOAD_BADMACHO; break; } //做了一个检测,与如何加载进入内存无关
/* * Act on struct load_command's for which kernel * intervention is required. */ switch(lcp->cmd) { case LC_SEGMENT: [...] ret = load_segment(lcp, header->filetype, control, file_offset, macho_size, vp, map, slide, result); break; case LC_SEGMENT_64: [...] ret = load_segment(lcp, header->filetype, control, file_offset, macho_size, vp, map, slide, result); break; case LC_UNIXTHREAD: if (pass != 1) break; ret = load_unixthread( (struct thread_command *) lcp, thread, slide, result); break; case LC_MAIN: if (pass != 1) break; if (depth != 1) break; ret = load_main( (struct entry_point_command *) lcp, thread, slide, result); break; case LC_LOAD_DYLINKER: if (pass != 3) break; if ((depth == 1) && (dlp == 0)) { dlp = (struct dylinker_command *)lcp; dlarchbits = (header->cputype & CPU_ARCH_MASK); } else { ret = LOAD_FAILURE; } break; case LC_UUID: if (pass == 1 && depth == 1) { ret = load_uuid((struct uuid_command *) lcp, (char *)addr + mach_header_sz + header->sizeofcmds, result); } break; case LC_CODE_SIGNATURE: [...] ret = load_code_signature( (struct linkedit_data_command *) lcp, vp, file_offset, macho_size, header->cputype, result); [...] break; #if CONFIG_CODE_DECRYPTION case LC_ENCRYPTION_INFO: case LC_ENCRYPTION_INFO_64: if (pass != 3) break; ret = set_code_unprotect( (struct encryption_info_command *) lcp, addr, map, slide, vp, file_offset, header->cputype, header->cpusubtype); if (ret != LOAD_SUCCESS) { printf("proc %d: set_code_unprotect() error %d " "for file \"%s\"\n", p->p_pid, ret, vp->v_name); /* * Don't let the app run if it's * encrypted but we failed to set up the * decrypter. If the keys are missing it will * return LOAD_DECRYPTFAIL. */ if (ret == LOAD_DECRYPTFAIL) { /* failed to load due to missing FP keys */ proc_lock(p); p->p_lflag |= P_LTERM_DECRYPTFAIL; proc_unlock(p); } psignal(p, SIGKILL); } break; #endif default: /* Other commands are ignored by the kernel */ ret = LOAD_SUCCESS; break; } if (ret != LOAD_SUCCESS) break; } if (ret != LOAD_SUCCESS) break; }