c# - 托管代码中的 GetBinaryType 给出相反的结果

标签 c# managed

我发现,当从托管代码调用 GetBinaryType 时,我得到的结果与从同一台机器上的 native 代码调用 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 位 native 二进制文件,GetBinaryType 返回 BinaryType.SCS_64BIT_BINARY (6),对于 64 位 native 二进制文件,返回 BinaryType.SCS_32BIT_BINARY (0)。

为了验证,我编写了一个 native 命令行工具,并针对相同的二进制文件运行它。

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 位 native 二进制文件正确返回 0 (SCS_32BIT_BINARY),为 64 位 native 二进制文件正确返回 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

还有其他人遇到过这个问题吗?

我意识到我可以在我的托管枚举中翻转定义,但这看起来非常笨拙。

最佳答案

这是 WinAPI 错误/开发人员的疏忽。 You may find this related question useful to read , 和 it's top answer may help you find the appropriate workaround ,

  1. Use a separate 64 bit process, and some IPC, to retrieve the information.

  2. Use WMI to get the module file name.

  3. Use QueryFullProcessImageName.

我最终采用了完全不同的解决方法。 This answer关于 PE 头文件提到了 32 位和 64 位 Windows 可执行文件中的 PE 头文件。您可以完全绕过 WinAPI 检查,并通过以二进制模式读取目标可执行文件并检查它是否与 PE 签名匹配来检查您的目标可执行文件。

遗憾的是,网上没有太多关于该问题的信息。我记得在某个论坛上看到过这个问题,它被明确列为错误,但这是大约 10 年前的事了。我希望在我们讨论这个问题时,更多的人会意识到这一点。

关于c# - 托管代码中的 GetBinaryType 给出相反的结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36486618/

相关文章:

c# - 我如何建模这个关系数据库,并将所有数据放在集合类中

c# - Asp.Net Global.asax获取当前请求的Page对象

c# - 预测 .Net 随机序列中的下一个数字

c# - 在一个文件中包含多个类定义是一种好习惯吗?

.net - 是否可以确定事后编写 .NET 程序集的语言?

c++ - WINFORM C++ Managed string->unmanaged string 在与 fstream 结合使用时产生意外结果

c# - 为什么必须在 Compare 方法的实现中包含接口(interface)名称?

c# - 如何找到无法加载 "A procedure imported by ' xxx.dll 的源。”异常?

C# 托管非托管代码

.net - .NET 中的 User32 API 调用