C# 托管代码中的GetBinaryType给出了相反的结果

C# 托管代码中的GetBinaryType给出了相反的结果,c#,managed,C#,Managed,我发现当从托管代码pinvoking 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 ap

我发现当从托管代码pinvoking 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_64位_二进制文件(6),对于64位本机二进制文件,返回BinaryType.SCS_32位_二进制文件(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;
}
PCWSTR rgBinTypes[]={
L“SCS\u 32位\u二进制文件”//0
L“SCS\U DOS\U二进制文件”//1
L“SCS\u WOW\u二进制文件”//2
L“SCS_PIF_二进制文件”//3
L“SCS_POSIX_BINARY”//4
L“SCS_OS216_二进制文件”//5
L“SCS_64位二进制文件”//6
};
int _tmain(int argc,_TCHAR*argv[]
{
德沃德宾斯型;
如果(argc<2)
{
wprintf(L“用法:%S\n”,argv[0]);
去清理;
}
if(!GetBinaryType(argv[1],&binType))
{
wprintf(L“错误:GetBinaryType失败:%d\n”,GetLastError());
去清理;
}
wprintf(L“二进制类型:%d(%s)\n”、binType、binType<7?rgBinTypes[binType]:L“”);
清理:
返回0;
}
对于32位本机二进制文件,命令行工具正确返回0(SCS_32位二进制文件),对于64位本机二进制文件,正确返回6(SCS_64位二进制文件)

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;
}
我发现有人提到其他人也有同样的问题,但没有提供答案:

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


我意识到我可以在我的托管枚举中翻转定义,但这似乎非常困难。

这是WinAPI错误/开发人员的疏忽,以及

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

  • 使用WMI获取模块文件名

  • 使用
    QueryFullProcessImageName

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


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

    GetBinaryType
    的行为会发生变化,无论您的应用程序是否在WOW64上运行,例如,如果您启用了“首选32位”或没有针对任何CPU。可能相关:您的C程序是否编译为64位或32位?如果为32,则可能正在经历重定向。