How can I determine if a .NET assembly was built for x86 or x64?

186,532

Solution 1

Look at System.Reflection.AssemblyName.GetAssemblyName(string assemblyFile).

You can examine assembly metadata from the returned AssemblyName instance:

Using PowerShell:

[36] C:\> [reflection.assemblyname]::GetAssemblyName("${pwd}\Microsoft.GLEE.dll") | fl

Name                  : Microsoft.GLEE
Version               : 1.0.0.0
CultureInfo           :
CodeBase              : file:///C:/projects/powershell/BuildAnalyzer/...
EscapedCodeBase       : file:///C:/projects/powershell/BuildAnalyzer/...
ProcessorArchitecture : MSIL
Flags                 : PublicKey
HashAlgorithm         : SHA1
VersionCompatibility  : SameMachine
KeyPair               :
FullName              : Microsoft.GLEE, Version=1.0.0.0, Culture=neut...

Here, ProcessorArchitecture identifies the target platform.

  • Amd64: A 64-bit processor based on the x64 architecture.
  • Arm: An ARM processor.
  • IA64: A 64-bit Intel Itanium processor only.
  • MSIL: Neutral with respect to processor and bits-per-word.
  • X86: A 32-bit Intel processor, either native or in the Windows on Windows environment on a 64-bit platform (WoW64).
  • None: An unknown or unspecified combination of processor and bits-per-word.

I'm using PowerShell in this example to call the method.

Solution 2

You can use the CorFlags CLI tool (for instance, C:\Program Files\Microsoft SDKs\Windows\v7.0\Bin\CorFlags.exe) to determine the status of an assembly, based on its output and opening an assembly as a binary asset you should be able to determine where you need to seek to determine if the 32BIT flag is set to 1 (x86) or 0 (Any CPU or x64, depending on PE):

Option    | PE    | 32BIT
----------|-------|---------
x86       | PE32  | 1
Any CPU   | PE32  | 0
x64       | PE32+ | 0

The blog post x64 Development with .NET has some information about corflags.

Even better, you can use Module.GetPEKind to determine whether an assembly is PortableExecutableKinds value PE32Plus (64-bit), Required32Bit (32-bit and WoW), or ILOnly (any CPU) along with other attributes.

Solution 3

Just for clarification, CorFlags.exe is part of the .NET Framework SDK. I have the development tools on my machine, and the simplest way for me determine whether a DLL is 32-bit only is to:

  1. Open the Visual Studio Command Prompt (In Windows: menu Start/Programs/Microsoft Visual Studio/Visual Studio Tools/Visual Studio 2008 Command Prompt)

  2. CD to the directory containing the DLL in question

  3. Run corflags like this: corflags MyAssembly.dll

You will get output something like this:

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  : 3
ILONLY    : 1
32BIT     : 1
Signed    : 0

As per comments the flags above are to be read as following:

  • Any CPU: PE = PE32 and 32BIT = 0
  • x86: PE = PE32 and 32BIT = 1
  • 64-bit: PE = PE32+ and 32BIT = 0

Solution 4

Just write your own. The core of the PE architecture hasn't been seriously changed since its implementation in Windows 95.

Here's a C# example:

    public static ushort GetPEArchitecture(string pFilePath)
    {
        ushort architecture = 0;
        try
        {
            using (System.IO.FileStream fStream = new System.IO.FileStream(pFilePath, System.IO.FileMode.Open, System.IO.FileAccess.Read))
            {
                using (System.IO.BinaryReader bReader = new System.IO.BinaryReader(fStream))
                {
                    // Check the MZ signature
                    if (bReader.ReadUInt16() == 23117)
                    {
                        // Seek to e_lfanew.
                        fStream.Seek(0x3A, System.IO.SeekOrigin.Current);

                        // Seek to the start of the NT header.
                        fStream.Seek(bReader.ReadUInt32(), System.IO.SeekOrigin.Begin);

                        if (bReader.ReadUInt32() == 17744) // Check the PE\0\0 signature.
                        {
                            // Seek past the file header,
                            fStream.Seek(20, System.IO.SeekOrigin.Current);

                            // Read the magic number of the optional header.
                            architecture = bReader.ReadUInt16();
                        }
                    }
                }
            }
        }
        catch (Exception) { /* TODO: Any exception handling you want
                                     to do, personally I just take 0
                                     as a sign of failure */
        }

        // If architecture returns 0, there has been an error.
        return architecture;
    }
}

Now the current constants are:

0x10B - PE32  format.
0x20B - PE32+ format.

But with this method it allows for the possibilities of new constants. Just validate the return as you see fit.

Solution 5

DotPeek from JetBrains provides a quick and easy way to see msil (Any CPU), x86, and x64:

DotPeek

Share:
186,532
Judah Gabriel Himango
Author by

Judah Gabriel Himango

Web developer, speaker, entrepreneur, startup founder, musician, dad, husband, Jewish follower of Jesus. I created Youth Service Network's YsnMN. It's an awesome project to help homeless youth in Minnesota. I blogged about it here, and that blog post made it to the front page of HackerNews - woohooo!) I created Chavah, a Pandora-like PWA for the Messianic Jewish religious community. I'm a RavenDB enthusiast and helped create Raven Studio. I help run Twin Cities Code Camp and built TwinCitiesCodeCamp.com. I built 3M's Visual Attention Software. I'm the creator of MessianicChords.com, an ad-free HTML5 site for lyrics and guitar chords to Messianic Jewish music. I built EtzMitzvot.com, a fun project visualizing the relationship between commandments in the Hebrew Bible. I blog about software at DebuggerDotBreak, and on life and faith over at Kineti.

Updated on July 08, 2022

Comments

  • Judah Gabriel Himango
    Judah Gabriel Himango almost 2 years

    I've got an arbitrary list of .NET assemblies.

    I need to programmatically check if each DLL was built for x86 (as opposed to x64 or Any CPU). Is this possible?

  • Judah Gabriel Himango
    Judah Gabriel Himango over 15 years
    After seeing your update, using the GetPEKind seems to be the proper way to do this. I've marked yours as the answer.
  • Scott Dorman
    Scott Dorman over 14 years
    Excellent tip about Module.GetPEKind, never knew about that until now. I've always used the corflags tool.
  • jjxtra
    jjxtra about 14 years
    GetPEKind fails in a 64 bit process when checking 32 bit assemblies
  • Rabeel
    Rabeel over 12 years
    Use ILSpy, it's a basic open source app that does much the same things as Reflector
  • Judah Gabriel Himango
    Judah Gabriel Himango about 12 years
    Interesting, thanks for the code with explanation. Module.GetPEKind is probably the easiest path. But this is helpful for learning's sake. Thanks.
  • 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?
  • Abhishek
    Abhishek over 11 years
    Forgive the stupid question - but what in this tells you that it's x86?
  • Brian Gillespie
    Brian Gillespie over 11 years
    The ProcessorArchitecture field is an enumeration; in the above example it is set to MSIL, which means "Neutral with respect to processor and bits-per-word." Other values include X86, IA64, Amd64. See msdn.microsoft.com/en-us/library/… for more details.
  • Ludwo
    Ludwo about 11 years
    You have to call GetPEKind from 32bit process
  • Kirill Osenkov
    Kirill Osenkov about 11 years
    This is the most accurate and useful answer.
  • PeterX
    PeterX over 10 years
    I get the following error trying to use PowerShell: Exception calling "GetAssemblyName" with "1" argument(s): "Could not load file or assembly '[DLLName].dll' or one of its dependencies. The system cannot find the file specified." (Yes, I've spelt it correctly).
  • x0n
    x0n over 10 years
    Try with [reflection.assemblyname]::GetAssemblyName("${pwd}\name.dll"‌​) as sometimes the process's current directory is not the same as the current provider's (which is where I assume the DLL is for you)
  • x0n
    x0n over 10 years
    Another caveat to look out for is forgetting to "unblock" the DLL if you downloaded it from the internets. Use unblock-file, or right click/properties/unblock from explorer. You will need to restart the shell for it to recognize the unblocked status if you've already failed once in the current session (blame internet explorer for that - yes, really.)
  • Kiquenet
    Kiquenet about 10 years
    What's is better: AssemblyName.ProcessorArchitecture, CorFlags, or PE reader stackoverflow.com/a/9767750/206730 ?
  • Kiquenet
    Kiquenet about 10 years
    I install VS 2008, VS 2010, VS 2012 and VS 2013. I have 8 files CorFlags.exe in subfolders in C:\Program Files (x86)\Microsoft SDKs\Windows\. Which I should be use ?
  • cfeduke
    cfeduke about 10 years
    md5sum each executable to see if any of them are different (or just check the file size and modified date); I suspect any one of them will work just fine.
  • Kiquenet
    Kiquenet about 10 years
    @cfeduke file size are differents for both version
  • Kiquenet
    Kiquenet about 10 years
    any "parser" for using corflags.exe programatically in C# (Process.Start and redirect output) ? Or better use stackoverflow.com/a/14936673/206730 ?
  • Kiquenet
    Kiquenet about 10 years
    @Ludwo any full source code sample using GetPEKind from 32 bit process?. PsychoDad says GetPEKind fails in a 64 bit process when checking 32 bit assemblies
  • Kiquenet
    Kiquenet about 10 years
    GetPEArchitecture works for assemblies compiled using .net 3.5, 4.0, 4.5 and 4.5.1 ? Anyways, I think, Module.GetPEKind fails in a 64 bit process when checking 32 bit assemblies.
  • Ludwo
    Ludwo about 10 years
    Check my answer below
  • metadings
    metadings over 9 years
    In ASP.NET MVC code, there is a comment // DevDiv 216459: This code originally used Assembly.GetName(), but that requires FileIOPermission, which isn't granted in medium trust. However, Assembly.FullName *is* accessible in medium trust. Sadly, there's no way to read ProcessorArchitecture without using the GetName instance method; using AssemblyName constructor, the field is always set to None.
  • angularsen
    angularsen over 9 years
    As pointed out in this answer, in .NET 4.5 there is 32BITREQ and 32BITPREF instead of the 32BIT flag. PE32/0/0 and PE32/0/1 are AnyCPU and AnyCPU 32-bit preferred, respectively.
  • Mido
    Mido about 9 years
    Thanks for this, One of our applications has to be built as x86, adding a unit test ensures that the build server's build libraries will be 32bit and avoids those mistakes from happening :)
  • O. R. Mapper
    O. R. Mapper about 9 years
    This just shows "Error: is not a valid Win32 application."
  • O. R. Mapper
    O. R. Mapper about 9 years
    This seems to have changed meanwhile; corflags now displays 32BITREQ and 32BITPREF rather than a single 32BIT value.
  • Kraang Prime
    Kraang Prime over 7 years
    How does this work when the exe/com/dll file is not built using .NET framework ? An example would be write.exe from Windows 95, or win386.dll from Windows 3.1, or himem.sys from DOS 6.x .
  • x0n
    x0n over 7 years
    @SamuelJackson The question clearly qualifies the input as being a .NET assembly. If it's not, that's a different question to solve. The code will fail to load the DLL, and will throw an exception.
  • RBT
    RBT about 7 years
    Microsoft .NET 4.5 introduced a new option, Any CPU 32-bit Preferred. Here are the details.
  • Peter Mortensen
    Peter Mortensen almost 7 years
    The link still works as of this writing, but as CodePlex is about to be shut down, it would be good to do the appropriate action before it is too late.
  • Uwe Keim
    Uwe Keim over 4 years
    The "Visual Studio Command Prompt" is nowadays called "Visual Studio 2019 Developer Command Prompt".
  • Ben Voigt
    Ben Voigt almost 4 years
    The "source code (zip)" download has a project file containing hard-coded paths to files on your computer and not included in the download :(
  • Peter Mortensen
    Peter Mortensen almost 2 years
    The link is utterly and completely broken now: "Hmm. We’re having trouble finding that site. We can’t connect to the server at apichange.codeplex.com."