在Windows Vista/7上运行低级别的C++应用程序会崩溃,除非在XP兼容模式下运行。

3

我有一个非常底层(像真的非常底层,基本上就是所有IOCTL调用和一些枚举API调用)的程序,在客户机的Windows Vista / 7上不时会崩溃。不幸的是,我无法获得任何崩溃转储文件,但一位乐于助人的用户提到在XP兼容模式下运行程序解决了问题。

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

在XP兼容模式下会发生什么? Windows向我的应用程序注入了什么或以其他方式对其进行了沙箱处理,以防止它在Vista / 7上崩溃?在被告知在XP兼容模式下运行良好之前,我最初怀疑存在堆损坏(虽然我已经尝试过复制或跟踪此问题而无果)。

是否有人可以建议任何可能的问题,在XP Compat模式下可以避免这些问题,我应该尝试解决此问题?谢谢!

编辑:

还有一件非常重要的事情需要提到:我正在从用户空间调用DDK /内核函数,以便访问某些未通过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调用?那听起来更像是一个驱动程序问题... - t0mm13b
当考虑到Windows 7的引导代码不同以及对Bitlocker的支持时,IOCTL可能已经发生了变化(我可能在这方面有些超纲)...此外,Win 7的驱动程序已经发生了变化,这可能解释了DDK函数在Win 7下无法100%工作的原因... - t0mm13b
我实际上是几个引导加载程序组件的作者,所以我可以相当自信地谈论这个问题:从NTLDR到强大的BCD的转换的主要原因之一是支持Bitlocker,但它是一个纯粹的启动时软件构造。唯一可能涉及的硬件是TPM模块;但这与IOCTL命令无关。我会仔细检查所有IOCTL返回代码,所以我不认为调用不受支持......但也许在某些情况下它返回无效数据。我不知道。 - Mahmoud Al-Qudsi
这与您的问题不完全相关,但我不确定ZwReadFile、ZwWriteFIle、ZwDeviceIoControlFile、ZwSetInformationFile和ZwClose所公开的任何功能是否也由它们的Win32对应项公开。您使用这些API的低级版本有什么原因吗? - Larry Osterman
实际上,Larry,有一件非常重要的事情:你可以打开哪些类型的文件/设备!你不能通过它们的NT设备名称(\Device*)或ARC[multi(a)disk(b)rdisk(c)partition(d)]路径来打开资源,除非使用Zw函数。 - Mahmoud Al-Qudsi
显示剩余2条评论
2个回答

1

这很奇怪,但我正在使用FsInformationClass设置为FileFsVolumeInformation调用ZwQueryVolumeInformationFile。

我首先正常分配了一个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缓冲区,这也会可靠地导致堆损坏。

似乎内核对缓冲区进行某种写保护,导致无论大小都会出现损坏。将第一VolumeLableLength字节复制到第二个缓冲区,然后在末尾添加 _T('\0') 解决了问题。不确定Windows如何/为什么使我分配并传递给参数的缓冲区只读,或者是否在FILE_FS_VOLUME_INFORMATION结构之后存储(它应该以字符数组结束!),但是只是不修改我传递的缓冲区中的任何数据就解决了问题......这很疯狂,因为它只在某些机器上(持续且100%可再现)发生。

无论如何:问题已解决 *轻松松*!


在我看来,这似乎是一个错误:您正在使用sizeof(TCHAR),但VolumeLabel是WCHAR,没有ANSI版本。然后,您的赋值将数组写到了末尾。 - Ben Voigt
不对。它们都是宽字符(UNICODE已定义),而且NULL确实位于正确的位置(通过日志和内存转储进行验证)。 - Mahmoud Al-Qudsi

0

从XP到Vista,底层驱动程序发生了许多变化。我怀疑您正在使用受其影响的IOCTL。


嗨,这段代码在十几台测试机上运行良好,这些机器运行着各种不同的Windows Vista/7版本,并且硬件也有所不同。但是某些硬件/软件组合会导致它崩溃。我使用的所有IOCTL都支持Vista/7。 - Mahmoud Al-Qudsi
@电脑大师:有哪些与其他配置不同的硬件/软件配置会导致崩溃? - t0mm13b
主要是分区表。Win32代码对GUID分区硬盘(类似于OS X)的支持仍然不太可靠,这也是我手动从DDK进行操作的原因之一。 - Mahmoud Al-Qudsi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接