3

如何以编程方式检测我在哪个环(-1、0、1、2、3)中运行?

4

4 回答 4

7

最简单的方法是,只运行 (x86) 命令并捕获相应的错误。

例如(SEH、Windows、内核模式)

bool ring_lower_0 = false;
__try
{
    __asm { <cmd> };
    ring_lower_0 = true;
}
__except( GetExceptionCode() == EXCEPTION_PRIV_INSTRUCTION )
{
    ring_lower_0 = false;
}

笔记:

cmd,是一个汇编命令。有关命令列表及其各自的响铃级别,请参阅英特尔架构参考手册。

Linux 有一个稍微不同的概念。

但请记住,位于较低级别的 VM 可能会通过模拟调用来掩盖结果。

(注意:VM 的工作是将无效指令翻译成有意义的调用)


如果您真的想检查您的虚拟机是否因此而停止执行,您应该阅读有关“红色药丸”的文章。

于 2009-07-06T13:06:23.203 回答
3

除非您是设备驱动程序,否则您将始终在环 3 中运行(对于本身具有“环”的系统)。

于 2009-07-06T12:36:03.933 回答
1

通常我会写你应该阅读“保护模式编程”。有一篇关于如何使用 windows XP SP2 与 ring 0 交互的文章。请注意,它会因其他 Windows 版本以及其他操作系统而改变。

http://www.codeproject.com/KB/threads/MinimalisticRingZero.aspx

如果您只是想检测您是否在虚拟机内部运行,以避免人们调试您的应用程序,例如,您可以在此处查看:

http://www.codeproject.com/KB/system/VmDetect.aspx

于 2009-07-06T13:11:57.770 回答
0

环是 64 位 x86 架构中代码段选择器 (CS) 寄存器的低两位。

您可以像这样提取它:(在线测试

#include <stdint.h>
#include <stdio.h>

int main(void) {
    uint64_t rcs = 0;
    int ring;

    asm ("mov %%cs, %0" : "=r" (rcs));
    ring = (int) (rcs & 3);
    printf("Hello, world. This program is running on ring %d!\n", ring);
    return 0;
}

该代码的问题在于它总是返回 3,因为您的代码将始终在 ring 3 上运行。要看到这种变化,您需要创建一个 Linux 内核模块或 Windows 设备驱动程序。

我有一个 github 存储库,我在 Ubuntu 18 中使用。在演示 1 中,我有与上面完全相同的代码。你可以运行它:

cd demo-1
. c-build.sh

在 demo-2 中,我有一个 Linux Kernel 模块,它将执行相同的代码,但在 ring 1 的内核内部:

代码链接

...

#define EXAMPLE_MSG "Hello, World. This is executed in ring: _ \n"

...

uint64_t rcs = 0;
asm ("mov %%cs, %0" : "=r" (rcs));
msg_buffer[MSG_BUFFER_LEN - 3] = (int) (rcs & 3) + '0';

您不能从内核驱动程序对控制台执行 printf。相反,您需要将设备作为文件打开并从中读取:

cat /dev/lkm_example

我建议您逐步按照自述文件进行操作,以便您可以看到它正在运行:)

于 2020-05-11T09:36:54.360 回答