【问题标题】:Is it possible to circumvent OS security by not using the supplied System Calls?是否可以通过不使用提供的系统调用来规避操作系统安全性?
【发布时间】:2025-12-07 09:20:07
【问题描述】:

我了解,当用户通过所述操作系统提供的系统调用使用系统和文件系统时,操作系统会强制用户执行安全策略。

是否可以通过实现您自己的硬件指令而不是使用操作系统提供的系统调用接口来规避这种安全性?即使在您通常无法访问的文件中写入一个位也足够了。

【问题讨论】:

  • 防止直接硬件访问使权限分离成为可能。硬件支持将用户空间进程与内核隔离开来。
  • 防止这种情况发生的一件事是限制哪些操作码可以在不同的环中使用。

标签: security assembly operating-system system-calls


【解决方案1】:

首先,为简单起见,我认为操作系统和内核是一回事。

在执行代码时,CPU 可以处于不同的模式。 假设一个假设的 CPU 只有两种执行模式(主管和用户)

  • 在超级用户模式下,您可以执行任何指令,并且您可以完全访问硬件资源。
  • 在用户模式下,有部分指令您无权访问,例如处理硬件或更改 CPU 模式的指令。尝试执行这些指令之一将导致操作系统被通知您的应用程序行为不端,并且它将被终止。该通知是通过中断完成的。此外,在用户模式下,您只能访问部分内存,因此您的应用程序甚至无法访问不应访问的内存。

现在,这个工作的诀窍是,在超级用户模式下,你可以切换到用户模式,因为它是一种特权较低的模式,但是在用户模式下,你不能回到超级用户模式,因为不再允许这样做的说明。 返回管理员模式的唯一方法是通过系统调用或中断。这使操作系统能够完全控制硬件。

一个可能的示例如何将所有东西组合到这个假设的 CPU 中:

  • CPU 在超级用户模式下启动
  • 由于 CPU 在超级用户模式下启动,首先运行的东西可以访问整个系统。这是操作系统。
  • 操作系统根据需要设置硬件、内存保护等。
  • 操作系统会在为该应用程序配置权限后启动您想要的任何应用程序。启动应用程序会切换到用户模式。
  • 应用程序正在运行,并且只能访问操作系统在启动时允许的资源。任何对硬件资源的访问都需要通过系统调用。

我只解释了单个应用程序的流程。 作为帮助您了解它如何与多个运行的应用程序配合使用的奖励,抢占式多任务如何工作的简化视图:

  • 在现实世界中。操作系统会在启动任何应用程序之前设置一个硬件计时器。
  • 当此计时器到期时,它会导致 CPU 中断它正在执行的任何操作(例如:运行应用程序),切换到超级用户模式并在属于操作系统且应用程序无权访问的预定位置执行代码到。
  • 由于我们回到超级用户模式并运行操作系统代码,操作系统现在选择下一个要运行的应用程序,设置任何所需的权限,切换到用户模式并恢复该应用程序。
  • 此定时器中断是您获得多任务错觉的方式。操作系统在应用程序之间不断变化。

这里的底线是,除非操作系统(或硬件设计)中存在错误,否则应用程序可以从用户模式进入超级用户模式的唯一方法是通过操作系统本身使用系统调用。

这是我在我的爱好项目(虚拟计算机)中使用的机制https://github.com/ruifig/G4DevKit

【讨论】:

  • 这篇文章很棒,让我了解了 cpu 执行的不同模式。这像英特尔处理器上的“真实”和“保护”模式吗?
  • @Titulum 不完全是。 “实模式”是为了向后兼容早于 286 的 CPU。早于 286 的 x86 CPU,根本不支持任何保护。这是一个免费的。 :) “保护模式”为操作系统提供了设置内存访问和硬件资源权限的可能性。 x86 cpu 在“真实模式”下启动以实现兼容性,然后操作系统的某些部分负责切换到“保护模式”并设置所需的权限。*有关于这两种模式的详细信息。
【解决方案2】:

硬件设备连接到 CPU 槽总线,CPU 确实使用与它们通信 in/out 指令在 I/O 端口读取/写入值(当前硬件使用不太多,在早期家用计算机的常用方法),或者设备内存的一部分被“映射”到 CPU 地址空间,CPU 通过在共享内存中定义的位置写入值来控制设备。

所有这些都不能在“用户级别”上下文中访问,其中常见的应用程序由操作系统执行(因此尝试写入该共享设备内存的应用程序会在非法内存访问时崩溃,实际上那块内存通常不是甚至映射到用户空间,即从用户应用程序的角度来看不存在)。直接in/out 指令在 CPU 级别也被阻塞。

设备由驱动程序代码控制,它要么运行是专门配置的用户级上下文,它具有特定的端口和内存映射(微内核模型,其中驱动程序不是内核的一部分,如 OS MINIX) .这种架构更加健壮(驱动程序崩溃无法关闭内核,内核可以隔离有问题的驱动程序并重新启动它,或者完全杀死它),但是内核和用户级别之间的上下文切换是一个非常昂贵的操作,因此吞吐量的数据受到了一点伤害。

或者设备驱动程序代码运行在内核级别(单片内核模型,如 Linux),因此驱动程序代码中的任何漏洞都可以直接攻击内核(仍然不是微不足道的,但比尝试从用户上下文中获取隧道要容易得多通过一些内核错误)。但是 I/O 的整体性能更好(尤其是对于像显卡或 RAID 磁盘集群这样的设备,其数据带宽达到每秒 GiBs)。例如,这就是为什么早期的 USB 驱动程序存在如此巨大的安全风险的原因,因为它们往往存在很多错误,因此特制的 USB 设备可以在内核级上下文中从设备执行一些恶意代码。

因此,正如 Hyd 已经回答的那样,在一般情况下,当一切正常时,用户级应用程序应该无法在其用户沙箱之外发出单个位,并且系统调用之外的可疑行为将被忽略,或使应用崩溃。

如果您找到了打破此规则的方法,那就是安全漏洞,通常会在操作系统供应商收到通知后尽快修补这些漏洞。

虽然目前的一些问题很难修补。例如,当前 DRAM 芯片的“行锤击”根本无法在 SW(OS)或 CPU(配置/固件闪存)级别修复!目前大多数 PC HW 都容易受到这种攻击。

或者在移动世界中,设备使用的是基于传统设计的无线电芯片,具有多年前开发的闭源固件,所以如果你有足够的资源来支付对这些的研究,你很可能能够通过伪造的 BTS 站向目标设备发送恶意无线电信号来获取任何特定设备。

等等......供应商与安全研究人员之间的持续战争以修补所有漏洞,而黑客则寻找理想的零日漏洞利用,或者至少挑选那些没有以足够快的速度修补他们的设备/软件与已知错误的用户。

【讨论】:

  • 技术术语是微内核与单片内核。你应该用它来让人们更容易地在谷歌上搜索更多信息。当然,在现代 Unix/Linux 桌面上,图形驱动程序部分位于用户空间、X 服务器甚至由非 root 进程运行的库代码 (libgl) 中。这在某种程度上是一种微内核方法,其中内核提供了类似于 Linux 的 Direct Rendering Manager 的东西。但是,不受信任的用户空间进程实际上并不直接执行 MMIO。我不确定 DRM 内核端对硬件命令的检查程度。
  • @PeterCordes 感谢您的建议,做了微小的修改(懒得做更多,或提供一些链接)。关于 DRM 检查/等:我怀疑发生了很多事情,现代游戏正在推动 GiB/s(可能接近 TiB/s 顺序)的数据,通常是特定卡的本机格式的图形命令执行缓冲区,因此内核可以'甚至无法决定什么是有效命令,什么不是。我认为内存边界保护和 I/O 端口是你能做的最好的。对我来说,检查数据听起来不太可能(只要你想拥有普通的消费级性能,而不是谈论安全级软件)。
  • 所以基本上答案是“通常不会,除非 CPU 和/或内核中存在错误”?
  • @aderchox 如果有一些通用的“合法”方式来规避内核,那么所有恶意软件都会使用这种方式。所以是的,通常不可能通过不使用提供的系统调用(来自用户空间代码)来规避操作系统安全性。您不应该能够读取或修改任何对安全敏感的状态部分,或绕过任何操作系统保护。如果有这样的方法,那是一个错误,需要修补。当然会发生错误......硬件和软件错误。
【解决方案3】:

不正常。如果有可能是因为操作系统软件错误。如果发现软件错误,它会被快速修复,因为它被认为是软件漏洞,这等于坏消息。

【讨论】:

  • 不完全正确。虽然解决临时问题的工作量太大,但用“修改”版本替换文件系统或其他驱动程序几乎可以做任何事情,包括忽略安全功能等。这基本上是 rootkit 所做的。他们用“邪恶”的替代品替换了 HAL 和系统驱动程序。另一种选择是使用另一个操作系统安装硬盘并对其执行任何操作。 Firewire 也是一种有时会被利用的后门。
  • @BitTickler 好吧,你有点同意他的回答。通过替换某些操作系统文件,您在技术上运行的是不同的操作系统,这不仅易受攻击,而且是故意易受攻击的。这不是“通常”。但是在正常工作的干净操作系统中,没有特权的用户首先应该无法安装这样的 rootkit/补丁(即,这可能会变成冗长的毫无意义的“意见”讨论)。就像整个操作系统/数据光盘被高度加密,引导加载程序被证书签名,机器代码在执行之前由安全芯片组验证,火线和 USB 被撕掉了板子。 :D 等
  • @Ped7g 由于“提供的系统调用”最终会调用加载的驱动程序,我很想用“是”来回答原始问题。要么你有一个完全密封的操作系统,甚至根/管理员/系统更新都不能更改已安装的驱动程序集,要么你有一个“开放”系统,允许为其编写新的第三方驱动程序。前一种情况在嵌入式系统世界之外不存在。后者是标准情况,没有办法同时做到这两点:一个开放、安全的系统。
【解决方案4】:

“系统”调用在比应用程序更高的处理器级别执行:通常是内核模式(但系统系统有多个系统级别模式)。

您所看到的“系统”调用实际上只是一个包装器,它设置寄存器然后触发某种更改模式异常(该方法是系统特定的)。系统异常处理程序分派给适当的系统服务器。

您不能只编写自己的函数并做坏事。诚然,有时人们会发现允许绕过系统保护的错误。作为一般原则,您无法访问设备,除非您通过系统服务进行访问。

【讨论】: