背景
编写一个涉及在python程序中执行机器代码的概念证明。要在osx上执行此操作,所以我必须使用ctypes和libc.dylib以及以下函数调用:
(禁用SIP)
问题:
问题出现在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在评论中建议,使用use_errno = True对ctypes.CDLL调用生成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有特殊的限制,并为每个进程设置了最大映射,因此添加了更多权限,同一进程的新映射将超过这样的最大限制(每个进程有多少次执行/写权限映射) 。如果我的假设是真的,我们如何解决这个问题?
答案 0 :(得分:1)
Apple的手册页不再在线,但请参阅POSIX man page for mprotect:
如果未通过调用mmap()建立映射,则未指定此函数的行为。
看起来Linux在这方面更宽容,并允许你或多或少地在你想要的任何内存上调用mprotect()。 Darwin更严格,如果你想调用mprotect(),则需要你使用mmap()中的内存。这是为什么从开始到结束阅读整个手册页都是值得的。
如果你考虑一下,这是一个合理的要求。由valloc()给出的内存由分配器管理,并且必须稍后使用free()返回到分配器,并且mprotect()在某种意义上绕过分配器的后面并改变内存的工作方式。对于mmap()和munmap(),情况并非如此,它们与mprotect()位于同一系列调用中。