How to find if a native DLL file is compiled as x64 or x86?

116,534

Solution 1

You can use DUMPBIN too. Use the /headers or /all flag and its the first file header listed.

dumpbin /headers cv210.dll

64-bit

Microsoft (R) COFF/PE Dumper Version 10.00.30319.01
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file cv210.dll

PE signature found

File Type: DLL

FILE HEADER VALUES
            8664 machine (x64)
               6 number of sections
        4BBAB813 time date stamp Tue Apr 06 12:26:59 2010
               0 file pointer to symbol table
               0 number of symbols
              F0 size of optional header
            2022 characteristics
                   Executable
                   Application can handle large (>2GB) addresses
                   DLL

32-bit

Microsoft (R) COFF/PE Dumper Version 10.00.30319.01
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file acrdlg.dll

PE signature found

File Type: DLL

FILE HEADER VALUES
             14C machine (x86)
               5 number of sections
        467AFDD2 time date stamp Fri Jun 22 06:38:10 2007
               0 file pointer to symbol table
               0 number of symbols
              E0 size of optional header
            2306 characteristics
                   Executable
                   Line numbers stripped
                   32 bit word machine
                   Debug information stripped
                   DLL

'find' can make life slightly easier:

dumpbin /headers cv210.dll |find "machine"
        8664 machine (x64)

Solution 2

There is an easy way to do this with CorFlags. Open the Visual Studio Command Prompt and type "corflags [your assembly]". You'll get something like this:

c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC>corflags "C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Data.dll"

Microsoft (R) .NET Framework CorFlags Conversion Tool. Version 3.5.21022.8 Copyright (c) Microsoft Corporation. All rights reserved.

Version : v2.0.50727 CLR Header: 2.5 PE : PE32 CorFlags : 24 ILONLY : 0 32BIT : 0 Signed : 1

You're looking at PE and 32BIT specifically.

  • Any CPU:

    PE: PE32
    32BIT: 0

  • x86:

    PE: PE32
    32BIT: 1

  • x64:

    PE: PE32+
    32BIT: 0

Solution 3

This trick works and requires only Notepad.

Open the dll file using a text editor (like Notepad) and find the first occurrence of the string PE. The following character defines if the dll is 32 or 64 bits.

32 bits:

PE  L

64 bits:

PE  d†

Solution 4

The Magic field of the IMAGE_OPTIONAL_HEADER (though there is nothing optional about the header in Windows executable images (DLL/EXE files)) will tell you the architecture of the PE.

Here's an example of grabbing the architecture from a file.

public static ushort GetImageArchitecture(string filepath) {
    using (var stream = new System.IO.FileStream(filepath, System.IO.FileMode.Open, System.IO.FileAccess.Read))
    using (var reader = new System.IO.BinaryReader(stream)) {
        //check the MZ signature to ensure it's a valid Portable Executable image
        if (reader.ReadUInt16() != 23117) 
            throw new BadImageFormatException("Not a valid Portable Executable image", filepath);

        // seek to, and read, e_lfanew then advance the stream to there (start of NT header)
        stream.Seek(0x3A, System.IO.SeekOrigin.Current); 
        stream.Seek(reader.ReadUInt32(), System.IO.SeekOrigin.Begin);

        // Ensure the NT header is valid by checking the "PE\0\0" signature
        if (reader.ReadUInt32() != 17744)
            throw new BadImageFormatException("Not a valid Portable Executable image", filepath);

        // seek past the file header, then read the magic number from the optional header
        stream.Seek(20, System.IO.SeekOrigin.Current); 
        return reader.ReadUInt16();
    }
}

The only two architecture constants at the moment are:

0x10b - PE32
0x20b - PE32+

Cheers

UPDATE It's been a while since I posted this answer, yet I still see that it gets a few upvotes now and again so I figured it was worth updating. I wrote a way to get the architecture of a Portable Executable image, which also checks to see if it was compiled as AnyCPU. Unfortunately the answer is in C++, but it shouldn't be too hard to port to C# if you have a few minutes to look up the structures in WinNT.h. If people are interested I'll write a port in C#, but unless people actually want it I wont spend much time stressing about it.

#include <Windows.h>

#define MKPTR(p1,p2) ((DWORD_PTR)(p1) + (DWORD_PTR)(p2))

typedef enum _pe_architecture {
    PE_ARCHITECTURE_UNKNOWN = 0x0000,
    PE_ARCHITECTURE_ANYCPU  = 0x0001,
    PE_ARCHITECTURE_X86     = 0x010B,
    PE_ARCHITECTURE_x64     = 0x020B
} PE_ARCHITECTURE;

LPVOID GetOffsetFromRva(IMAGE_DOS_HEADER *pDos, IMAGE_NT_HEADERS *pNt, DWORD rva) {
    IMAGE_SECTION_HEADER *pSecHd = IMAGE_FIRST_SECTION(pNt);
    for(unsigned long i = 0; i < pNt->FileHeader.NumberOfSections; ++i, ++pSecHd) {
        // Lookup which section contains this RVA so we can translate the VA to a file offset
        if (rva >= pSecHd->VirtualAddress && rva < (pSecHd->VirtualAddress + pSecHd->Misc.VirtualSize)) {
            DWORD delta = pSecHd->VirtualAddress - pSecHd->PointerToRawData;
            return (LPVOID)MKPTR(pDos, rva - delta);
        }
    }
    return NULL;
}

PE_ARCHITECTURE GetImageArchitecture(void *pImageBase) {
    // Parse and validate the DOS header
    IMAGE_DOS_HEADER *pDosHd = (IMAGE_DOS_HEADER*)pImageBase;
    if (IsBadReadPtr(pDosHd, sizeof(pDosHd->e_magic)) || pDosHd->e_magic != IMAGE_DOS_SIGNATURE)
        return PE_ARCHITECTURE_UNKNOWN;

    // Parse and validate the NT header
    IMAGE_NT_HEADERS *pNtHd = (IMAGE_NT_HEADERS*)MKPTR(pDosHd, pDosHd->e_lfanew);
    if (IsBadReadPtr(pNtHd, sizeof(pNtHd->Signature)) || pNtHd->Signature != IMAGE_NT_SIGNATURE)
        return PE_ARCHITECTURE_UNKNOWN;

    // First, naive, check based on the 'Magic' number in the Optional Header.
    PE_ARCHITECTURE architecture = (PE_ARCHITECTURE)pNtHd->OptionalHeader.Magic;

    // If the architecture is x86, there is still a possibility that the image is 'AnyCPU'
    if (architecture == PE_ARCHITECTURE_X86) {
        IMAGE_DATA_DIRECTORY comDirectory = pNtHd->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR];
        if (comDirectory.Size) {
            IMAGE_COR20_HEADER *pClrHd = (IMAGE_COR20_HEADER*)GetOffsetFromRva(pDosHd, pNtHd, comDirectory.VirtualAddress);
            // Check to see if the CLR header contains the 32BITONLY flag, if not then the image is actually AnyCpu
            if ((pClrHd->Flags & COMIMAGE_FLAGS_32BITREQUIRED) == 0)
                architecture = PE_ARCHITECTURE_ANYCPU;
        }
    }

    return architecture;
}

The function accepts a pointer to an in-memory PE image (so you can choose your poison on how to get it their; memory-mapping or reading the whole thing into memory...whatever).

Solution 5

For an unmanaged DLL file, you need to first check if it is a 16-bit DLL file (hopefully not). Then check the IMAGE\_FILE_HEADER.Machine field.

Someone else took the time to work this out already, so I will just repeat here:

To distinguish between a 32-bit and 64-bit PE file, you should check IMAGE_FILE_HEADER.Machine field. Based on the Microsoft PE and COFF specification below, I have listed out all the possible values for this field: http://download.microsoft.com/download/9/c/5/9c5b2167-8017-4bae-9fde-d599bac8184a/pecoff_v8.doc

IMAGE_FILE_MACHINE_UNKNOWN 0x0 The contents of this field are assumed to be applicable to any machine type

IMAGE_FILE_MACHINE_AM33 0x1d3 Matsushita AM33

IMAGE_FILE_MACHINE_AMD64 0x8664 x64

IMAGE_FILE_MACHINE_ARM 0x1c0 ARM little endian

IMAGE_FILE_MACHINE_EBC 0xebc EFI byte code

IMAGE_FILE_MACHINE_I386 0x14c Intel 386 or later processors and compatible processors

IMAGE_FILE_MACHINE_IA64 0x200 Intel Itanium processor family

IMAGE_FILE_MACHINE_M32R 0x9041 Mitsubishi M32R little endian

IMAGE_FILE_MACHINE_MIPS16 0x266 MIPS16

IMAGE_FILE_MACHINE_MIPSFPU 0x366 MIPS with FPU

IMAGE_FILE_MACHINE_MIPSFPU16 0x466 MIPS16 with FPU

IMAGE_FILE_MACHINE_POWERPC 0x1f0 Power PC little endian

IMAGE_FILE_MACHINE_POWERPCFP 0x1f1 Power PC with floating point support

IMAGE_FILE_MACHINE_R4000 0x166 MIPS little endian

IMAGE_FILE_MACHINE_SH3 0x1a2 Hitachi SH3

IMAGE_FILE_MACHINE_SH3DSP 0x1a3 Hitachi SH3 DSP

IMAGE_FILE_MACHINE_SH4 0x1a6 Hitachi SH4

IMAGE_FILE_MACHINE_SH5 0x1a8 Hitachi SH5

IMAGE_FILE_MACHINE_THUMB 0x1c2 Thumb

IMAGE_FILE_MACHINE_WCEMIPSV2 0x169 MIPS little-endian WCE v2

Yes, you may check IMAGE_FILE_MACHINE_AMD64|IMAGE_FILE_MACHINE_IA64 for 64bit and IMAGE_FILE_MACHINE_I386 for 32bit.

Share:
116,534
Ohad Horesh
Author by

Ohad Horesh

Updated on July 08, 2022

Comments

  • Ohad Horesh
    Ohad Horesh almost 2 years

    I want to determine if a native assembly is complied as x64 or x86 from a managed code application (C#).

    I think it must be somewhere in the PE header since the OS loader needs to know this information, but I couldn't find it. Of course I prefer to do it in managed code, but if it necessary, I can use native C++.

  • Ohad Horesh
    Ohad Horesh about 14 years
    @BLogan you should look at my comment to Steven Behnke above. I'm aware of the corflags utility but it doesn't work on native assemblies.
  • Ant
    Ant about 13 years
    Slightly more user friendly ;)
  • Samuel
    Samuel almost 12 years
    Very interesting but when I have an application compiled with Any CPU, the result is 0x10B. This is wrong because my application is run in a x64 system. Is there any other flag to check?
  • Jason Larke
    Jason Larke almost 12 years
    AnyCPU means just that: AnyCPU, so it's listed as 0x10B in the PE header for backwards compatibility with 32-bit. To check the difference between that and straight 32-bit, you'd need to find out where CorFlags gets its 32BIT flag from in the PE, I don't know off the top of my head.
  • Jason Larke
    Jason Larke about 11 years
    @Samuel Updated to check the AnyCPU flag.
  • Pierre
    Pierre over 10 years
    DUMPBIN doesn't work for .NET EXEs. I have a 64-bit .NET EXE that DUMPBIN says is 32-bit ("14C machine (x86)"), but corflags says is Any CPU ("PE: PE32, 32BIT: 0"). Dependency Walker also misdiagnoses it.
  • Kiquenet
    Kiquenet about 10 years
    that C# code works in a 64 bit process when checking 32 bit assemblies ? For example, Module.GetPEKind msdn.microsoft.com/en-us/library/… fails
  • Jason Larke
    Jason Larke about 10 years
    It should work fine, it's just doing basic IO and interpreting what it reads, nothing too fancy @Kiquenet
  • Dmitry
    Dmitry almost 10 years
    It required mspdb100.dll:(
  • Dmitry
    Dmitry almost 10 years
    Can't find "dt" and "L." on the "Far Manager" HEX viewer.
  • ADTC
    ADTC over 9 years
    @Altaveron I had the same issue, but resolved it by copying the DLL file mspdb100.dll to the folder where dumpbin.exe is located. DUMPBIN can run after that. For me, the EXE is at <Visual Studio Install folder>\VC\bin and the DLL is at <Visual Studio Install folder>\Common7\IDE.
  • Wes
    Wes over 9 years
    What Corflags outputs changed in latter versions (Windows SDK 8 or higher). Now instead of 32BIT it has 32BITREQUIRED and 32BITPREFERRED. See description in CorHdr.h located C:\Program Files (x86)\Windows Kits\8.0\Include\um\CorHdr.h. From what I can tell 32BITREQUIRED replaces 32BIT. Also see answer to this question.
  • gpalex
    gpalex over 8 years
    your second link is dead :s
  • Grault
    Grault over 8 years
    Windows 10: >corflags libzmq.dll \n\n ... corflags : error CF008 : The specified file does not have a valid managed header
  • Zax
    Zax almost 8 years
    Showed as d. and L.
  • Alan Macdonald
    Alan Macdonald about 7 years
    DUMPBIN is available from Visual Studio command prompt for those with Visual Studio installed
  • Richard Lalancette
    Richard Lalancette about 3 years
    Cool. That was my issue. (rg = ripgrep is now available on windows) I used this on the VS terminal: dumpbin.exe /headers .\ImGuiExtension.dll | rg machine