Handmade macOS executable

Viewed 217

I'm trying to implement a tiny compiler for macOS. I'm running macOS 11.5 on a MacBook Pro with M1. The assembly encoding works fine and I'm quite happy with the result (when handed over to Clang compiles and runs just fine).

My problem is that I couldn't find a way generate a valid executable file on my own. I got to a point where radare2 disassembles correctly every part of the executable, but every time I try to run my executable I get SIGKILL (9) from the terminal.

I read this whole file since I couldn't find any other source of documentation on the Mach-O format. SPOILER: It didn't work very well , that is why I'm hoping on some kind of Mach-O wizard to read this.

My problem in detail: The Mach-O header is fine. My problem is all about load commands.

I tried to inject the following segments/commands:

  • __PAGEZERO
  • __TEXT
  • __TEXT,__text
  • __LINKEDIT
  • LC_DYLD_INFO
  • LC_LOAD_DYLINKER
  • LC_MAIN
  • LC_LOAD_DYLIB

but no matter what I tried (I even tried to copy their values from other executables and then I "replaced" the address of the entry point to match mine), I couldn't find a way to make my executable file work.

Does anybody know what are the exact load commands I need to inject into the executable and their values?

PS: I would be happier if there was a way not to use dyld (I'm planning to stick with syscalls)

1 Answers

You should be able to ditch dyld if you use LC_UNIXTHREAD instead of LC_MAIN.

But at least one reason you get killed is because you don't have a code signature. While x86_64 code is allowed to run without one, arm64(e) absolutely must have one. Apple even modified their linker to implicitly add an ad-hoc code signature for arm64 (which you can disable with -Wl,-no_adhoc_codesign, but then it's not gonna run).
Try running codesign -s - path/to/binary on your crafted file and see if that makes it work. I can't be sure that's the only problem with your binary, but it is certainly one. And if you would like to generate these code signatures yourself too, then the most straightforward code to look at will likely be libcodedirectory.c in ld64 source. Apple has also open sourced much more sophisticated codesigning code, and there's 3rd-party implementations like ldid.

Related