我创建了两个非常简单的Win32应用程序(来自Asm源代码)。这两个应用程序在代码部分只包含几个字节,我还在代码部分中包含了一些差异,因此操作系统不会认为这两个可执行文件是相同的。我用OllyDbg打开了两个可执行文件。
我想了解为什么OllyDbg中显示的CS和(E)IP寄存器的内容在两个调试会话中都是相同的。我一直认为这两个寄存器定义了代码段的内存位置。 (在DOS和早期的Windows版本中就是这种情况。)
OllyDbg是否可以看到这些寄存器的仿真版本?有什么想法吗?
答案 0 :(得分:1)
跟进评论并提供直接答案:
正如Hans Passant所说,某些就像为每个进程创建了一个虚拟机。但你是对的,这并不意味着处理器的操作是模拟的。 (事实上,现代处理器通常具有内置的虚拟化功能,甚至允许虚拟化软件(如VirtualBox或VMware)本地运行指令,而“虚拟”部分则由CPU本身完成,从而允许更快的执行速度虚拟机。)
这里虚拟化的是记忆。在protected mode中,可以使用段寄存器和32位偏移来访问存储器,但是段寄存器只是表的索引,该表包含描述哪些虚拟存储器块映射到哪些实际块的映射记忆。它们甚至可以映射到任何东西,但是配备了一个特殊标志,当访问该内存页时,该标志会导致CPU运行中断例程,允许操作系统透明地将内存分页到文件并仅在需要时将其分页。然而,该表本身是特定于该过程的,并且只要进程的代码将要运行,就由OS代码设置。
这是处理器直接提供的功能。因此,代码 直接在处理器上运行,但内存访问仍然是抽象的。 (请注意,仿真和虚拟化是两种不同的,虽然相关的东西。)
有几个级别的权限,称为“响铃”。大多数情况下,只使用两个环:环0(内核模式)和环3(用户模式)。在较高环中运行的代码比在较低环中运行的代码具有更少的权限。这确保了,例如,进程中的用户模式代码不能修改上述存储器映射表,因此不能访问属于其他进程的存储器。有一些特殊的方法(例如sysenter
指令或特殊的中断调用)允许用户模式代码通过明确定义的入口点“调用”操作系统提供的内核模式代码,这可以执行需要更高的操作特权。
Windows在所有进程中对段寄存器使用相同的值,因为它们的含义无论如何都是进程本地的。并且由于EXE文件可以指定它想要加载的基址(使用PE文件头),并且您的两个程序可能具有指定的相同地址(广泛使用的0x400000
地址),加载到的虚拟内存地址在两种情况下都是相同的。
回答你的问题:OllyDbg看到了寄存器的正确值,就像进程本身看到的那样。但它们的含义与早期的含义不同。您在EIP中看到的偏移量是一个虚拟地址(VA),并且段寄存器值就像一个ID,它的真正含义是您无法看到的。
您还会注意到大多数段寄存器具有相同的值。唯一真正不同的是FS
,它设置为偏移0指向当前线程的TIB (thread information block)。