Created
January 15, 2015 20:52
-
-
Save C0deH4cker/734a2167bb870ccc661e to your computer and use it in GitHub Desktop.
Example for parsing a mach-o using the ITERCMDS macro (best thing ever!)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <stdbool.h> | |
#include <stdint.h> | |
#include <unistd.h> | |
#include <fcntl.h> | |
#include <sys/mman.h> | |
#include <mach-o/loader.h> | |
/* Get the next load command from the current one */ | |
#define NEXTCMD(cmd) (struct load_command*)((char*)(cmd) + (cmd)->cmdsize) | |
/* Iterate through all load commands */ | |
#define ITERCMDS(i, cmd, cmds, ncmds) for(i = 0, cmd = (cmds); i < (ncmds); i++, cmd = NEXTCMD(cmd)) | |
/* Prints the names and address ranges of all segments in the mach-o */ | |
void print_segment_names(struct mach_header* mh, size_t filesize) { | |
bool is64bit = false; | |
uint32_t i, ncmds; | |
struct load_command* cmd, *cmds; | |
/* Parse mach_header to get the first load command and the number of commands */ | |
if(mh->magic != MH_MAGIC) { | |
if(mh->magic == MH_MAGIC_64) { | |
is64bit = true; | |
struct mach_header_64* mh64 = (struct mach_header_64*)mh; | |
cmds = (struct load_command*)&mh64[1]; | |
ncmds = mh64->ncmds; | |
} | |
else { | |
fprintf(stderr, "Invalid magic number: %08X\n", mh->magic); | |
return; | |
} | |
} | |
else { | |
cmds = (struct load_command*)&mh[1]; | |
ncmds = mh->ncmds; | |
} | |
/* Iterate through the mach-o's load commands */ | |
ITERCMDS(i, cmd, cmds, ncmds) { | |
/* Make sure we don't loop infinitely */ | |
if(cmd->cmdsize == 0) { | |
break; | |
} | |
/* Make sure the load command is completely contained in the file */ | |
if((uintptr_t)cmd + cmd->cmdsize - (uintptr_t)mh > filesize) { | |
break; | |
} | |
/* Process the load command */ | |
switch(cmd->cmd) { | |
case LC_SEGMENT: { | |
struct segment_command* seg = (struct segment_command*)cmd; | |
printf("%16s: %08x - %08x\n", seg->segname, seg->vmaddr, seg->vmsize); | |
break; | |
} | |
case LC_SEGMENT_64: { | |
struct segment_command_64* seg = (struct segment_command_64*)cmd; | |
printf("%16s: %016llx - %016llx\n", seg->segname, seg->vmaddr, seg->vmsize); | |
break; | |
} | |
default: | |
continue; | |
} | |
} | |
} | |
int main(int argc, char* argv[]) { | |
if(argc < 2) { | |
fprintf(stderr, "Usage: %s <mach-o file> [<mach-o file>...]\n", argv[0]); | |
return 1; | |
} | |
/* Print segments of each file specified in the argument list */ | |
for(int i = 1; i < argc; i++) { | |
if(i > 1) { | |
printf("\n"); | |
} | |
printf("%s:\n", argv[i]); | |
/* Get an open file descriptor for mmap */ | |
int fd = open(argv[i], O_RDONLY); | |
if(fd == -1) { | |
perror(argv[i]); | |
continue; | |
} | |
/* Get filesize for mmap */ | |
size_t filesize = lseek(fd, 0, SEEK_END); | |
lseek(fd, 0, SEEK_SET); | |
/* Map the file */ | |
void* map = mmap(NULL, filesize, PROT_READ, MAP_PRIVATE, fd, 0); | |
if(map == MAP_FAILED) { | |
perror("mmap"); | |
close(fd); | |
continue; | |
} | |
/* Attempt to print its segment names */ | |
print_segment_names(map, filesize); | |
/* Clean up */ | |
munmap(map, filesize); | |
close(fd); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment