我越是阅读有关C,指针和内存管理等低级语言的内容,它让我对现代操作系统和内存保护的当前最新技术感到疑惑。例如,什么样的检查可以防止某些流氓程序随意尝试读取尽可能多的地址空间并忽略操作系统设置的规则?
一般而言,这些内存保护方案如何工作?他们的优点和缺点是什么?换句话说,在现代操作系统中运行已编译的程序时,是否存在根本无法完成的事情,即使您拥有C并且您拥有所需的任何调整编译器?
答案 0 :(得分:4)
内存保护在硬件中实施,通常具有KB的最小粒度。
来自维基百科关于memory protection的文章:
在分页中,内存地址空间是 分成相等的小块, 被称为页面。使用虚拟内存 机制,每个页面都可以 居住在物理的任何位置 记忆,或被标记为存在 保护。虚拟内存使它 可能有线性虚拟 内存地址空间并使用它 访问块在物理上碎片化 内存地址空间。
大多数计算机体系结构基于 页面,最着名的是x86架构, 还使用页面进行内存保护。
页表用于映射 虚拟内存到物理内存。该 页表通常是不可见的 处理。页表使它更容易 分配新内存,作为每个新页面 可以从任何地方分配 物理记忆。
通过这样的设计,它是不可能的 一个访问页面的应用程序 尚未明确分配给 它,只是因为任何内存地址, 即使是一个完全随机的,那个 申请也可以决定使用 指向已分配的页面,或 生成页面错误(PF)错误。 未分配的页面根本没有 来自应用程序的任何地址 观点。
答案 1 :(得分:4)
保护由硬件(即,由CPU)强制执行。应用程序只能将地址表示为虚拟地址,CPU使用lookaside buffers解析虚拟地址到物理地址的映射。每当CPU需要解析未知地址时,它就会生成“页面错误”,它会中断当前正在运行的应用程序并将控制权切换到操作系统。操作系统负责查找其内部结构(page tables)并查找应用程序触及的虚拟地址与实际物理地址之间的映射。找到映射后,CPU可以恢复应用程序。
加载物理地址和虚拟地址之间的映射所需的CPU指令受到保护,因此只能由受保护的组件(即OS内核)执行。
整体而言,该计划的实施原因是:
如果在内核中加载了流氓模块,该方案会失败,因为在该保护级别它可以读取和写入任何物理地址。
应用程序可以读取和写入其他进程内存,但只能通过要求内核为它们执行此操作(例如,在Win32 ReadProcessMemory中),并且此类API受访问保护控制(调用者需要某些特权)。
答案 2 :(得分:1)
您应该向Google询问分段错误,内存违规错误和常规保护失败。这些是各种操作系统返回的错误,以响应程序试图访问它不应访问的内存地址。
Windows Vista(或7)具有随机dll附加的例程,这意味着缓冲区溢出可以在每次发生时将您带到不同的地址。这也使得缓冲区溢出攻击的可重复性稍差。
答案 3 :(得分:1)
因此,将您的问题发布的答案链接在一起。尝试读取未映射到其地址空间的任何内存地址的程序将导致处理器发出页面错误异常,将执行控制转移到操作系统代码(可信代码),然后内核将检查哪个是错误的地址,如果当前进程地址空间中没有映射,它会将SIGSEV(分段错误)信号发送到通常杀死进程的进程(在这里谈论Linux / Unix),在Windows上你会得到同样的东西。
注意:您可以在Linux和POSIX操作系统中查看mprotect(),它允许您显式保护内存页,像malloc()这样的函数返回具有默认保护的页面上的内存,然后您可以修改,这样你可以保护内存区域只读(但只是页面大小的块,通常大约4KB)。