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);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|