mach-o文件頭和 cmd 解析
阿新 • • 發佈:2018-04-17
mach-o
//
// 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 解析