I'm working on a project to implement a basic nm
using memory-mapping mmap
. I have been able to parse 64-bit binaries using the code:
void handle_64(char *ptr)
{
int ncmds;
struct mach_header_64 *header;
struct load_command *lc;
struct symtab_command *sym;
int i;
i = 0;
header = (struct mach_header_64 *)ptr;
ncmds = header->ncmds;
lc = (void *)ptr + sizeof(*header);
while (i < ncmds)
{
if (lc->cmd == LC_SYMTAB)
{
sym = (struct symtab_command *)lc;
build_list (sym->nsyms, sym->symoff, sym->stroff, ptr);
break;
}
lc = (void *) lc + lc->cmdsize;
i++;
}
}
According to this link the only difference between a mach-o and a fat binary is the fat_header
struct above it, but simply skipping over with
lc = (void *)ptr + sizeof(struct fat_header) + sizeof(struct mach_header_64);
doesn't get me to the load_command area (segfault). How do I access the load commands of a fat/universal binary.
I'm working on a 64-bit Mac running macOS High Sierra. Thank you.
You've got multiple problems:
struct fat_header
.Considering all of that, you need to parse the fat header (and not just ignore it) if you want any hope of getting useful results.
Now,
fat_header
is defined as follows:Firstly, the magic value that I usually see for fat binaries is
FAT_CIGAM
rather thanFAT_MAGIC
, despite the comment stating otherwise (take care though - this means that integers in the fat header are big endian rather than little endian!). But secondly, it is indicated that certain structs follow this header, namely:This works the same way a "thin" Mach-O header does with its load commands.
fat_arch.offset
is the offset from the very beginning of the file. Following that, it's quite simple to print all slices of a fat Mach-O:Note that the above function is incomplete, as it does not know the length of
buf
and thus cannot and does not check any accessed memory against it. In a serious implementation, you should make sure to never read outside the buffer you're given. The fact that your code segfaulted also hints at it not doing enough data sanitisation.