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: }