5
// Jb Evain (jbevain@gmail.com)
7
// Copyright (c) 2008 - 2010 Jb Evain
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:
17
// The above copyright notice and this permission notice shall be
18
// included in all copies or substantial portions of the Software.
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.
32
using Mono.Cecil.Metadata;
34
using RVA = System.UInt32;
36
namespace Mono.Cecil.PE {
38
sealed class ImageReader : BinaryStreamReader {
43
DataDirectory metadata;
45
public ImageReader (Stream stream)
50
image.FileName = stream.GetFullyQualifiedName ();
53
void MoveTo (DataDirectory directory)
55
BaseStream.Position = image.ResolveVirtualAddress (directory.VirtualAddress);
58
void MoveTo (uint position)
60
BaseStream.Position = position;
65
if (BaseStream.Length < 128)
66
throw new BadImageFormatException ();
75
if (ReadUInt16 () != 0x5a4d)
76
throw new BadImageFormatException ();
80
MoveTo (ReadUInt32 ());
82
if (ReadUInt32 () != 0x00004550)
83
throw new BadImageFormatException ();
88
image.Architecture = ReadArchitecture ();
91
ushort sections = ReadUInt16 ();
94
// PointerToSymbolTable 4
96
// OptionalHeaderSize 2
100
ushort characteristics = ReadUInt16 ();
103
ReadOptionalHeaders (out subsystem);
104
ReadSections (sections);
108
image.Kind = GetModuleKind (characteristics, subsystem);
111
TargetArchitecture ReadArchitecture ()
113
var machine = ReadUInt16 ();
116
return TargetArchitecture.I386;
118
return TargetArchitecture.AMD64;
120
return TargetArchitecture.IA64;
123
throw new NotSupportedException ();
126
static ModuleKind GetModuleKind (ushort characteristics, ushort subsystem)
128
if ((characteristics & 0x2000) != 0) // ImageCharacteristics.Dll
129
return ModuleKind.Dll;
131
if (subsystem == 0x2 || subsystem == 0x9) // SubSystem.WindowsGui || SubSystem.WindowsCeGui
132
return ModuleKind.Windows;
134
return ModuleKind.Console;
137
void ReadOptionalHeaders (out ushort subsystem)
139
// - PEOptionalHeader
140
// - StandardFieldsHeader
143
bool pe64 = ReadUInt16 () == 0x20b;
150
// InitializedDataSize 4
151
// UninitializedDataSize4
156
// - NTSpecificFieldsHeader
159
// SectionAlignment 4
174
subsystem = ReadUInt16 ();
177
// StackReserveSize 4 || 8
178
// StackCommitSize 4 || 8
179
// HeapReserveSize 4 || 8
180
// HeapCommitSize 4 || 8
184
// - DataDirectoriesHeader
190
// CertificateTable 8
191
// BaseRelocationTable 8
193
Advance (pe64 ? 90 : 74);
196
image.Debug = ReadDataDirectory ();
204
// DelayImportDescriptor8
208
cli = ReadDataDirectory ();
211
throw new BadImageFormatException ();
217
string ReadAlignedString (int length)
220
var buffer = new char [length];
221
while (read < length) {
222
var current = ReadByte ();
226
buffer [read++] = (char) current;
229
Advance (-1 + ((read + 4) & ~3) - read);
231
return new string (buffer, 0, read);
234
string ReadZeroTerminatedString (int length)
237
var buffer = new char [length];
238
var bytes = ReadBytes (length);
239
while (read < length) {
240
var current = bytes [read];
244
buffer [read++] = (char) current;
247
return new string (buffer, 0, read);
250
void ReadSections (ushort count)
252
var sections = new Section [count];
254
for (int i = 0; i < count; i++) {
255
var section = new Section ();
258
section.Name = ReadZeroTerminatedString (8);
264
section.VirtualAddress = ReadUInt32 ();
266
section.SizeOfRawData = ReadUInt32 ();
267
// PointerToRawData 4
268
section.PointerToRawData = ReadUInt32 ();
270
// PointerToRelocations 4
271
// PointerToLineNumbers 4
272
// NumberOfRelocations 2
273
// NumberOfLineNumbers 2
277
sections [i] = section;
279
if (section.Name == ".reloc")
282
ReadSectionData (section);
285
image.Sections = sections;
288
void ReadSectionData (Section section)
290
var position = BaseStream.Position;
292
MoveTo (section.PointerToRawData);
294
var length = (int) section.SizeOfRawData;
295
var data = new byte [length];
296
int offset = 0, read;
298
while ((read = Read (data, offset, length - offset)) > 0)
303
BaseStream.Position = position;
306
void ReadCLIHeader ()
313
// MajorRuntimeVersion 2
314
// MinorRuntimeVersion 2
318
metadata = ReadDataDirectory ();
320
image.Attributes = (ModuleAttributes) ReadUInt32 ();
322
image.EntryPointToken = ReadUInt32 ();
324
image.Resources = ReadDataDirectory ();
325
// StrongNameSignature 8
326
// CodeManagerTable 8
328
// ExportAddressTableJumps 8
329
// ManagedNativeHeader 8
336
if (ReadUInt32 () != 0x424a5342)
337
throw new BadImageFormatException ();
344
var version = ReadZeroTerminatedString (ReadInt32 ());
345
image.Runtime = version.ParseRuntime ();
350
var streams = ReadUInt16 ();
352
var section = image.GetSectionAtVirtualAddress (metadata.VirtualAddress);
354
throw new BadImageFormatException ();
356
image.MetadataSection = section;
358
for (int i = 0; i < streams; i++)
359
ReadMetadataStream (section);
361
if (image.TableHeap != null)
365
void ReadMetadataStream (Section section)
368
uint start = metadata.VirtualAddress - section.VirtualAddress + ReadUInt32 (); // relative to the section start
371
uint size = ReadUInt32 ();
373
var name = ReadAlignedString (16);
377
image.TableHeap = new TableHeap (section, start, size);
380
image.StringHeap = new StringHeap (section, start, size);
383
image.BlobHeap = new BlobHeap (section, start, size);
386
image.GuidHeap = new GuidHeap (section, start, size);
389
image.UserStringHeap = new UserStringHeap (section, start, size);
394
void ReadTableHeap ()
396
var heap = image.TableHeap;
398
uint start = heap.Section.PointerToRawData;
400
MoveTo (heap.Offset + start);
408
var sizes = ReadByte ();
414
heap.Valid = ReadInt64 ();
417
heap.Sorted = ReadInt64 ();
419
for (int i = 0; i < TableHeap.TableIdentifiers.Length; i++) {
420
var table = TableHeap.TableIdentifiers [i];
421
if (!heap.HasTable (table))
424
heap.Tables [(int) table].Length = ReadUInt32 ();
427
SetIndexSize (image.StringHeap, sizes, 0x1);
428
SetIndexSize (image.GuidHeap, sizes, 0x2);
429
SetIndexSize (image.BlobHeap, sizes, 0x4);
431
ComputeTableInformations ();
434
static void SetIndexSize (Heap heap, uint sizes, byte flag)
439
heap.IndexSize = (sizes & flag) > 0 ? 4 : 2;
442
int GetTableIndexSize (Table table)
444
return image.GetTableIndexSize (table);
447
int GetCodedIndexSize (CodedIndex index)
449
return image.GetCodedIndexSize (index);
452
void ComputeTableInformations ()
454
uint offset = (uint) BaseStream.Position - image.MetadataSection.PointerToRawData; // header
456
int stridx_size = image.StringHeap.IndexSize;
457
int blobidx_size = image.BlobHeap != null ? image.BlobHeap.IndexSize : 2;
459
var heap = image.TableHeap;
460
var tables = heap.Tables;
462
for (int i = 0; i < TableHeap.TableIdentifiers.Length; i++) {
463
var table = TableHeap.TableIdentifiers [i];
464
if (!heap.HasTable (table))
470
size = 2 // Generation
471
+ stridx_size // Name
472
+ (image.GuidHeap.IndexSize * 3); // Mvid, EncId, EncBaseId
475
size = GetCodedIndexSize (CodedIndex.ResolutionScope) // ResolutionScope
476
+ (stridx_size * 2); // Name, Namespace
480
+ (stridx_size * 2) // Name, Namespace
481
+ GetCodedIndexSize (CodedIndex.TypeDefOrRef) // BaseType
482
+ GetTableIndexSize (Table.Field) // FieldList
483
+ GetTableIndexSize (Table.Method); // MethodList
486
size = GetTableIndexSize (Table.Field); // Field
490
+ stridx_size // Name
491
+ blobidx_size; // Signature
493
case Table.MethodPtr:
494
size = GetTableIndexSize (Table.Method); // Method
497
size = 8 // Rva 4, ImplFlags 2, Flags 2
498
+ stridx_size // Name
499
+ blobidx_size // Signature
500
+ GetTableIndexSize (Table.Param); // ParamList
503
size = GetTableIndexSize (Table.Param); // Param
506
size = 4 // Flags 2, Sequence 2
507
+ stridx_size; // Name
509
case Table.InterfaceImpl:
510
size = GetTableIndexSize (Table.TypeDef) // Class
511
+ GetCodedIndexSize (CodedIndex.TypeDefOrRef); // Interface
513
case Table.MemberRef:
514
size = GetCodedIndexSize (CodedIndex.MemberRefParent) // Class
515
+ stridx_size // Name
516
+ blobidx_size; // Signature
520
+ GetCodedIndexSize (CodedIndex.HasConstant) // Parent
521
+ blobidx_size; // Value
523
case Table.CustomAttribute:
524
size = GetCodedIndexSize (CodedIndex.HasCustomAttribute) // Parent
525
+ GetCodedIndexSize (CodedIndex.CustomAttributeType) // Type
526
+ blobidx_size; // Value
528
case Table.FieldMarshal:
529
size = GetCodedIndexSize (CodedIndex.HasFieldMarshal) // Parent
530
+ blobidx_size; // NativeType
532
case Table.DeclSecurity:
534
+ GetCodedIndexSize (CodedIndex.HasDeclSecurity) // Parent
535
+ blobidx_size; // PermissionSet
537
case Table.ClassLayout:
538
size = 6 // PackingSize 2, ClassSize 4
539
+ GetTableIndexSize (Table.TypeDef); // Parent
541
case Table.FieldLayout:
543
+ GetTableIndexSize (Table.Field); // Field
545
case Table.StandAloneSig:
546
size = blobidx_size; // Signature
549
size = GetTableIndexSize (Table.TypeDef) // Parent
550
+ GetTableIndexSize (Table.Event); // EventList
553
size = GetTableIndexSize (Table.Event); // Event
557
+ stridx_size // Name
558
+ GetCodedIndexSize (CodedIndex.TypeDefOrRef); // EventType
560
case Table.PropertyMap:
561
size = GetTableIndexSize (Table.TypeDef) // Parent
562
+ GetTableIndexSize (Table.Property); // PropertyList
564
case Table.PropertyPtr:
565
size = GetTableIndexSize (Table.Property); // Property
569
+ stridx_size // Name
570
+ blobidx_size; // Type
572
case Table.MethodSemantics:
573
size = 2 // Semantics
574
+ GetTableIndexSize (Table.Method) // Method
575
+ GetCodedIndexSize (CodedIndex.HasSemantics); // Association
577
case Table.MethodImpl:
578
size = GetTableIndexSize (Table.TypeDef) // Class
579
+ GetCodedIndexSize (CodedIndex.MethodDefOrRef) // MethodBody
580
+ GetCodedIndexSize (CodedIndex.MethodDefOrRef); // MethodDeclaration
582
case Table.ModuleRef:
583
size = stridx_size; // Name
586
size = blobidx_size; // Signature
589
size = 2 // MappingFlags
590
+ GetCodedIndexSize (CodedIndex.MemberForwarded) // MemberForwarded
591
+ stridx_size // ImportName
592
+ GetTableIndexSize (Table.ModuleRef); // ImportScope
596
+ GetTableIndexSize (Table.Field); // Field
599
size = 16 // HashAlgId 4, Version 4 * 2, Flags 4
600
+ blobidx_size // PublicKey
601
+ (stridx_size * 2); // Name, Culture
603
case Table.AssemblyProcessor:
604
size = 4; // Processor
606
case Table.AssemblyOS:
607
size = 12; // Platform 4, Version 2 * 4
609
case Table.AssemblyRef:
610
size = 12 // Version 2 * 4 + Flags 4
611
+ (blobidx_size * 2) // PublicKeyOrToken, HashValue
612
+ (stridx_size * 2); // Name, Culture
614
case Table.AssemblyRefProcessor:
615
size = 4 // Processor
616
+ GetTableIndexSize (Table.AssemblyRef); // AssemblyRef
618
case Table.AssemblyRefOS:
619
size = 12 // Platform 4, Version 2 * 4
620
+ GetTableIndexSize (Table.AssemblyRef); // AssemblyRef
624
+ stridx_size // Name
625
+ blobidx_size; // HashValue
627
case Table.ExportedType:
628
size = 8 // Flags 4, TypeDefId 4
629
+ (stridx_size * 2) // Name, Namespace
630
+ GetCodedIndexSize (CodedIndex.Implementation); // Implementation
632
case Table.ManifestResource:
633
size = 8 // Offset, Flags
634
+ stridx_size // Name
635
+ GetCodedIndexSize (CodedIndex.Implementation); // Implementation
637
case Table.NestedClass:
638
size = GetTableIndexSize (Table.TypeDef) // NestedClass
639
+ GetTableIndexSize (Table.TypeDef); // EnclosingClass
641
case Table.GenericParam:
642
size = 4 // Number, Flags
643
+ GetCodedIndexSize (CodedIndex.TypeOrMethodDef) // Owner
644
+ stridx_size; // Name
646
case Table.MethodSpec:
647
size = GetCodedIndexSize (CodedIndex.MethodDefOrRef) // Method
648
+ blobidx_size; // Instantiation
650
case Table.GenericParamConstraint:
651
size = GetTableIndexSize (Table.GenericParam) // Owner
652
+ GetCodedIndexSize (CodedIndex.TypeDefOrRef); // Constraint
655
throw new NotSupportedException ();
658
int index = (int) table;
660
tables [index].RowSize = (uint) size;
661
tables [index].Offset = offset;
663
offset += (uint) size * tables [index].Length;
667
public static Image ReadImageFrom (Stream stream)
670
var reader = new ImageReader (stream);
673
} catch (EndOfStreamException e) {
674
throw new BadImageFormatException (stream.GetFullyQualifiedName (), e);