【问题标题】:How do I know which memory addresses I can read-write in x86 assembly?我如何知道在 x86 程序集中我可以读写哪些内存地址?
【发布时间】:2020-05-26 14:50:31
【问题描述】:

我正在尝试了解有关 x86 程序集 (masm) 以及它如何处理内存的更多信息。 具体来说,我遇到了以下声明:

mov eax,ds:0x83f413c

我知道这会将内存地址 0x83f413c 上的内容复制到 eax 中,这引发了问题。我可以读取和写入每个内存位置吗?我怎么知道 0x83f413c 是否是一个有效的内存位置?

【问题讨论】:

  • 通常我们通过使用汇编指令和声明存储来选择要读/写的内存位置,例如全局变量,我们可以通过它们的标签来引用,或者通过调用操作系统调用或库函数来动态返回指向某些可用内存的指针,或者通过分配堆栈空间,这是相对于堆栈指针完成的。对于大多数目的,我们不必事先知道任何绝对地址。如果您看到这一点,则需要在其上下文中理解它——我们不能期望它适用于任何设置。
  • 你可以尝试读写任何内存位置。如果不允许这样做,则会引发异常。

标签: assembly memory memory-management x86 masm


【解决方案1】:

上下文就是一切 :) 如果 在加载的用户空间程序中找到该行(OP 没有提及,但我会假设),这可能是它的起源。 mov 指令正在从程序的数据段中读取一个有效的 DWORD 大小的变量,并且模块要么被加载到它的首选加载地址,要么包含一个重定位记录,该记录会将 mov 命令中的地址调整为正确的地址.

ds: 前缀只是反汇编程序试图覆盖所有基础的一个例子。 mov reg, mem 命令默认使用ds

一般来说,您无法访问任何旧地址。但是,任何程序都需要一些内存——至少要存储其静态声明的变量。当操作系统加载程序时,它必须为代码和数据分配一些内存。一旦加载,程序在内存中的布局是可预测的。链接器知道,如果程序是从 0x8300000 开始加载的,它的变量 foo 将在 0x83f413c 处找到。因此,可以直接对读取该变量的值进行编码——假设程序被加载到其首选地址,在本例中为 0x8300000。首选地址存储在程序头中,以便操作系统在加载时知道它。

如果程序没有加载到首选地址怎么办?然后还有另一种技术在起作用,它被称为重定位。程序头包含一组记录,告诉加载器在加载时调整代码。类似于:“在偏移量 0x7000 的代码部分中,有一个 mov reg, mem 命令使用与加载地址相关的内存偏移量,请进行相应调整”。程序加载器是操作系统的一部分,它会看到并按照指示进行操作。

总而言之,像这样的mov 命令,i。 e.从静态地址读取是安全的,只要它是由知道它在做什么的构建工具链(编译器/链接器)生成的。在基于操作系统的程序加载器的帮助下,这样的静态地址可以安全使用。


所有这些都是假设 OP 在针对受保护模式操作系统(Windows、Linux 等)的已编译用户态程序中遇到有问题的行。例如,如果它在设备驱动程序或 OS 内核、引导加载程序或实模式 32 位程序(这些存在!)中,则需要考虑不同的因素。

【讨论】:

  • 谢谢!我应该提到它,但这条线实际上源于使用 objdump 反汇编可执行文件。所以如果我理解正确,地址是已知的,可以安全使用,因为程序是编译和加载的?
  • 程序变量的地址对于链接器是已知的,并且它们可以被安全地使用,因为链接器和加载器共同保证了它的安全。
  • 只要回答了问题,我们就通过投票和/或接受答案来表示感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-16
  • 2012-02-02
相关资源
最近更新 更多