How to find if a native DLL file is compiled as x64 or x86?
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.
Ohad Horesh
Updated on July 08, 2022Comments
-
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++.
-
Vikas Gupta over 9 yearsTo be clear, the dll in question is also a .Net assembly? You say native DLL in title of the post, but native assembly in the description... if you are still actively looking at this post from 09 :)
-
Matt almost 9 yearsYou might also want to check out this one: check-if-unmanaged-dll-is-32-bit-or-64-bit.
-
Wai Ha Lee over 4 years
-
-
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 about 13 yearsSlightly more user friendly ;)
-
Samuel almost 12 yearsVery 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 almost 12 yearsAnyCPU 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 about 11 years@Samuel Updated to check the AnyCPU flag.
-
Pierre over 10 yearsDUMPBIN 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 about 10 yearsthat 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 about 10 yearsIt should work fine, it's just doing basic IO and interpreting what it reads, nothing too fancy @Kiquenet
-
Dmitry almost 10 yearsIt required
mspdb100.dll
:( -
Dmitry almost 10 yearsCan't find "dt" and "L." on the "Far Manager" HEX viewer.
-
ADTC over 9 years@Altaveron I had the same issue, but resolved it by copying the DLL file
mspdb100.dll
to the folder wheredumpbin.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 over 9 yearsWhat 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 over 8 yearsyour second link is dead :s
-
Grault over 8 yearsWindows 10:
>corflags libzmq.dll \n\n ... corflags : error CF008 : The specified file does not have a valid managed header
-
Zax almost 8 yearsShowed as d. and L.
-
Alan Macdonald about 7 yearsDUMPBIN is available from Visual Studio command prompt for those with Visual Studio installed
-
Richard Lalancette about 3 yearsCool. 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