How can I quickly tell if a EXE or DLL I have is managed code or not?

I spent some time recently trying to disassemble a file and then later learned through some traces in the code that I could have skipped all that work and just used ILspy. How can I avoid repeating that experience in the future?


A managed DLL / Application will have a primary dependency on MSCOREE.dll... So, if you open the DLL in Dependency Walker you have no problems in telling a managed library from an unmanaged one.


Quoted from here.

Other useful MSDN links:

  • 4
    See answers from broadway and peter ferrie. Checking for an mscoree.dll dependency is somewhat reliable, but not 100%. – dyasta Apr 8 '13 at 22:01
  • 3
    To confirm, I made PoCs that imports mscoree.dll and even have fake .NET-looking EntryPoint, but no .COM directory. – Ange Apr 10 '13 at 8:26
  • 2
    That's not a very constructive comment. I'm just trying to prove that COM directory is a more reliable indicator than imports or EntryPoint for this question. – Ange Apr 13 '13 at 5:23

Check the dword at offset 0xE8 (32-bit) or 0xF8 (64-bit) in the PE header. If it's non-zero, it's the pointer to the CLR header. That's a managed file (you can't put random data there because direct .NET parsing support is built into XP and later, so the file won't load if the data aren't valid). The presence of mscoree.dll is not enough in itself, because the application might be doing things with managed files but not be managed itself.

  • 2
    This answer deserves top billing. Allows you to get the answer with NO extra tools besides your brain and a knowledge of the PE header. – avgvstvs Apr 1 '14 at 23:00
  • 2
    The offset can be different depending whether it is a PE32 or PE32+. – Karsten Hahn May 14 '14 at 8:39
  • @Veitch, I finally edited my answer to include that. – peter ferrie May 14 '14 at 15:47
  • FYI This is equivalent to @broadway's answer and Karsten Hahn's answer: offset 0xe8 or 0xf8 is of the VirtualAddress of IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR. – pts Apr 2 '20 at 16:47
  • @pts there is a significant difference: using the #define means a 32-bit program will recognise only a 32-bit program, 64-bit will only recognise 64-bit. This is why I suggested using the hard-coded values. – peter ferrie Apr 9 '20 at 3:48

Checking DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress in the data directory portion of the PE header for a nonzero value is probably the fastest way.

#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 // COM Runtime descriptor


  • This is the method I use. The 14th member of the Data Directory array is IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR , since it isn't listed in the post. We should discourage absolute references like that. – dyasta Apr 7 '13 at 1:03
  • a hexeditor has no concept of data directories, though, hence the absolute offset. – peter ferrie Apr 7 '13 at 23:57
  • 1
    depends on the hex editor, really. 010 has PE templates. – broadway Apr 9 '13 at 18:49

Manually, i prefer to observe the following signs in the PE header:

1- Presence of mscoree!_CorExeMain in the import table.

2- VirtualAddress and Size of the CLR Header/*Com Descriptor* data directory are set. Size set to 0x48.

3- Size of the Base Relocation data directory set to 0x0C i.e. Only one fixup.

Also, one minor sign is:

4- SectionAlignment set to 0x2000.


Try opening it in ILSpy first. It should tell you if the assembly isn't managed.

  • This implies that ILSpy is able to open it, which is not always the case. – Ange Apr 10 '13 at 19:32
  • ILSpy has a specific message if the assembly isn't managed. If it fails to load for another reason I'm sure there's a different message :) Could you show me a managed assembly which ILSpy says isn't managed? – Peter Andersson Apr 10 '13 at 19:39
  • If it fails to load the PE (with managed code or not), it gives some Mono.Cecil.PE.ImageReader error. TinyNet is using the common malware trick of having a small NumOfRVA to hide its COM directory - which fails ILSpy - even though it's using managed code. – Ange Apr 10 '13 at 19:47

The fastest heuristic method I found so far was to check whether it imports mscoree.dll.

In the version resource of mscoree.dll Microsoft calls it: Microsoft .NET Runtime Execution Engine.

  • 1
    No, this won't work, as many other executables also import from mscoree.dll that are not managed assemblies. – Abel Dec 19 '13 at 15:05
  • @Abel examples please. – 0xC0000022L Apr 22 at 14:50
  • 1
    it's 8 years ago :D, but let's try: mscoree.dll could be linked by any compiler (just create a C++ prj) without it becoming a CLR binary.The inverse is also true, some .NET binaries do not have a link to mscoree.dll. And apparently, it may be mscoreei.dll in some cases. I'm not sure about reference assemblies. I'd rely on PE headers, which will give you the .NET version info and CLR. – Abel Apr 26 at 13:37
  • Thanks @Abel ... much appreciated. I am actually really interested (again) in this topic, that's why I asked. – 0xC0000022L Apr 26 at 13:40
  • 1
    I see :). That said, I just checked all loaded binaries that reference mscoree.dll in-memory. The exception on my machine seems to be procexp64.exe, which has a reference to mscoree.dll but is not a CLI assembly. Everything else follows the rule "if it has mscoree.dll, then it is .NET". – Abel Apr 26 at 13:42

In addition to peter ferries answer, some python code to check for the same:

import sys

def unpack(byte):
    return sum([
        ord(b) << (8 * i) for i, b in enumerate(byte)

if len(sys.argv) == 1:
    print >> sys.stderr, "No input file given!"
    myfile = sys.argv[1]

    with open(myfile, "r") as f:
        peoffset = unpack(f.read(2))
        optoffset = peoffset + 24
        magic = f.read(2)
        offset = -1
        if magic == '\x0b\x01':
            offset = 208 + optoffset
            offset = 224 + optoffset
        clr_address = unpack(f.read(4))
        if clr_address == 0:
            print "no managed executable"
            print "managed executable"

CorFlags.exe is a utility that ships with the Windows SDK. Execute that passing in the name of the file in question and if it is a managed file it will tell you what version of the Dotnet framework it uses and whether the file is all managed code or mixed mode, whether it is signed, and a few other useful bits of info.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.