31

I was asked in an interview as to how Windows OS differentiate between a regular EXE and a .NET EXE.

My reply was, when a .NET exe is build, the compiler puts some information into the header. The information is PE32 or PE32+. Windows verifies the header to determine if it needs to load MSCOREE.dll which loads the CLR and executes the EXE.

Is my answer correct?

Cole Tobin
  • 9,206
  • 15
  • 49
  • 74
AlwaysAProgrammer
  • 2,927
  • 2
  • 31
  • 40
  • 8
    wow, that's a rough interview question – brydgesk Apr 14 '10 at 15:53
  • 6
    a no mercy question ;) – Jhonny D. Cano -Leftware- Apr 14 '10 at 15:55
  • 6
    The person doing the interview probably just read a book about the CLR or IL the night before. – Matthew Whited Apr 14 '10 at 16:18
  • 1
    Correct answer. If I was interviewing you, that would be a standard question, and not regarded rough at all. That would be an easy question. Fail that and you fail the interview, no point asking any more detailed questions. – Stephen Kellett May 12 '10 at 16:37
  • I can't agree. A .NET EXE is a 'regular EXE'. It's just one that happens to load the framework first. Windows as an Operating System does not differentiate at all. – Kieren Johnstone Jul 23 '10 at 21:46
  • 2
    If the job isn't for writing low level code, then it looks like you've run into one of the standard useless large company technical interview questions. It's like asking a train conductor what size are the pistons in the train engine. No relation to reality. – Andrew Lewis Jul 23 '10 at 21:47
  • 1
    @KierenJohnstone: That's wrong. At first glance it seems like what you said. But if you try some modifications to the EXE file you will see that Windows OS does completely different path when it detects that the running application is a .NET app. – Vahid Nasehi Feb 12 '12 at 00:11
  • Did you accepted for this job? :) – Uğur Aldanmaz Mar 06 '14 at 09:52

4 Answers4

17

I think that the following two links are a good resource to get an understanding the PE file structure and the Windows loader.

The exact quote from the March 2002 article, which I believe answers your question, is:

The primary purpose of a .NET executable is to get the .NET-specific information such as metadata and intermediate language (IL) into memory. In addition, a .NET executable links against MSCOREE.DLL. This DLL is the starting point for a .NET process. When a .NET executable loads, its entry point is usually a tiny stub of code. That stub just jumps to an exported function in MSCOREE.DLL (_CorExeMain or _CorDllMain). From there, MSCOREE takes charge, and starts using the metadata and IL from the executable file. This setup is similar to the way apps in Visual Basic (prior to .NET) used MSVBVM60.DLL.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Doruk
  • 171
  • 5
6

While I agree with GregC in general there are times when this type of information is useful. But that is one tough question to be expected to answer in an interview (unless it's for the CLR team :)

Web Pages and Blogs...

Books...

Matthew Whited
  • 22,160
  • 4
  • 52
  • 69
5

In brief, and it has been a while so some of this might be a little dated...

For XP and later, the OS loader is enhanced to detect managed assemblies based on a PE directory entry, if the directory entry is present the loader automatically loads the mscoree.dll and a jump is made to a function in mscoree, _CorExeMain(2) for executables and _CorDllMain for dlls. _CorExeMain is then responsible for loading the CLR and kickstarting the execution of the managed code.

I used the following to remind myself of the entry point names...

C:\Windows\System32>dumpbin -exports mscoree.dll
Microsoft (R) COFF/PE Dumper Version 9.00.30729.01
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file mscoree.dll

File Type: DLL

  Section contains the following exports for mscoree.dll

    00000000 characteristics
    4AF3AF84 time date stamp Fri Nov 06 07:09:24 2009
        0.00 version
          17 ordinal base
         126 number of functions
         123 number of names

    ordinal hint RVA      name

         38    0 0001AAA0 CLRCreateInstance
... Lots of stuff left out...
        136   76 00015030 _CorDllMain
        138   77 00004DDB _CorExeMain
        137   78 0001A981 _CorExeMain2
        139   79 0002033B _CorImageUnloading
        140   7A 000042D0 _CorValidateImage
         24      00008017 [NONAME]
        142      00014C4D [NONAME]

  Summary

        4000 .data
        4000 .reloc
        1000 .rsrc
       40000 .text
Chris Taylor
  • 52,623
  • 10
  • 78
  • 89
  • While tempting to look at a DLL's imports to see if it imports from mscoree.dll this is not the right way to determine if a DLL/EXE uses .Net. You cannot rely on being linked to mscoree.dll. That will be true for a native DLL that uses .Net as well as for a .Net only dll. You need to also look at the PE header characteristics to know for sure if .Net only or mixed mode. We've been caught out in the past by looking only for mscoree.dll and making assumptions based on its presence/absence. – Stephen Kellett May 12 '10 at 16:40
  • @Stephen Kellet, I agree. But I wonder what your comment has to do with the posted answer? I look at the "exports" to confirm the name of the entry point used to boot strap a .NET exe, this is not to determine if an arbitrary dll is a .NET dll. – Chris Taylor May 12 '10 at 16:49
  • Its relevant because someone could easily jump to the conclusion that if you are looking for mscoree.dll then that is a logical thing to also find in the imports table. – Stephen Kellett May 12 '10 at 17:04
  • This is not quite correct. As far as Windows is concerned, it doesn't know that it's loading a .NET executable. All it knows is that it is loading a native binary along with some dependent DLLs. The executable's entry point is a bootstrapper that jumps to mscoree.dll which starts up the CLR. – Sam Aug 30 '15 at 09:07
  • @Sam, prior to Windows XP you are correct, but starting with XP the windows loader was enhanced to recognize .NET assemblies vs. native assemblies. – Chris Taylor Aug 30 '15 at 09:33
  • @ChrisTaylor hm really? Do you have a reference for that? That could actually explain some weirdness that I'm seeing in something I'm working on. – Sam Aug 30 '15 at 09:41
  • 1
    @Sam, I did a quick google for you, the link below is one of many references I could find on short notice. It refers to the windows module loader in ntdll.dll detecting that it is loading a .NET executable and taking special action. https://books.google.com/books?id=GbNCAwAAQBAJ&pg=PT68&lpg=PT68&dq=how+windows+loads+a+.net+executable&source=bl&ots=mpyMZlTzzZ&sig=ZO-tAKQg8CgD4NQ_TsMVttXaYyk&hl=en&sa=X&ved=0CEcQ6AEwB2oVChMIi5rVvsTQxwIVhRk-Ch2ROgOr#v=onepage&q=how%20windows%20loads%20a%20.net%20executable&f=false – Chris Taylor Aug 30 '15 at 10:00
  • Thank you very much! I had been googling but hadn't found anything concrete yet, just mentions of "XP and later doesn't do this". This explains why the entry point in the PE header of a .NET executable never seems to be executed. It still points to the stub that jumps to `_CorExeMain` for backwards compatibility I assume. Thank you again, I've spent most of the day trying to figure that out! – Sam Aug 30 '15 at 10:17
  • 1
    And of course now that I know what I'm looking for it's obvious. For future searchers, the docs here specify this behaviour: https://msdn.microsoft.com/en-us/library/4ce9k7xb(v=vs.110).aspx – Sam Aug 30 '15 at 10:58
2

Tough question. Did you get the job? ;-)

I know it's been a while, but for anyone looking for an answer: The answer can be found in MSDN here: https://learn.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/corvalidateimage-function

In Windows XP and later versions, the operating system loader checks for managed modules by examining the COM Descriptor Directory bit in the common object file format (COFF) header. A set bit indicates a managed module. If the loader detects a managed module, it loads MsCorEE.dll and calls _CorValidateImage...

You can check this yourself with dumpbin /clrheader (which will be empty for a native module).

If you think about it (at least in .NET4+), this must be done by the loader before the process starts (meaning you could not wait for the module to call CLR initialization routines) because AnyCPU means the loader dynamically determines the bitness of the process, which obviously must be known before the process starts.

Eli Finkel
  • 463
  • 2
  • 13