我发现当从托管代码中调用GetBinaryType时,我得到了在同一台机器上从本机代码调用GetBinaryType的相反结果。
我从其他地方借来了编组声明:
public enum BinaryType : uint
{
SCS_32BIT_BINARY = 0, // A 32-bit Windows-based application
SCS_64BIT_BINARY = 6, // A 64-bit Windows-based application.
SCS_DOS_BINARY = 1, // An MS-DOS – based application
SCS_OS216_BINARY = 5, // A 16-bit OS/2-based application
SCS_PIF_BINARY = 3, // A PIF file that executes an MS-DOS – based application
SCS_POSIX_BINARY = 4, // A POSIX – based application
SCS_WOW_BINARY = 2 // A 16-bit Windows-based application
}
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetBinaryType(
string lpApplicationName,
out BinaryType dwBinType
);
然后将该函数调用为
bool is64bit = false;
BinaryType binType = BinaryType.SCS_32BIT_BINARY;
// Figure out if it's 32-bit or 64-bit binary
if (GetBinaryType(phpPath, out binType) &&
binType == BinaryType.SCS_64BIT_BINARY)
{
is64bit = true;
}
对于32位本机二进制文件,GetBinaryType返回BinaryType.SCS_64BIT_BINARY(6),对于64位本机二进制文件,返回BinaryType.SCS_32BIT_BINARY(0)。
为了验证,我编写了一个本机命令行工具,并针对相同的二进制文件运行它。
PCWSTR rgBinTypes[] = {
L"SCS_32BIT_BINARY", // 0
L"SCS_DOS_BINARY", // 1
L"SCS_WOW_BINARY", // 2
L"SCS_PIF_BINARY", // 3
L"SCS_POSIX_BINARY", // 4
L"SCS_OS216_BINARY", // 5
L"SCS_64BIT_BINARY", // 6
};
int _tmain(int argc, _TCHAR* argv[])
{
DWORD binType;
if (argc < 2)
{
wprintf(L"Usage: %S <binary-path>\n", argv[0]);
goto Cleanup;
}
if (!GetBinaryType(argv[1], &binType))
{
wprintf(L"Error: GetBinaryType failed: %d\n", GetLastError());
goto Cleanup;
}
wprintf(L"Binary type: %d (%s)\n", binType, binType < 7 ? rgBinTypes[binType] : L"<unknown>");
Cleanup:
return 0;
}
命令行工具正确地为32位本机二进制文件返回0(SCS_32BIT_BINARY),为64位本机二进制文件返回6(SCS_64BIT_BINARY)。
我发现有人提到同一个问题,但未提供任何答案:https://social.msdn.microsoft.com/Forums/en-US/fc4c1cb4-399a-4636-b3c3-a3b48f0415f8/strange-behavior-of-getbinarytype-in-64bit-windows-server-2008?forum=netfx64bit
还有其他人遇到过这个问题吗?
我意识到我可以在我的Managed枚举中翻转定义,但这看起来非常糟糕。
答案 0 :(得分:0)
这是WinAPI错误/开发人员的监督。 You may find this related question useful to read和it's top answer may help you find the appropriate workaround,
使用单独的64位进程和某些IPC来检索信息。
使用WMI获取模块文件名。
使用
Update()
。
我最终寻求了一个完全不同的解决方法。关于PE标头的This answer提到了32位和64位Windows可执行文件中的PE标头。您可以完全绕开WinAPI检查,并通过在Binary模式下读取目标可执行文件并检查其是否与PE签名相匹配来检查目标可执行文件。
遗憾的是,在线上没有太多有关此问题的信息。我记得在某个论坛上看到过这个问题,该论坛被明确列为bug,但这大约是10年前。我希望当我们讨论这个问题时,更多的人意识到它。