794 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			794 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| //
 | |
| // Author:
 | |
| //   Jb Evain (jbevain@gmail.com)
 | |
| //
 | |
| // Copyright (c) 2008 - 2015 Jb Evain
 | |
| // Copyright (c) 2008 - 2011 Novell, Inc.
 | |
| //
 | |
| // Licensed under the MIT/X11 license.
 | |
| //
 | |
| 
 | |
| using MonoFN.Cecil.Cil;
 | |
| using MonoFN.Cecil.Metadata;
 | |
| using System;
 | |
| using System.IO;
 | |
| 
 | |
| namespace MonoFN.Cecil.PE {
 | |
| 
 | |
| 	sealed class ImageReader : BinaryStreamReader {
 | |
| 
 | |
| 		readonly Image image;
 | |
| 
 | |
| 		DataDirectory cli;
 | |
| 		DataDirectory metadata;
 | |
| 
 | |
| 		uint table_heap_offset;
 | |
| 
 | |
| 		public ImageReader (Disposable<Stream> stream, string file_name)
 | |
| 			: base (stream.value)
 | |
| 		{
 | |
| 			image = new Image ();
 | |
| 			image.Stream = stream;
 | |
| 			image.FileName = file_name;
 | |
| 		}
 | |
| 
 | |
| 		void MoveTo (DataDirectory directory)
 | |
| 		{
 | |
| 			BaseStream.Position = image.ResolveVirtualAddress (directory.VirtualAddress);
 | |
| 		}
 | |
| 
 | |
| 		void ReadImage ()
 | |
| 		{
 | |
| 			if (BaseStream.Length < 128)
 | |
| 				throw new BadImageFormatException ();
 | |
| 
 | |
| 			// - DOSHeader
 | |
| 
 | |
| 			// PE					2
 | |
| 			// Start				58
 | |
| 			// Lfanew				4
 | |
| 			// End					64
 | |
| 
 | |
| 			if (ReadUInt16 () != 0x5a4d)
 | |
| 				throw new BadImageFormatException ();
 | |
| 
 | |
| 			Advance (58);
 | |
| 
 | |
| 			MoveTo (ReadUInt32 ());
 | |
| 
 | |
| 			if (ReadUInt32 () != 0x00004550)
 | |
| 				throw new BadImageFormatException ();
 | |
| 
 | |
| 			// - PEFileHeader
 | |
| 
 | |
| 			// Machine				2
 | |
| 			image.Architecture = ReadArchitecture ();
 | |
| 
 | |
| 			// NumberOfSections		2
 | |
| 			ushort sections = ReadUInt16 ();
 | |
| 
 | |
| 			// TimeDateStamp		4
 | |
| 			image.Timestamp = ReadUInt32 ();
 | |
| 			// PointerToSymbolTable	4
 | |
| 			// NumberOfSymbols		4
 | |
| 			// OptionalHeaderSize	2
 | |
| 			Advance (10);
 | |
| 
 | |
| 			// Characteristics		2
 | |
| 			ushort characteristics = ReadUInt16 ();
 | |
| 
 | |
| 			ushort subsystem, dll_characteristics;
 | |
| 			ReadOptionalHeaders (out subsystem, out dll_characteristics);
 | |
| 			ReadSections (sections);
 | |
| 			ReadCLIHeader ();
 | |
| 			ReadMetadata ();
 | |
| 			ReadDebugHeader ();
 | |
| 
 | |
| 			image.Characteristics = characteristics;
 | |
| 			image.Kind = GetModuleKind (characteristics, subsystem);
 | |
| 			image.DllCharacteristics = (ModuleCharacteristics)dll_characteristics;
 | |
| 		}
 | |
| 
 | |
| 		TargetArchitecture ReadArchitecture ()
 | |
| 		{
 | |
| 			return (TargetArchitecture)ReadUInt16 ();
 | |
| 		}
 | |
| 
 | |
| 		static ModuleKind GetModuleKind (ushort characteristics, ushort subsystem)
 | |
| 		{
 | |
| 			if ((characteristics & 0x2000) != 0) // ImageCharacteristics.Dll
 | |
| 				return ModuleKind.Dll;
 | |
| 
 | |
| 			if (subsystem == 0x2 || subsystem == 0x9) // SubSystem.WindowsGui || SubSystem.WindowsCeGui
 | |
| 				return ModuleKind.Windows;
 | |
| 
 | |
| 			return ModuleKind.Console;
 | |
| 		}
 | |
| 
 | |
| 		void ReadOptionalHeaders (out ushort subsystem, out ushort dll_characteristics)
 | |
| 		{
 | |
| 			// - PEOptionalHeader
 | |
| 			//   - StandardFieldsHeader
 | |
| 
 | |
| 			// Magic				2
 | |
| 			bool pe64 = ReadUInt16 () == 0x20b;
 | |
| 
 | |
| 			//						pe32 || pe64
 | |
| 
 | |
| 			image.LinkerVersion = ReadUInt16 ();
 | |
| 			// CodeSize				4
 | |
| 			// InitializedDataSize	4
 | |
| 			// UninitializedDataSize4
 | |
| 			// EntryPointRVA		4
 | |
| 			// BaseOfCode			4
 | |
| 			// BaseOfData			4 || 0
 | |
| 
 | |
| 			//   - NTSpecificFieldsHeader
 | |
| 
 | |
| 			// ImageBase			4 || 8
 | |
| 			// SectionAlignment		4
 | |
| 			// FileAlignement		4
 | |
| 			// OSMajor				2
 | |
| 			// OSMinor				2
 | |
| 			// UserMajor			2
 | |
| 			// UserMinor			2
 | |
| 			// SubSysMajor			2
 | |
| 			// SubSysMinor			2
 | |
| 			Advance (44);
 | |
| 
 | |
| 			image.SubSystemMajor = ReadUInt16 ();
 | |
| 			image.SubSystemMinor = ReadUInt16 ();
 | |
| 
 | |
| 			// Reserved				4
 | |
| 			// ImageSize			4
 | |
| 			// HeaderSize			4
 | |
| 			// FileChecksum			4
 | |
| 			Advance (16);
 | |
| 
 | |
| 			// SubSystem			2
 | |
| 			subsystem = ReadUInt16 ();
 | |
| 
 | |
| 			// DLLFlags				2
 | |
| 			dll_characteristics = ReadUInt16 ();
 | |
| 			// StackReserveSize		4 || 8
 | |
| 			// StackCommitSize		4 || 8
 | |
| 			// HeapReserveSize		4 || 8
 | |
| 			// HeapCommitSize		4 || 8
 | |
| 			// LoaderFlags			4
 | |
| 			// NumberOfDataDir		4
 | |
| 
 | |
| 			//   - DataDirectoriesHeader
 | |
| 
 | |
| 			// ExportTable			8
 | |
| 			// ImportTable			8
 | |
| 
 | |
| 			Advance (pe64 ? 56 : 40);
 | |
| 
 | |
| 			// ResourceTable		8
 | |
| 
 | |
| 			image.Win32Resources = ReadDataDirectory ();
 | |
| 
 | |
| 			// ExceptionTable		8
 | |
| 			// CertificateTable		8
 | |
| 			// BaseRelocationTable	8
 | |
| 
 | |
| 			Advance (24);
 | |
| 
 | |
| 			// Debug				8
 | |
| 			image.Debug = ReadDataDirectory ();
 | |
| 
 | |
| 			// Copyright			8
 | |
| 			// GlobalPtr			8
 | |
| 			// TLSTable				8
 | |
| 			// LoadConfigTable		8
 | |
| 			// BoundImport			8
 | |
| 			// IAT					8
 | |
| 			// DelayImportDescriptor8
 | |
| 			Advance (56);
 | |
| 
 | |
| 			// CLIHeader			8
 | |
| 			cli = ReadDataDirectory ();
 | |
| 
 | |
| 			if (cli.IsZero)
 | |
| 				throw new BadImageFormatException ();
 | |
| 
 | |
| 			// Reserved				8
 | |
| 			Advance (8);
 | |
| 		}
 | |
| 
 | |
| 		string ReadAlignedString (int length)
 | |
| 		{
 | |
| 			int read = 0;
 | |
| 			var buffer = new char [length];
 | |
| 			while (read < length) {
 | |
| 				var current = ReadByte ();
 | |
| 				if (current == 0)
 | |
| 					break;
 | |
| 
 | |
| 				buffer [read++] = (char)current;
 | |
| 			}
 | |
| 
 | |
| 			Advance (-1 + ((read + 4) & ~3) - read);
 | |
| 
 | |
| 			return new string (buffer, 0, read);
 | |
| 		}
 | |
| 
 | |
| 		string ReadZeroTerminatedString (int length)
 | |
| 		{
 | |
| 			int read = 0;
 | |
| 			var buffer = new char [length];
 | |
| 			var bytes = ReadBytes (length);
 | |
| 			while (read < length) {
 | |
| 				var current = bytes [read];
 | |
| 				if (current == 0)
 | |
| 					break;
 | |
| 
 | |
| 				buffer [read++] = (char)current;
 | |
| 			}
 | |
| 
 | |
| 			return new string (buffer, 0, read);
 | |
| 		}
 | |
| 
 | |
| 		void ReadSections (ushort count)
 | |
| 		{
 | |
| 			var sections = new Section [count];
 | |
| 
 | |
| 			for (int i = 0; i < count; i++) {
 | |
| 				var section = new Section ();
 | |
| 
 | |
| 				// Name
 | |
| 				section.Name = ReadZeroTerminatedString (8);
 | |
| 
 | |
| 				// VirtualSize		4
 | |
| 				Advance (4);
 | |
| 
 | |
| 				// VirtualAddress	4
 | |
| 				section.VirtualAddress = ReadUInt32 ();
 | |
| 				// SizeOfRawData	4
 | |
| 				section.SizeOfRawData = ReadUInt32 ();
 | |
| 				// PointerToRawData	4
 | |
| 				section.PointerToRawData = ReadUInt32 ();
 | |
| 
 | |
| 				// PointerToRelocations		4
 | |
| 				// PointerToLineNumbers		4
 | |
| 				// NumberOfRelocations		2
 | |
| 				// NumberOfLineNumbers		2
 | |
| 				// Characteristics			4
 | |
| 				Advance (16);
 | |
| 
 | |
| 				sections [i] = section;
 | |
| 			}
 | |
| 
 | |
| 			image.Sections = sections;
 | |
| 		}
 | |
| 
 | |
| 		void ReadCLIHeader ()
 | |
| 		{
 | |
| 			MoveTo (cli);
 | |
| 
 | |
| 			// - CLIHeader
 | |
| 
 | |
| 			// Cb						4
 | |
| 			// MajorRuntimeVersion		2
 | |
| 			// MinorRuntimeVersion		2
 | |
| 			Advance (8);
 | |
| 
 | |
| 			// Metadata					8
 | |
| 			metadata = ReadDataDirectory ();
 | |
| 			// Flags					4
 | |
| 			image.Attributes = (ModuleAttributes)ReadUInt32 ();
 | |
| 			// EntryPointToken			4
 | |
| 			image.EntryPointToken = ReadUInt32 ();
 | |
| 			// Resources				8
 | |
| 			image.Resources = ReadDataDirectory ();
 | |
| 			// StrongNameSignature		8
 | |
| 			image.StrongName = ReadDataDirectory ();
 | |
| 			// CodeManagerTable			8
 | |
| 			// VTableFixups				8
 | |
| 			// ExportAddressTableJumps	8
 | |
| 			// ManagedNativeHeader		8
 | |
| 		}
 | |
| 
 | |
| 		void ReadMetadata ()
 | |
| 		{
 | |
| 			MoveTo (metadata);
 | |
| 
 | |
| 			if (ReadUInt32 () != 0x424a5342)
 | |
| 				throw new BadImageFormatException ();
 | |
| 
 | |
| 			// MajorVersion			2
 | |
| 			// MinorVersion			2
 | |
| 			// Reserved				4
 | |
| 			Advance (8);
 | |
| 
 | |
| 			image.RuntimeVersion = ReadZeroTerminatedString (ReadInt32 ());
 | |
| 
 | |
| 			// Flags		2
 | |
| 			Advance (2);
 | |
| 
 | |
| 			var streams = ReadUInt16 ();
 | |
| 
 | |
| 			var section = image.GetSectionAtVirtualAddress (metadata.VirtualAddress);
 | |
| 			if (section == null)
 | |
| 				throw new BadImageFormatException ();
 | |
| 
 | |
| 			image.MetadataSection = section;
 | |
| 
 | |
| 			for (int i = 0; i < streams; i++)
 | |
| 				ReadMetadataStream (section);
 | |
| 
 | |
| 			if (image.PdbHeap != null)
 | |
| 				ReadPdbHeap ();
 | |
| 
 | |
| 			if (image.TableHeap != null)
 | |
| 				ReadTableHeap ();
 | |
| 		}
 | |
| 
 | |
| 		void ReadDebugHeader ()
 | |
| 		{
 | |
| 			if (image.Debug.IsZero) {
 | |
| 				image.DebugHeader = new ImageDebugHeader (Empty<ImageDebugHeaderEntry>.Array);
 | |
| 				return;
 | |
| 			}
 | |
| 
 | |
| 			MoveTo (image.Debug);
 | |
| 
 | |
| 			var entries = new ImageDebugHeaderEntry [(int)image.Debug.Size / ImageDebugDirectory.Size];
 | |
| 
 | |
| 			for (int i = 0; i < entries.Length; i++) {
 | |
| 				var directory = new ImageDebugDirectory {
 | |
| 					Characteristics = ReadInt32 (),
 | |
| 					TimeDateStamp = ReadInt32 (),
 | |
| 					MajorVersion = ReadInt16 (),
 | |
| 					MinorVersion = ReadInt16 (),
 | |
| 					Type = (ImageDebugType)ReadInt32 (),
 | |
| 					SizeOfData = ReadInt32 (),
 | |
| 					AddressOfRawData = ReadInt32 (),
 | |
| 					PointerToRawData = ReadInt32 (),
 | |
| 				};
 | |
| 
 | |
| 				if (directory.PointerToRawData == 0 || directory.SizeOfData < 0) {
 | |
| 					entries [i] = new ImageDebugHeaderEntry (directory, Empty<byte>.Array);
 | |
| 					continue;
 | |
| 				}
 | |
| 
 | |
| 				var position = Position;
 | |
| 				try {
 | |
| 					MoveTo ((uint)directory.PointerToRawData);
 | |
| 					var data = ReadBytes (directory.SizeOfData);
 | |
| 					entries [i] = new ImageDebugHeaderEntry (directory, data);
 | |
| 				}
 | |
| 				finally {
 | |
| 					Position = position;
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			image.DebugHeader = new ImageDebugHeader (entries);
 | |
| 		}
 | |
| 
 | |
| 		void ReadMetadataStream (Section section)
 | |
| 		{
 | |
| 			// Offset		4
 | |
| 			uint offset = metadata.VirtualAddress - section.VirtualAddress + ReadUInt32 (); // relative to the section start
 | |
| 
 | |
| 			// Size			4
 | |
| 			uint size = ReadUInt32 ();
 | |
| 
 | |
| 			var data = ReadHeapData (offset, size);
 | |
| 
 | |
| 			var name = ReadAlignedString (16);
 | |
| 			switch (name) {
 | |
| 			case "#~":
 | |
| 			case "#-":
 | |
| 				image.TableHeap = new TableHeap (data);
 | |
| 				table_heap_offset = offset;
 | |
| 				break;
 | |
| 			case "#Strings":
 | |
| 				image.StringHeap = new StringHeap (data);
 | |
| 				break;
 | |
| 			case "#Blob":
 | |
| 				image.BlobHeap = new BlobHeap (data);
 | |
| 				break;
 | |
| 			case "#GUID":
 | |
| 				image.GuidHeap = new GuidHeap (data);
 | |
| 				break;
 | |
| 			case "#US":
 | |
| 				image.UserStringHeap = new UserStringHeap (data);
 | |
| 				break;
 | |
| 			case "#Pdb":
 | |
| 				image.PdbHeap = new PdbHeap (data);
 | |
| 				break;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		byte [] ReadHeapData (uint offset, uint size)
 | |
| 		{
 | |
| 			var position = BaseStream.Position;
 | |
| 			MoveTo (offset + image.MetadataSection.PointerToRawData);
 | |
| 			var data = ReadBytes ((int)size);
 | |
| 			BaseStream.Position = position;
 | |
| 
 | |
| 			return data;
 | |
| 		}
 | |
| 
 | |
| 		void ReadTableHeap ()
 | |
| 		{
 | |
| 			var heap = image.TableHeap;
 | |
| 
 | |
| 			MoveTo (table_heap_offset + image.MetadataSection.PointerToRawData);
 | |
| 
 | |
| 			// Reserved			4
 | |
| 			// MajorVersion		1
 | |
| 			// MinorVersion		1
 | |
| 			Advance (6);
 | |
| 
 | |
| 			// HeapSizes		1
 | |
| 			var sizes = ReadByte ();
 | |
| 
 | |
| 			// Reserved2		1
 | |
| 			Advance (1);
 | |
| 
 | |
| 			// Valid			8
 | |
| 			heap.Valid = ReadInt64 ();
 | |
| 
 | |
| 			// Sorted			8
 | |
| 			heap.Sorted = ReadInt64 ();
 | |
| 
 | |
| 			if (image.PdbHeap != null) {
 | |
| 				for (int i = 0; i < Mixin.TableCount; i++) {
 | |
| 					if (!image.PdbHeap.HasTable ((Table)i))
 | |
| 						continue;
 | |
| 
 | |
| 					heap.Tables [i].Length = image.PdbHeap.TypeSystemTableRows [i];
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			for (int i = 0; i < Mixin.TableCount; i++) {
 | |
| 				if (!heap.HasTable ((Table)i))
 | |
| 					continue;
 | |
| 
 | |
| 				heap.Tables [i].Length = ReadUInt32 ();
 | |
| 			}
 | |
| 
 | |
| 			SetIndexSize (image.StringHeap, sizes, 0x1);
 | |
| 			SetIndexSize (image.GuidHeap, sizes, 0x2);
 | |
| 			SetIndexSize (image.BlobHeap, sizes, 0x4);
 | |
| 
 | |
| 			ComputeTableInformations ();
 | |
| 		}
 | |
| 
 | |
| 		static void SetIndexSize (Heap heap, uint sizes, byte flag)
 | |
| 		{
 | |
| 			if (heap == null)
 | |
| 				return;
 | |
| 
 | |
| 			heap.IndexSize = (sizes & flag) > 0 ? 4 : 2;
 | |
| 		}
 | |
| 
 | |
| 		int GetTableIndexSize (Table table)
 | |
| 		{
 | |
| 			return image.GetTableIndexSize (table);
 | |
| 		}
 | |
| 
 | |
| 		int GetCodedIndexSize (CodedIndex index)
 | |
| 		{
 | |
| 			return image.GetCodedIndexSize (index);
 | |
| 		}
 | |
| 
 | |
| 		void ComputeTableInformations ()
 | |
| 		{
 | |
| 			uint offset = (uint)BaseStream.Position - table_heap_offset - image.MetadataSection.PointerToRawData; // header
 | |
| 
 | |
| 			int stridx_size = image.StringHeap != null ? image.StringHeap.IndexSize : 2;
 | |
| 			int guididx_size = image.GuidHeap != null ? image.GuidHeap.IndexSize : 2;
 | |
| 			int blobidx_size = image.BlobHeap != null ? image.BlobHeap.IndexSize : 2;
 | |
| 
 | |
| 			var heap = image.TableHeap;
 | |
| 			var tables = heap.Tables;
 | |
| 
 | |
| 			for (int i = 0; i < Mixin.TableCount; i++) {
 | |
| 				var table = (Table)i;
 | |
| 				if (!heap.HasTable (table))
 | |
| 					continue;
 | |
| 
 | |
| 				int size;
 | |
| 				switch (table) {
 | |
| 				case Table.Module:
 | |
| 					size = 2    // Generation
 | |
| 						+ stridx_size   // Name
 | |
| 						+ (guididx_size * 3);   // Mvid, EncId, EncBaseId
 | |
| 					break;
 | |
| 				case Table.TypeRef:
 | |
| 					size = GetCodedIndexSize (CodedIndex.ResolutionScope)   // ResolutionScope
 | |
| 						+ (stridx_size * 2);    // Name, Namespace
 | |
| 					break;
 | |
| 				case Table.TypeDef:
 | |
| 					size = 4    // Flags
 | |
| 						+ (stridx_size * 2) // Name, Namespace
 | |
| 						+ GetCodedIndexSize (CodedIndex.TypeDefOrRef)   // BaseType
 | |
| 						+ GetTableIndexSize (Table.Field)   // FieldList
 | |
| 						+ GetTableIndexSize (Table.Method); // MethodList
 | |
| 					break;
 | |
| 				case Table.FieldPtr:
 | |
| 					size = GetTableIndexSize (Table.Field); // Field
 | |
| 					break;
 | |
| 				case Table.Field:
 | |
| 					size = 2    // Flags
 | |
| 						+ stridx_size   // Name
 | |
| 						+ blobidx_size; // Signature
 | |
| 					break;
 | |
| 				case Table.MethodPtr:
 | |
| 					size = GetTableIndexSize (Table.Method);    // Method
 | |
| 					break;
 | |
| 				case Table.Method:
 | |
| 					size = 8    // Rva 4, ImplFlags 2, Flags 2
 | |
| 						+ stridx_size   // Name
 | |
| 						+ blobidx_size  // Signature
 | |
| 						+ GetTableIndexSize (Table.Param); // ParamList
 | |
| 					break;
 | |
| 				case Table.ParamPtr:
 | |
| 					size = GetTableIndexSize (Table.Param); // Param
 | |
| 					break;
 | |
| 				case Table.Param:
 | |
| 					size = 4    // Flags 2, Sequence 2
 | |
| 						+ stridx_size;  // Name
 | |
| 					break;
 | |
| 				case Table.InterfaceImpl:
 | |
| 					size = GetTableIndexSize (Table.TypeDef)    // Class
 | |
| 						+ GetCodedIndexSize (CodedIndex.TypeDefOrRef);  // Interface
 | |
| 					break;
 | |
| 				case Table.MemberRef:
 | |
| 					size = GetCodedIndexSize (CodedIndex.MemberRefParent)   // Class
 | |
| 						+ stridx_size   // Name
 | |
| 						+ blobidx_size; // Signature
 | |
| 					break;
 | |
| 				case Table.Constant:
 | |
| 					size = 2    // Type
 | |
| 						+ GetCodedIndexSize (CodedIndex.HasConstant)    // Parent
 | |
| 						+ blobidx_size; // Value
 | |
| 					break;
 | |
| 				case Table.CustomAttribute:
 | |
| 					size = GetCodedIndexSize (CodedIndex.HasCustomAttribute)    // Parent
 | |
| 						+ GetCodedIndexSize (CodedIndex.CustomAttributeType)    // Type
 | |
| 						+ blobidx_size; // Value
 | |
| 					break;
 | |
| 				case Table.FieldMarshal:
 | |
| 					size = GetCodedIndexSize (CodedIndex.HasFieldMarshal)   // Parent
 | |
| 						+ blobidx_size; // NativeType
 | |
| 					break;
 | |
| 				case Table.DeclSecurity:
 | |
| 					size = 2    // Action
 | |
| 						+ GetCodedIndexSize (CodedIndex.HasDeclSecurity)    // Parent
 | |
| 						+ blobidx_size; // PermissionSet
 | |
| 					break;
 | |
| 				case Table.ClassLayout:
 | |
| 					size = 6    // PackingSize 2, ClassSize 4
 | |
| 						+ GetTableIndexSize (Table.TypeDef);    // Parent
 | |
| 					break;
 | |
| 				case Table.FieldLayout:
 | |
| 					size = 4    // Offset
 | |
| 						+ GetTableIndexSize (Table.Field);  // Field
 | |
| 					break;
 | |
| 				case Table.StandAloneSig:
 | |
| 					size = blobidx_size;    // Signature
 | |
| 					break;
 | |
| 				case Table.EventMap:
 | |
| 					size = GetTableIndexSize (Table.TypeDef)    // Parent
 | |
| 						+ GetTableIndexSize (Table.Event);  // EventList
 | |
| 					break;
 | |
| 				case Table.EventPtr:
 | |
| 					size = GetTableIndexSize (Table.Event); // Event
 | |
| 					break;
 | |
| 				case Table.Event:
 | |
| 					size = 2    // Flags
 | |
| 						+ stridx_size // Name
 | |
| 						+ GetCodedIndexSize (CodedIndex.TypeDefOrRef);  // EventType
 | |
| 					break;
 | |
| 				case Table.PropertyMap:
 | |
| 					size = GetTableIndexSize (Table.TypeDef)    // Parent
 | |
| 						+ GetTableIndexSize (Table.Property);   // PropertyList
 | |
| 					break;
 | |
| 				case Table.PropertyPtr:
 | |
| 					size = GetTableIndexSize (Table.Property);  // Property
 | |
| 					break;
 | |
| 				case Table.Property:
 | |
| 					size = 2    // Flags
 | |
| 						+ stridx_size   // Name
 | |
| 						+ blobidx_size; // Type
 | |
| 					break;
 | |
| 				case Table.MethodSemantics:
 | |
| 					size = 2    // Semantics
 | |
| 						+ GetTableIndexSize (Table.Method)  // Method
 | |
| 						+ GetCodedIndexSize (CodedIndex.HasSemantics);  // Association
 | |
| 					break;
 | |
| 				case Table.MethodImpl:
 | |
| 					size = GetTableIndexSize (Table.TypeDef)    // Class
 | |
| 						+ GetCodedIndexSize (CodedIndex.MethodDefOrRef) // MethodBody
 | |
| 						+ GetCodedIndexSize (CodedIndex.MethodDefOrRef);    // MethodDeclaration
 | |
| 					break;
 | |
| 				case Table.ModuleRef:
 | |
| 					size = stridx_size; // Name
 | |
| 					break;
 | |
| 				case Table.TypeSpec:
 | |
| 					size = blobidx_size;    // Signature
 | |
| 					break;
 | |
| 				case Table.ImplMap:
 | |
| 					size = 2    // MappingFlags
 | |
| 						+ GetCodedIndexSize (CodedIndex.MemberForwarded)    // MemberForwarded
 | |
| 						+ stridx_size   // ImportName
 | |
| 						+ GetTableIndexSize (Table.ModuleRef);  // ImportScope
 | |
| 					break;
 | |
| 				case Table.FieldRVA:
 | |
| 					size = 4    // RVA
 | |
| 						+ GetTableIndexSize (Table.Field);  // Field
 | |
| 					break;
 | |
| 				case Table.EncLog:
 | |
| 					size = 8;
 | |
| 					break;
 | |
| 				case Table.EncMap:
 | |
| 					size = 4;
 | |
| 					break;
 | |
| 				case Table.Assembly:
 | |
| 					size = 16 // HashAlgId 4, Version 4 * 2, Flags 4
 | |
| 						+ blobidx_size  // PublicKey
 | |
| 						+ (stridx_size * 2);    // Name, Culture
 | |
| 					break;
 | |
| 				case Table.AssemblyProcessor:
 | |
| 					size = 4;   // Processor
 | |
| 					break;
 | |
| 				case Table.AssemblyOS:
 | |
| 					size = 12;  // Platform 4, Version 2 * 4
 | |
| 					break;
 | |
| 				case Table.AssemblyRef:
 | |
| 					size = 12   // Version 2 * 4 + Flags 4
 | |
| 						+ (blobidx_size * 2)    // PublicKeyOrToken, HashValue
 | |
| 						+ (stridx_size * 2);    // Name, Culture
 | |
| 					break;
 | |
| 				case Table.AssemblyRefProcessor:
 | |
| 					size = 4    // Processor
 | |
| 						+ GetTableIndexSize (Table.AssemblyRef);    // AssemblyRef
 | |
| 					break;
 | |
| 				case Table.AssemblyRefOS:
 | |
| 					size = 12   // Platform 4, Version 2 * 4
 | |
| 						+ GetTableIndexSize (Table.AssemblyRef);    // AssemblyRef
 | |
| 					break;
 | |
| 				case Table.File:
 | |
| 					size = 4    // Flags
 | |
| 						+ stridx_size   // Name
 | |
| 						+ blobidx_size; // HashValue
 | |
| 					break;
 | |
| 				case Table.ExportedType:
 | |
| 					size = 8    // Flags 4, TypeDefId 4
 | |
| 						+ (stridx_size * 2) // Name, Namespace
 | |
| 						+ GetCodedIndexSize (CodedIndex.Implementation);    // Implementation
 | |
| 					break;
 | |
| 				case Table.ManifestResource:
 | |
| 					size = 8    // Offset, Flags
 | |
| 						+ stridx_size   // Name
 | |
| 						+ GetCodedIndexSize (CodedIndex.Implementation);    // Implementation
 | |
| 					break;
 | |
| 				case Table.NestedClass:
 | |
| 					size = GetTableIndexSize (Table.TypeDef)    // NestedClass
 | |
| 						+ GetTableIndexSize (Table.TypeDef);    // EnclosingClass
 | |
| 					break;
 | |
| 				case Table.GenericParam:
 | |
| 					size = 4    // Number, Flags
 | |
| 						+ GetCodedIndexSize (CodedIndex.TypeOrMethodDef)    // Owner
 | |
| 						+ stridx_size;  // Name
 | |
| 					break;
 | |
| 				case Table.MethodSpec:
 | |
| 					size = GetCodedIndexSize (CodedIndex.MethodDefOrRef)    // Method
 | |
| 						+ blobidx_size; // Instantiation
 | |
| 					break;
 | |
| 				case Table.GenericParamConstraint:
 | |
| 					size = GetTableIndexSize (Table.GenericParam)   // Owner
 | |
| 						+ GetCodedIndexSize (CodedIndex.TypeDefOrRef);  // Constraint
 | |
| 					break;
 | |
| 				case Table.Document:
 | |
| 					size = blobidx_size // Name
 | |
| 						+ guididx_size  // HashAlgorithm
 | |
| 						+ blobidx_size  // Hash
 | |
| 						+ guididx_size; // Language
 | |
| 					break;
 | |
| 				case Table.MethodDebugInformation:
 | |
| 					size = GetTableIndexSize (Table.Document)  // Document
 | |
| 						+ blobidx_size; // SequencePoints
 | |
| 					break;
 | |
| 				case Table.LocalScope:
 | |
| 					size = GetTableIndexSize (Table.Method) // Method
 | |
| 						+ GetTableIndexSize (Table.ImportScope) // ImportScope
 | |
| 						+ GetTableIndexSize (Table.LocalVariable)   // VariableList
 | |
| 						+ GetTableIndexSize (Table.LocalConstant)   // ConstantList
 | |
| 						+ 4 * 2;    // StartOffset, Length
 | |
| 					break;
 | |
| 				case Table.LocalVariable:
 | |
| 					size = 2    // Attributes
 | |
| 						+ 2     // Index
 | |
| 						+ stridx_size;  // Name
 | |
| 					break;
 | |
| 				case Table.LocalConstant:
 | |
| 					size = stridx_size  // Name
 | |
| 						+ blobidx_size; // Signature
 | |
| 					break;
 | |
| 				case Table.ImportScope:
 | |
| 					size = GetTableIndexSize (Table.ImportScope)    // Parent
 | |
| 						+ blobidx_size;
 | |
| 					break;
 | |
| 				case Table.StateMachineMethod:
 | |
| 					size = GetTableIndexSize (Table.Method) // MoveNextMethod
 | |
| 						+ GetTableIndexSize (Table.Method); // KickOffMethod
 | |
| 					break;
 | |
| 				case Table.CustomDebugInformation:
 | |
| 					size = GetCodedIndexSize (CodedIndex.HasCustomDebugInformation) // Parent
 | |
| 						+ guididx_size  // Kind
 | |
| 						+ blobidx_size; // Value
 | |
| 					break;
 | |
| 				default:
 | |
| 					throw new NotSupportedException ();
 | |
| 				}
 | |
| 
 | |
| 				tables [i].RowSize = (uint)size;
 | |
| 				tables [i].Offset = offset;
 | |
| 
 | |
| 				offset += (uint)size * tables [i].Length;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		void ReadPdbHeap ()
 | |
| 		{
 | |
| 			var heap = image.PdbHeap;
 | |
| 
 | |
| 			var buffer = new ByteBuffer (heap.data);
 | |
| 
 | |
| 			heap.Id = buffer.ReadBytes (20);
 | |
| 			heap.EntryPoint = buffer.ReadUInt32 ();
 | |
| 			heap.TypeSystemTables = buffer.ReadInt64 ();
 | |
| 			heap.TypeSystemTableRows = new uint [Mixin.TableCount];
 | |
| 
 | |
| 			for (int i = 0; i < Mixin.TableCount; i++) {
 | |
| 				var table = (Table)i;
 | |
| 				if (!heap.HasTable (table))
 | |
| 					continue;
 | |
| 
 | |
| 				heap.TypeSystemTableRows [i] = buffer.ReadUInt32 ();
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		public static Image ReadImage (Disposable<Stream> stream, string file_name)
 | |
| 		{
 | |
| 			try {
 | |
| 				var reader = new ImageReader (stream, file_name);
 | |
| 				reader.ReadImage ();
 | |
| 				return reader.image;
 | |
| 			}
 | |
| 			catch (EndOfStreamException e) {
 | |
| 				throw new BadImageFormatException (stream.value.GetFileName (), e);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		public static Image ReadPortablePdb (Disposable<Stream> stream, string file_name)
 | |
| 		{
 | |
| 			try {
 | |
| 				var reader = new ImageReader (stream, file_name);
 | |
| 				var length = (uint)stream.value.Length;
 | |
| 
 | |
| 				reader.image.Sections = new [] {
 | |
| 					new Section {
 | |
| 						PointerToRawData = 0,
 | |
| 						SizeOfRawData = length,
 | |
| 						VirtualAddress = 0,
 | |
| 						VirtualSize = length,
 | |
| 					}
 | |
| 				};
 | |
| 
 | |
| 				reader.metadata = new DataDirectory (0, length);
 | |
| 				reader.ReadMetadata ();
 | |
| 				return reader.image;
 | |
| 			}
 | |
| 			catch (EndOfStreamException e) {
 | |
| 				throw new BadImageFormatException (stream.value.GetFileName (), e);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 |