【问题标题】:Low-Level C++ App Crashes on Windows Vista/7 Unless Run in XP Compatibility Mode除非在 XP 兼容模式下运行,否则低级 C++ 应用程序在 Windows Vista/7 上崩溃
【发布时间】:2011-01-11 06:19:37
【问题描述】:

我有一个低级别(像真的低级别,它基本上是所有 IOCTL 调用和对枚举 API 的几个调用),在客户端计算机上的 Windows Vista/7 上偶尔崩溃。不幸的是,我无法获得任何故障转储,但一位乐于助人的用户确实提到在 XP 兼容模式下运行程序解决了这个问题。

应用程序始终以完全管理员权限启动(它是从另一个需要管理员授权的程序启动的),因此这不是 UAC 问题。我不使用任何已弃用的 API,也不依赖任何注册表黑客等。我只是发出调用以枚举磁盘,然后使用 IOCTL 命令获取有关所有连接设备的更多低级信息。

在 XP 兼容模式下会发生什么? Windows 将什么注入我的应用程序或以其他方式将其沙箱化以防止它在 Vista/7 上崩溃?在被告知它在 XP 兼容模式下运行良好之前,我最初怀疑堆损坏(尽管我已经拔出头发试图复制或追踪问题)。

谁能提出在 XP 兼容模式下可以避免的任何可能的问题,我应该研究一下以尝试解决这个问题?谢谢!

编辑:

还有一件事可能非常重要:我从用户空间调用 DDK/Kernel 函数,以便获得某些未通过 WIN32 API 公开的功能。

我正在使用 ZwReadFile、ZwCreateFile、ZwWriteFile、RtlInitUnicodeString、ZwQueryVolumeInformationFile、ZwDeviceIoControlFile、ZwSetInformationFile、ZwClose。

我调用的 IOCTL 包括 IOCTL_DISK_GET_PARTITION_INFO_EX、IOCTL_STORAGE_GET_DEVICE_NUMBER、IOCTL_DISK_GET_LENGTH_INFO 和 IOCTL_DISK_GET_DRIVE_LAYOUT_EX。

【问题讨论】:

  • 你能提供代码示例吗?您正在使用哪些特定的 IOCTL 调用?这听起来更像是驱动程序问题...
  • 我已经更新了我的帖子。我完全忘了提到最重要的事情,那就是我正在从用户空间调用内核/ddk 函数!我还列出了我正在使用的 IOCTL。
  • 当您考虑到它们的启动代码不同并且对 Bitlocker 的支持(我可能在这个问题上有点过分)时,可能 IOCTL 已针对 Windows 7 进行了更改...此外,Win 7 的驱动程序已更改,这可以解释 DDK 功能在 Win 7 下无法 100% 工作...
  • 我实际上是几个引导加载程序组件的作者,所以我可以非常自信地谈论这一点:从 NTLDR 切换到强大的 BCD 的主要原因之一是 Bitlocker 支持,但它是纯粹的启动时软件结构。 (可能)涉及的唯一硬件是 TPM 模块;但这些都与 IOCTL 命令无关。我仔细检查了所有 IOCTL 返回代码,所以我不认为调用不受支持......但在某些情况下它可能返回无效数据。我不知道。
  • 这与您的问题不是 100% 相关,但我不确定 ZwReadFile、ZwWriteFIle、ZwDeviceIoControlFile、ZwSetInformationFile 和 ZwClose 是否公开了它们的 Win32 对应项未公开的任何功能。您使用这些 API 的低级版本是否有原因?

标签: c++ windows-7 compatibility-mode kernel32


【解决方案1】:

从 XP 到 vista 的低级驱动程序发生了许多变化。我怀疑您正在使用受它影响的 IOCTL。

【讨论】:

  • 我,这段代码正在十多台测试机器上运行,这些机器在各种各样的硬件上运行 Windows Vista/7 的各种排列。某些硬件/软件组合导致它崩溃。 Vista/7 支持我使用的所有 IOCTL。
  • @Computer Guru:哪些硬件/软件配置与其他硬件配置不同导致崩溃?
  • 主要是分区表。 Win32 代码对 GUID 分区硬盘(OS X 风格)的支持仍然很不稳定,这也是我从 DDK 手动执行操作的原因之一。
【解决方案2】:

这很奇怪,但我调用 ZwQueryVolumeInformationFile 时将 FsInformationClass 设置为 FileFsVolumeInformation。

我传入了一个 FILE_FS_VOLUME_INFORMATION 的缓冲区,首先正常分配,然后过度分配给(sizeof(FILE_FS_VOLUME_INFORMATION) + sizeof(TCHAR)*FILE_FS_VOLUME_INFORMATION->VolumeLabelLength)

然后我打电话给 FILE_FS_VOLUME_INFORMATION->VolumeLabel[FILE_FS_VOLUME_INFORMATION->VolumeLabelLength/2] = _T('\0');仅在某些机器上这会导致内存损坏。

不管过度分配的大小(甚至尝试额外分配完整的 256 个字符!),当使用vector<unsigned char> 作为 FILE_FS_VOLUME_INFORMATION 缓冲区时,这将可靠地导致堆损坏甚至。 p>

似乎内核以某种方式在缓冲区上设置了某种写保护,无论大小如何都会导致损坏。将第一个 VolumeLableLength 字节复制到第二个缓冲区,然后后待处理的_T('\0') 解决了这个问题。不确定 Windows 如何/为什么将 I 分配并作为只读参数传入的缓冲区 如果它在 FILE_FS_VOLUME_INFORMATION 结构之后存储 应该以字符数组结尾!),但只是不修改我传递的缓冲区中的任何数据就可以了......这很疯狂,因为它只会发生(一致且 100% 可重现) 在某些机器上。

无论如何:问题解决了 *phew*!

【讨论】:

  • 对我来说看起来像一个错误:您使用的是 sizeof(TCHAR) 但 VolumeLabel 是 WCHAR,没有 ANSI 版本。然后你的赋值会注销数组的末尾。
  • 不。它们都是宽字符(定义了 UNICODE),并且 NULL 放置在正确的位置(通过日志记录和内存转储验证)。
猜你喜欢
  • 1970-01-01
  • 2011-03-21
  • 2011-08-05
  • 1970-01-01
  • 2013-04-11
  • 1970-01-01
  • 2011-06-06
  • 1970-01-01
  • 2012-07-17
相关资源
最近更新 更多