Detect if an assembly is a managed assembly

While using a great IOC/DI container (read for those not familiar with it read this post) I wrote some code to auto detect and auto load the necessary dependencies (I really, really, REALLY hate the XML configuration file so …) Besides a lot of other issues with this method worth a blog post on it’s own, the whole thing crashed as soon as an unmanaged assembly was found in the path.

After some googling I found a few ways to solve my problem:

Use .Net Reflection:

Try to do a AssemblyName.GetAssemblyName(path); If it throws an exception it’s not a managed assembly. As you would suspect this is horribly slow.

Read the binary data from the assembly to detect the assembly type.

Actually the .Net managed assemblies are with specific values in the header. To read these we could use the command and then walk through the headers with pointers as explained on this site. Since this loads the assembly in memory it was a no-go for me.

There are alot of unmanaged solutions out there (read here and here) that are candidates to port to c# but Rupreet’s weblog saved the day. And here are the relevant code fragments of my AssemblyInfo class:

   1:  try
   2:  {
   3:      if (dataDictionaryRVA == null)
   4:      {
   5:          GetHeaders();
   6:      }
   7:      return dataDictionaryRVA[14] != 0;
   8:  }
   9:  catch (Exception)
  10:  {
  11:      // when an error occurs return false.
  12:  }
  13:  return false;

Obviously the interesting code is inside the GetHeaders method including the comments from Rupreet:

   1: dataDictionaryRVA = new uint[16];
   2: dataDictionarySize = new uint[16];
   3:  
   4: using (FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read))
   5: {
   6:     BinaryReader reader = new BinaryReader(fs);
   7:  
   8:     //PE Header starts @ 0x3C (60). Its a 4 byte header.
   9:     fs.Position = PeHeaderStart;
  10:     peHeader = reader.ReadUInt32();
  11:  
  12:     //Moving to PE Header start location...
  13:     fs.Position = peHeader;
  14:     peHeaderSignature = reader.ReadUInt32();
  15:  
  16:     //We can also show all these value, but we will be       
  17:     //limiting to the CLI header test.
  18:     machine = reader.ReadUInt16();
  19:     sections = reader.ReadUInt16();
  20:     timestamp = reader.ReadUInt32();
  21:     pSymbolTable = reader.ReadUInt32();
  22:     noOfSymbol = reader.ReadUInt32();
  23:     optionalHeaderSize = reader.ReadUInt16();
  24:     characteristics = reader.ReadUInt16();
  25:  
  26:     /*
  27:     Now we are at the end of the PE Header and from here, the
  28:     PE Optional Headers starts...
  29:     To go directly to the datadictionary, we'll increase the      
  30:     stream’s current position to with 96 (0x60). 96 because,
  31:     28 for Standard fields
  32:     68 for NT-specific fields
  33:     From here DataDictionary starts...and its of total 128 bytes. DataDictionay has 16 directories in total,
  34:     doing simple maths 128/16 = 8.
  35:     So each directory is of 8 bytes.
  36:     In this 8 bytes, 4 bytes is of RVA and 4 bytes of Size.
  37: 
  38:     btw, the 15th directory consist of CLR header! if its 0, its not a CLR file :)
  39:     */
  40:  
  41:     dataDictionaryStart = Convert.ToUInt16(Convert.ToUInt16(fs.Position) + 0x60);
  42:     fs.Position = dataDictionaryStart;
  43:  
  44:     for (int i = 0; i < 15; i++)
  45:     {
  46:         dataDictionaryRVA[i] = reader.ReadUInt32();
  47:         dataDictionarySize[i] = reader.ReadUInt32();
  48:     }
  49:  
  50:     fs.Close();
  51: }

My complete class implementation is here:

   1: using System;
   2: using System.IO;
   3: using System.Reflection;
   4:  
   5: namespace Williame.Koen.Blog
   6: {
   7:     /// <summary>
   8:     /// Returns information about an assembly without loading it into the appdomain.
   9:     /// </summary>
  10:     public class AssemblyInfo
  11:     {
  12:         /// <summary>
  13:         /// PE Header starts @ 0x3C (60). Its a 4 byte header.
  14:         /// </summary>
  15:         public const long PeHeaderStart = 0x3C;
  16:  
  17:         protected uint peHeader;
  18:         protected uint peHeaderSignature;
  19:         protected ushort machine;
  20:         protected ushort sections;
  21:         protected uint timestamp;
  22:         protected uint pSymbolTable;
  23:         protected uint noOfSymbol;
  24:         protected ushort optionalHeaderSize;
  25:         protected ushort characteristics;
  26:         protected ushort dataDictionaryStart;
  27:         protected uint[] dataDictionaryRVA;
  28:         protected uint[] dataDictionarySize;
  29:         protected string file;
  30:         protected AssemblyName name; 
  31:  
  32:         public AssemblyInfo(string fileName)
  33:         {
  34:             this.file = Path.GetFullPath(fileName);
  35:         }
  36:  
  37:         protected void GetHeaders()
  38:         {
  39:             dataDictionaryRVA = new uint[16];
  40:             dataDictionarySize = new uint[16];
  41:  
  42:             using (FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read))
  43:             {
  44:                 BinaryReader reader = new BinaryReader(fs);
  45:  
  46:                 //PE Header starts @ 0x3C (60). Its a 4 byte header.
  47:                 fs.Position = PeHeaderStart;
  48:                 peHeader = reader.ReadUInt32();
  49:  
  50:                 //Moving to PE Header start location...
  51:                 fs.Position = peHeader;
  52:                 peHeaderSignature = reader.ReadUInt32();
  53:  
  54:                 //We can also show all these value, but we will be       
  55:                 //limiting to the CLI header test.
  56:                 machine = reader.ReadUInt16();
  57:                 sections = reader.ReadUInt16();
  58:                 timestamp = reader.ReadUInt32();
  59:                 pSymbolTable = reader.ReadUInt32();
  60:                 noOfSymbol = reader.ReadUInt32();
  61:                 optionalHeaderSize = reader.ReadUInt16();
  62:                 characteristics = reader.ReadUInt16();
  63:  
  64:                 /*
  65:                 Now we are at the end of the PE Header and from here, the
  66:                 PE Optional Headers starts...
  67:                 To go directly to the datadictionary, we'll increase the      
  68:                 stream’s current position to with 96 (0x60). 96 because,
  69:                 28 for Standard fields
  70:                 68 for NT-specific fields
  71:                 From here DataDictionary starts...and its of total 128 bytes. DataDictionay has 16 directories in total,
  72:                 doing simple maths 128/16 = 8.
  73:                 So each directory is of 8 bytes.
  74:                 In this 8 bytes, 4 bytes is of RVA and 4 bytes of Size.
  75: 
  76:                 btw, the 15th directory consist of CLR header! if its 0, its not a CLR file :)
  77:                 */
  78:  
  79:                 dataDictionaryStart = Convert.ToUInt16(Convert.ToUInt16(fs.Position) + 0x60);
  80:                 fs.Position = dataDictionaryStart;
  81:  
  82:                 for (int i = 0; i < 15; i++)
  83:                 {
  84:                     dataDictionaryRVA[i] = reader.ReadUInt32();
  85:                     dataDictionarySize[i] = reader.ReadUInt32();
  86:                 }
  87:  
  88:                 fs.Close();
  89:             }
  90:         }
  91:  
  92:         public bool IsManaged
  93:         {
  94:             get
  95:             {
  96:                 try
  97:                 {
  98:                     if (dataDictionaryRVA == null)
  99:                     {
 100:                         GetHeaders();
 101:                     }
 102:                     return dataDictionaryRVA[14] != 0;
 103:                 }
 104:                 catch (Exception)
 105:                 {
 106:                     // when an error occurs return false.
 107:                 }
 108:                 return false;
 109:             }
 110:         }
 111:  
 112:         public AssemblyName Name
 113:         {
 114:             get
 115:             {
 116:                 if (name == null)
 117:                 {
 118:                     name = AssemblyName.GetAssemblyName(file);
 119:                 }
 120:                 return name;
 121:             }
 122:         }
 123:     }
 124: }

As you can see, I also included the AssemblyName which can give me some more information withtout loading the assembly in memory.

Issues:

  • This is example code so be careful with it in production code.
  • In addition, check the "magic" field of the PE header (the first 2 bytes) to ensure it is a 32-bit image file (0x010B). The data directory table for 64-bit PE headers start at offset 112 - as opposed to 96 for 32-bit headers.
  • This example ignores recommendations in Microsoft's PE specification to check the values of size fields so you don't read the wrong data

Tags: , , , , , ,

Comments

payday loans
payday loans United States
11/21/2009 3:05:59 PM Permalink

Hmmm interesting stuff

cash loans
cash loans United States
11/28/2009 9:00:53 PM Permalink

I like what I see. keep it going

anonymous proxy
anonymous proxy Thailand
12/16/2009 9:50:14 PM Permalink

Great insights. I loved to read your article. You must be putting a lot of time into your blog!

proxy
proxy Thailand
12/17/2009 8:03:03 PM Permalink

Great share. Keep up the good work.

Camera lense
Camera lense
12/18/2009 8:44:53 AM Permalink

Excellent post.

Digital camera
Digital camera United States
12/18/2009 9:38:04 AM Permalink

Great post. I like it.

ผลบอล
ผลบอล Thailand
12/21/2009 7:27:48 PM Permalink

This is a very nice post.

unblock myspace
unblock myspace
12/22/2009 9:14:10 AM Permalink

Great blog, this could be the best blog I ever visited thi month. Never stop to write something useful dude!.

fast payday loans
fast payday loans United States
12/27/2009 1:56:18 PM Permalink

thanks!  very helpful post!! like the template btw ;)

Ggler
Ggler United States
12/29/2009 5:49:05 AM Permalink

Nice post. I love it.

Festival Museum Nusantara
Festival Museum Nusantara United States
1/1/2010 11:11:30 PM Permalink

Thanks for posting this info. I just want to let you know that I just check out your site and I find it very interesting and informative. I can’t wait to read lots of your posts.


payday loans
payday loans United States
1/27/2010 10:19:15 AM Permalink

If you realize that all things change, there is nothing you will try to hold on to... there is nothing you cannot achieve.

fast payday loans
fast payday loans United States
1/30/2010 11:00:02 AM Permalink

If someone is going down the wrong road, he doesn't need motivation to speed him up. What he needs is education to turn him around.

cash loans
cash loans United States
2/4/2010 7:19:41 PM Permalink

All men's gains are the fruit of venturing.

lifestyle
lifestyle United States
2/13/2010 11:37:39 AM Permalink

One may walk over the highest mountain one step at a time.

payday loans
payday loans United States
2/14/2010 2:03:13 PM Permalink

Make no small plans for they have no power to stir the soul.

Nicolas Daul
Nicolas Daul United States
2/17/2010 5:58:20 PM Permalink

This is a excellent post, but I was wondering how do I suscribe to the RSS feed?

Arianne Grum
Arianne Grum United States
2/19/2010 1:20:04 AM Permalink

This is a very fascinating post, I was looking for this info. Just so you know I located your webpage when I was browsing for blogs like mine, so please check out my site sometime and leave me a comment to let me know what you think.

Ella Voltz
Ella Voltz United States
2/19/2010 2:04:37 PM Permalink

This is a good write-up, I was wondering if I could use this write-up on my website, I will link it back to your website though. If this is a problem please let me know and I will take it down right away.

Berry Vasko
Berry Vasko United States
2/20/2010 5:14:21 AM Permalink

I have read a few of the articles on your website now, and I really like your style of blogging. I added it to my favorites blog list and will be checking back soon. Please check out my site as well and let me know what you think.

Rudy Mccloude
Rudy Mccloude United States
2/20/2010 2:50:56 PM Permalink

This is a very important post, I was looking for this info. Just so you know I located your blog site when I was checking for blogs like mine, so please check out my site sometime and leave me a comment to let me know what you think.

Soon Kingham
Soon Kingham United States
2/20/2010 11:34:33 PM Permalink

I have read a few of the articles on your website now, and I really like your style of blogging. I added it to my favorites website list and will be checking back soon. Please check out my site as well and let me know what you think.

Noah Rosenstock
Noah Rosenstock United States
2/22/2010 2:02:26 AM Permalink

This is a good article, I was wondering if I could use this posting on my website, I will link it back to your website though. If this is a problem please let me know and I will take it down right away.

Luba Yetto
Luba Yetto United States
2/22/2010 3:01:49 PM Permalink

Im pleased I located this site, I couldnt discover any information on this subject matter before. I also operate a website and if you wish to ever serious in a little bit of guest writing for me make sure you feel free to let me know, im always look for people to check out my web site. Please stop by and leave a comment sometime!

Lori Malpica
Lori Malpica United States
2/25/2010 4:43:41 AM Permalink

This is a very fascinating post, I was looking for this information. Just so you know I discovered your weblog when I was browsing for blogs like mine, so please check out my site sometime and leave me a comment to let me know what you think.

Bettye Meloan
Bettye Meloan United States
2/25/2010 3:08:29 PM Permalink

Im glad I discovered this weblog, I couldnt get any information on this subject before. Also operate a website and if you're ever serious in doing some visitor writing for me make sure you feel free to let me know, im always look for people to check out my web site. Please stop by and leave a comment sometime!

Kiesha Healey
Kiesha Healey United States
2/26/2010 1:21:10 AM Permalink

This is a good piece of writing, I discovered your web page looking around google for a similar subject and came to this. I couldnt find to much different information on this blog, so it was good to discover this one. I will certainly end up being back again to look at some other articles that you have another time.

Lucien Measeck
Lucien Measeck United States
2/26/2010 11:29:14 AM Permalink

I don't agree with everything in this summary, but you do make some very good points. Im very interested in this topic and I myself do alot of research as well. Either way it was a well thoughtout and nice read so I figured I would leave you a comment. Feel free to check out my website sometime and let me know what you think.

Add comment




  Country flag

biuquote
  • Comment
  • Preview
Loading