Last active
April 27, 2024 05:19
-
-
Save jndok/2b0ce89521d3fc5fd61e404465c04218 to your computer and use it in GitHub Desktop.
MachOMan - a basic Mach-O parsing library
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
// | |
// machoman.c | |
// machoman | |
// | |
// Created by jndok on 14/05/16. | |
// Copyright © 2016 jndok. All rights reserved. | |
// | |
#include "machoman.h" | |
macho_map_t *map_macho_with_path(const char *path) | |
{ | |
if (!path) return NULL; | |
if (access(path, R_OK) == -1) return NULL; | |
int32_t fd = open(path, O_RDONLY); | |
if (fd < 0) | |
return NULL; | |
struct stat st; | |
if(fstat(fd, &st) != 0) | |
goto fail; | |
macho_map_t *map = (macho_map_t *)malloc(sizeof(macho_map_t)); | |
if((map->map_data = mmap(NULL, st.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0x0)) == MAP_FAILED) | |
goto fail; | |
map->map_magic = MACHO_MAP_MAGIC; | |
map->map_size = (mach_vm_size_t)st.st_size; | |
map->unique_id = (uint32_t)(((uint64_t)map << 32) >> 32); | |
return map; | |
fail: | |
close(fd); | |
return NULL; | |
} | |
void free_macho_map(macho_map_t *map) | |
{ | |
if (!is_valid_macho_map(map)) { | |
return; | |
} | |
munmap(map->map_data, map->map_size); | |
free(map); | |
map = NULL; | |
} | |
__attribute__((always_inline)) | |
boolean_t is_valid_macho_file(const char *path) | |
{ | |
if (!path) return FALSE; | |
if (access(path, R_OK) == -1) return FALSE; | |
int32_t fd = open(path, O_RDONLY); | |
if (fd < 0) | |
return FALSE; | |
uint32_t magic = 0; | |
if (read(fd, (void*)&magic, sizeof(uint32_t)) == -1) | |
return FALSE; | |
if ((magic == MH_MAGIC) || (magic == MH_MAGIC_64)) | |
return TRUE; | |
else | |
return FALSE; | |
} | |
__attribute__((always_inline)) | |
boolean_t is_valid_macho_map(macho_map_t *map) | |
{ | |
if (!map) return FALSE; | |
if (!map->map_data) FALSE; | |
if (map->map_magic != MACHO_MAP_MAGIC) return FALSE; | |
return TRUE; | |
} | |
__attribute__((always_inline)) | |
struct mach_header_64 *get_mach_header_64(macho_map_t *map) | |
{ | |
if (!is_valid_macho_map(map)) return NULL; | |
return (struct mach_header_64*)(map->map_data); | |
} | |
__attribute__((always_inline)) | |
struct load_command **find_all_load_commands(struct mach_header_64 *mh) | |
{ | |
struct load_command **all_lcmds = (struct load_command **)malloc(sizeof(struct load_command *) * mh->ncmds); | |
struct load_command *lcmd = (struct load_command *)(mh + 1); | |
for (uint32_t i=0; i<mh->ncmds; i++, lcmd += (lcmd->cmdsize / sizeof(struct load_command))) { | |
all_lcmds[i] = lcmd; | |
} | |
return all_lcmds; | |
} | |
__attribute__((always_inline)) | |
struct load_command *find_load_command(struct mach_header_64 *mh, uint32_t lc) | |
{ | |
struct load_command *lcmd = (struct load_command *)(mh + 1); | |
for (uint32_t i=0; i<mh->ncmds; i++, lcmd += (lcmd->cmdsize / sizeof(struct load_command))) { | |
if (lcmd->cmd == lc) | |
return lcmd; | |
} | |
return NULL; | |
} | |
__attribute__((always_inline)) | |
struct segment_command_64 *find_segment_command64(struct mach_header_64 *mh, const char *segname) | |
{ | |
struct load_command *lcmd = (struct load_command *)(mh + 1); | |
for (uint32_t i=0; i<mh->ncmds; i++, lcmd += (lcmd->cmdsize / sizeof(struct load_command))) { | |
if (lcmd->cmd == LC_SEGMENT_64) { | |
struct segment_command_64 *seg64 = (struct segment_command_64*)(lcmd); | |
if (strcmp(seg64->segname, segname) == 0) | |
return seg64; | |
} | |
} | |
return NULL; | |
} | |
__attribute__((always_inline)) | |
struct section_64 *find_section64(struct segment_command_64 *seg64, const char *sectname) | |
{ | |
struct section_64 *sect64 = (struct section_64 *)(seg64 + 1); | |
for (uint32_t i=0; i<seg64->nsects; i++, sect64++) { | |
if (strcmp(sect64->sectname, sectname) == 0) | |
return sect64; | |
} | |
return NULL; | |
} | |
__attribute__((always_inline)) | |
struct symtab_command *find_symtab_command(struct mach_header_64 *mh) | |
{ | |
return (struct symtab_command *)find_load_command(mh, LC_SYMTAB); | |
} | |
__attribute__((always_inline)) | |
struct dysymtab_command *find_dysymtab_command(struct mach_header_64 *mh) | |
{ | |
return (struct dysymtab_command *)find_load_command(mh, LC_DYSYMTAB); | |
} |
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
/* | |
* == libmachoman v0.1.0 == | |
* | |
* A simple library providing all you need | |
* for generic Mach-O parsing. | |
* I found myself rewriting this fucking code | |
* in every project, so I finally decided to | |
* do it right, once and for all! | |
* | |
*/ | |
// | |
// machoman.h | |
// machoman | |
// | |
// Created by jndok on 26/05/16. | |
// Copyright © 2016 jndok. All rights reserved. | |
// | |
#ifndef machoman_h | |
#define machoman_h | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <unistd.h> | |
#include <sys/stat.h> | |
#include <sys/mman.h> | |
#include <fcntl.h> | |
#include <mach-o/loader.h> | |
#include <mach-o/nlist.h> | |
#define MACHO_MAP_MAGIC 0xDEADC0DE | |
#define MACHO_MAP_SLIDE_OFFSET(map, off) ((uint64_t)(map->map_data) + (uint64_t)off) | |
#define MACHO_MAP_UNSLIDE_OFFSET(map, off) ((uint64_t)off > (uint64_t)(map->map_data)) ? ((uint64_t)off - (uint64_t)(map->map_data)) : ((uint64_t)off) | |
enum { | |
MMRC_ErrGen = 1 | |
}; | |
typedef struct macho_map { | |
uint32_t map_magic; | |
void *map_data; | |
mach_vm_size_t map_size; | |
uint32_t unique_id; | |
} macho_map_t; | |
macho_map_t *map_macho_with_path(const char *path); | |
void free_macho_map(macho_map_t *map); | |
__attribute__((always_inline)) boolean_t is_valid_macho_file(const char *path); /* before you map */ | |
__attribute__((always_inline)) boolean_t is_valid_macho_map(macho_map_t *map); | |
__attribute__((always_inline)) struct mach_header_64 *get_mach_header_64(macho_map_t *map); | |
__attribute__((always_inline)) struct load_command **find_all_load_commands(struct mach_header_64 *mh); | |
__attribute__((always_inline)) struct load_command *find_load_command(struct mach_header_64 *mh, uint32_t lc); | |
__attribute__((always_inline)) struct segment_command_64 *find_segment_command64(struct mach_header_64 *mh, const char *segname); | |
__attribute__((always_inline)) struct section_64 *find_section64(struct segment_command_64 *seg64, const char *sectname); | |
__attribute__((always_inline)) struct symtab_command *find_symtab_command(struct mach_header_64 *mh); | |
__attribute__((always_inline)) struct dysymtab_command *find_dysymtab_command(struct mach_header_64 *mh); | |
#endif /* machoman_h */ |
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
all: | |
clang machoman.c -dynamiclib -o libmachoman.dylib | |
clean: | |
rm -rf libmachoman.dylib |
wouldn't is_valid_macho_file()
return false for a FAT macho file? I'm guessing the check isn't there because it's expected that you pass a thin macho but just letting you know 👍
@Razzile: yep, that's it. I'll add fat mach-o parsing in future, but this was meant to be super bare-bones.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hey @jndok have a look at my revisions, I've fixed a bug in
free_macho_map
👍