背景:
编写涉及在python程序中执行机器代码的概念证明。要在osx上执行此操作,因此必须使用ctypes和libc.dylib以及以下函数调用:
(禁用SIP)
valloc分配对齐的内存
mprotect授予wrx权限分配的内存
记忆将可执行代码复制到分配的内存中;投;和
执行...
问题:
该问题出现在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现在将失败,并出现segfault错误消息(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特权的映射)。如果我的假设是正确的,我们如何解决呢?
最佳答案
苹果的手册页不再在线,而是参考POSIX man page for mprotect:
如果未通过调用mmap()建立映射,则未指定此函数的行为。
在这方面,Linux似乎更为宽容,它允许您或多或少在所需的任何内存上调用mprotect()。 Darwin更为严格,如果要调用mprotect(),则要求您使用mmap()中的内存。这就是为什么从头到尾阅读整个手册页都值得的原因之一。
如果您考虑一下,这是一个合理的要求。由valloc()给定的内存由分配器管理,并且稍后必须通过free()返回给分配器,并且mprotect()在某种意义上绕过了分配器的背面,并改变了内存的工作方式。 mmap()和munmap()并非如此,它们与mprotect()在同一系列的系统调用中。
关于python - 10.13 High Sierra OSX-使用ENOMEM授予执行权限时,Python mprotect总是失败,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/50673522/