我是一名新的C程序员,仍在学习语言本身。
无论如何 - 我正在尝试访问特定的内存地址。
我写了这段代码:
#include <stdio.h>
int main()
{
int* p = (int*) 0x4e0f68;
*p = 12;
getchar();
}
当我尝试访问这样的特定内存地址时,程序崩溃了。
我不知道这些信息是否相关,但我使用的是Windows 7和Linux Ubuntu (我在Windows 7上尝试过这段代码)。
程序崩溃的原因有何解释? 如何访问特定的内存地址(编译时已知的地址,我不是指动态内存分配)?
感谢。
答案 0 :(得分:3)
你不拥有并且访问它的内存是未定义的行为。任何事情都可能发生,包括崩溃。
在大多数系统上,你可以检查内存(虽然技术上仍然是未定义的行为),但写一个完全不同的故事。
答案 1 :(得分:3)
严格来说,你不能像这样创建一个有效的指针。有效指针必须指向有效对象(在堆栈上或从malloc
获得)。
对于大多数现代操作系统,您有一个只有您的进程才能看到的虚拟内存空间。当您从系统请求更多内存(malloc
,VirtualAlloc
,mmap
等)时,此虚拟内存将映射到可以安全读取和写入的实际可用内存中。所以你不能只是采取任意地址,并尝试在没有OS合作的情况下使用它。
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;
}
请注意,这会在不同的运行中为您提供不同的结果。不止一次尝试。
答案 2 :(得分:0)
只是为了克服OP写的一个短语:严格来说,编译时不知道与程序(代码或数据)相关的地址。程序通常在OS确定的任何地址加载。程序看到的最终地址(例如,读取全局变量)由OS在程序代码中使用某种重定位表进行修补。由程序调用的DLL函数具有类似的机制,其中可执行文件的IDATA部分被转换为跳转表,以跳转到DLL中函数的实际地址,从内存中获取DLL中的实际地址。
也就是说,如果程序没有重定位信息,那么确实可以预先知道变量将放在哪里。这在Windows中是可行的,您可以告诉链接器将程序加载到绝对虚拟地址。如果可能,OS加载程序将尝试将程序加载到该地址。
但是,不建议使用此功能,因为它可能导致轻松利用可能的安全漏洞。如果攻击者在程序中发现安全漏洞并尝试向其中注入代码,那么如果程序在特定地址中具有所有变量和函数,则对他来说会更容易,因此恶意代码将知道在何处制作补丁以获得控制权该计划。
答案 3 :(得分:0)
您所获得的是一个段错误 - 当您尝试访问内存时,您无权访问。指针,至少对于用户空间,必须指向一些变量,对象,函数等。您可以使用&amp;设置指向变量的指针。 operator - int* somePtr = &variableToPointTo
,或另一个指针 - int* someNewPtr = somePtr
。在内核模式(环0)或OS开发中,您可以这样做,但不建议这样做。在MS-DOS中,你可能会破坏你的机器,因为没有针对它的保护。