1. 问题现象
- 环境
Windows 10专业版,64位操作系统,基于x64的处理器。 - 在命令行窗口中查询当前用户,正常显示。
- 在32Bit应用调用相应的命令行
Python代码:
结果:cmd = r"cmd /c query user" os.system(cmd)
2. 分析问题
- 定位query模块
通过everything来搜索query,结果如下图:
- 区分
System32目录中存放的是32Bit版本,后面存放的是64Bit版本吗?不是这样的。
3. Windows系统简介
Windows是一个多子系统的操作系统,Win32也是其子系统之一。
那么Windows 64位操作系统是如何兼容32位应用程序的呢?
- x64的处理有两套指令,分别支持32操作和64位操作。
- 32位代码编译时,自动转换成相应的32位操作指令;64位代码则转成64位操作指令。
- Windows 64位系统下有64位系统目录,存放64位应用程序所需要的相关库文件,为了保持操作系统默认向前兼容,64位系统默认的系统路径和32位操作系统一样,均为:C:\Windows\System32。
- Windows 64位系统中,新增加了C:\Windows\SysWOW64目录,存放32位子系统,也被称为WoW64(Windows-on-Windows 64-bit)子系统的相关库文件。
4. Windows 64位系统调用32位应用程序
应用程序运行时,系统会检测PE文件头,了解这个应用程序是32位还是64位,然后将相应的32位系统库文件加载到exe进程中。Windows32位程序,针对不同硬件架构(ARM、x86),有部分涉及硬件的库有差别,所以有部分库文件存放在C:\Windows\WinSxS中的amd64xxx和wow64xxx两个类目录中。
- 32位应用程序,在32位操作系统中,默认是加载C:\Windows\System32下的相关库文件。
- 32位应用程序,在64位操作系统中,默认依然是去加载C:\Windows\System32下的相关库文件。但是64位系统中,C:\Windows\System32目录下存放的是64位库文件,不相匹配。Windows 64位操作系统为了解决了这个问题,在文件系统驱动层,增加一个文件重定位的功能。即32位程序在64位系统下,访问C:\Windows\System32目录,会被重定位到C:\Windows\SysWOW64目录。
- Python 32位程序,调用默认的系统模块时,代码层面会去打开即会去C:\Windows\System32打开相应的模块,但是因为文件系统定位的关系,其实际是打开的C:\Windows\SysWOW64目录中的模块。
- 像32位的query.exe不在此目录,而是在C:\Windows\WinSxS中的amd64xxx和wow64xxx目录中。此时怎么办呢?Windwos操作系统提供了一个虚拟的路径C:\Windows\Sysnative(并没有这个真实路径),操作系统针对32位的进程访问此路径时,会进行一个重定位操作。默认是重定位到C:\Windows\SysWOW64目录中。但是针对一些因为内核架构不同的模块,如query,会定位到C:\Windows\WinSxS中的amd64xxx或wow64xxx目录中。
5. 解决方案
-
直接指定模块的路径
-
指定cmd的路径
指定cmd路径之后,CMD会自动地根据内核框架去找相应的模块
-
使用64位程序
6. 注意
- 64位系统不能使用sysnative虚拟目录。
- C++等其他语言在Windows上开发的程序均符合此规则。
- 受影响的模块很多,主要有 change.exe、chglogon.exe、chgport.exe、chgusr.exe、logoff.exe、qappsrv.exe、qprocess.exe、query.exe、reset.exe、rwinsta.exe、tscon.exe、tsdiscon.exe、tskill.exe等。