mach-o文件头和 cmd 解析

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mach-o文件头和 cmd 解析相关的知识,希望对你有一定的参考价值。

// // main.cpp // mach-o // // Created by Allenboy on 2018/4/16. // Copyright ? 2018年 Allenboy. All rights reserved. // #include <stdio.h> #include <stdlib.h> #include <mach-o/loader.h> #include <mach-o/swap.h> #include <mach-o/fat.h> //解析segments //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 */ //}; void dump_segments(FILE *obj_file); //----------------------------------------------------------------------main------------------------------------------------------------------------------// int main(int argc, char *argv[]) { const char *filename ="/Applications/Notes.app/Contents/MacOS/Notes"; //打开一个 mach-o 文件 FILE *obj_file = fopen(filename, "rb"); //解析 dump_segments(obj_file); //关闭 fclose(obj_file); return 0; } //读文件头magic uint32_t read_magic(FILE *obj_file, int offset) { uint32_t magic; fseek(obj_file, offset, SEEK_SET); fread(&magic, sizeof(uint32_t), 1, obj_file); return magic; } //判断是多少位 int is_magic_64(uint32_t magic) { return magic == MH_MAGIC_64 || magic == MH_CIGAM_64; } //要让 Linux 系统访问虚拟内存,则必须有一个交换分区,当内存(RAM)用完的时候,将硬盘中指定分区(即 Swap 分区)当做内存来使用。因此,当有足够的系统内存(RAM)来满足系统的所有的需求时,我们并不需要划分交换分区。尽管如此,是否使用交换分区取决于管理员。 //判断要用哪各格式去虚拟分区 int should_swap_bytes(uint32_t magic) { return magic == MH_CIGAM || magic == MH_CIGAM_64 || magic == FAT_CIGAM; } //判断是胖二进制(fat)还是普通二进制 int is_fat(uint32_t magic) { return magic == FAT_MAGIC || magic == FAT_CIGAM; } //cpu 类型 struct _cpu_type_names { cpu_type_t cputype; const char *cpu_name; }; static struct _cpu_type_names cpu_type_names[] = { { CPU_TYPE_I386, "i386" }, { CPU_TYPE_X86_64, "x86_64" }, { CPU_TYPE_ARM, "arm" }, { CPU_TYPE_ARM64, "arm64" } }; //找出cpu 类型名称 static const char *cpu_type_name(cpu_type_t cpu_type) { static int cpu_type_names_size = sizeof(cpu_type_names) / sizeof(struct _cpu_type_names); for (int i = 0; i < cpu_type_names_size; i++ ) { if (cpu_type == cpu_type_names[i].cputype) { return cpu_type_names[i].cpu_name; } } return "unknown"; } //根据结构体大小解析的 void *load_bytes(FILE *obj_file, int offset, int size) { //分配 1 块size大小的内存 void *buf = calloc(1, size); fseek(obj_file, offset, SEEK_SET); fread(buf, size, 1, obj_file); return buf; } //解析segment_command void dump_segment_commands(FILE *obj_file, int offset, int is_swap, uint32_t ncmds) { int actual_offset = offset; //解析所有命令 printf("---------------------------------------segment_command_64-----------------------------------\n"); for (int i = 0; i < ncmds; i++) { struct load_command *cmd = load_bytes(obj_file, actual_offset, sizeof(struct load_command)); if (is_swap) { swap_load_command(cmd, 0); } //判断是哪种命令 //#define LC_LOAD_WEAK_DYLIB (0x18 | LC_REQ_DYLD) // //#define LC_SEGMENT_64 0x19 /* 64-bit segment of this file to be //mapped */ //#define LC_ROUTINES_64 0x1a /* 64-bit image routines */ //#define LC_UUID 0x1b /* the uuid */ //#define LC_RPATH (0x1c | LC_REQ_DYLD) /* runpath additions */ //#define LC_CODE_SIGNATURE 0x1d /* local of code signature */ //#define LC_SEGMENT_SPLIT_INFO 0x1e /* local of info to split segments */ //#define LC_REEXPORT_DYLIB (0x1f | LC_REQ_DYLD) /* load and re-export dylib */ //#define LC_LAZY_LOAD_DYLIB 0x20 /* delay load of dylib until first use */ //#define LC_ENCRYPTION_INFO 0x21 /* encrypted segment information */ //#define LC_DYLD_INFO 0x22 /* compressed dyld information */ //#define LC_DYLD_INFO_ONLY (0x22|LC_REQ_DYLD) /* compressed dyld information only */ //#define LC_LOAD_UPWARD_DYLIB (0x23 | LC_REQ_DYLD) /* load upward dylib */ //#define LC_VERSION_MIN_MACOSX 0x24 /* build for MacOSX min OS version */ //#define LC_VERSION_MIN_IPHONEOS 0x25 /* build for iPhoneOS min OS version */ //#define LC_FUNCTION_STARTS 0x26 /* compressed table of function start addresses */ //#define LC_DYLD_ENVIRONMENT 0x27 /* string for dyld to treat //like environment variable */ //#define LC_MAIN (0x28|LC_REQ_DYLD) /* replacement for LC_UNIXTHREAD */ //#define LC_DATA_IN_CODE 0x29 /* table of non-instructions in __text */ //#define LC_SOURCE_VERSION 0x2A /* source version used to build binary */ //#define LC_DYLIB_CODE_SIGN_DRS 0x2B /* Code signing DRs copied from linked dylibs */ //#define LC_ENCRYPTION_INFO_64 0x2C /* 64-bit encrypted segment information */ //#define LC_LINKER_OPTION 0x2D /* linker options in MH_OBJECT files */ //#define LC_LINKER_OPTIMIZATION_HINT 0x2E /* optimization hints in MH_OBJECT files */ //#define LC_VERSION_MIN_TVOS 0x2F /* build for AppleTV min OS version */ //#define LC_VERSION_MIN_WATCHOS 0x30 /* build for Watch min OS version */ //#define LC_NOTE 0x31 /* arbitrary data included within a Mach-O file */ //#define LC_BUILD_VERSION 0x32 /* build for platform min OS version */ if (cmd->cmd == LC_SEGMENT_64) { struct segment_command_64 *segment = load_bytes(obj_file, actual_offset, sizeof(struct segment_command_64)); if (is_swap) { swap_segment_command_64(segment, 0); } // 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 */ // }; //----------------------------------------------------------------------------------------------------------------------- printf("------------------------------------LC_SEGMENT_64-------------------------------------------\n"); printf("uint32_t cmd; %x\n",segment->cmd); printf("uint32_t cmdsize; %x\n",segment->cmdsize); printf("char segname[16]; %s\n",segment->segname); printf("uint64_t vmaddr; %llx\n",segment->vmaddr); printf("uint64_t vmsize; %llx\n",segment->vmsize); printf("uint64_t fileoff; %llx\n",segment->fileoff); printf("uint64_t filesize; %llx\n",segment->filesize); printf("vm_prot_t maxprot; %x\n",segment->maxprot); printf("vm_prot_t initprot; %x\n",segment->initprot); printf("uint32_t nsects; %x\n",segment->nsects); printf("uint32_t flags; %x\n",segment->flags); //------------------------------------------------------------------------------------------------------------------------ printf("segname: %s\n", segment->segname); for (int i=0; i<segment->nsects; i++) { // 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 */ // }; //当前的地址 // struct section_64 * mysection = load_bytes(obj_file, actual_offset, sizeof(struct section_64)); } free(segment); } else if (cmd->cmd == LC_SEGMENT) { struct segment_command *segment = load_bytes(obj_file, actual_offset, sizeof(struct segment_command)); if (is_swap) { swap_segment_command(segment, 0); } // 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 */ // }; //----------------------------------------------------------------------------------------------------------------------- printf("-------------------------------------LC_SEGMENT---------------------------------------------\n"); printf("uint32_t cmd; %x\n",segment->cmd); printf("uint32_t cmdsize; %x\n",segment->cmdsize); printf("char segname[16]; %s\n",segment->segname); printf("uint64_t vmaddr; %x\n",segment->vmaddr); printf("uint64_t vmsize; %x\n",segment->vmsize); printf("uint64_t fileoff; %x\n",segment->fileoff); printf("uint64_t filesize; %x\n",segment->filesize); printf("vm_prot_t maxprot; %x\n",segment->maxprot); printf("vm_prot_t initprot; %x\n",segment->initprot); printf("uint32_t nsects; %x\n",segment->nsects); printf("uint32_t flags; %x\n",segment->flags); //------------------------------------------------------------------------------------------------------------------------ printf("segname: %s\n", segment->segname); free(segment); } else if (cmd->cmd == LC_IDFVMLIB||cmd->cmd == LC_LOADFVMLIB) { struct fvmlib_command *segment = load_bytes(obj_file, actual_offset, sizeof(struct fvmlib_command)); if (is_swap) { swap_fvmlib_command(segment, 0); } // struct fvmlib_command { // uint32_t cmd; /* LC_IDFVMLIB or LC_LOADFVMLIB */ // uint32_t cmdsize; /* includes pathname string */ // struct fvmlib fvmlib; /* the library identification */ // }; //----------------------------------------------------------------------------------------------------------------------- printf("-------------------------------------LC_SEGMENT---------------------------------------------\n"); printf("uint32_t cmd; %x\n",segment->cmd); printf("uint32_t cmdsize; %x\n",segment->cmdsize); printf("struct fvmlib fvmlib; %x\n",segment->fvmlib); //------------------------------------------------------------------------------------------------------------------------ free(segment); } else if (cmd->cmd == LC_ID_DYLIB||cmd->cmd == LC_REEXPORT_DYLIB||cmd->cmd == LC_LOAD_UPWARD_DYLIB) { struct dylib_command *segment = load_bytes(obj_file, actual_offset, sizeof(struct dylib_command)); if (is_swap) { swap_dylib_command(segment, 0); } // struct dylib_command { // uint32_t cmd; /* LC_ID_DYLIB, LC_LOAD_{,WEAK_}DYLIB, // LC_REEXPORT_DYLIB */ // uint32_t cmdsize; /* includes pathname string */ // struct dylib dylib; /* the library identification */ // }; //----------------------------------------------------------------------------------------------------------------------- printf("-------------------------------------LC_ID_DYLIB---------------------------------------------\n"); printf("uint32_t cmd; %x\n",segment->cmd); printf("uint32_t cmdsize; %x\n",segment->cmdsize); printf("struct dylib dylib; %x\n",segment->dylib); //------------------------------------------------------------------------------------------------------------------------ free(segment); } //加上当前的cmdsize到就是下一个命令 actual_offset += cmd->cmdsize; free(cmd); } } //解析mach头 void dump_mach_header(FILE *obj_file, int offset, int is_64, int is_swap) { uint32_t ncmds; //加载命令偏移 int load_commands_offset = offset; if (is_64) {//64 位 int header_size = sizeof(struct mach_header_64); struct mach_header_64 *header = load_bytes(obj_file, offset, header_size); if (is_swap) { swap_mach_header_64(header, 0); } // 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 */ // }; //----------------------------------------------------------------------------------------------------------------------- printf("------------------------------------mach_header_64------------------------------------------\n"); printf("uint32_t magic; %x\n",header->magic); printf("cpu_type_t cputype; %x\n",header->cputype); printf("cpu_subtype_t cpusubtype; %x\n",header->cpusubtype); printf("uint32_t filetype; %x\n",header->filetype); printf("uint32_t ncmds; %x\n",header->ncmds); printf("uint32_t sizeofcmds; %x\n",header->sizeofcmds); printf("uint32_t flags; %x\n",header->flags); printf("uint32_t reserved; %x\n",header->reserved); //------------------------------------------------------------------------------------------------------------------------ //加载命令个数 ncmds = header->ncmds; //++ load_commands_offset += header_size; //打印 cpu 类型 printf("%s\n", cpu_type_name(header->cputype)); // free(header); } else {//32 位 int header_size = sizeof(struct mach_header); struct mach_header *header = load_bytes(obj_file, offset, header_size); if (is_swap) { swap_mach_header(header, 0); } // 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 */ // }; //----------------------------------------------------------------------------------------------------------------------- printf("------------------------------------mach_header_32----------------------------------------------\n"); printf("uint32_t magic; %x\n",header->magic); printf("cpu_type_t cputype; %x\n",header->cputype); printf("cpu_subtype_t cpusubtype; %x\n",header->cpusubtype); printf("uint32_t filetype; %x\n",header->filetype); printf("uint32_t ncmds; %x\n",header->ncmds); printf("uint32_t sizeofcmds; %x\n",header->sizeofcmds); printf("uint32_t flags; %x\n",header->flags); //------------------------------------------------------------------------------------------------------------------------ ncmds = header->ncmds; load_commands_offset += header_size; printf("%s\n", cpu_type_name(header->cputype)); free(header); } //解析commands命令 dump_segment_commands(obj_file, load_commands_offset, is_swap, ncmds); } //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 */ //}; void dump_fat_header(FILE *obj_file, int is_swap) { //头结构体大小 int header_size = sizeof(struct fat_header); //cpu 架构结构体大小 int arch_size = sizeof(struct fat_arch); //解析 fat 头结构体 struct fat_header *header = load_bytes(obj_file, 0, header_size); //在传进来的判断是否合法 if (is_swap) { //虚拟分区 swap_fat_header(header, 0); } //arch架构偏移 int arch_offset = header_size; //遍历所有架构 for (int i = 0; i < header->nfat_arch; i++) { //解析 struct fat_arch *arch = load_bytes(obj_file, arch_offset, arch_size); if (is_swap) { swap_fat_arch(arch, 1, 0); } // int mach_header_offset = arch->offset; free(arch); //下一个结构体 arch_offset += arch_size; //读header magic uint32_t magic = read_magic(obj_file, mach_header_offset); //判断 int is_64 = is_magic_64(magic); // int is_swap_mach = should_swap_bytes(magic); //解析头 dump_mach_header(obj_file, mach_header_offset, is_64, is_swap_mach); } free(header); } //解析 void dump_segments(FILE *obj_file) { //先读文件头 uint32_t magic = read_magic(obj_file, 0); //判断多少位 int is_64 = is_magic_64(magic); //判断什么格式虚拟分区(把磁盘虚拟成内存使用的作用) int is_swap = should_swap_bytes(magic); //判断是胖二进制还是普通二进制 int fat = is_fat(magic); if (fat) { //解析 fat 头 dump_fat_header(obj_file, is_swap); } else { //解析mach 头 dump_mach_header(obj_file, 0, is_64, is_swap); } }

以上是关于mach-o文件头和 cmd 解析的主要内容,如果未能解决你的问题,请参考以下文章

iOS系统分析Mach-O二进制文件解析

逆向-PE头解析

HTTP中的请求头和响应头属性解析

PE文件和COFF文件格式分析——签名COFF文件头和可选文件头2

转wave 文件解析

使用go命令可以定位到文件头和文件末