Windows 7 和 Windows 8.1 之间的堆栈地址差异
Posted
技术标签:
【中文标题】Windows 7 和 Windows 8.1 之间的堆栈地址差异【英文标题】:Stack Address Difference Between Windows 7 and Windows 8.1 【发布时间】:2016-05-02 18:49:58 【问题描述】:考虑以下简单代码:
#include <iostream>
#include <iomanip>
int main(int argc, char* argv[])
int i = -1;
std::cout << std::hex << &i << std::endl;
return 0;
我在 Windows 7 Professional 上使用 Visual Studio 2015 for Desktop 编译代码,作为发布模式下的 32 位控制台应用程序。我禁用了 ASLR。如果我随后将可执行文件传输到我的 Windows 8.1 计算机,i 的地址将相差 8 个字节(在 Windows 8.1 计算机上它低 8 个字节)。
-
为什么两种环境的堆栈地址不同?
有没有办法(例如,链接器开关)使堆栈地址相同?
我尝试指定目标环境链接器选项,使用 /FIXED(这是程序的基地址,而不是堆栈),并在 Windows 7 兼容模式下运行可执行文件,但均无济于事。
为了给这个问题添加一些上下文,我正在尝试准备一个示例来描述如何使用WriteProcessMemory 函数。我希望我可以运行一个简单的可执行文件,从上面的代码构建,然后使用 WriteProcessMemory 来修改 i.如果 i 的地址在 pltaform 之间是静态的,那就太好了,因为它会简化我的 WriteProcessMemory 示例。
提前致谢。
【问题讨论】:
一些同事要求我讨论WriteProcessMemory 函数。我写了一些简单的代码,然后从结果过程中读/写。然而,问题是我的示例代码仅适用于 Windows 7,因为堆栈地址在 Windows 8.1 中发生了变化。 为什么需要这么严格的栈地址定位规则? 它们是不同的操作系统,您为什么希望进程内存布局相同? 很可能只是运行时库的不同。调用main()
的堆栈帧有一些额外的变量。或者堆栈的起始位置可能不同。
Windows 进程由在进程内运行的操作系统代码在应用程序堆栈上初始化。不期望加载器每次使用完全相同的堆栈空间量。
【参考方案1】:
让我们看看一个进程是如何创建的(简化的):
-
操作系统创建地址和进程空间(从父进程)。
调度程序切换到新进程并运行存根(现在在创建的进程上下文中),创建进程的内核堆栈和应用程序堆栈(假设每个线程有 1 个内核和应用程序堆栈)。
进入用户模式。
存根拉入可执行文件、库和资源。设置额外的东西,比如安全的东西和初始化句柄。一切都使用应用程序的堆栈。
跳转到程序入口,在您的示例中为 C 运行时。
crt 调用 ctor 并做最后的事情。
main()
由于 C 运行时是静态链接的并且在两个测试中没有改变,所以它也很简单,我怀疑进程存根是变量,它还有更多工作要做。
顺便说一下,C(和 C++)有详细记录的启动条件,但是堆栈地址不在要求的条件范围内。
PS。因为我们都没有windows的代码。我们所能做的就是有根据的猜测。
【讨论】:
OP 没有指定他使用的是静态链接的运行时 - @avejidah,你能澄清一下吗? @davidbak 我尝试使用 /MT 开关进行静态链接。虽然它确实会影响堆栈地址,但在 Windows 7 和 8.1 计算机上 i 的地址仍然相差 8 个字节。 即使你使用 msvcrt.dll 并且它们在两次测试中有所不同,启动代码(程序入口)仍然是静态链接的,启动代码可能会从 dll 调用 init 函数,但是既然那应该与 C 兼容的 abi 堆栈不应更改。 是的,没有理由期望加载器每次都使用相同数量的堆栈。如果您希望变量始终位于同一个位置,则必须将其设为静态变量(并禁用重定位)。 感谢@Harry Johnston,关于使变量变为静态的评论实际上很有帮助,并解决了我的问题。我可以在我的 WriteProcessMemory 示例中使用静态变量,并且静态变量在两个环境中具有相同的地址。但是,我将 Calvin 的答案标记为已接受的答案,因为他确实回答了我关于为什么堆栈上的地址不同的问题。以上是关于Windows 7 和 Windows 8.1 之间的堆栈地址差异的主要内容,如果未能解决你的问题,请参考以下文章
微软已于10月底停止销售预装Windows 7/8.1的电脑
Windows 7 或 Windows 8.1用户如何免费升级至Windows 10?
关于Windows_8.1/Windows 7下普通用户运行软件提示需要输入管理员密码解决方法