PageRenderTime 35ms CodeModel.GetById 10ms app.highlight 19ms RepoModel.GetById 1ms app.codeStats 1ms

/Mono.Cecil.PE/ImageReader.cs

http://github.com/jbevain/cecil
C# | 793 lines | 560 code | 126 blank | 107 comment | 50 complexity | d686551c2e1bb0a02d4e5356741f1a6a MD5 | raw file
  1//
  2// Author:
  3//   Jb Evain (jbevain@gmail.com)
  4//
  5// Copyright (c) 2008 - 2015 Jb Evain
  6// Copyright (c) 2008 - 2011 Novell, Inc.
  7//
  8// Licensed under the MIT/X11 license.
  9//
 10
 11using System;
 12using System.IO;
 13
 14using Mono.Cecil.Cil;
 15using Mono.Cecil.Metadata;
 16using Mono.Collections.Generic;
 17
 18using RVA = System.UInt32;
 19
 20namespace Mono.Cecil.PE {
 21
 22	sealed class ImageReader : BinaryStreamReader {
 23
 24		readonly Image image;
 25
 26		DataDirectory cli;
 27		DataDirectory metadata;
 28
 29		uint table_heap_offset;
 30
 31		public ImageReader (Disposable<Stream> stream, string file_name)
 32			: base (stream.value)
 33		{
 34			image = new Image ();
 35			image.Stream = stream;
 36			image.FileName = file_name;
 37		}
 38
 39		void MoveTo (DataDirectory directory)
 40		{
 41			BaseStream.Position = image.ResolveVirtualAddress (directory.VirtualAddress);
 42		}
 43
 44		void ReadImage ()
 45		{
 46			if (BaseStream.Length < 128)
 47				throw new BadImageFormatException ();
 48
 49			// - DOSHeader
 50
 51			// PE					2
 52			// Start				58
 53			// Lfanew				4
 54			// End					64
 55
 56			if (ReadUInt16 () != 0x5a4d)
 57				throw new BadImageFormatException ();
 58
 59			Advance (58);
 60
 61			MoveTo (ReadUInt32 ());
 62
 63			if (ReadUInt32 () != 0x00004550)
 64				throw new BadImageFormatException ();
 65
 66			// - PEFileHeader
 67
 68			// Machine				2
 69			image.Architecture = ReadArchitecture ();
 70
 71			// NumberOfSections		2
 72			ushort sections = ReadUInt16 ();
 73
 74			// TimeDateStamp		4
 75			image.Timestamp = ReadUInt32 ();
 76			// PointerToSymbolTable	4
 77			// NumberOfSymbols		4
 78			// OptionalHeaderSize	2
 79			Advance (10);
 80
 81			// Characteristics		2
 82			ushort characteristics = ReadUInt16 ();
 83
 84			ushort subsystem, dll_characteristics;
 85			ReadOptionalHeaders (out subsystem, out dll_characteristics);
 86			ReadSections (sections);
 87			ReadCLIHeader ();
 88			ReadMetadata ();
 89			ReadDebugHeader ();
 90
 91			image.Kind = GetModuleKind (characteristics, subsystem);
 92			image.Characteristics = (ModuleCharacteristics) dll_characteristics;
 93		}
 94
 95		TargetArchitecture ReadArchitecture ()
 96		{
 97			return (TargetArchitecture) ReadUInt16 ();
 98		}
 99
100		static ModuleKind GetModuleKind (ushort characteristics, ushort subsystem)
101		{
102			if ((characteristics & 0x2000) != 0) // ImageCharacteristics.Dll
103				return ModuleKind.Dll;
104
105			if (subsystem == 0x2 || subsystem == 0x9) // SubSystem.WindowsGui || SubSystem.WindowsCeGui
106				return ModuleKind.Windows;
107
108			return ModuleKind.Console;
109		}
110
111		void ReadOptionalHeaders (out ushort subsystem, out ushort dll_characteristics)
112		{
113			// - PEOptionalHeader
114			//   - StandardFieldsHeader
115
116			// Magic				2
117			bool pe64 = ReadUInt16 () == 0x20b;
118
119			//						pe32 || pe64
120
121			image.LinkerVersion = ReadUInt16 ();
122			// CodeSize				4
123			// InitializedDataSize	4
124			// UninitializedDataSize4
125			// EntryPointRVA		4
126			// BaseOfCode			4
127			// BaseOfData			4 || 0
128
129			//   - NTSpecificFieldsHeader
130
131			// ImageBase			4 || 8
132			// SectionAlignment		4
133			// FileAlignement		4
134			// OSMajor				2
135			// OSMinor				2
136			// UserMajor			2
137			// UserMinor			2
138			// SubSysMajor			2
139			// SubSysMinor			2
140			Advance(44);
141
142			image.SubSystemMajor = ReadUInt16 ();
143			image.SubSystemMinor = ReadUInt16 ();
144
145			// Reserved				4
146			// ImageSize			4
147			// HeaderSize			4
148			// FileChecksum			4
149			Advance (16);
150
151			// SubSystem			2
152			subsystem = ReadUInt16 ();
153
154			// DLLFlags				2
155			dll_characteristics = ReadUInt16 ();
156			// StackReserveSize		4 || 8
157			// StackCommitSize		4 || 8
158			// HeapReserveSize		4 || 8
159			// HeapCommitSize		4 || 8
160			// LoaderFlags			4
161			// NumberOfDataDir		4
162
163			//   - DataDirectoriesHeader
164
165			// ExportTable			8
166			// ImportTable			8
167
168			Advance (pe64 ? 56 : 40);
169
170			// ResourceTable		8
171
172			image.Win32Resources = ReadDataDirectory ();
173
174			// ExceptionTable		8
175			// CertificateTable		8
176			// BaseRelocationTable	8
177
178			Advance (24);
179
180			// Debug				8
181			image.Debug = ReadDataDirectory ();
182
183			// Copyright			8
184			// GlobalPtr			8
185			// TLSTable				8
186			// LoadConfigTable		8
187			// BoundImport			8
188			// IAT					8
189			// DelayImportDescriptor8
190			Advance (56);
191
192			// CLIHeader			8
193			cli = ReadDataDirectory ();
194
195			if (cli.IsZero)
196				throw new BadImageFormatException ();
197
198			// Reserved				8
199			Advance (8);
200		}
201
202		string ReadAlignedString (int length)
203		{
204			int read = 0;
205			var buffer = new char [length];
206			while (read < length) {
207				var current = ReadByte ();
208				if (current == 0)
209					break;
210
211				buffer [read++] = (char) current;
212			}
213
214			Advance (-1 + ((read + 4) & ~3) - read);
215
216			return new string (buffer, 0, read);
217		}
218
219		string ReadZeroTerminatedString (int length)
220		{
221			int read = 0;
222			var buffer = new char [length];
223			var bytes = ReadBytes (length);
224			while (read < length) {
225				var current = bytes [read];
226				if (current == 0)
227					break;
228
229				buffer [read++] = (char) current;
230			}
231
232			return new string (buffer, 0, read);
233		}
234
235		void ReadSections (ushort count)
236		{
237			var sections = new Section [count];
238
239			for (int i = 0; i < count; i++) {
240				var section = new Section ();
241
242				// Name
243				section.Name = ReadZeroTerminatedString (8);
244
245				// VirtualSize		4
246				Advance (4);
247
248				// VirtualAddress	4
249				section.VirtualAddress = ReadUInt32 ();
250				// SizeOfRawData	4
251				section.SizeOfRawData = ReadUInt32 ();
252				// PointerToRawData	4
253				section.PointerToRawData = ReadUInt32 ();
254
255				// PointerToRelocations		4
256				// PointerToLineNumbers		4
257				// NumberOfRelocations		2
258				// NumberOfLineNumbers		2
259				// Characteristics			4
260				Advance (16);
261
262				sections [i] = section;
263			}
264
265			image.Sections = sections;
266		}
267
268		void ReadCLIHeader ()
269		{
270			MoveTo (cli);
271
272			// - CLIHeader
273
274			// Cb						4
275			// MajorRuntimeVersion		2
276			// MinorRuntimeVersion		2
277			Advance (8);
278
279			// Metadata					8
280			metadata = ReadDataDirectory ();
281			// Flags					4
282			image.Attributes = (ModuleAttributes) ReadUInt32 ();
283			// EntryPointToken			4
284			image.EntryPointToken = ReadUInt32 ();
285			// Resources				8
286			image.Resources = ReadDataDirectory ();
287			// StrongNameSignature		8
288			image.StrongName = ReadDataDirectory ();
289			// CodeManagerTable			8
290			// VTableFixups				8
291			// ExportAddressTableJumps	8
292			// ManagedNativeHeader		8
293		}
294
295		void ReadMetadata ()
296		{
297			MoveTo (metadata);
298
299			if (ReadUInt32 () != 0x424a5342)
300				throw new BadImageFormatException ();
301
302			// MajorVersion			2
303			// MinorVersion			2
304			// Reserved				4
305			Advance (8);
306
307			image.RuntimeVersion = ReadZeroTerminatedString (ReadInt32 ());
308
309			// Flags		2
310			Advance (2);
311
312			var streams = ReadUInt16 ();
313
314			var section = image.GetSectionAtVirtualAddress (metadata.VirtualAddress);
315			if (section == null)
316				throw new BadImageFormatException ();
317
318			image.MetadataSection = section;
319
320			for (int i = 0; i < streams; i++)
321				ReadMetadataStream (section);
322
323			if (image.PdbHeap != null)
324				ReadPdbHeap ();
325
326			if (image.TableHeap != null)
327				ReadTableHeap ();
328		}
329
330		void ReadDebugHeader ()
331		{
332			if (image.Debug.IsZero) {
333				image.DebugHeader = new ImageDebugHeader (Empty<ImageDebugHeaderEntry>.Array);
334				return;
335			}
336
337			MoveTo (image.Debug);
338
339			var entries = new ImageDebugHeaderEntry [(int) image.Debug.Size / ImageDebugDirectory.Size];
340
341			for (int i = 0; i < entries.Length; i++) {
342				var directory = new ImageDebugDirectory {
343					Characteristics = ReadInt32 (),
344					TimeDateStamp = ReadInt32 (),
345					MajorVersion = ReadInt16 (),
346					MinorVersion = ReadInt16 (),
347					Type = (ImageDebugType) ReadInt32 (),
348					SizeOfData = ReadInt32 (),
349					AddressOfRawData = ReadInt32 (),
350					PointerToRawData = ReadInt32 (),
351				};
352
353				if (directory.PointerToRawData == 0 || directory.SizeOfData < 0) {
354					entries [i] = new ImageDebugHeaderEntry (directory, Empty<byte>.Array);
355					continue;
356				}
357
358				var position = Position;
359				try {
360					MoveTo ((uint) directory.PointerToRawData);
361					var data = ReadBytes (directory.SizeOfData);
362					entries [i] = new ImageDebugHeaderEntry (directory, data);
363				} finally {
364					Position = position;
365				}
366			}
367
368			image.DebugHeader = new ImageDebugHeader (entries);
369		}
370
371		void ReadMetadataStream (Section section)
372		{
373			// Offset		4
374			uint offset = metadata.VirtualAddress - section.VirtualAddress + ReadUInt32 (); // relative to the section start
375
376			// Size			4
377			uint size = ReadUInt32 ();
378
379			var data = ReadHeapData (offset, size);
380
381			var name = ReadAlignedString (16);
382			switch (name) {
383			case "#~":
384			case "#-":
385				image.TableHeap = new TableHeap (data);
386				table_heap_offset = offset;
387				break;
388			case "#Strings":
389				image.StringHeap = new StringHeap (data);
390				break;
391			case "#Blob":
392				image.BlobHeap = new BlobHeap (data);
393				break;
394			case "#GUID":
395				image.GuidHeap = new GuidHeap (data);
396				break;
397			case "#US":
398				image.UserStringHeap = new UserStringHeap (data);
399				break;
400			case "#Pdb":
401				image.PdbHeap = new PdbHeap (data);
402				break;
403			}
404		}
405
406		byte [] ReadHeapData (uint offset, uint size)
407		{
408			var position = BaseStream.Position;
409			MoveTo (offset + image.MetadataSection.PointerToRawData);
410			var data = ReadBytes ((int) size);
411			BaseStream.Position = position;
412
413			return data;
414		}
415
416		void ReadTableHeap ()
417		{
418			var heap = image.TableHeap;
419
420			MoveTo (table_heap_offset + image.MetadataSection.PointerToRawData);
421
422			// Reserved			4
423			// MajorVersion		1
424			// MinorVersion		1
425			Advance (6);
426
427			// HeapSizes		1
428			var sizes = ReadByte ();
429
430			// Reserved2		1
431			Advance (1);
432
433			// Valid			8
434			heap.Valid = ReadInt64 ();
435
436			// Sorted			8
437			heap.Sorted = ReadInt64 ();
438
439			if (image.PdbHeap != null) {
440				for (int i = 0; i < Mixin.TableCount; i++) {
441					if (!image.PdbHeap.HasTable ((Table) i))
442						continue;
443
444					heap.Tables [i].Length = image.PdbHeap.TypeSystemTableRows [i];
445				}
446			}
447
448			for (int i = 0; i < Mixin.TableCount; i++) {
449				if (!heap.HasTable ((Table) i))
450					continue;
451
452				heap.Tables [i].Length = ReadUInt32 ();
453			}
454
455			SetIndexSize (image.StringHeap, sizes, 0x1);
456			SetIndexSize (image.GuidHeap, sizes, 0x2);
457			SetIndexSize (image.BlobHeap, sizes, 0x4);
458
459			ComputeTableInformations ();
460		}
461
462		static void SetIndexSize (Heap heap, uint sizes, byte flag)
463		{
464			if (heap == null)
465				return;
466
467			heap.IndexSize = (sizes & flag) > 0 ? 4 : 2;
468		}
469
470		int GetTableIndexSize (Table table)
471		{
472			return image.GetTableIndexSize (table);
473		}
474
475		int GetCodedIndexSize (CodedIndex index)
476		{
477			return image.GetCodedIndexSize (index);
478		}
479
480		void ComputeTableInformations ()
481		{
482			uint offset = (uint) BaseStream.Position - table_heap_offset - image.MetadataSection.PointerToRawData; // header
483
484			int stridx_size = image.StringHeap.IndexSize;
485			int guididx_size = image.GuidHeap != null ? image.GuidHeap.IndexSize : 2;
486			int blobidx_size = image.BlobHeap != null ? image.BlobHeap.IndexSize : 2;
487
488			var heap = image.TableHeap;
489			var tables = heap.Tables;
490
491			for (int i = 0; i < Mixin.TableCount; i++) {
492				var table = (Table) i;
493				if (!heap.HasTable (table))
494					continue;
495
496				int size;
497				switch (table) {
498				case Table.Module:
499					size = 2	// Generation
500						+ stridx_size	// Name
501						+ (guididx_size * 3);	// Mvid, EncId, EncBaseId
502					break;
503				case Table.TypeRef:
504					size = GetCodedIndexSize (CodedIndex.ResolutionScope)	// ResolutionScope
505						+ (stridx_size * 2);	// Name, Namespace
506					break;
507				case Table.TypeDef:
508					size = 4	// Flags
509						+ (stridx_size * 2)	// Name, Namespace
510						+ GetCodedIndexSize (CodedIndex.TypeDefOrRef)	// BaseType
511						+ GetTableIndexSize (Table.Field)	// FieldList
512						+ GetTableIndexSize (Table.Method);	// MethodList
513					break;
514				case Table.FieldPtr:
515					size = GetTableIndexSize (Table.Field);	// Field
516					break;
517				case Table.Field:
518					size = 2	// Flags
519						+ stridx_size	// Name
520						+ blobidx_size;	// Signature
521					break;
522				case Table.MethodPtr:
523					size = GetTableIndexSize (Table.Method);	// Method
524					break;
525				case Table.Method:
526					size = 8	// Rva 4, ImplFlags 2, Flags 2
527						+ stridx_size	// Name
528						+ blobidx_size	// Signature
529						+ GetTableIndexSize (Table.Param); // ParamList
530					break;
531				case Table.ParamPtr:
532					size = GetTableIndexSize (Table.Param); // Param
533					break;
534				case Table.Param:
535					size = 4	// Flags 2, Sequence 2
536						+ stridx_size;	// Name
537					break;
538				case Table.InterfaceImpl:
539					size = GetTableIndexSize (Table.TypeDef)	// Class
540						+ GetCodedIndexSize (CodedIndex.TypeDefOrRef);	// Interface
541					break;
542				case Table.MemberRef:
543					size = GetCodedIndexSize (CodedIndex.MemberRefParent)	// Class
544						+ stridx_size	// Name
545						+ blobidx_size;	// Signature
546					break;
547				case Table.Constant:
548					size = 2	// Type
549						+ GetCodedIndexSize (CodedIndex.HasConstant)	// Parent
550						+ blobidx_size;	// Value
551					break;
552				case Table.CustomAttribute:
553					size = GetCodedIndexSize (CodedIndex.HasCustomAttribute)	// Parent
554						+ GetCodedIndexSize (CodedIndex.CustomAttributeType)	// Type
555						+ blobidx_size;	// Value
556					break;
557				case Table.FieldMarshal:
558					size = GetCodedIndexSize (CodedIndex.HasFieldMarshal)	// Parent
559						+ blobidx_size;	// NativeType
560					break;
561				case Table.DeclSecurity:
562					size = 2	// Action
563						+ GetCodedIndexSize (CodedIndex.HasDeclSecurity)	// Parent
564						+ blobidx_size;	// PermissionSet
565					break;
566				case Table.ClassLayout:
567					size = 6	// PackingSize 2, ClassSize 4
568						+ GetTableIndexSize (Table.TypeDef);	// Parent
569					break;
570				case Table.FieldLayout:
571					size = 4	// Offset
572						+ GetTableIndexSize (Table.Field);	// Field
573					break;
574				case Table.StandAloneSig:
575					size = blobidx_size;	// Signature
576					break;
577				case Table.EventMap:
578					size = GetTableIndexSize (Table.TypeDef)	// Parent
579						+ GetTableIndexSize (Table.Event);	// EventList
580					break;
581				case Table.EventPtr:
582					size = GetTableIndexSize (Table.Event);	// Event
583					break;
584				case Table.Event:
585					size = 2	// Flags
586						+ stridx_size // Name
587						+ GetCodedIndexSize (CodedIndex.TypeDefOrRef);	// EventType
588					break;
589				case Table.PropertyMap:
590					size = GetTableIndexSize (Table.TypeDef)	// Parent
591						+ GetTableIndexSize (Table.Property);	// PropertyList
592					break;
593				case Table.PropertyPtr:
594					size = GetTableIndexSize (Table.Property);	// Property
595					break;
596				case Table.Property:
597					size = 2	// Flags
598						+ stridx_size	// Name
599						+ blobidx_size;	// Type
600					break;
601				case Table.MethodSemantics:
602					size = 2	// Semantics
603						+ GetTableIndexSize (Table.Method)	// Method
604						+ GetCodedIndexSize (CodedIndex.HasSemantics);	// Association
605					break;
606				case Table.MethodImpl:
607					size = GetTableIndexSize (Table.TypeDef)	// Class
608						+ GetCodedIndexSize (CodedIndex.MethodDefOrRef)	// MethodBody
609						+ GetCodedIndexSize (CodedIndex.MethodDefOrRef);	// MethodDeclaration
610					break;
611				case Table.ModuleRef:
612					size = stridx_size;	// Name
613					break;
614				case Table.TypeSpec:
615					size = blobidx_size;	// Signature
616					break;
617				case Table.ImplMap:
618					size = 2	// MappingFlags
619						+ GetCodedIndexSize (CodedIndex.MemberForwarded)	// MemberForwarded
620						+ stridx_size	// ImportName
621						+ GetTableIndexSize (Table.ModuleRef);	// ImportScope
622					break;
623				case Table.FieldRVA:
624					size = 4	// RVA
625						+ GetTableIndexSize (Table.Field);	// Field
626					break;
627				case Table.EncLog:
628					size = 8;
629					break;
630				case Table.EncMap:
631					size = 4;
632					break;
633				case Table.Assembly:
634					size = 16 // HashAlgId 4, Version 4 * 2, Flags 4
635						+ blobidx_size	// PublicKey
636						+ (stridx_size * 2);	// Name, Culture
637					break;
638				case Table.AssemblyProcessor:
639					size = 4;	// Processor
640					break;
641				case Table.AssemblyOS:
642					size = 12;	// Platform 4, Version 2 * 4
643					break;
644				case Table.AssemblyRef:
645					size = 12	// Version 2 * 4 + Flags 4
646						+ (blobidx_size * 2)	// PublicKeyOrToken, HashValue
647						+ (stridx_size * 2);	// Name, Culture
648					break;
649				case Table.AssemblyRefProcessor:
650					size = 4	// Processor
651						+ GetTableIndexSize (Table.AssemblyRef);	// AssemblyRef
652					break;
653				case Table.AssemblyRefOS:
654					size = 12	// Platform 4, Version 2 * 4
655						+ GetTableIndexSize (Table.AssemblyRef);	// AssemblyRef
656					break;
657				case Table.File:
658					size = 4	// Flags
659						+ stridx_size	// Name
660						+ blobidx_size;	// HashValue
661					break;
662				case Table.ExportedType:
663					size = 8	// Flags 4, TypeDefId 4
664						+ (stridx_size * 2)	// Name, Namespace
665						+ GetCodedIndexSize (CodedIndex.Implementation);	// Implementation
666					break;
667				case Table.ManifestResource:
668					size = 8	// Offset, Flags
669						+ stridx_size	// Name
670						+ GetCodedIndexSize (CodedIndex.Implementation);	// Implementation
671					break;
672				case Table.NestedClass:
673					size = GetTableIndexSize (Table.TypeDef)	// NestedClass
674						+ GetTableIndexSize (Table.TypeDef);	// EnclosingClass
675					break;
676				case Table.GenericParam:
677					size = 4	// Number, Flags
678						+ GetCodedIndexSize (CodedIndex.TypeOrMethodDef)	// Owner
679						+ stridx_size;	// Name
680					break;
681				case Table.MethodSpec:
682					size = GetCodedIndexSize (CodedIndex.MethodDefOrRef)	// Method
683						+ blobidx_size;	// Instantiation
684					break;
685				case Table.GenericParamConstraint:
686					size = GetTableIndexSize (Table.GenericParam)	// Owner
687						+ GetCodedIndexSize (CodedIndex.TypeDefOrRef);	// Constraint
688					break;
689				case Table.Document:
690					size = blobidx_size	// Name
691						+ guididx_size	// HashAlgorithm
692						+ blobidx_size	// Hash
693						+ guididx_size;	// Language
694					break;
695				case Table.MethodDebugInformation:
696					size = GetTableIndexSize (Table.Document)  // Document
697						+ blobidx_size;	// SequencePoints
698					break;
699				case Table.LocalScope:
700					size = GetTableIndexSize (Table.Method)	// Method
701						+ GetTableIndexSize (Table.ImportScope)	// ImportScope
702						+ GetTableIndexSize (Table.LocalVariable)	// VariableList
703						+ GetTableIndexSize (Table.LocalConstant)	// ConstantList
704						+ 4 * 2;	// StartOffset, Length
705					break;
706				case Table.LocalVariable:
707					size = 2	// Attributes
708						+ 2		// Index
709						+ stridx_size;	// Name
710					break;
711				case Table.LocalConstant:
712					size = stridx_size	// Name
713						+ blobidx_size;	// Signature
714					break;
715				case Table.ImportScope:
716					size = GetTableIndexSize (Table.ImportScope)	// Parent
717						+ blobidx_size;
718					break;
719				case Table.StateMachineMethod:
720					size = GetTableIndexSize (Table.Method) // MoveNextMethod
721						+ GetTableIndexSize (Table.Method);	// KickOffMethod
722					break;
723				case Table.CustomDebugInformation:
724					size = GetCodedIndexSize (CodedIndex.HasCustomDebugInformation) // Parent
725						+ guididx_size	// Kind
726						+ blobidx_size;	// Value
727					break;
728				default:
729					throw new NotSupportedException ();
730				}
731
732				tables [i].RowSize = (uint) size;
733				tables [i].Offset = offset;
734
735				offset += (uint) size * tables [i].Length;
736			}
737		}
738
739		void ReadPdbHeap ()
740		{
741			var heap = image.PdbHeap;
742
743			var buffer = new ByteBuffer (heap.data);
744
745			heap.Id = buffer.ReadBytes (20);
746			heap.EntryPoint = buffer.ReadUInt32 ();
747			heap.TypeSystemTables = buffer.ReadInt64 ();
748			heap.TypeSystemTableRows = new uint [Mixin.TableCount];
749
750			for (int i = 0; i < Mixin.TableCount; i++) {
751				var table = (Table) i;
752				if (!heap.HasTable (table))
753					continue;
754
755				heap.TypeSystemTableRows [i] = buffer.ReadUInt32 ();
756			}
757		}
758
759		public static Image ReadImage (Disposable<Stream> stream, string file_name)
760		{
761			try {
762				var reader = new ImageReader (stream, file_name);
763				reader.ReadImage ();
764				return reader.image;
765			} catch (EndOfStreamException e) {
766				throw new BadImageFormatException (stream.value.GetFileName (), e);
767			}
768		}
769
770		public static Image ReadPortablePdb (Disposable<Stream> stream, string file_name)
771		{
772			try {
773				var reader = new ImageReader (stream, file_name);
774				var length = (uint) stream.value.Length;
775
776				reader.image.Sections = new[] {
777					new Section {
778						PointerToRawData = 0,
779						SizeOfRawData = length,
780						VirtualAddress = 0,
781						VirtualSize = length,
782					}
783				};
784
785				reader.metadata = new DataDirectory (0, length);
786				reader.ReadMetadata ();
787				return reader.image;
788			} catch (EndOfStreamException e) {
789				throw new BadImageFormatException (stream.value.GetFileName (), e);
790			}
791		}
792	}
793}