- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我制作了一个简单的 C 程序,它在执行时简单地打印 main()
的地址:
printf("%08X\n", &main);
我用 Visual C++ 2015 用参数 /DYNAMICBASE
为 x86 编译它(为 x64 编译时发生同样的事情)。
前两次我运行它,返回的地址不同,正如预期的那样。但是,两次之后,程序返回的地址还是一样的:
00C31050
00221050
00221050
00221050
重新编译或重命名可执行文件会再次随机化地址。
这里发生了什么? Windows 是否以某种方式缓存可执行文件?
最佳答案
首先,您不需要获取函数地址,并且指针最好使用 %p 说明符打印,这有助于编译器检查类型。更准确的代码是:
printf ("%p\n", main);
关于主题,ASLR technology ,负责重新定位可执行镜像是一项操作系统功能,旨在通过降低地址的可预测性来抵御缓冲区溢出攻击。 它不保证对于两次连续运行,图像将被放置在不同的位置,但操作系统会尝试不时改 rebase 础,这取决于许多因素.对于我的测试,我在编译后立即在 Windows-7 32 位构建中获得了以下结果,连续运行 10 次:
00BE1260
00BE1260
00221260
00F71260
01391260
01391260
01391260
01391260
01391260
003A1260
如您所见,即使连续运行放置在相同的位置,基地也会在一段时间后改变。可以保证的是,不支持动态库的可执行镜像将始终放置在库中,由链接器在 exe 头文件中设置。可执行镜像的默认基数是 400000h,因此打印的值将是这样的:
00401260
00401260
00401260
00401260
00401260
...
至于您的情况,我认为操作系统 rebase 算法更具预测性,因为操作系统算法处理攻击威胁的可能性较小或由于缺乏熵或资源。 rebase 需要额外的时间和资源来重新映射内存页面和调整重定位,因此操作系统可能会决定在您的情况下不需要频繁 rebase 。
当然,Windows 会缓存加载的可执行文件以加快其启动速度。这就是为什么下一次运行时碱基不会改变的概率足够高的原因。如果您有足够的 RAM,则用于缓存的 RAM 越多,该图像就越有可能不会被重新定位。如果图像完全重新加载,则没有理由保持相同的基础。此外, rebase 策略可能因操作系统版本而异。
关于缓存。它不仅是功能上的缓存。如果图像被加载到内存中,它可以同时用于多个进程(实例)。这些实例可以安全地共享代码页,因为代码是只读的。这是 Windows 在进程终止后不立即“卸载”图像的主要原因之一。但是只有当代码调整到相同的基础时,两个进程才能共享代码,因为重定位会修补内存中的代码。如果我们强制不同的进程重新定位,我们不可避免地需要放弃代码共享,这将导致 RAM 消耗增加。
编辑:
顺便说一句,我发现/DYNAMICBASE 选项被 VS2015 忽略,并且链接器总是生成支持 ASLR 的可执行镜像,即使我明确设置/DYNAMICBASE:NO。逐位比较还表明,除了一个时间戳和(作为结果)校验和之外,编译的文件是相同的。要在没有 ASLR 支持的情况下获得由 VS2015 构建的可执行文件,我必须手动删除 exe-header 中的 IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE 位。不知道是故意的还是微软的bug。
关于c - 为什么 Windows 不继续随机化我的可执行文件的基地址?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44842899/
我是一名优秀的程序员,十分优秀!