在" C和C ++中的安全编码",作者提到,
" W ^ X策略允许内存段可写或可执行,但不能同时使用。此策略无法阻止覆盖目标,例如atexit()所需的目标,这些目标需要在运行时和可执行文件中都是可写的。 "
我有两个问题:
atexit需要通过函数指针注册函数作为参数。函数指针指向的函数在当前程序中定义,其中链接器将查找定义,或者运行时加载程序将查找函数体。在任何一种情况下,我们都会知道函数定义。然后它只需要是可执行的。那么为什么atexit()的内存段需要在运行时可写并且可执行?
任何C / C ++专家都可以告诉我具有此属性的其他类型的API(在运行时可写和可执行)吗? (让我们将范围仅限于linux)
答案 0 :(得分:1)
从根本上说,可以编写和执行的内存非常容易调整,并且可以更容易地导致漏洞,因为不需要使用ROP或其他花哨的方法,您可以简单地在段中的任何地方写入要执行的代码和分支到它。 在你的引用中,这个上下文中目标的含义很可能是在退出时调用的函数指针列表。根据C API,列表本身需要是可写/可变的。这些函数指向的代码只需要是可执行的。在这里,因为列表是可变的,您可以通过插入指向代码的指针来简单地修改此列表来利用程序,并强制程序退出以执行代码。在这种情况下,保持所有内存段可写或可执行将不会保存您,因为这里使用了2个不同的段(一个可写入函数指针列表,另一个可执行代码)。
可写&在运行时动态生成代码的任何东西都需要可执行的内存段:JIT,内核,可执行的解包器等。对于这些中的每一个,没有技术要求这些段同时拥有这两个属性。可以首先分配存储器,复制/生成代码并调用mprotect(),使其可执行(并删除可写属性)。我可以看到的唯一情况是,同时拥有这两个属性可能会受到内存限制的环境(例如:解压缩可执行文件)。
请注意,某些平台不支持在用户空间中分配可执行内存:Xbox360&例如PS3不支持JIT。 (内核/ api支持它,但你无法发布你的软件,微软和索尼将拒绝你的提交,因为这个功能只能用于开发。)