Free cookie consent management tool by TermsFeed Policy Generator

source: branches/RemoveBackwardsCompatibility/HeuristicLab.ExtLibs/HeuristicLab.Cecil/0.9.5/Mono.Cecil-0.9.5/Mono.Cecil/Mono.Cecil.PE/ImageReader.cs @ 18242

Last change on this file since 18242 was 11700, checked in by jkarder, 10 years ago

#2077: created branch and added first version

File size: 16.7 KB
Line 
1//
2// ImageReader.cs
3//
4// Author:
5//   Jb Evain (jbevain@gmail.com)
6//
7// Copyright (c) 2008 - 2011 Jb Evain
8//
9// Permission is hereby granted, free of charge, to any person obtaining
10// a copy of this software and associated documentation files (the
11// "Software"), to deal in the Software without restriction, including
12// without limitation the rights to use, copy, modify, merge, publish,
13// distribute, sublicense, and/or sell copies of the Software, and to
14// permit persons to whom the Software is furnished to do so, subject to
15// the following conditions:
16//
17// The above copyright notice and this permission notice shall be
18// included in all copies or substantial portions of the Software.
19//
20// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27//
28
29using System;
30using System.IO;
31
32using Mono.Cecil.Metadata;
33
34using RVA = System.UInt32;
35
36namespace Mono.Cecil.PE {
37
38  sealed class ImageReader : BinaryStreamReader {
39
40    readonly Image image;
41
42    DataDirectory cli;
43    DataDirectory metadata;
44
45    public ImageReader (Stream stream)
46      : base (stream)
47    {
48      image = new Image ();
49
50      image.FileName = stream.GetFullyQualifiedName ();
51    }
52
53    void MoveTo (DataDirectory directory)
54    {
55      BaseStream.Position = image.ResolveVirtualAddress (directory.VirtualAddress);
56    }
57
58    void MoveTo (uint position)
59    {
60      BaseStream.Position = position;
61    }
62
63    void ReadImage ()
64    {
65      if (BaseStream.Length < 128)
66        throw new BadImageFormatException ();
67
68      // - DOSHeader
69
70      // PE         2
71      // Start        58
72      // Lfanew       4
73      // End          64
74
75      if (ReadUInt16 () != 0x5a4d)
76        throw new BadImageFormatException ();
77
78      Advance (58);
79
80      MoveTo (ReadUInt32 ());
81
82      if (ReadUInt32 () != 0x00004550)
83        throw new BadImageFormatException ();
84
85      // - PEFileHeader
86
87      // Machine        2
88      image.Architecture = ReadArchitecture ();
89
90      // NumberOfSections   2
91      ushort sections = ReadUInt16 ();
92
93      // TimeDateStamp    4
94      // PointerToSymbolTable 4
95      // NumberOfSymbols    4
96      // OptionalHeaderSize 2
97      Advance (14);
98
99      // Characteristics    2
100      ushort characteristics = ReadUInt16 ();
101
102      ushort subsystem;
103      ReadOptionalHeaders (out subsystem);
104      ReadSections (sections);
105      ReadCLIHeader ();
106      ReadMetadata ();
107
108      image.Kind = GetModuleKind (characteristics, subsystem);
109    }
110
111    TargetArchitecture ReadArchitecture ()
112    {
113      var machine = ReadUInt16 ();
114      switch (machine) {
115      case 0x014c:
116        return TargetArchitecture.I386;
117      case 0x8664:
118        return TargetArchitecture.AMD64;
119      case 0x0200:
120        return TargetArchitecture.IA64;
121      }
122
123      throw new NotSupportedException ();
124    }
125
126    static ModuleKind GetModuleKind (ushort characteristics, ushort subsystem)
127    {
128      if ((characteristics & 0x2000) != 0) // ImageCharacteristics.Dll
129        return ModuleKind.Dll;
130
131      if (subsystem == 0x2 || subsystem == 0x9) // SubSystem.WindowsGui || SubSystem.WindowsCeGui
132        return ModuleKind.Windows;
133
134      return ModuleKind.Console;
135    }
136
137    void ReadOptionalHeaders (out ushort subsystem)
138    {
139      // - PEOptionalHeader
140      //   - StandardFieldsHeader
141
142      // Magic        2
143      bool pe64 = ReadUInt16 () == 0x20b;
144
145      //            pe32 || pe64
146
147      // LMajor       1
148      // LMinor       1
149      // CodeSize       4
150      // InitializedDataSize  4
151      // UninitializedDataSize4
152      // EntryPointRVA    4
153      // BaseOfCode     4
154      // BaseOfData     4 || 0
155
156      //   - NTSpecificFieldsHeader
157
158      // ImageBase      4 || 8
159      // SectionAlignment   4
160      // FileAlignement   4
161      // OSMajor        2
162      // OSMinor        2
163      // UserMajor      2
164      // UserMinor      2
165      // SubSysMajor      2
166      // SubSysMinor      2
167      // Reserved       4
168      // ImageSize      4
169      // HeaderSize     4
170      // FileChecksum     4
171      Advance (66);
172
173      // SubSystem      2
174      subsystem = ReadUInt16 ();
175
176      // DLLFlags       2
177      // StackReserveSize   4 || 8
178      // StackCommitSize    4 || 8
179      // HeapReserveSize    4 || 8
180      // HeapCommitSize   4 || 8
181      // LoaderFlags      4
182      // NumberOfDataDir    4
183
184      //   - DataDirectoriesHeader
185
186      // ExportTable      8
187      // ImportTable      8
188      // ResourceTable    8
189      // ExceptionTable   8
190      // CertificateTable   8
191      // BaseRelocationTable  8
192
193      Advance (pe64 ? 90 : 74);
194
195      // Debug        8
196      image.Debug = ReadDataDirectory ();
197
198      // Copyright      8
199      // GlobalPtr      8
200      // TLSTable       8
201      // LoadConfigTable    8
202      // BoundImport      8
203      // IAT          8
204      // DelayImportDescriptor8
205      Advance (56);
206
207      // CLIHeader      8
208      cli = ReadDataDirectory ();
209
210      if (cli.IsZero)
211        throw new BadImageFormatException ();
212
213      // Reserved       8
214      Advance (8);
215    }
216
217    string ReadAlignedString (int length)
218    {
219      int read = 0;
220      var buffer = new char [length];
221      while (read < length) {
222        var current = ReadByte ();
223        if (current == 0)
224          break;
225
226        buffer [read++] = (char) current;
227      }
228
229      Advance (-1 + ((read + 4) & ~3) - read);
230
231      return new string (buffer, 0, read);
232    }
233
234    string ReadZeroTerminatedString (int length)
235    {
236      int read = 0;
237      var buffer = new char [length];
238      var bytes = ReadBytes (length);
239      while (read < length) {
240        var current = bytes [read];
241        if (current == 0)
242          break;
243
244        buffer [read++] = (char) current;
245      }
246
247      return new string (buffer, 0, read);
248    }
249
250    void ReadSections (ushort count)
251    {
252      var sections = new Section [count];
253
254      for (int i = 0; i < count; i++) {
255        var section = new Section ();
256
257        // Name
258        section.Name = ReadZeroTerminatedString (8);
259
260        // VirtualSize    4
261        Advance (4);
262
263        // VirtualAddress 4
264        section.VirtualAddress = ReadUInt32 ();
265        // SizeOfRawData  4
266        section.SizeOfRawData = ReadUInt32 ();
267        // PointerToRawData 4
268        section.PointerToRawData = ReadUInt32 ();
269
270        // PointerToRelocations   4
271        // PointerToLineNumbers   4
272        // NumberOfRelocations    2
273        // NumberOfLineNumbers    2
274        // Characteristics      4
275        Advance (16);
276
277        sections [i] = section;
278
279        if (section.Name == ".reloc")
280          continue;
281
282        ReadSectionData (section);
283      }
284
285      image.Sections = sections;
286    }
287
288    void ReadSectionData (Section section)
289    {
290      var position = BaseStream.Position;
291
292      MoveTo (section.PointerToRawData);
293
294      var length = (int) section.SizeOfRawData;
295      var data = new byte [length];
296      int offset = 0, read;
297
298      while ((read = Read (data, offset, length - offset)) > 0)
299        offset += read;
300
301      section.Data = data;
302
303      BaseStream.Position = position;
304    }
305
306    void ReadCLIHeader ()
307    {
308      MoveTo (cli);
309
310      // - CLIHeader
311
312      // Cb           4
313      // MajorRuntimeVersion    2
314      // MinorRuntimeVersion    2
315      Advance (8);
316
317      // Metadata         8
318      metadata = ReadDataDirectory ();
319      // Flags          4
320      image.Attributes = (ModuleAttributes) ReadUInt32 ();
321      // EntryPointToken      4
322      image.EntryPointToken = ReadUInt32 ();
323      // Resources        8
324      image.Resources = ReadDataDirectory ();
325      // StrongNameSignature    8
326      // CodeManagerTable     8
327      // VTableFixups       8
328      // ExportAddressTableJumps  8
329      // ManagedNativeHeader    8
330    }
331
332    void ReadMetadata ()
333    {
334      MoveTo (metadata);
335
336      if (ReadUInt32 () != 0x424a5342)
337        throw new BadImageFormatException ();
338
339      // MajorVersion     2
340      // MinorVersion     2
341      // Reserved       4
342      Advance (8);
343
344      var version = ReadZeroTerminatedString (ReadInt32 ());
345      image.Runtime = version.ParseRuntime ();
346
347      // Flags    2
348      Advance (2);
349
350      var streams = ReadUInt16 ();
351
352      var section = image.GetSectionAtVirtualAddress (metadata.VirtualAddress);
353      if (section == null)
354        throw new BadImageFormatException ();
355
356      image.MetadataSection = section;
357
358      for (int i = 0; i < streams; i++)
359        ReadMetadataStream (section);
360
361      if (image.TableHeap != null)
362        ReadTableHeap ();
363    }
364
365    void ReadMetadataStream (Section section)
366    {
367      // Offset   4
368      uint start = metadata.VirtualAddress - section.VirtualAddress + ReadUInt32 (); // relative to the section start
369
370      // Size     4
371      uint size = ReadUInt32 ();
372
373      var name = ReadAlignedString (16);
374      switch (name) {
375      case "#~":
376      case "#-":
377        image.TableHeap = new TableHeap (section, start, size);
378        break;
379      case "#Strings":
380        image.StringHeap = new StringHeap (section, start, size);
381        break;
382      case "#Blob":
383        image.BlobHeap = new BlobHeap (section, start, size);
384        break;
385      case "#GUID":
386        image.GuidHeap = new GuidHeap (section, start, size);
387        break;
388      case "#US":
389        image.UserStringHeap = new UserStringHeap (section, start, size);
390        break;
391      }
392    }
393
394    void ReadTableHeap ()
395    {
396      var heap = image.TableHeap;
397
398      uint start = heap.Section.PointerToRawData;
399
400      MoveTo (heap.Offset + start);
401
402      // Reserved     4
403      // MajorVersion   1
404      // MinorVersion   1
405      Advance (6);
406
407      // HeapSizes    1
408      var sizes = ReadByte ();
409
410      // Reserved2    1
411      Advance (1);
412
413      // Valid      8
414      heap.Valid = ReadInt64 ();
415
416      // Sorted     8
417      heap.Sorted = ReadInt64 ();
418
419      for (int i = 0; i < TableHeap.TableCount; i++) {
420        if (!heap.HasTable ((Table) i))
421          continue;
422
423        heap.Tables [i].Length = ReadUInt32 ();
424      }
425
426      SetIndexSize (image.StringHeap, sizes, 0x1);
427      SetIndexSize (image.GuidHeap, sizes, 0x2);
428      SetIndexSize (image.BlobHeap, sizes, 0x4);
429
430      ComputeTableInformations ();
431    }
432
433    static void SetIndexSize (Heap heap, uint sizes, byte flag)
434    {
435      if (heap == null)
436        return;
437
438      heap.IndexSize = (sizes & flag) > 0 ? 4 : 2;
439    }
440
441    int GetTableIndexSize (Table table)
442    {
443      return image.GetTableIndexSize (table);
444    }
445
446    int GetCodedIndexSize (CodedIndex index)
447    {
448      return image.GetCodedIndexSize (index);
449    }
450
451    void ComputeTableInformations ()
452    {
453      uint offset = (uint) BaseStream.Position - image.MetadataSection.PointerToRawData; // header
454
455      int stridx_size = image.StringHeap.IndexSize;
456      int blobidx_size = image.BlobHeap != null ? image.BlobHeap.IndexSize : 2;
457
458      var heap = image.TableHeap;
459      var tables = heap.Tables;
460
461      for (int i = 0; i < TableHeap.TableCount; i++) {
462        var table = (Table) i;
463        if (!heap.HasTable (table))
464          continue;
465
466        int size;
467        switch (table) {
468        case Table.Module:
469          size = 2  // Generation
470            + stridx_size // Name
471            + (image.GuidHeap.IndexSize * 3); // Mvid, EncId, EncBaseId
472          break;
473        case Table.TypeRef:
474          size = GetCodedIndexSize (CodedIndex.ResolutionScope) // ResolutionScope
475            + (stridx_size * 2);  // Name, Namespace
476          break;
477        case Table.TypeDef:
478          size = 4  // Flags
479            + (stridx_size * 2) // Name, Namespace
480            + GetCodedIndexSize (CodedIndex.TypeDefOrRef) // BaseType
481            + GetTableIndexSize (Table.Field) // FieldList
482            + GetTableIndexSize (Table.Method); // MethodList
483          break;
484        case Table.FieldPtr:
485          size = GetTableIndexSize (Table.Field); // Field
486          break;
487        case Table.Field:
488          size = 2  // Flags
489            + stridx_size // Name
490            + blobidx_size; // Signature
491          break;
492        case Table.MethodPtr:
493          size = GetTableIndexSize (Table.Method);  // Method
494          break;
495        case Table.Method:
496          size = 8  // Rva 4, ImplFlags 2, Flags 2
497            + stridx_size // Name
498            + blobidx_size  // Signature
499            + GetTableIndexSize (Table.Param); // ParamList
500          break;
501        case Table.ParamPtr:
502          size = GetTableIndexSize (Table.Param); // Param
503          break;
504        case Table.Param:
505          size = 4  // Flags 2, Sequence 2
506            + stridx_size;  // Name
507          break;
508        case Table.InterfaceImpl:
509          size = GetTableIndexSize (Table.TypeDef)  // Class
510            + GetCodedIndexSize (CodedIndex.TypeDefOrRef);  // Interface
511          break;
512        case Table.MemberRef:
513          size = GetCodedIndexSize (CodedIndex.MemberRefParent) // Class
514            + stridx_size // Name
515            + blobidx_size; // Signature
516          break;
517        case Table.Constant:
518          size = 2  // Type
519            + GetCodedIndexSize (CodedIndex.HasConstant)  // Parent
520            + blobidx_size; // Value
521          break;
522        case Table.CustomAttribute:
523          size = GetCodedIndexSize (CodedIndex.HasCustomAttribute)  // Parent
524            + GetCodedIndexSize (CodedIndex.CustomAttributeType)  // Type
525            + blobidx_size; // Value
526          break;
527        case Table.FieldMarshal:
528          size = GetCodedIndexSize (CodedIndex.HasFieldMarshal) // Parent
529            + blobidx_size; // NativeType
530          break;
531        case Table.DeclSecurity:
532          size = 2  // Action
533            + GetCodedIndexSize (CodedIndex.HasDeclSecurity)  // Parent
534            + blobidx_size; // PermissionSet
535          break;
536        case Table.ClassLayout:
537          size = 6  // PackingSize 2, ClassSize 4
538            + GetTableIndexSize (Table.TypeDef);  // Parent
539          break;
540        case Table.FieldLayout:
541          size = 4  // Offset
542            + GetTableIndexSize (Table.Field);  // Field
543          break;
544        case Table.StandAloneSig:
545          size = blobidx_size;  // Signature
546          break;
547        case Table.EventMap:
548          size = GetTableIndexSize (Table.TypeDef)  // Parent
549            + GetTableIndexSize (Table.Event);  // EventList
550          break;
551        case Table.EventPtr:
552          size = GetTableIndexSize (Table.Event); // Event
553          break;
554        case Table.Event:
555          size = 2  // Flags
556            + stridx_size // Name
557            + GetCodedIndexSize (CodedIndex.TypeDefOrRef);  // EventType
558          break;
559        case Table.PropertyMap:
560          size = GetTableIndexSize (Table.TypeDef)  // Parent
561            + GetTableIndexSize (Table.Property); // PropertyList
562          break;
563        case Table.PropertyPtr:
564          size = GetTableIndexSize (Table.Property);  // Property
565          break;
566        case Table.Property:
567          size = 2  // Flags
568            + stridx_size // Name
569            + blobidx_size; // Type
570          break;
571        case Table.MethodSemantics:
572          size = 2  // Semantics
573            + GetTableIndexSize (Table.Method)  // Method
574            + GetCodedIndexSize (CodedIndex.HasSemantics);  // Association
575          break;
576        case Table.MethodImpl:
577          size = GetTableIndexSize (Table.TypeDef)  // Class
578            + GetCodedIndexSize (CodedIndex.MethodDefOrRef) // MethodBody
579            + GetCodedIndexSize (CodedIndex.MethodDefOrRef);  // MethodDeclaration
580          break;
581        case Table.ModuleRef:
582          size = stridx_size; // Name
583          break;
584        case Table.TypeSpec:
585          size = blobidx_size;  // Signature
586          break;
587        case Table.ImplMap:
588          size = 2  // MappingFlags
589            + GetCodedIndexSize (CodedIndex.MemberForwarded)  // MemberForwarded
590            + stridx_size // ImportName
591            + GetTableIndexSize (Table.ModuleRef);  // ImportScope
592          break;
593        case Table.FieldRVA:
594          size = 4  // RVA
595            + GetTableIndexSize (Table.Field);  // Field
596          break;
597        case Table.EncLog:
598        case Table.EncMap:
599          size = 4;
600          break;
601        case Table.Assembly:
602          size = 16 // HashAlgId 4, Version 4 * 2, Flags 4
603            + blobidx_size  // PublicKey
604            + (stridx_size * 2);  // Name, Culture
605          break;
606        case Table.AssemblyProcessor:
607          size = 4; // Processor
608          break;
609        case Table.AssemblyOS:
610          size = 12;  // Platform 4, Version 2 * 4
611          break;
612        case Table.AssemblyRef:
613          size = 12 // Version 2 * 4 + Flags 4
614            + (blobidx_size * 2)  // PublicKeyOrToken, HashValue
615            + (stridx_size * 2);  // Name, Culture
616          break;
617        case Table.AssemblyRefProcessor:
618          size = 4  // Processor
619            + GetTableIndexSize (Table.AssemblyRef);  // AssemblyRef
620          break;
621        case Table.AssemblyRefOS:
622          size = 12 // Platform 4, Version 2 * 4
623            + GetTableIndexSize (Table.AssemblyRef);  // AssemblyRef
624          break;
625        case Table.File:
626          size = 4  // Flags
627            + stridx_size // Name
628            + blobidx_size; // HashValue
629          break;
630        case Table.ExportedType:
631          size = 8  // Flags 4, TypeDefId 4
632            + (stridx_size * 2) // Name, Namespace
633            + GetCodedIndexSize (CodedIndex.Implementation);  // Implementation
634          break;
635        case Table.ManifestResource:
636          size = 8  // Offset, Flags
637            + stridx_size // Name
638            + GetCodedIndexSize (CodedIndex.Implementation);  // Implementation
639          break;
640        case Table.NestedClass:
641          size = GetTableIndexSize (Table.TypeDef)  // NestedClass
642            + GetTableIndexSize (Table.TypeDef);  // EnclosingClass
643          break;
644        case Table.GenericParam:
645          size = 4  // Number, Flags
646            + GetCodedIndexSize (CodedIndex.TypeOrMethodDef)  // Owner
647            + stridx_size;  // Name
648          break;
649        case Table.MethodSpec:
650          size = GetCodedIndexSize (CodedIndex.MethodDefOrRef)  // Method
651            + blobidx_size; // Instantiation
652          break;
653        case Table.GenericParamConstraint:
654          size = GetTableIndexSize (Table.GenericParam) // Owner
655            + GetCodedIndexSize (CodedIndex.TypeDefOrRef);  // Constraint
656          break;
657        default:
658          throw new NotSupportedException ();
659        }
660
661        tables [i].RowSize = (uint) size;
662        tables [i].Offset = offset;
663
664        offset += (uint) size * tables [i].Length;
665      }
666    }
667
668    public static Image ReadImageFrom (Stream stream)
669    {
670      try {
671        var reader = new ImageReader (stream);
672        reader.ReadImage ();
673        return reader.image;
674      } catch (EndOfStreamException e) {
675        throw new BadImageFormatException (stream.GetFullyQualifiedName (), e);
676      }
677    }
678  }
679}
Note: See TracBrowser for help on using the repository browser.