加载Mach-O可执行文件需要什么?

时间:2016-10-04 23:09:34

标签: mach-o xnu

我正在尝试手写一个Mach-O可执行文件。有三个加载命令:

  • LC_SEGMENT_64正在加载__PAGEZERO
  • LC_SEGMENT_64正在加载__TEXT,只有一个__text部分
  • LC_UNIXTHREAD并设置了适当的rip

每个命令都匹配mach/loader.h和相关标头中的结构。 otool -l按预期列出信息,不报告任何错误。从各方面来看,它是一个格式良好的目标文件 - 但OS X 10.10.5终止了任务(SIGKILL)。

在OS X加载之前检查Mach-O可执行文件的哪些功能?这些信息在哪里?这些功能是否会将版本更改为版本? (经常引用的“OS X ABI Mach-O参考”显然是缺失的。)

这是二进制文件的partially annotated hexdump

otool完整性检查(摘录):

$ otool -l machtest
machtest:
Load command 0
      cmd LC_SEGMENT_64
  cmdsize 72
  segname __PAGEZERO
…
Load command 1
      cmd LC_SEGMENT_64
  cmdsize 152
  segname __TEXT
…
Section
  sectname __text
   segname __TEXT
…
Load command 2
        cmd LC_UNIXTHREAD
…

2 个答案:

答案 0 :(得分:4)

自10.10.5 Yosemite以来,可执行文件必须至少 4096 字节长(PAGE_SIZE),否则它将立即被杀死。 @Siguza在XNU kernel exec_activate_image函数https://github.com/apple/darwin-xnu/blob/0a798f6738bc1db01281fc08ae024145e84df927/bsd/kern/kern_exec.c#L1456

中找到的相关代码

没有dyld

假设您只想使用系统调用来获得64位macOS可执行文件,则需要:

  • Mach-O 64位标题
  • LC_SEGMENT_64 __PAGEZERO(非零大小,名称可以是任何内容)
  • LC_SEGMENT_64 __TEXT(名称可以是任何内容;必须是可读且可执行的;部分是可选的)
  • LC_UNIXTHREAD

对于这种情况,这是my example

使用dyld

如果没有dyld,你不能做太多,所以如果你想使用它,最小的设置是:

  • Mach-O 64位标题
  • LC_SEGMENT_64 __PAGEZERO(非零大小)
  • LC_SEGMENT_64 __TEXT(名称可以是任何内容;必须是可读且可执行的;部分是可选的)
  • LC_SEGMENT_64 __LINKEDIT(必须可写,因为dyld需要可写段,在ld链接二进制文件中,可写段通常为__DATA
  • LC_DYLD_INFO_ONLY(指定实际dyld加载命令在可执行文件中的实际位置,通常会找到它们__LINKEDIT,但对此没有限制)或有趣LC_SYMTAB相反,如果没有dyld,这将使实际的LC_DYLD_INFO_ONLY无法使用。
  • LC_DYSYMTAB(这可能是空的)
  • LC_LOAD_DYLINKER
  • LC_MAINLC_UNIXTHREAD
  • LC_LOAD_DYLIB(至少有一个实际的dylib加载LC_MAIN才能工作)

LC_UNIXTHREADLC_MAIN

在现代可执行文件中(自10.7 Mountain Lion起),LC_UNIXTHREADLC_MAIN取代,后者需要dyld - 但从10.12开始,任何可执行文件仍支持LC_UNIXTHREAD Sierra(它应该是未来的MacOS版本,因为dyld可执行文件本身实际启动它。)

要使dyld工作,额外的步骤取决于绑定类型:
bind at load是最省力的方法,其中LC_DYLD_INFO_ONLY指向指向可写段的有效dyld load commands将起作用。
lazy binding还需要__TEXT中额外的特定于平台的代码,该代码在加载时dyld_stub_binder使用绑定到dyld加载函数的延迟加载地址。
我还没有其他类型的dyld binding

可在此处找到更多详细信息:https://github.com/opensource-apple/dyld/blob/master/src/ImageLoaderMachO.cpp

答案 1 :(得分:0)

不是100%肯定,但您需要LC_LOAD_DYLINKER加载命令才能在可执行文件之前运行dyld,我很确定 OSX 如果加载,则不会自动映射到/usr/lib/dyld命令不可用。

您是否需要使用/usr/lib/libSystem.B.dylib加载命令LC_LOAD_DYLIB?我不这么认为,但这样做既不好又不花钱。