我正在尝试创建一个读取某个地址值的程序。 我有这个:
int _tmain(int argc, _TCHAR* argv[])
{
int *address;
address = (int*)0x00000021;
cout << *address;
return 0;
}
但这会产生读取违规错误。我究竟做错了什么? 感谢
答案 0 :(得分:5)
它在进程自己的空间中读取该地址的值。如果要读取另一个进程的空间或物理内存,则需要使用其他方法。
答案 1 :(得分:3)
对OlyDbg向您展示的确切问题持开放态度。 32位(和64位)Windows使用虚拟内存,这意味着您在程序中使用的地址不与通过总线实际发送到内存芯片的地址相同。相反,Windows(我应该添加其他操作系统,如Linux,MacOS,* bsd等,大致相同)设置一些表(实质上)当程序使用中的地址< / em> range,使用 范围的物理地址。
此映射是在逐页的基础上完成的(其中每个页面通常为4K字节,但其他大小也是可能的)。在该表中,它还可以将页面标记为“不存在” - 这是支持将内存分页到磁盘的内容。当您尝试读取标记为不存在的页面时,CPU会生成异常。然后,OS通过将数据从磁盘读入内存块来处理该异常,并更新表以说明数据存在于物理地址X.除了不存在之外,表还支持一些其他值,例如只读,所以你可以通过不写一些地址来阅读。
Windows(同样,与其他操作系统一样)为地址空间的第一部分设置表,但不将任何内存与它们相关联。从用户程序的角度来看,绝不应该使用这些地址。
这让我们回想起当你要求它从地址0x21读取时OlyDbg给你的不确定性。该地址根本不涉及任何真实数据 - 从来没有,也永远不会。
其他人所说的也是如此:调试器通常会使用一些操作系统功能(例如ReadProcessMemory
和WriteProcessMemory
,以及Windows下的其他功能)来访问您无法读取的内容或直接写。这些将允许您在另一个进程中读写内存,而普通指针无法直接访问该进程。这些都不会有助于尝试从地址0x21读取 - 该地址不会引用任何进程中的任何实际内存。
答案 2 :(得分:2)
您只能使用指向实际对象的指针。
如果您在地址0x00000021
没有对象,则无效。
如果要在免费商店(堆)上创建对象,则需要使用new
执行此操作:
int* address = new int;
*address = 42;
cout << *address;
delete address;
答案 3 :(得分:1)
当您的程序在提供虚拟内存的操作系统上运行时(Windows,* nix,OS X)并非所有地址都由内存支持。支持虚拟内存的CPU使用名为Page Tables的东西来控制哪个地址引用内存。单个页面的大小通常为4096字节,但确实有所不同,将来可能会更大。
用于查询页表的API不是标准C / C ++运行时的一部分,因此您需要使用特定于操作系统的函数来了解哪些地址可以读取以及哪些地址会导致您故障。在Windows上,您将使用VirtualQuery来确定是否可以读取,写入,执行给定地址,或者是否具有上述任何一个地址。
答案 4 :(得分:0)
您不能只从内存中的任意地址读取数据。