来自托管代码的GetBinaryType会产生相反的结果

时间:2016-04-07 20:31:54

标签: c# managed

我发现当从托管代码中调用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枚举中翻转定义,但这看起来非常糟糕。

1 个答案:

答案 0 :(得分:0)

这是WinAPI错误/开发人员的监督。 You may find this related question useful to readit's top answer may help you find the appropriate workaround

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

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

  4.   
  5. 使用Update()

  6.   

我最终寻求了一个完全不同的解决方法。关于PE标头的This answer提到了32位和64位Windows可执行文件中的PE标头。您可以完全绕开WinAPI检查,并通过在Binary模式下读取目标可执行文件并检查其是否与PE签名相匹配来检查目标可执行文件。

遗憾的是,在线上没有太多有关此问题的信息。我记得在某个论坛上看到过这个问题,该论坛被明确列为bug,但这大约是10年前。我希望当我们讨论这个问题时,更多的人意识到它。