3 using System
.Collections
;
8 /**************************************************************************/
10 /// Image for a PEFile
12 /// DOS Header (128 bytes)
13 /// PE Signature ("PE\0\0")
14 /// PEFileHeader (20 bytes)
15 /// PEOptionalHeader (224 bytes)
16 /// SectionHeaders (40 bytes * NumSections)
18 /// Sections .text (always present - contains metadata)
19 /// .sdata (contains any initialised data in the file - may not be present)
20 /// (for ilams /debug this contains the Debug table)
21 /// .reloc (always present - in pure CIL only has one fixup)
22 /// others??? c# produces .rsrc section containing a Resource Table
25 /// IAT (single entry 8 bytes for pure CIL)
26 /// CLIHeader (72 bytes)
27 /// CIL instructions for all methods (variable size)
29 /// Root (20 bytes + UTF-8 Version String + quad align padding)
30 /// StreamHeaders (8 bytes + null terminated name string + quad align padding)
32 /// #~ (always present - holds metadata tables)
33 /// #Strings (always present - holds identifier strings)
34 /// #US (Userstring heap)
35 /// #Blob (signature blobs)
36 /// #GUID (guids for assemblies or Modules)
37 /// ImportTable (40 bytes)
38 /// ImportLookupTable(8 bytes) (same as IAT for standard CIL files)
39 /// Hint/Name Tables with entry "_CorExeMain" for .exe file and "_CorDllMain" for .dll (14 bytes)
40 /// ASCII string "mscoree.dll" referenced in ImportTable (+ padding = 16 bytes)
41 /// Entry Point (0xFF25 followed by 4 bytes 0x400000 + RVA of .text)
43 /// #~ stream structure
45 /// Rows (4 bytes * numTables)
48 internal class FileImage
: BinaryWriter
{
50 internal readonly static uint[] iByteMask
= {0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000}
;
51 internal readonly static ulong[] lByteMask
= {0x00000000000000FF, 0x000000000000FF00,
52 0x0000000000FF0000, 0x00000000FF000000,
53 0x000000FF00000000, 0x0000FF0000000000,
54 0x00FF000000000000, 0xFF00000000000000 };
55 internal readonly static uint nibble0Mask
= 0x0000000F;
56 internal readonly static uint nibble1Mask
= 0x000000F0;
58 private static readonly byte[] DOSHeader
= { 0x4d,0x5a,0x90,0x00,0x03,0x00,0x00,0x00,
59 0x04,0x00,0x00,0x00,0xff,0xff,0x00,0x00,
60 0xb8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
61 0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
62 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
63 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
64 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
65 0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,
66 0x0e,0x1f,0xba,0x0e,0x00,0xb4,0x09,0xcd,
67 0x21,0xb8,0x01,0x4c,0xcd,0x21,0x54,0x68,
68 0x69,0x73,0x20,0x70,0x72,0x6f,0x67,0x72,
69 0x61,0x6d,0x20,0x63,0x61,0x6e,0x6e,0x6f,
70 0x74,0x20,0x62,0x65,0x20,0x72,0x75,0x6e,
71 0x20,0x69,0x6e,0x20,0x44,0x4f,0x53,0x20,
72 0x6d,0x6f,0x64,0x65,0x2e,0x0d,0x0d,0x0a,
73 0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
75 private static byte[] PEHeader
= { 0x4c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
76 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
77 0xE0, 0x00, 0x0E, 0x01, // PE Header Standard Fields
78 0x0B, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
79 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
80 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
83 private static readonly uint minFileAlign
= 0x200;
84 private static readonly uint maxFileAlign
= 0x1000;
85 private static readonly uint fileHeaderSize
= 0x178;
86 private static readonly uint sectionHeaderSize
= 40;
87 private static readonly uint SectionAlignment
= 0x2000;
88 private static readonly uint ImageBase
= 0x400000;
89 private static readonly uint ImportTableSize
= 40;
90 private static readonly uint IATSize
= 8;
91 private static readonly uint CLIHeaderSize
= 72;
92 private uint runtimeFlags
= 0x01; // COMIMAGE_FLAGS_ILONLY
93 // 32BITREQUIRED 0x02, STRONGNAMESIGNED 0x08, TRACKDEBUGDATA 0x10000
94 private static readonly uint StrongNameSignatureSize
= 128;
95 private bool reserveStrongNameSignatureSpace
= false;
97 private static readonly uint relocFlags
= 0x42000040;
98 private static readonly ushort exeCharacteristics
= 0x010E;
99 private static readonly ushort dllCharacteristics
= 0x210E;
100 // section names are all 8 bytes
101 private static readonly string textName
= ".text\0\0\0";
102 private static readonly string sdataName
= ".sdata\0\0";
103 private static readonly string relocName
= ".reloc\0\0";
104 private static readonly string rsrcName
= ".rsrc\0\0\0";
105 private static readonly string exeHintNameTable
= "\0\0_CorExeMain\0";
106 private static readonly string dllHintNameTable
= "\0\0_CorDllMain\0";
107 private static readonly string runtimeEngineName
= "mscoree.dll\0\0";
109 private Section text
, sdata
;
110 static readonly Section rsrc
= null;
112 BinaryWriter reloc
= new BinaryWriter(new MemoryStream());
114 DateTime origin
= new DateTime(1970,1,1);
115 uint numSections
= 2; // always have .text and .reloc sections
116 internal SubSystem subSys
= SubSystem
.Windows_CUI
; // default is Windows Console mode
117 internal long stackReserve
= 0x100000; // default is 1Mb
118 internal uint fileAlign
= minFileAlign
;
119 uint entryPointOffset
, entryPointPadding
, imageSize
, headerSize
, headerPadding
, entryPointToken
= 0;
120 uint relocOffset
, relocRVA
, relocSize
, relocPadding
, relocTide
, hintNameTableOffset
;
121 uint metaDataOffset
, runtimeEngineOffset
, initDataSize
= 0, importTablePadding
;
122 uint resourcesSize
, resourcesOffset
;
123 uint strongNameSigOffset
;
124 uint importTableOffset
, importLookupTableOffset
, totalImportTableSize
;
126 char[] runtimeEngine
= runtimeEngineName
.ToCharArray(), hintNameTable
;
127 bool doDLL
, largeStrings
, largeGUID
, largeUS
, largeBlob
;
128 ushort characteristics
;
130 internal FileImage(bool makeDLL
, string fileName
) : base(new FileStream(fileName
,FileMode
.Create
))
132 InitFileImage(makeDLL
);
133 TimeSpan tmp
= System
.IO
.File
.GetCreationTime(fileName
).Subtract(origin
);
134 dateStamp
= Convert
.ToUInt32(tmp
.TotalSeconds
);
137 internal FileImage(bool makeDLL
, Stream str
) : base(str
)
139 InitFileImage(makeDLL
);
140 TimeSpan tmp
= DateTime
.Now
.Subtract(origin
);
141 dateStamp
= Convert
.ToUInt32(tmp
.TotalSeconds
);
144 private void InitFileImage(bool makeDLL
)
148 hintNameTable
= dllHintNameTable
.ToCharArray();
149 characteristics
= dllCharacteristics
;
151 hintNameTable
= exeHintNameTable
.ToCharArray();
152 characteristics
= exeCharacteristics
;
154 text
= new Section(textName
,0x60000020); // IMAGE_SCN_CNT CODE, EXECUTE, READ
155 // rsrc = new Section(rsrcName,0x40000040); // IMAGE_SCN_CNT INITIALIZED_DATA, READ
156 metaData
= new MetaData(this);
159 internal MetaData
GetMetaData()
164 private uint GetNextSectStart(uint rva
, uint tide
)
166 uint c
= tide
/ SectionAlignment
;
167 if ((tide
% SectionAlignment
) != 0)
169 return rva
+ (c
* SectionAlignment
);
172 private void BuildTextSection()
175 // IAT (single entry 8 bytes for pure CIL)
176 // CLIHeader (72 bytes)
177 // CIL instructions for all methods (variable size)
179 // ImportTable (40 bytes)
180 // ImportLookupTable(8 bytes) (same as IAT for standard CIL files)
181 // Hint/Name Tables with entry "_CorExeMain" for .exe file and "_CorDllMain" for .dll (14 bytes)
182 // ASCII string "mscoree.dll" referenced in ImportTable (+ padding = 16 bytes)
183 // Entry Point (0xFF25 followed by 4 bytes 0x400000 + RVA of .text)
184 metaData
.BuildMetaData(IATSize
+ CLIHeaderSize
);
185 metaDataOffset
= IATSize
+ CLIHeaderSize
;
186 // Console.WriteLine("Code starts at " + metaDataOffset);
187 metaDataOffset
+= metaData
.CodeSize();
189 resourcesOffset
= metaDataOffset
+ metaData
.Size ();
190 resourcesSize
= metaData
.GetResourcesSize ();
191 if (reserveStrongNameSignatureSpace
) {
192 strongNameSigOffset
= resourcesOffset
+ resourcesSize
;
193 // fixUps = RVA for vtable
194 importTableOffset
= strongNameSigOffset
+ StrongNameSignatureSize
;
196 strongNameSigOffset
= 0;
197 // fixUps = RVA for vtable
198 importTableOffset
= resourcesOffset
+ resourcesSize
;
200 importTablePadding
= NumToAlign(importTableOffset
,16);
201 importTableOffset
+= importTablePadding
;
202 importLookupTableOffset
= importTableOffset
+ ImportTableSize
;
203 hintNameTableOffset
= importLookupTableOffset
+ IATSize
;
204 runtimeEngineOffset
= hintNameTableOffset
+ (uint)hintNameTable
.Length
;
205 entryPointOffset
= runtimeEngineOffset
+ (uint)runtimeEngine
.Length
;
206 totalImportTableSize
= entryPointOffset
- importTableOffset
;
207 // Console.WriteLine("total import table size = " + totalImportTableSize);
208 // Console.WriteLine("entrypoint offset = " + entryPointOffset);
209 entryPointPadding
= NumToAlign(entryPointOffset
,4) + 2;
210 entryPointOffset
+= entryPointPadding
;
211 text
.AddReloc(entryPointOffset
+2);
212 text
.IncTide(entryPointOffset
+ 6);
213 //if (text.Tide() < fileAlign) fileAlign = minFileAlign;
214 text
.SetSize(NumToAlign(text
.Tide(),fileAlign
));
215 // Console.WriteLine("text size = " + text.Size() + " text tide = " + text.Tide() + " text padding = " + text.Padding());
216 // Console.WriteLine("metaDataOffset = " + Hex.Int(metaDataOffset));
217 // Console.WriteLine("importTableOffset = " + Hex.Int(importTableOffset));
218 // Console.WriteLine("importLookupTableOffset = " + Hex.Int(importLookupTableOffset));
219 // Console.WriteLine("hintNameTableOffset = " + Hex.Int(hintNameTableOffset));
220 // Console.WriteLine("runtimeEngineOffset = " + Hex.Int(runtimeEngineOffset));
221 // Console.WriteLine("entryPointOffset = " + Hex.Int(entryPointOffset));
222 // Console.WriteLine("entryPointPadding = " + Hex.Int(entryPointPadding));
226 internal void BuildRelocSection()
228 text
.DoRelocs(reloc
);
229 if (sdata
!= null) sdata
.DoRelocs(reloc
);
230 if (rsrc
!= null) rsrc
.DoRelocs(reloc
);
231 relocTide
= (uint)reloc
.Seek(0,SeekOrigin
.Current
);
232 relocPadding
= NumToAlign(relocTide
,fileAlign
);
233 relocSize
= relocTide
+ relocPadding
;
234 imageSize
= relocRVA
+ SectionAlignment
;
235 initDataSize
+= relocSize
;
238 private void CalcOffsets()
244 headerSize
= fileHeaderSize
+ (numSections
* sectionHeaderSize
);
245 headerPadding
= NumToAlign(headerSize
,fileAlign
);
246 headerSize
+= headerPadding
;
247 uint offset
= headerSize
;
248 uint rva
= SectionAlignment
;
249 text
.SetOffset(offset
);
251 offset
+= text
.Size();
252 rva
= GetNextSectStart(rva
,text
.Tide());
253 // Console.WriteLine("headerSize = " + headerSize);
254 // Console.WriteLine("headerPadding = " + headerPadding);
255 // Console.WriteLine("textOffset = " + Hex.Int(text.Offset()));
257 sdata
.SetSize(NumToAlign(sdata
.Tide(),fileAlign
));
258 sdata
.SetOffset(offset
);
260 offset
+= sdata
.Size();
261 rva
= GetNextSectStart(rva
,sdata
.Tide());
262 initDataSize
+= sdata
.Size();
265 rsrc
.SetSize(NumToAlign(rsrc
.Tide(),fileAlign
));
266 rsrc
.SetOffset(offset
);
268 offset
+= rsrc
.Size();
269 rva
= GetNextSectStart(rva
,rsrc
.Tide());
270 initDataSize
+= rsrc
.Size();
272 relocOffset
= offset
;
276 internal void MakeFile()
278 if (doDLL
) hintNameTable
= dllHintNameTable
.ToCharArray();
279 else hintNameTable
= exeHintNameTable
.ToCharArray();
290 private void WriteHeader()
293 // Console.WriteLine("Writing PEHeader at offset " + Seek(0,SeekOrigin.Current));
295 // Console.WriteLine("Writing text section header at offset " + Hex.Long(Seek(0,SeekOrigin.Current)));
296 text
.WriteHeader(this,relocRVA
);
297 if (sdata
!= null) sdata
.WriteHeader(this,relocRVA
);
298 if (rsrc
!= null) rsrc
.WriteHeader(this,relocRVA
);
299 // Console.WriteLine("Writing reloc section header at offset " + Seek(0,SeekOrigin.Current));
300 WriteRelocSectionHeader();
301 // Console.WriteLine("Writing padding at offset " + Seek(0,SeekOrigin.Current));
302 WriteZeros(headerPadding
);
305 private void WriteSections()
307 // Console.WriteLine("Writing text section at offset " + Seek(0,SeekOrigin.Current));
309 if (sdata
!= null) WriteSDataSection();
310 if (rsrc
!= null) WriteRsrcSection();
314 private void WriteIAT()
316 Write(text
.RVA() + hintNameTableOffset
);
320 private void WriteImportTables()
323 WriteZeros(importTablePadding
);
324 // Console.WriteLine("Writing import tables at offset " + Hex.Long(Seek(0,SeekOrigin.Current)));
325 Write(importLookupTableOffset
+ text
.RVA());
327 Write(runtimeEngineOffset
+ text
.RVA());
328 Write(text
.RVA()); // IAT is at the beginning of the text section
330 // Import Lookup Table
331 WriteIAT(); // lookup table and IAT are the same
333 // Console.WriteLine("Writing hintname table at " + Hex.Long(Seek(0,SeekOrigin.Current)));
334 Write(hintNameTable
);
335 Write(runtimeEngineName
.ToCharArray());
338 private void WriteTextSection()
342 // Console.WriteLine("Writing code at " + Hex.Long(Seek(0,SeekOrigin.Current)));
343 metaData
.WriteByteCodes(this);
344 // Console.WriteLine("Finished writing code at " + Hex.Long(Seek(0,SeekOrigin.Current)));
345 largeStrings
= metaData
.LargeStringsIndex();
346 largeGUID
= metaData
.LargeGUIDIndex();
347 largeUS
= metaData
.LargeUSIndex();
348 largeBlob
= metaData
.LargeBlobIndex();
349 metaData
.WriteMetaData(this);
350 metaData
.WriteResources (this);
351 if (reserveStrongNameSignatureSpace
) {
352 WriteZeros(StrongNameSignatureSize
);
355 WriteZeros(entryPointPadding
);
356 Write((ushort)0x25FF);
357 Write(ImageBase
+ text
.RVA());
358 WriteZeros(text
.Padding());
361 private void WriteCLIHeader()
363 Write(CLIHeaderSize
); // Cb
364 Write((short)2); // Major runtime version
365 Write((short)0); // Minor runtime version
366 Write(text
.RVA() + metaDataOffset
);
367 Write(metaData
.Size());
369 Write(entryPointToken
);
370 if (resourcesSize
> 0) {
371 Write (text
.RVA () + resourcesOffset
);
372 Write (resourcesSize
);
376 // Strong Name Signature (RVA, size)
377 if (reserveStrongNameSignatureSpace
) {
378 Write(text
.RVA() + strongNameSigOffset
);
379 Write(StrongNameSignatureSize
);
383 WriteZeros(8); // CodeManagerTable
384 WriteZeros(8); // VTableFixups NYI
385 WriteZeros(16); // ExportAddressTableJumps, ManagedNativeHeader
388 private void WriteSDataSection()
390 long size
= sdata
.Size ();
391 long start
= BaseStream
.Position
;
392 for (int i
=0; i
< data
.Count
; i
++) {
393 ((DataConstant
)data
[i
]).Write(this);
395 while (BaseStream
.Position
< (start
+ size
))
399 private void WriteRsrcSection()
403 private void WriteRelocSection()
405 // Console.WriteLine("Writing reloc section at " + Seek(0,SeekOrigin.Current) + " = " + relocOffset);
406 MemoryStream str
= (MemoryStream
)reloc
.BaseStream
;
407 Write(str
.ToArray());
408 WriteZeros(NumToAlign((uint)str
.Position
,fileAlign
));
411 internal void SetEntryPoint(uint entryPoint
)
413 entryPointToken
= entryPoint
;
416 internal void AddInitData(DataConstant cVal
)
419 sdata
= new Section(sdataName
,0xC0000040); // IMAGE_SCN_CNT INITIALIZED_DATA, READ, WRITE
420 data
= new ArrayList();
423 cVal
.DataOffset
= sdata
.Tide();
424 sdata
.IncTide(cVal
.GetSize());
427 internal void WriteZeros(uint numZeros
)
429 for (int i
=0; i
< numZeros
; i
++) {
434 internal void WritePEHeader()
436 Write((ushort)0x014C); // Machine - always 0x14C for Managed PE Files (allow others??)
437 Write((ushort)numSections
);
439 WriteZeros(8); // Pointer to Symbol Table and Number of Symbols (always zero for ECMA CLI files)
440 Write((ushort)0x00E0); // Size of Optional Header
441 Write(characteristics
);
442 // PE Optional Header
443 Write((ushort)0x010B); // Magic
444 Write((byte)0x6); // LMajor pure-IL = 6 C++ = 7
445 Write((byte)0x0); // LMinor
448 Write(0); // Check other sections here!!
449 Write(text
.RVA() + entryPointOffset
);
452 if (sdata
!= null) dataBase
= sdata
.RVA();
453 else if (rsrc
!= null) dataBase
= rsrc
.RVA();
454 else dataBase
= relocRVA
;
457 Write(SectionAlignment
);
459 Write((ushort)0x04); // OS Major
460 WriteZeros(6); // OS Minor, User Major, User Minor
461 Write((ushort)0x04); // SubSys Major
462 WriteZeros(6); // SybSys Minor, Reserved
465 Write((int)0); // File Checksum
466 Write((ushort)subSys
);
467 Write((short)0); // DLL Flags
468 Write((uint)stackReserve
); // Stack Reserve Size
469 Write((uint)0x1000); // Stack Commit Size
470 Write((uint)0x100000); // Heap Reserve Size
471 Write((uint)0x1000); // Heap Commit Size
472 Write(0); // Loader Flags
473 Write(0x10); // Number of Data Directories
474 WriteZeros(8); // Export Table
475 Write(importTableOffset
+ text
.RVA());
476 Write(totalImportTableSize
);
477 WriteZeros(24); // Resource, Exception and Certificate Tables
480 WriteZeros(48); // Debug, Copyright, Global Ptr, TLS, Load Config and Bound Import Tables
481 Write(text
.RVA()); // IATRVA - IAT is at start of .text Section
483 WriteZeros(8); // Delay Import Descriptor
484 Write(text
.RVA()+IATSize
); // CLIHeader immediately follows IAT
485 Write(CLIHeaderSize
);
486 WriteZeros(8); // Reserved
489 internal void WriteRelocSectionHeader()
491 Write(relocName
.ToCharArray());
500 private void Align (MemoryStream str
, int val
)
502 if ((str
.Position
% val
) != 0) {
503 for (int i
=val
- (int)(str
.Position
% val
); i
> 0; i
--) {
509 private uint Align(uint val
, uint alignVal
)
511 if ((val
% alignVal
) != 0) {
512 val
+= alignVal
- (val
% alignVal
);
517 private uint NumToAlign(uint val
, uint alignVal
)
519 if ((val
% alignVal
) == 0) return 0;
520 return alignVal
- (val
% alignVal
);
523 internal void StringsIndex(uint ix
)
525 if (largeStrings
) Write(ix
);
526 else Write((ushort)ix
);
529 internal void GUIDIndex(uint ix
)
531 if (largeGUID
) Write(ix
);
532 else Write((ushort)ix
);
535 internal void USIndex(uint ix
)
537 if (largeUS
) Write(ix
);
538 else Write((ushort)ix
);
541 internal void BlobIndex(uint ix
)
543 if (largeBlob
) Write(ix
);
544 else Write((ushort)ix
);
547 internal void WriteIndex(MDTable tabIx
,uint ix
)
549 if (metaData
.LargeIx(tabIx
)) Write(ix
);
550 else Write((ushort)ix
);
553 internal void WriteCodedIndex(CIx code
, MetaDataElement elem
)
555 metaData
.WriteCodedIndex(code
,elem
,this);
558 internal void WriteCodeRVA(uint offs
)
560 Write(text
.RVA() + offs
);
563 internal void WriteDataRVA(uint offs
)
565 Write(sdata
.RVA() + offs
);
568 internal void Write3Bytes(uint val
)
570 byte b3
= (byte)((val
& FileImage
.iByteMask
[2]) >> 16);
571 byte b2
= (byte)((val
& FileImage
.iByteMask
[1]) >> 8);;
572 byte b1
= (byte)(val
& FileImage
.iByteMask
[0]);
578 internal bool ReserveStrongNameSignatureSpace
{
579 get { return reserveStrongNameSignatureSpace; }
580 set { reserveStrongNameSignatureSpace = value; }
585 /**************************************************************************/
587 /// Base class for the PEFile (starting point)
589 public class PEFile
{
591 private static readonly string mscorlibName
= "mscorlib";
592 private Module thisMod
;
593 private ClassDef moduleClass
;
594 private ArrayList resources
= new ArrayList ();
595 private Assembly thisAssembly
;
596 private static bool isMSCorlib
;
597 private int corFlags
= 1;
602 /// Create a new PEFile. Each PEFile is a module.
604 /// <param name="name">module name, also used for the file name</param>
605 /// <param name="isDLL">create a .dll or .exe file</param>
606 /// <param name="hasAssembly">this file is an assembly and
607 /// will contain the assembly manifest. The assembly name is the
608 /// same as the module name</param>
609 public PEFile(string name
, bool isDLL
, bool hasAssembly
)
610 : this (name
, null, isDLL
, hasAssembly
, null, null)
612 // Console.WriteLine(Hex.Byte(0x12));
613 // Console.WriteLine(Hex.Short(0x1234));
614 // Console.WriteLine(Hex.Int(0x12345678));
618 /// Create a new PEFile. Each PEFile is a module.
620 /// <param name="name">module name, also used for the file name</param>
621 /// <param name="isDLL">create a .dll or .exe file</param>
622 /// <param name="hasAssembly">this file is an assembly and
623 /// will contain the assembly manifest. The assembly name is the
624 /// same as the module name</param>
625 /// <param name="outputDir">write the PEFile to this directory. If this
626 /// string is null then the output will be to the current directory</param>
627 public PEFile(string name
, bool isDLL
, bool hasAssembly
, string outputDir
)
628 : this (name
, null, isDLL
, hasAssembly
, outputDir
, null)
630 // Console.WriteLine(Hex.Byte(0x12));
631 // Console.WriteLine(Hex.Short(0x1234));
632 // Console.WriteLine(Hex.Int(0x12345678));
636 /// Create a new PEFile
638 /// <param name="name">module name</param>
639 /// <param name="isDLL">create a .dll or .exe</param>
640 /// <param name="hasAssembly">this PEfile is an assembly and
641 /// will contain the assemly manifest. The assembly name is the
642 /// same as the module name</param>
643 /// <param name="outStream">write the PEFile to this stream instead
644 /// of to a new file</param>
645 public PEFile(string name
, bool isDLL
, bool hasAssembly
, Stream outStream
)
646 : this (name
, null, isDLL
, hasAssembly
, null, outStream
)
650 public PEFile(string name
, string module_name
, bool isDLL
, bool hasAssembly
, Stream outStream
)
651 : this (name
, module_name
, isDLL
, hasAssembly
, null, outStream
)
655 public PEFile(string name
, string module_name
, bool isDLL
, bool hasAssembly
, string outputDir
, Stream outStream
)
658 string fname
= module_name
== null ? MakeFileName (outputDir
, name
, isDLL
) : module_name
;
659 if (outStream
== null)
660 fileImage
= new FileImage (isDLL
, fname
);
662 fileImage
= new FileImage (isDLL
, outStream
);
664 InitPEFile (name
, fname
, hasAssembly
);
667 private void SetName (string name
)
669 if (name
== "mscorlib")
673 private void InitPEFile(string name
, string fName
, bool hasAssembly
)
675 metaData
= fileImage
.GetMetaData();
676 thisMod
= new Module(fName
,metaData
);
678 thisAssembly
= new Assembly(name
,metaData
);
679 metaData
.AddToTable(MDTable
.Assembly
,thisAssembly
);
681 moduleClass
= AddClass(TypeAttr
.Private
,"","<Module>");
682 moduleClass
.SpecialNoSuper();
683 metaData
.AddToTable(MDTable
.Module
,thisMod
);
686 internal static bool IsMSCorlib
{
687 get { return isMSCorlib; }
690 public ClassDef ModuleClass
{
691 get { return moduleClass; }
695 /// Set the subsystem (.subsystem) (Default is Windows Console mode)
697 /// <param name="subS">subsystem value</param>
698 public void SetSubSystem(SubSystem subS
)
700 fileImage
.subSys
= subS
;
704 /// Set the flags (.corflags)
706 /// <param name="flags">the flags value</param>
707 public void SetCorFlags(int flags
)
712 public void SetStackReserve (long stackReserve
)
714 fileImage
.stackReserve
= stackReserve
;
717 private string MakeFileName(string dirName
, string name
, bool isDLL
)
720 if ((dirName
!= null) && (dirName
.CompareTo("") != 0)) {
722 if (!dirName
.EndsWith("\\")) result
+= "\\";
726 // if (isDLL) result += ".dll"; else result += ".exe";
732 /// Add an external assembly to this PEFile (.assembly extern)
734 /// <param name="assemName">the external assembly name</param>
735 /// <returns>a descriptor for this external assembly</returns>
736 public AssemblyRef
AddExternAssembly(string assemName
)
738 if (assemName
.CompareTo(mscorlibName
) == 0) return metaData
.mscorlib
;
739 AssemblyRef anAssem
= new AssemblyRef(metaData
,assemName
);
740 metaData
.AddToTable(MDTable
.AssemblyRef
,anAssem
);
741 // Console.WriteLine("Adding assembly " + assemName);
746 /// Add an external module to this PEFile (.module extern)
748 /// <param name="name">the external module name</param>
749 /// <returns>a descriptor for this external module</returns>
750 public ModuleRef
AddExternModule(string name
)
752 ModuleRef modRef
= new ModuleRef(metaData
,name
);
753 metaData
.AddToTable(MDTable
.ModuleRef
,modRef
);
757 public ClassRef
AddExternClass(string ns
, string name
, TypeAttr attrs
, MetaDataElement declRef
)
759 return new ExternClassRef (attrs
, ns
, name
, declRef
, metaData
);
763 /// Add a "global" method to this module
765 /// <param name="name">method name</param>
766 /// <param name="retType">return type</param>
767 /// <param name="pars">method parameters</param>
768 /// <returns>a descriptor for this new "global" method</returns>
769 public MethodDef
AddMethod (string name
, Param ret_param
, Param
[] pars
)
771 return moduleClass
.AddMethod (name
, ret_param
, pars
);
774 public MethodDef
AddMethod(string name
, Type retType
, Param
[] pars
)
776 return AddMethod (name
, new Param (ParamAttr
.Default
, "", retType
), pars
);
780 /// Add a "global" method to this module
782 /// <param name="mAtts">method attributes</param>
783 /// <param name="iAtts">method implementation attributes</param>
784 /// <param name="name">method name</param>
785 /// <param name="retType">return type</param>
786 /// <param name="pars">method parameters</param>
787 /// <returns>a descriptor for this new "global" method</returns>
788 public MethodDef
AddMethod (MethAttr mAtts
, ImplAttr iAtts
, string name
, Param ret_param
, Param
[] pars
)
790 return moduleClass
.AddMethod (mAtts
, iAtts
, name
, ret_param
, pars
);
793 public MethodDef
AddMethod(MethAttr mAtts
, ImplAttr iAtts
, string name
, Type retType
, Param
[] pars
)
795 return AddMethod (mAtts
, iAtts
, name
, new Param (ParamAttr
.Default
, "", retType
), pars
);
798 public MethodRef
AddMethodToTypeSpec (Type item
, string name
, Type retType
, Type
[] pars
)
800 return AddMethodToTypeSpec (item
, name
, retType
, pars
, 0);
803 public MethodRef
AddMethodToTypeSpec (Type item
, string name
, Type retType
, Type
[] pars
, int gen_param_count
)
805 MethodRef meth
= new MethodRef (item
.GetTypeSpec (metaData
), name
, retType
, pars
, false, null, gen_param_count
);
806 metaData
.AddToTable (MDTable
.MemberRef
,meth
);
810 public MethodRef
AddVarArgMethodToTypeSpec (Type item
, string name
, Type retType
,
811 Type
[] pars
, Type
[] optPars
) {
812 MethodRef meth
= new MethodRef(item
.GetTypeSpec (metaData
), name
,retType
,pars
,true,optPars
, 0);
813 metaData
.AddToTable(MDTable
.MemberRef
,meth
);
817 public FieldRef
AddFieldToTypeSpec (Type item
, string name
, Type fType
)
819 FieldRef field
= new FieldRef (item
.GetTypeSpec (metaData
), name
,fType
);
820 metaData
.AddToTable (MDTable
.MemberRef
,field
);
824 public Method
AddMethodSpec (Method m
, GenericMethodSig g_sig
)
826 MethodSpec ms
= new MethodSpec (m
, g_sig
);
827 metaData
.AddToTable (MDTable
.MethodSpec
, ms
);
832 /// Add a "global" field to this module
834 /// <param name="name">field name</param>
835 /// <param name="fType">field type</param>
836 /// <returns>a descriptor for this new "global" field</returns>
837 public FieldDef
AddField(string name
, Type fType
)
839 return moduleClass
.AddField(name
,fType
);
843 /// Add a "global" field to this module
845 /// <param name="attrSet">attributes of this field</param>
846 /// <param name="name">field name</param>
847 /// <param name="fType">field type</param>
848 /// <returns>a descriptor for this new "global" field</returns>
849 public FieldDef
AddField(FieldAttr attrSet
, string name
, Type fType
)
851 return moduleClass
.AddField(attrSet
,name
,fType
);
855 /// Add a class to this module
857 /// <param name="attrSet">attributes of this class</param>
858 /// <param name="nsName">name space name</param>
859 /// <param name="name">class name</param>
860 /// <returns>a descriptor for this new class</returns>
861 public ClassDef
AddClass(TypeAttr attrSet
, string nsName
, string name
)
863 return AddClass (attrSet
, nsName
, name
, null);
867 /// Add a class which extends System.ValueType to this module
869 /// <param name="attrSet">attributes of this class</param>
870 /// <param name="nsName">name space name</param>
871 /// <param name="name">class name</param>
872 /// <returns>a descriptor for this new class</returns>
873 public ClassDef
AddValueClass(TypeAttr attrSet
, string nsName
, string name
, ValueClass vClass
)
875 ClassDef aClass
= new ClassDef(attrSet
,nsName
,name
,metaData
);
876 if (!ClassDef
.IsValueType (nsName
, name
) && !ClassDef
.IsEnum (nsName
, name
)) {
877 aClass
.MakeValueClass(vClass
);
879 if (ClassDef
.IsEnum (nsName
, name
))
880 aClass
.SetSuper (metaData
.mscorlib
.ValueType ());
882 aClass
.SetSuper (metaData
.mscorlib
.GetSpecialSystemClass (PrimitiveType
.Object
));
884 metaData
.mscorlib
.SetSpecialSystemClass (nsName
, name
, aClass
);
886 aClass
.SetTypeIndex (PrimitiveType
.ValueType
.GetTypeIndex ());
887 metaData
.AddToTable(MDTable
.TypeDef
,aClass
);
892 /// Add a class to this module
894 /// <param name="attrSet">attributes of this class</param>
895 /// <param name="nsName">name space name</param>
896 /// <param name="name">class name</param>
897 /// <param name="superType">super type of this class (extends)</param>
898 /// <returns>a descriptor for this new class</returns>
899 public ClassDef
AddClass(TypeAttr attrSet
, string nsName
, string name
, Class superType
)
901 ClassDef aClass
= new ClassDef(attrSet
,nsName
,name
,metaData
);
902 if (superType
!= null)
903 aClass
.SetSuper(superType
);
904 if (PEFile
.IsMSCorlib
)
905 metaData
.mscorlib
.SetSpecialSystemClass (nsName
, name
, aClass
);
906 metaData
.AddToTable(MDTable
.TypeDef
,aClass
);
910 public void AddGenericClass (GenericTypeInst gti
)
912 metaData
.AddToTable (MDTable
.TypeSpec
, gti
);
915 public void AddGenericParam (GenParam param
)
917 metaData
.AddToTable (MDTable
.TypeSpec
, param
);
920 public FileRef
AddFile(string fName
, byte[] hashBytes
, bool hasMetaData
, bool entryPoint
)
922 FileRef file
= new FileRef(fName
,hashBytes
,hasMetaData
,entryPoint
,metaData
);
923 metaData
.AddToTable(MDTable
.File
,file
);
927 public PrimitiveTypeRef
AddPrimitiveType (PrimitiveType type
)
929 return new PrimitiveTypeRef (type
, metaData
);
933 /// Add a manifest resource to this PEFile NOT YET IMPLEMENTED
935 /// <param name="mr"></param>
936 public void AddManifestResource(ManifestResource mr
)
938 metaData
.AddToTable(MDTable
.ManifestResource
,mr
);
940 //mr.FixName(metaData);
943 public void AddCustomAttribute (Method meth
, byte [] data
, MetaDataElement element
)
945 metaData
.AddCustomAttribute (new CustomAttribute (element
, meth
, data
));
946 element
.HasCustomAttr
= true;
949 public void AddCustomAttribute (Method meth
, Constant constant
, MetaDataElement element
)
951 metaData
.AddCustomAttribute (new CustomAttribute (element
, meth
, constant
));
952 element
.HasCustomAttr
= true;
955 public void AddDeclSecurity (SecurityAction sec_action
, byte [] data
, MetaDataElement element
)
957 metaData
.AddDeclSecurity (new DeclSecurity (element
, (ushort) sec_action
, data
));
960 public void AddDeclSecurity (SecurityAction sec_action
, PEAPI
.PermissionSet ps
, MetaDataElement element
)
962 metaData
.AddDeclSecurity (new DeclSecurity_20 (element
, (ushort) sec_action
, ps
));
966 /// Add a managed resource from another assembly.
968 /// <param name="resName">The name of the resource</param>
969 /// <param name="assem">The assembly where the resource is</param>
970 /// <param name="isPublic">Access for the resource</param>
971 public void AddExternalManagedResource (string resName
, AssemblyRef assem
, uint flags
)
973 resources
.Add (new ManifestResource (resName
, flags
, assem
));
977 /// Add a managed resource from another assembly.
979 /// <param name="mr"></param>
980 /// <param name="isPublic"></param>
981 public void AddExternalManagedResource (ManifestResource mr
)
983 resources
.Add (new ManifestResource (mr
));
988 /// <param name="name">The name of the resource</param>
989 /// <returns>The resource with the name "name" or null </returns>
990 public ManifestResource
GetResource (string name
)
992 for (int i
= 0; i
< resources
.Count
; i
++) {
993 if (((ManifestResource
) resources
[i
]).Name
== name
)
994 return (ManifestResource
) resources
[i
];
999 public ManifestResource
[] GetResources()
1001 return (ManifestResource
[]) resources
.ToArray (typeof (ManifestResource
));
1005 /// Write out the PEFile (the "bake" function)
1007 public void WritePEFile() { /* the "bake" function */
1008 if (thisAssembly
!= null)
1009 fileImage
.ReserveStrongNameSignatureSpace
= thisAssembly
.HasPublicKey
;
1010 fileImage
.MakeFile();
1014 /// Get the descriptor of this module
1016 /// <returns>the descriptor for this module</returns>
1017 public Module
GetThisModule()
1023 /// Get the descriptor for this assembly. The PEFile must have been
1024 /// created with hasAssembly = true
1026 /// <returns>the descriptor for this assembly</returns>
1027 public Assembly
GetThisAssembly()
1029 return thisAssembly
;
1034 /**************************************************************************/
1036 /// Descriptor for a Section in a PEFile eg .text, .sdata
1038 internal class Section
{
1039 private static readonly uint relocPageSize
= 4096; // 4K pages for fixups
1042 uint offset
= 0, tide
= 0, size
= 0, rva
= 0, relocTide
= 0;
1043 //uint relocOff = 0;
1044 uint flags
= 0, padding
= 0;
1047 internal Section(string sName
, uint sFlags
)
1049 name
= sName
.ToCharArray();
1053 internal uint Tide() { return tide; }
1055 internal void IncTide(uint incVal
) { tide += incVal; }
1057 internal uint Padding() { return padding; }
1059 internal uint Size() { return size; }
1061 internal void SetSize(uint pad
)
1064 size
= tide
+ padding
;
1067 internal uint RVA() { return rva; }
1069 internal void SetRVA(uint rva
) { this.rva = rva; }
1071 internal uint Offset() { return offset; }
1073 internal void SetOffset(uint offs
) { offset = offs; }
1075 internal void DoBlock(BinaryWriter reloc
, uint page
, int start
, int end
)
1077 //Console.WriteLine("rva = " + rva + " page = " + page);
1078 reloc
.Write(rva
+ page
);
1079 reloc
.Write((uint)(((end
-start
+1)*2) + 8));
1080 for (int j
=start
; j
< end
; j
++) {
1081 //Console.WriteLine("reloc offset = " + relocs[j]);
1082 reloc
.Write((ushort)((0x3 << 12) | (relocs
[j
] - page
)));
1084 reloc
.Write((ushort)0);
1087 internal void DoRelocs(BinaryWriter reloc
)
1089 if (relocTide
> 0) {
1090 //relocOff = (uint)reloc.Seek(0,SeekOrigin.Current);
1091 uint block
= (relocs
[0]/relocPageSize
+ 1) * relocPageSize
;
1093 for (int i
=1; i
< relocTide
; i
++) {
1094 if (relocs
[i
] >= block
) {
1095 DoBlock(reloc
,block
-relocPageSize
,start
,i
);
1097 block
= (relocs
[i
]/relocPageSize
+ 1) * relocPageSize
;
1100 DoBlock(reloc
,block
-relocPageSize
,start
,(int)relocTide
);
1104 internal void AddReloc(uint offs
)
1107 if (relocs
== null) {
1108 relocs
= new uint[5];
1110 if (relocTide
>= relocs
.Length
) {
1111 uint[] tmp
= relocs
;
1112 relocs
= new uint[tmp
.Length
+ 5];
1113 for (int i
=0; i
< relocTide
; i
++) {
1117 while ((pos
< relocTide
) && (relocs
[pos
] < offs
)) pos
++;
1118 for (int i
=pos
; i
< relocTide
; i
++) {
1119 relocs
[i
+1] = relocs
[i
];
1126 internal void WriteHeader(BinaryWriter output
, uint relocRVA
)
1132 output
.Write(offset
);
1134 //output.Write(relocRVA + relocOff);
1137 //output.Write((ushort)relocTide);
1138 //output.Write((ushort)0);
1139 output
.Write(flags
);
1145 readonly static char[] hexDigit
= {'0','1','2','3','4','5','6','7',
1146 '8','9','A','B','C','D','E','F'};
1147 readonly static uint[] iByteMask
= {0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000}
;
1148 readonly static ulong[] lByteMask
= {0x00000000000000FF, 0x000000000000FF00,
1149 0x0000000000FF0000, 0x00000000FF000000,
1150 0x000000FF00000000, 0x0000FF0000000000,
1151 0x00FF000000000000, 0xFF00000000000000 };
1152 readonly static uint nibble0Mask
= 0x0000000F;
1153 readonly static uint nibble1Mask
= 0x000000F0;
1155 public static String
Byte(int b
)
1157 char[] str
= new char[2];
1159 uint b1
= num
& nibble0Mask
;
1160 uint b2
= (num
& nibble1Mask
) >> 4;
1161 str
[0] = hexDigit
[b2
];
1162 str
[1] = hexDigit
[b1
];
1163 return new String(str
);
1166 public static String
Short(int b
)
1168 char[] str
= new char[4];
1169 uint num1
= (uint)b
& iByteMask
[0];
1170 uint num2
= ((uint)b
& iByteMask
[1]) >> 8;
1171 uint b1
= num1
& nibble0Mask
;
1172 uint b2
= (num1
& nibble1Mask
) >> 4;
1173 uint b3
= num2
& nibble0Mask
;
1174 uint b4
= (num2
& nibble1Mask
) >> 4;
1175 str
[0] = hexDigit
[b4
];
1176 str
[1] = hexDigit
[b3
];
1177 str
[2] = hexDigit
[b2
];
1178 str
[3] = hexDigit
[b1
];
1179 return new String(str
);
1182 public static String
Int(int val
)
1184 char[] str
= new char[8];
1185 uint num
= (uint)val
;
1187 for (int i
=0; i
< iByteMask
.Length
; i
++) {
1188 uint b
= num
& iByteMask
[i
];
1190 uint b1
= b
& nibble0Mask
;
1191 uint b2
= (b
& nibble1Mask
) >> 4;
1192 str
[strIx
--] = hexDigit
[b1
];
1193 str
[strIx
--] = hexDigit
[b2
];
1195 return new String(str
);
1198 public static String
Int(uint num
)
1200 char[] str
= new char[8];
1202 for (int i
=0; i
< iByteMask
.Length
; i
++) {
1203 uint b
= num
& iByteMask
[i
];
1205 uint b1
= b
& nibble0Mask
;
1206 uint b2
= (b
& nibble1Mask
) >> 4;
1207 str
[strIx
--] = hexDigit
[b1
];
1208 str
[strIx
--] = hexDigit
[b2
];
1210 return new String(str
);
1213 public static String
Long(long lnum
)
1215 ulong num
= (ulong)lnum
;
1216 char[] str
= new char[16];
1218 for (int i
=0; i
< lByteMask
.Length
; i
++) {
1219 ulong b
= num
& lByteMask
[i
];
1221 ulong b1
= b
& nibble0Mask
;
1222 ulong b2
= (b
& nibble1Mask
) >> 4;
1223 str
[strIx
--] = hexDigit
[b1
];
1224 str
[strIx
--] = hexDigit
[b2
];
1226 return new String(str
);
1231 /// Error for invalid PE file
1233 public class PEFileException
: System
.Exception
{
1234 public PEFileException(string msg
) : base(msg
) { }
1237 public class NotYetImplementedException
: System
.Exception
{
1238 public NotYetImplementedException(string msg
) : base(msg
+ " Not Yet Implemented") { }
1241 public class TypeSignatureException
: System
.Exception
{
1242 public TypeSignatureException(string msg
) : base(msg
) { }