在 C/C++ 中,如何在虚拟内存空间中获取数据?
Posted
技术标签:
【中文标题】在 C/C++ 中,如何在虚拟内存空间中获取数据?【英文标题】:In C/C++, how do I get the data in a virtual memory space? 【发布时间】:2012-09-24 23:31:11 【问题描述】:我正在处理调试信息。我正在尝试编写类似于“调试信息解析器”的方式,我正在使用 DWARF 和 ELF 库来执行此操作,但是除了内存空间的信息之外,它们不提供任何东西,我正在尝试获取该内存空间中的数据.我迷上了这个程序。我正在使用一个名为 Pin 的工具,所以我实际上是在另一个程序中运行代码。这就是为什么我可以访问它的变量。
假设我有一个指向地址的指针,我想获取存储在该地址中的所有数据以及接下来的 4 个字节(例如)。
例如,假设我有一个地址 0xDEADBEEF,我想从该地址开始遍历接下来的 4 个字节并读取数据(取消引用每个字节上的指针)
我对 C 比较陌生,我想做的是:
char * address = "0xDEADBEEF";
unsigned int bytesize = 4;
ptr = (void *) address;
ptr_limit = ptr + bytesize;
for(ptr; ptr < ptr_limit; ptr++)
cout << ptr;
我知道这可能是完全错误的,而且我遇到了很多编译错误,但这只是为了展示我正在尝试使用的一些逻辑......
【问题讨论】:
您是否正在尝试编写调试器? @therefromhere 不,但我正在处理调试信息。我正在尝试编写类似于“调试信息解析器”的方式,我正在使用 DWARF 和 ELF 库来执行此操作,但是除了内存空间的信息之外,它们不提供任何东西,我正在尝试获取该内存空间中的数据 C 和 C++ 是不同的语言,请告诉我们您使用的是哪一种。另外,ptr
和 ptr_limit
的类型是什么?
我将 C 和 C++ 用于一个名为 Pin 的工具以及读取 ELF 和 DWARF 库。 ptr 和 ptr_limit 只是 void 指针,但我可以更改它们并使它们成为我需要的任何类型
一方面,"0xDEADBEEF"
不是地址,也不是数字。 0xDEADBEEF
是一个数字。试试看。
【参考方案1】:
好吧,C 和 C++ 是低级的,但它们不是狂野的西部。您不能只是编造一个地址并访问它。在大多数操作系统上,您不能在 assembly 中这样做;这就是 SegFaults 的来源。
你获得内存的方式是分配它。这个过程包括告诉操作系统你想要一块一定大小的内存。此时,操作系统会执行它的工作,以便您可以访问一定范围的虚拟内存。尝试访问此范围之外的内存(或操作系统允许您访问的任何范围)将导致操作系统终止您的程序。
在 C 语言中,您通常使用 malloc
/calloc
/realloc
分配内存并使用 free
告诉操作系统您已经完成了它。 C++ 使用new
分配对象并使用delete
释放它们。
我正在尝试编写类似于“调试信息解析器”的方式,我正在使用 DWARF 和 ELF 库来执行此操作,但是除了内存空间信息之外它们不提供任何内容,我正在尝试获取数据那个内存空间
如果你能在你的问题中加入这样的东西,那就太好了。
在任何情况下,您都在谈论访问其他人的内存,这并没有完成。好吧,标准 C 和 C++ 的规则不允许这样做。各种操作系统都有调用,可以让你将另一个进程的一些地址空间映射到你的。但这要复杂得多,而且是特定于操作系统的。
【讨论】:
嗯,内存已经分配好了。我正在做的是使用 DWARF 库来获取一堆变量的地址,以及每个变量的字节大小。但有时我会遇到结构和字符数组。取消引用整数没有问题,因为我只是取消引用指针并使用 int 变量来读取它,但我试图取消引用更大的变量,这就是我得到的大小.. @attis: "内存已经分配好了。" 是在你的进程中分配的吗?目前还不清楚你在这里做什么。我们是在谈论触摸别人的记忆,还是您正在阅读 ELF 和 DWARF 文件并试图以此为基础做一些事情? 我正在读取 ELF 和 DWARF 文件并尝试从我从它们那里获得的内存地址中获取数据。 @attis:每个程序都有自己的地址空间。如果其他程序在地址0xDEADBEEF
分配一个字符,而您在地址0xDEADBEEF
读取一个字符,您将看不到它们的数据,它在内存中的不同位置。
@MooingDuck 我迷上了这个程序。我正在使用一个名为 Pin 的工具,所以我实际上是在另一个程序中运行代码。这就是为什么我可以访问它的变量。【参考方案2】:
内存地址是整数类型(读取数字)。
在您的示例中,您有一个 char *
(读取 string)。
以下代码:
char * address = "0xDEADBEEF";
void * ptr = ( void * )address;
只会将该char *
变量的地址作为void *
放入p
。
它不会设置指向内存地址0xDEADBEEF
的指针。
如果你想访问那个特定的内存位置(假设你知道自己在做什么),你需要这样的东西:
void * ptr = ( void * )0xDEADBEEF;
我说“假设你知道自己在做什么”,因为访问这样一个特定地址最终会导致段错误,因为你基本上不知道这样一个地址在你的地址空间中,除非你正在做的事情在环 0(读取内核)中,例如,使用 DMA。 但是我会假设你知道指针是一个数字,而不是一个字符串......
【讨论】:
好吧,我将地址存储为无符号整数中的十进制数,我只是想在该示例中使用 char * 来处理十六进制值并向您显示它是一个地址..它不是随机地址,而是我可以访问的地址。它来自我连接到 ptrace 的程序中的一个变量,我使用 DWARF 从该程序中获取了所有调试信息【参考方案3】:代码可以很简单:
char *address, *limit;
for(address = (char *)0xdeadbeef, limit = address+4; address < limit; address++)
cout << *address;
但是请注意,虽然允许将任意整数转换为地址,但使用结果指针的结果是不可移植的(甚至接近于)。根据您的评论(您通过调试信息获取地址),因此您获取的地址应该是有效的,结果应该正常工作(只是不能保证它是可移植的)。
【讨论】:
这正是我的想法,但每当我取消引用地址变量时,我获取的不是数据而是实际地址。所以打印的只是地址而不是数据.. @attis:那是因为您从 string 中的地址开始。当您执行char *whatever = "whatever";
时,您正在初始化指向该字符串的指针,因此当您打印出字符时,您会打印出字符串的内容。在上面的例子中,我没有使用字符串,而是一个 int 常量。如果必须以字符串开头,请先使用strtol
之类的内容转换为整数。
是的,我知道,我只是想寻找一种将字符串转换为 int 的方法,因为它给了我编译错误,但该函数工作正常!非常感谢.. @JerryCoffin【参考方案4】:
将您的地址存储为 DWORD => DWORD address = 0xDEADBEEF
然后将此地址转换为指针 => void *ptr = (void *)address
这是一个例子:
char *pointer = "FOO";
DWORD address = (DWORD)pointer;
printf("0x%u\n", address);
printf("%s\n", (char *)address); // prints FOO
address++; //move 1 byte
printf("%s\n", (char *)address); // prints OO
【讨论】:
以上是关于在 C/C++ 中,如何在虚拟内存空间中获取数据?的主要内容,如果未能解决你的问题,请参考以下文章
java String 内存地址问题?如何获取 String 内存地址!