Skip to content

Instantly share code, notes, and snippets.

@C0deH4cker
Created January 15, 2015 20:52
Show Gist options
  • Save C0deH4cker/734a2167bb870ccc661e to your computer and use it in GitHub Desktop.
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!)
#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