汇编语言中的虚拟地址转换

逆向工程 拆卸
2021-06-19 10:12:31

notepad.exe在 Ollydbg 中运行时,我得到以下执行跟踪:

(CPU)
...
[0x00C73689] CALL notepad.0073053
[0x00C7369E] PUSH 58
...

(Memory Map)    
Address    Size     Owner    Section  Contains      Type  Access   Initial  Mapped as
...
000FD000   00002000                                 Priv  RW       Guar     RW
000FF000   00011000                   stack of mai  Priv  RW       Guar     RW
...
00A90000   00001000                                 Priv  RW                RW
00C70000   00001000 notepad           PE header     Imag  R                 RWE
00C71000   0000B000 notepad  .text    code,imports  Imag  R                 RWE
...

在windows操作系统的虚拟地址系统下,

某些地址不在物理内存或 RAM 中,

  1. 翻译CALL notepad.0073053CALL [Real address 0x??????]

  2. 当该地址被文件映射时,谁将用汇编语言从磁盘读取该值?

2个回答

您在谈论内存虚拟化,除非您正在开发操作系统,否则您不必关心它,因为它对用户进程是透明的。

确实,您的程序看到的地址 notepad.0073053 与处理器硬件地址引脚上的物理地址不同。但是,当处理器执行调用指令时,它不会通过某种魔法转换目标地址,而是将转换后的地址放入程序计数器 - 程序计数器会。通话后,保持 0x007353。

虚拟化是在内存管理单元 (MMU) 中完成的,您可以将其视为实际处理器和内存之间的单独硬件。(当然,它们在现代处理器中位于同一芯片上,但很久以前曾经有单独的 MMU)。可以这样想:

+-----------------+           +----------------------+          +-----------------+
| CPU             |           | MMU lookup table     |          | RAM             |
+-----------------+           +----------------------+          +-----------------+
| call 73053      |  73053    | virtual      | phys. | 63053    |00000            |
| access 73053 on |---------->| 10000-20000  | a0000 |--------->|10000            |
| the address bus |           | 40000-50000  | 30000 |          |20000            |
+-----------------+           | 70000-80000  | 60000 |          |30000            |
                              +----------------------+          |40000            |
                                                                |50000            |
                                                                |60000    X       |
                                                                |70000            |
                                                                |80000            |
                                                                +-----------------+  

MMU 包含一个查找表 - 哪个虚拟地址范围映射到哪个物理地址范围。每当处理器访问内存时,它都会告诉mmu访问哪个虚拟地址;MMU 使用其查找表来确定实际的物理地址,这就是它放在地址总线上的内容。但是,处理器并不关心这种转换。您在 Ollydbg 中看到的始终是虚拟地址,而不是物理地址。

MMU 条目在操作系统内部处理,操作系统可以根据需要重新排列它们。例如,操作系统可能决定需要 60000 处的 RAM 块用于其他用途,将 60000 处的块复制到例如 20000 处,并更新 MMU 表。您的程序不会注意到任何事情 - 它仍然访问相同的虚拟内存位置,该位置现在位于物理内存中的不同位置。

+-----------------+           +----------------------+          +-----------------+
| CPU             |           | MMU lookup table     |          | RAM             |
+-----------------+           +----------------------+          +-----------------+
| call 73053      |  73053    | virtual      | phys. | 23053    |00000            |
| access 73053 on |---------->| 10000-20000  | a0000 |--------->|10000            |
| the address bus |           | 40000-50000  | 30000 |          |20000    X       |
+-----------------+           | 70000-80000  | 20000 |          |30000            |
                              +----------------------+          |40000            |
                                                                |50000            |
                                                                |60000            |
                                                                |70000            |
                                                                |80000            |
                                                                +-----------------+  

如果操作系统决定将内存块分页到磁盘,它将清除相应的 MMU 条目。现在,当处理器尝试访问该虚拟内存时,MMU 将生成一个page fault,告诉处理器它无法访问该内存。

+-----------------+           +----------------------+          +-----------------+
| CPU             |           | MMU lookup table     |          | RAM             |
+-----------------+  73053    +----------------------+          +-----------------+
| call 73053      |---------->| virtual      | phys. |          |00000            |
| access 73053 on |           | 10000-20000  | a0000 |          |10000            |
| the address bus | fault!    | 40000-50000  | 30000 |          |20000            |
+-----------------+<----------| 90000-a0000  | 40000 |          |30000            |
                              +----------------------+          |40000            |
                                                                |50000            |
                                                                |60000            |
                                                                |70000            |
                                                                |80000            |
                                                                +-----------------+

此页面错误将使处理器调用操作系统内的页面错误处理程序。操作系统保留一个它已写入磁盘的页面的列表,找到当前未使用的内存位置,从磁盘读取所需的页面到该位置,相应地更新 MMU,然后返回到用户程序并重新执行指令产生页面错误。用户程序对此一无所知(除非它努力寻找,例如通过测量所需的实时时间并将其与预期时间进行比较)。在Windows中,perfmon小号Ram/Page faults per second柜台将告诉你如何往往是发生了。

(实际上,页面错误有很多种。MMU 表中的空间非常有限,它通常不会映射用户程序的所有虚拟地址。当页面错误发生时,操作系统首先检查“是那块内存吗?在 RAM 某处,只缺少 MMU 条目?”。如果是,操作系统只会生成 MMU 条目并允许程序继续。这称为小页面错误,处理起来非常快;实际访问的页面错误磁盘称为主要页面错误,对性能的影响更大)。

抱歉,您的问题不是很清楚。根据我的理解,

  1. 翻译CALL notepad.0073053CALL [Real address 0x??????]

为此,您需要查看英特尔指令集参考CALL指令有许多不同类型的操作码在您发布的代码中,它使用以下形式
CALL rel32/rel16this 的意思是Call Near、relative、displacement relative 到下一条指令即,操作数指定从EIP(指令指针)之后紧接的下一条指令的偏移量当处理器遇到此类代码时,它只是将操作数值添加到 中EIP以获取调用目标。重要的是要了解 OllyDbg 中显示的反汇编代码仅供您理解。实际上,指令只会在运行时被翻译,当处理器遇到它时。

  1. 当该地址被文件映射时,谁将用汇编语言从磁盘读取该值?

PE加载器是负责加载在内存中的可执行文件在指定的地址PE头基址指定装载的地址,虽然在现代的操作系统,这是情况并非总是如此。ASLR (地址空间布局随机化)也在确定加载地址方面发挥作用。

在windows操作系统的虚拟地址系统下,有些地址不在物理内存或RAM中,

虚拟内存是一种内存管理技术,它将程序使用的内存地址(称为虚拟地址)映射到计算机内存中的物理地址。这是在软件和硬件中实现的。分页是虚拟内存实现的一部分,它方便了二级存储的使用,用于存储程序数据。可能会出现处理器需要访问当前 RAM 中不可用的数据的情况。在这种情况下,处理器将产生页面错误操作系统会知道这一点,随后会暂停程序的执行,它将页面从磁盘读回内存,然后可以继续执行。