通过 C# 运行 在 64 位中获取文件系统上的二进制文件类型

Get type of binary on filesystem via C# running in 64 bit

我有一个 C# 应用程序,在 Visual Studio 2017 年在 'Any CPU' 目标上编译,禁用了 'Prefer 32-bit' 选项。在此应用程序中,我尝试调用 kernel32!GetBinaryType()。当 运行 'Prefer 32-bit' 启用时,它工作正常。当 运行 从 C++ 可执行文件以 32 位或 64 位模式运行时,它工作正常。我不确定 64 位 C# 应用程序做错了什么。

这是我的 pinvoke 签名:

[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetBinaryTypeW([MarshalAs(UnmanagedType.LPWStr)] string path, out UInt32 result);

从 64 位模式调用,GetLastError() returns 193,根据 https://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx

ERROR_BAD_EXE_FORMAT.

我已将 64 位调试器附加到我的 C# 应用程序和我的 C++ 应用程序,以确保字符串到达​​ GetBinaryTypeW() 在堆栈的正确位置,在我看来它是。

我担心我 运行 编组器中的一些细微错误。

我的方法有什么问题?

更新

评论中提到的问题不符合这种情况。在那个问题中,对 LoadLibrary() 的调用失败了,因为它被用来尝试将 32 位 DLL 加载到 64 位进程中。我没有尝试加载任何 DLL。我只是想使用 GetBinaryType() 来检查可执行文件的 PE header。

GetBinaryType 在 WOW6432 space 中进程为 运行 时会做一些有趣的事情,而 .NET 运行时可能会加剧这种情况。不幸的是,我现在不记得所有细节了。然而,这里有一个更健壮的解决方案,它适用于 EXE 和 DLL。请注意,这仅检测 PE 二进制类型。如果您正在处理编译为 AnyCPU 的 .NET 程序集,您可能会或可能不会得到您期望的结果。我将把任何进一步的调查留作 reader.

的练习
public enum BinaryType : uint
{
    SCS_32BIT_BINARY = 0,
    SCS_64BIT_BINARY = 6,
    SCS_DOS_BINARY = 1,
    SCS_OS216_BINARY = 5,
    SCS_PIF_BINARY = 3,
    SCS_POSIX_BINARY = 4,
    SCS_WOW_BINARY = 2
}

public static BinaryType? GetBinaryType(string path)
{
    using (FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read))
    {
        stream.Seek(0x3C, SeekOrigin.Begin);
        using (var reader = new BinaryReader(stream))
        {
            if (stream.Position + sizeof(int) > stream.Length)
                return null;
            var peOffset = reader.ReadInt32();
            stream.Seek(peOffset, SeekOrigin.Begin);
            if (stream.Position + sizeof(uint) > stream.Length)
                return null;
            var peHead = reader.ReadUInt32();
            if (peHead != 0x00004550) // "PE[=10=][=10=]"
                return null;
            if (stream.Position + sizeof(ushort) > stream.Length)
                return null;
            switch (reader.ReadUInt16())
            {
                case 0x14c:
                    return BinaryType.SCS_32BIT_BINARY;
                case 0x8664:
                    return BinaryType.SCS_64BIT_BINARY;
                default:
                    return null;
            }
        }
    }
}