2010-03-25 63 views
4

我正试图让程序读取某个地址处的值。 我有这个:在地址处读取值

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    int *address; 
    address = (int*)0x00000021; 
    cout << *address; 
    return 0; 
} 

但是,这给出了读取违规错误。我究竟做错了什么? 谢谢

+0

为什么在这个世界上你想要这样做? – 2010-03-25 21:30:38

+0

你从哪里得到地址?你是否以虚拟模式运行(我怀疑...)?程序是否以内核模式链接(大概不是......)? – 2010-03-25 21:31:39

+0

因为我想了解更多关于电脑如何工作的信息 – jmasterx 2010-03-25 21:31:48

回答

2

您只能使用指向实际对象的指针。

如果您没有地址0x00000021的对象,则此操作无效。

如果你想创建的自由存储区(堆)的对象,你需要做的所以使用new

int* address = new int; 
*address = 42; 
cout << *address; 
delete address; 
+0

那么我怎样才能获得内存中的值,因为OlyDbg可以告诉我这个地址是什么... – jmasterx 2010-03-25 21:30:36

+2

@ user146780:调试器通常使用特定于操作系统和特定于环境的挂钩来从进程的虚拟地址空间或物理内存中的给定地址读取数据。 – 2010-03-25 21:33:35

5

读取的过程中自己的空间范围内的地址的值。如果要读取另一个进程的空间或物理内存,则需要使用其他方法。

0

您不能只从内存中的任意地址读取数据。

1

当您的程序在提供虚拟内存的操作系统上运行时(Windows,* nix,OS X)并非所有地址都由内存支持。支持虚拟内存的CPU使用称为Page Tables的东西来控制指向内存的地址。单个页面的大小通常是4096个字节,但是确实有所不同,未来可能会更大。

用于查询页表的API不是标准C/C++运行时的一部分,因此您需要使用操作系统特定的功能来了解哪些地址可以读取,哪些会导致您过错。在Windows上,您可以使用VirtualQuery来确定给定的地址是可以读取,写入,执行还是以上任何一项。

3

对于OlyDbg向您展示的内容,有些问题是可以接受的。 32位(和64位)Windows使用虚拟内存,这意味着您在程序中使用的地址是而不是,与实际通过总线发送到内存芯片的地址相同。相反,Windows(我应该补充说其他操作系统,比如Linux,MacOS,* bsd等,大致相同)建立了一些表格,说明(实质上)何时该程序使用这个范围内的地址,使用范围的物理地址。

该映射是逐页完成的(每个页面通常为4K字节,尽管其他大小也是可能的)。在该表中,它也可以将页面标记为“不存在” - 这是支持将内存分页到磁盘的内容。当您尝试读取标记为不存在的页面时,CPU会生成一个异常。然后,OS通过从磁盘读取数据到一块内存来处理该异常,并更新表格以表示数据存在于物理地址X处。除非存在,表格还支持其他一些值,例如只读,所以你可以通过不写一些地址来阅读。

Windows(与其他操作系统一样)为地址空间的第一部分设置表,但不会将任何内存与它们关联。从用户程序的角度来看,这些地址不应该被使用。

这让我们回想起OlyDbg在你要求从地址0x21读取时给你的东西的不确定性。该地址根本不涉及任何真实的数据 - 永远不会有,也永远不会。

什么其他人所说的是事实,以及:一个调试器通常会使用一些OS功能(例如ReadProcessMemoryWriteProcessMemory等等Windows下),以获得访问的东西,你不能直接读写。这些将允许您在另一个进程中读写内存,这是不能由普通指针直接访问的。尽管这两个地址都不会帮助尝试读取地址0x21 - 该地址并不涉及任何进程中的任何实际内存。