0

背景:

编写涉及在 python 程序中执行机器代码的概念证明。要在 osx 上执行此操作,我必须使用 ctypes 和 libc.dylib 以及以下函数调用:

(禁用 SIP)

  1. valloc 分配对齐的内存
  2. mprotect 授予 wrx 分配内存的权限
  3. memmove 将可执行代码复制到分配的内存;投掷; 并执行...

问题

问题出现在 mprotect 函数调用中,它总是返回 -1 表示失败。

脚本:(逻辑几乎与 linux 系统相同,因为它们都是 posix 系列)

import ctypes

buf = "machine code..."
libc = cytpes.CDLL('libc.dylib')
size = len(buf)
buf_ptr = ctypes.c_char_p(buf)

# allocate aligned memory space
alloc_space = ctypes.c_void_p(ctypes.valloc(size))

# this always evaluates true, and mprotect fails every attempt
if 0 != libc.mprotect(alloc_space, size, 1 |2 |4):
  print "mprotect failed"

ctypes.mmove(alloc_space, buf_ptr, size)

mmove 现在将失败并显示段错误错误消息(b/c 写入可能只有读取权限的内存空间),并且程序陷入困境......

问题出在 mprotect 上,这种方法在 linux 中效果很好,我现在看到 mac osx 的结果非常不同

问题:

Mac OSX 是否具有限制 mprotect 操作类型的额外安全功能(即使禁用 SIP)?如果是这样,如何绕过它?

更新:

根据评论中建议的@DietrichEpp,在 ctypes.CDLL 调用上使用 use_errno=True 会生成 errno。它评估为 errno:12,无法分配内存。此 errno 是 mprotect 手册页上 ENOMEM 的值。

尽管手册页上有一些 ENOMEM,但我怀疑这是最后一种情况:(b/c valloc 调用没有错误)

   ENOMEM Changing the protection of a memory region would result in the
          total number of mappings with distinct attributes (e.g., read
          versus read/write protection) exceeding the allowed maximum.
          (For example, making the protection of a range PROT_READ in
          the middle of a region currently protected as
          PROT_READ|PROT_WRITE would result in three mappings: two
          read/write mappings at each end and a read-only mapping in the
          middle.)

我怀疑 osx 有特殊限制,并且为每个进程设置了最大映射,因此添加更多权限,同一进程的新映射将超过这个最大限制(每个进程有多少个具有 exec/write 权限的映射)。如果我的假设是正确的,我们该如何解决呢?

4

1 回答 1

1

Apple 的手册页不再在线,但请参阅mprotect 的 POSIX 手册页

如果映射不是通过调用 mmap() 建立的,则未指定此函数的行为。

Linux 在这方面似乎更宽容,并且允许您在任何您想要的内存上调用 mprotect(),或多或少。达尔文更严格,如果你想调用 mprotect(),它要求你使用来自 mmap() 的内存。这就是为什么从头到尾阅读整个手册页是值得的原因之一。

仔细想想,这是一个合理的要求。由 valloc() 提供的内存由分配器管理,以后必须使用 free() 将其返回给分配器,而 mprotect() 在某种意义上绕过了分配器并改变了内存的工作方式。mmap() 和 munmap() 不是这种情况,它们与 mprotect() 属于同一系统调用系列。

于 2018-06-05T03:19:14.840 回答