【问题标题】:Access to a specific memory address访问特定的内存地址
【发布时间】:2013-12-31 03:56:11
【问题描述】:

我是一名新的 C 程序员,仍在学习语言本身。

无论如何- 我正在尝试访问特定的内存地址。

我已经写了这段代码:

#include <stdio.h>

int main()
{
    int* p = (int*) 0x4e0f68;
    *p = 12;
    getchar();
}

当我尝试访问这样的特定内存地址时,程序崩溃了。

我不知道这些信息是否相关,但我使用的是 Windows 7 和 Linux Ubuntu。
(我只在 Windows 7 上尝试过此代码)。

程序崩溃的原因有什么解释吗? 如何访问特定的内存地址(编译时已知的地址,我不是指动态内存分配)?

谢谢。

【问题讨论】:

标签: c memory-management


【解决方案1】:

那是你不拥有的内存,访问它是未定义的行为。任何事情都可能发生,包括崩溃。

在大多数系统上,您可以检查内存(尽管从技术上讲仍然是未定义的行为),但写入它是完全不同的故事。

【讨论】:

  • 操作系统是否阻止 c 代码接触未拥有的内存?如果是这样,如何解决这个问题?
  • @EdgarArouiounian 可能是的。你想达到什么目的?
  • 这是一个浮现在脑海中的问题,而不是目前的特殊情况。
  • 谢谢。所以访问无主内存是未定义的行为。所以不可能访问无主内存(例如在 Windows 中)?如果有可能,比怎么做?
【解决方案2】:

严格来说,你不能像这样创建一个有效的指针。有效指针必须指向有效对象(在您的堆栈上或从malloc 获得)。

对于大多数现代操作系统,您都有一个只有您的进程才能看到的虚拟内存空间。当您向系统请求更多内存时(mallocVirtualAllocmmap 等),此虚拟内存将映射到您可以安全读取和写入的真实可用内存。所以你不能随便取一个地址,在没有操作系统合作的情况下尝试使用它。

windows 示例:

#include <windows.h>
#include <stdio.h>

int main(void)
{
    SYSTEM_INFO sysinfo;
    GetSystemInfo(&sysinfo);
    unsigned pageSize = sysinfo.dwPageSize;
    printf("page size: %d\n", pageSize);

    void* target = (void*)0x4e0f68;
    printf("trying to allocate exactly one page containing 0x%p...\n", target);
    void* ptr = VirtualAlloc(target, pageSize, MEM_COMMIT, PAGE_READWRITE);

    if (ptr)
        printf("got: 0x%p\n", ptr); //   ptr <= target < ptr+pageSize
    else
        printf("failed! OS wont let us use that address.\n");

    return 0;
}

请注意,这将在不同的运行中为您提供不同的结果。多试几次。

【讨论】:

  • 非常感谢。我在想操作系统应该支持这样的访问。
  • 尝试不同的基地址。在这里它大约有三分之一的时间起作用。
  • 另一个问题:我正在尝试运行该程序的两个不同进程 - 在一个进程中写入地址,因此它会影响另一个进程中该地址中的值。但是,在第二个过程中似乎并没有影响这个地址的值——为什么会这样?
  • 因为虚拟内存。每个进程似乎都可以使用整个系统内存。操作系统负责将每个进程地址映射到实际内存中。这就是为什么一个进程不能简单地读取/写入其他人的内存的原因。看这里:Virtual Memory.
  • 当然有。使用这个:WriteProcessMemory。请注意,您只需为地址空间中的数据提供一个缓冲区。将它复制到其他地址是内核的工作。您无法像原始指针那样直接访问它。
【解决方案3】:

只是为了澄清 OP 写的一句话:严格来说,在编译时不知道与程序(代码或数据)相关的地址。程序通常加载到操作系统确定的任何地址。程序看到的最终地址(例如,读取全局变量)由操作系统在程序代码中使用某种重定位表进行修补。程序调用的 DLL 函数具有类似的机制,其中可执行文件的 IDATA 部分被转换为跳转表以跳转到 DLL 中函数的实际地址,并从内存中的 DLL 中获取实际地址。

也就是说,如果程序在没有重定位信息的情况下链接,则确实可以提前知道变量的放置位置。这在 Windows 中是可能的,您可以告诉链接器将程序加载到绝对虚拟地址。如果可能,操作系统加载器会尝试将您的程序加载到该地址。

但是,不推荐使用此功能,因为它可能会导致轻松利用可能的安全漏洞。如果攻击者发现程序中的安全漏洞并尝试向其中注入代码,如果程序的所有变量和函数都在特定地址中对他来说会更容易,这样恶意代码就会知道在哪里打补丁以获得控制权那个程序。

【讨论】:

    【解决方案4】:

    你得到的是一个段错误 - 当你试图访问你没有访问权限的内存时。指针,至少对于用户空间来说,必须指向某个变量、对象、函数等。您可以使用 & 运算符 - int* somePtr = &amp;variableToPointTo 或另一个指针 - int* someNewPtr = somePtr 设置指向变量的指针。在内核模式(环 0)或操作系统开发中,您可以这样做,但不建议这样做。在 MS-DOS 中,您可能会破坏您的机器,因为没有针对这种情况的保护。

    【讨论】:

      猜你喜欢
      • 2022-08-17
      • 2019-04-13
      • 2010-09-12
      • 2021-10-28
      • 2010-11-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-14
      • 2012-01-05
      相关资源
      最近更新 更多