3

I'm finding that when pinvoking GetBinaryType from managed code, I'm getting the opposite result of calling GetBinaryType from native code on the same machine.

I've borrowed the marshalling declaration from elsewhere:

    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
        );

and then call the function as

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;
}

For 32-bit native binaries, GetBinaryType returns BinaryType.SCS_64BIT_BINARY (6), and for 64-bit native binaries, returns BinaryType.SCS_32BIT_BINARY (0).

To verify, I wrote a native command line tool, and ran it against the same binaries.

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;
}

The command line tool correctly returns 0 (SCS_32BIT_BINARY) for 32-bit native binaries, and 6 (SCS_64BIT_BINARY) for 64-bit native binaries.

I found one reference to someone else having this same issue, but no answer was provided: https://social.msdn.microsoft.com/Forums/en-US/fc4c1cb4-399a-4636-b3c3-a3b48f0415f8/strange-behavior-of-getbinarytype-in-64bit-windows-server-2008?forum=netfx64bit

Has anyone else run into this issue?

I realize I could just flip the definitions in my Managed enum, but that seems awfully kludgy.

Ajay
  • 18,086
  • 12
  • 59
  • 105
DropPhone
  • 396
  • 2
  • 9
  • `GetBinaryType`'s behavior changes whether or not your application is running on WOW64, e.g. if you have "prefer 32-bit" enabled or aren't targeting Any CPU. – vcsjones Apr 07 '16 at 20:43
  • Possibly related: [Detect whether Office is 32bit or 64bit via the registry](http://stackoverflow.com/a/22655027) – kreinsch Apr 07 '16 at 21:09
  • 1
    Possible duplicate of [Why do I get nonsense from GetModuleFileNameEx on 64-bit Windows 8?](https://stackoverflow.com/questions/25063530/why-do-i-get-nonsense-from-getmodulefilenameex-on-64-bit-windows-8) – TAbdiukov Nov 22 '19 at 03:35
  • 1
    Is your C# program compiled as 64-bit or 32-bit? If 32-but, it may be experiencing redirection. – Raymond Chen Nov 22 '19 at 03:46

1 Answers1

0

This is a WinAPI bug/developer's oversight. You may find this related question useful to read, and 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.

I ended up going for a completely different workaround. This answer about PE headers mentions the PE headers among 32 and 64 bit Windows executables. You can completely circumvent the WinAPI checking, and have your target executable checked via reading it in the Binary mode and checking if it matches the PE signature.

Sadly, there isn't much info on the problem online. I remember seeing this problem on some forum, where is was clearly listed as bug, but this was about ~10 years ago. I hope as we discuss this problem, more people become aware of it.

Community
  • 1
  • 1
TAbdiukov
  • 1,185
  • 3
  • 12
  • 25