【问题标题】:GetBinaryType from Managed code gives opposite results托管代码中的 GetBinaryType 给出相反的结果
【发布时间】:2016-04-07 20:31:54
【问题描述】:

我发现当从托管代码中调用 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

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

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

【问题讨论】:

标签: c# managed


【解决方案1】:

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

  1. 使用单独的 64 位进程和一些 IPC 来检索信息。

  2. 使用 WMI 获取模块文件名。

  3. 使用QueryFullProcessImageName

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

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

【讨论】:

    猜你喜欢
    • 2014-03-04
    • 2021-08-23
    • 1970-01-01
    • 1970-01-01
    • 2011-01-29
    • 2015-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多