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, rsrc;
111 BinaryWriter reloc = new BinaryWriter(new MemoryStream());
113 DateTime origin = new DateTime(1970,1,1);
114 uint numSections = 2; // always have .text and .reloc sections
115 internal SubSystem subSys = SubSystem.Windows_CUI; // default is Windows Console mode
116 internal long stackReserve = 0x100000; // default is 1Mb
117 internal uint fileAlign = minFileAlign;
118 uint entryPointOffset, entryPointPadding, imageSize, headerSize, headerPadding, entryPointToken = 0;
119 uint relocOffset, relocRVA, relocSize, relocPadding, relocTide, hintNameTableOffset;
120 uint metaDataOffset, runtimeEngineOffset, initDataSize = 0, importTablePadding;
121 uint resourcesSize, resourcesOffset;
122 uint strongNameSigOffset;
123 uint importTableOffset, importLookupTableOffset, totalImportTableSize;
125 char[] runtimeEngine = runtimeEngineName.ToCharArray(), hintNameTable;
126 bool doDLL, largeStrings, largeGUID, largeUS, largeBlob;
127 ushort characteristics;
129 internal FileImage(bool makeDLL, string fileName) : base(new FileStream(fileName,FileMode.Create))
131 InitFileImage(makeDLL);
132 TimeSpan tmp = System.IO.File.GetCreationTime(fileName).Subtract(origin);
133 dateStamp = Convert.ToUInt32(tmp.TotalSeconds);
136 internal FileImage(bool makeDLL, Stream str) : base(str)
138 InitFileImage(makeDLL);
139 TimeSpan tmp = DateTime.Now.Subtract(origin);
140 dateStamp = Convert.ToUInt32(tmp.TotalSeconds);
143 private void InitFileImage(bool makeDLL)
147 hintNameTable = dllHintNameTable.ToCharArray();
148 characteristics = dllCharacteristics;
150 hintNameTable = exeHintNameTable.ToCharArray();
151 characteristics = exeCharacteristics;
153 text = new Section(textName,0x60000020); // IMAGE_SCN_CNT CODE, EXECUTE, READ
154 // rsrc = new Section(rsrcName,0x40000040); // IMAGE_SCN_CNT INITIALIZED_DATA, READ
155 metaData = new MetaData(this);
158 internal MetaData GetMetaData()
163 private uint GetNextSectStart(uint rva, uint tide)
165 uint c = tide / SectionAlignment;
166 if ((tide % SectionAlignment) != 0)
168 return rva + (c * SectionAlignment);
171 private void BuildTextSection()
174 // IAT (single entry 8 bytes for pure CIL)
175 // CLIHeader (72 bytes)
176 // CIL instructions for all methods (variable size)
178 // ImportTable (40 bytes)
179 // ImportLookupTable(8 bytes) (same as IAT for standard CIL files)
180 // Hint/Name Tables with entry "_CorExeMain" for .exe file and "_CorDllMain" for .dll (14 bytes)
181 // ASCII string "mscoree.dll" referenced in ImportTable (+ padding = 16 bytes)
182 // Entry Point (0xFF25 followed by 4 bytes 0x400000 + RVA of .text)
183 metaData.BuildMetaData(IATSize + CLIHeaderSize);
184 metaDataOffset = IATSize + CLIHeaderSize;
185 // Console.WriteLine("Code starts at " + metaDataOffset);
186 metaDataOffset += metaData.CodeSize();
188 resourcesOffset = metaDataOffset + metaData.Size ();
189 resourcesSize = metaData.GetResourcesSize ();
190 if (reserveStrongNameSignatureSpace) {
191 strongNameSigOffset = resourcesOffset + resourcesSize;
192 // fixUps = RVA for vtable
193 importTableOffset = strongNameSigOffset + StrongNameSignatureSize;
195 strongNameSigOffset = 0;
196 // fixUps = RVA for vtable
197 importTableOffset = resourcesOffset + resourcesSize;
199 importTablePadding = NumToAlign(importTableOffset,16);
200 importTableOffset += importTablePadding;
201 importLookupTableOffset = importTableOffset + ImportTableSize;
202 hintNameTableOffset = importLookupTableOffset + IATSize;
203 runtimeEngineOffset = hintNameTableOffset + (uint)hintNameTable.Length;
204 entryPointOffset = runtimeEngineOffset + (uint)runtimeEngine.Length;
205 totalImportTableSize = entryPointOffset - importTableOffset;
206 // Console.WriteLine("total import table size = " + totalImportTableSize);
207 // Console.WriteLine("entrypoint offset = " + entryPointOffset);
208 entryPointPadding = NumToAlign(entryPointOffset,4) + 2;
209 entryPointOffset += entryPointPadding;
210 text.AddReloc(entryPointOffset+2);
211 text.IncTide(entryPointOffset + 6);
212 //if (text.Tide() < fileAlign) fileAlign = minFileAlign;
213 text.SetSize(NumToAlign(text.Tide(),fileAlign));
214 // Console.WriteLine("text size = " + text.Size() + " text tide = " + text.Tide() + " text padding = " + text.Padding());
215 // Console.WriteLine("metaDataOffset = " + Hex.Int(metaDataOffset));
216 // Console.WriteLine("importTableOffset = " + Hex.Int(importTableOffset));
217 // Console.WriteLine("importLookupTableOffset = " + Hex.Int(importLookupTableOffset));
218 // Console.WriteLine("hintNameTableOffset = " + Hex.Int(hintNameTableOffset));
219 // Console.WriteLine("runtimeEngineOffset = " + Hex.Int(runtimeEngineOffset));
220 // Console.WriteLine("entryPointOffset = " + Hex.Int(entryPointOffset));
221 // Console.WriteLine("entryPointPadding = " + Hex.Int(entryPointPadding));
225 internal void BuildRelocSection()
227 text.DoRelocs(reloc);
228 if (sdata != null) sdata.DoRelocs(reloc);
229 if (rsrc != null) rsrc.DoRelocs(reloc);
230 relocTide = (uint)reloc.Seek(0,SeekOrigin.Current);
231 relocPadding = NumToAlign(relocTide,fileAlign);
232 relocSize = relocTide + relocPadding;
233 imageSize = relocRVA + SectionAlignment;
234 initDataSize += relocSize;
237 private void CalcOffsets()
243 headerSize = fileHeaderSize + (numSections * sectionHeaderSize);
244 headerPadding = NumToAlign(headerSize,fileAlign);
245 headerSize += headerPadding;
246 uint offset = headerSize;
247 uint rva = SectionAlignment;
248 text.SetOffset(offset);
250 offset += text.Size();
251 rva = GetNextSectStart(rva,text.Tide());
252 // Console.WriteLine("headerSize = " + headerSize);
253 // Console.WriteLine("headerPadding = " + headerPadding);
254 // Console.WriteLine("textOffset = " + Hex.Int(text.Offset()));
256 sdata.SetSize(NumToAlign(sdata.Tide(),fileAlign));
257 sdata.SetOffset(offset);
259 offset += sdata.Size();
260 rva = GetNextSectStart(rva,sdata.Tide());
261 initDataSize += sdata.Size();
264 rsrc.SetSize(NumToAlign(rsrc.Tide(),fileAlign));
265 rsrc.SetOffset(offset);
267 offset += rsrc.Size();
268 rva = GetNextSectStart(rva,rsrc.Tide());
269 initDataSize += rsrc.Size();
271 relocOffset = offset;
275 internal void MakeFile()
277 if (doDLL) hintNameTable = dllHintNameTable.ToCharArray();
278 else hintNameTable = exeHintNameTable.ToCharArray();
289 private void WriteHeader()
292 // Console.WriteLine("Writing PEHeader at offset " + Seek(0,SeekOrigin.Current));
294 // Console.WriteLine("Writing text section header at offset " + Hex.Long(Seek(0,SeekOrigin.Current)));
295 text.WriteHeader(this,relocRVA);
296 if (sdata != null) sdata.WriteHeader(this,relocRVA);
297 if (rsrc != null) rsrc.WriteHeader(this,relocRVA);
298 // Console.WriteLine("Writing reloc section header at offset " + Seek(0,SeekOrigin.Current));
299 WriteRelocSectionHeader();
300 // Console.WriteLine("Writing padding at offset " + Seek(0,SeekOrigin.Current));
301 WriteZeros(headerPadding);
304 private void WriteSections()
306 // Console.WriteLine("Writing text section at offset " + Seek(0,SeekOrigin.Current));
308 if (sdata != null) WriteSDataSection();
309 if (rsrc != null) WriteRsrcSection();
313 private void WriteIAT()
315 Write(text.RVA() + hintNameTableOffset);
319 private void WriteImportTables()
322 WriteZeros(importTablePadding);
323 // Console.WriteLine("Writing import tables at offset " + Hex.Long(Seek(0,SeekOrigin.Current)));
324 Write(importLookupTableOffset + text.RVA());
326 Write(runtimeEngineOffset + text.RVA());
327 Write(text.RVA()); // IAT is at the beginning of the text section
329 // Import Lookup Table
330 WriteIAT(); // lookup table and IAT are the same
332 // Console.WriteLine("Writing hintname table at " + Hex.Long(Seek(0,SeekOrigin.Current)));
333 Write(hintNameTable);
334 Write(runtimeEngineName.ToCharArray());
337 private void WriteTextSection()
341 // Console.WriteLine("Writing code at " + Hex.Long(Seek(0,SeekOrigin.Current)));
342 metaData.WriteByteCodes(this);
343 // Console.WriteLine("Finished writing code at " + Hex.Long(Seek(0,SeekOrigin.Current)));
344 largeStrings = metaData.LargeStringsIndex();
345 largeGUID = metaData.LargeGUIDIndex();
346 largeUS = metaData.LargeUSIndex();
347 largeBlob = metaData.LargeBlobIndex();
348 metaData.WriteMetaData(this);
349 metaData.WriteResources (this);
350 if (reserveStrongNameSignatureSpace) {
351 WriteZeros(StrongNameSignatureSize);
354 WriteZeros(entryPointPadding);
355 Write((ushort)0x25FF);
356 Write(ImageBase + text.RVA());
357 WriteZeros(text.Padding());
360 private void WriteCLIHeader()
362 Write(CLIHeaderSize); // Cb
363 Write((short)2); // Major runtime version
364 Write((short)0); // Minor runtime version
365 Write(text.RVA() + metaDataOffset);
366 Write(metaData.Size());
368 Write(entryPointToken);
369 if (resourcesSize > 0) {
370 Write (text.RVA () + resourcesOffset);
371 Write (resourcesSize);
375 // Strong Name Signature (RVA, size)
376 if (reserveStrongNameSignatureSpace) {
377 Write(text.RVA() + strongNameSigOffset);
378 Write(StrongNameSignatureSize);
382 WriteZeros(8); // CodeManagerTable
383 WriteZeros(8); // VTableFixups NYI
384 WriteZeros(16); // ExportAddressTableJumps, ManagedNativeHeader
387 private void WriteSDataSection()
389 long size = sdata.Size ();
390 long start = BaseStream.Position;
391 for (int i=0; i < data.Count; i++) {
392 ((DataConstant)data[i]).Write(this);
394 while (BaseStream.Position < (start + size))
398 private void WriteRsrcSection()
402 private void WriteRelocSection()
404 // Console.WriteLine("Writing reloc section at " + Seek(0,SeekOrigin.Current) + " = " + relocOffset);
405 MemoryStream str = (MemoryStream)reloc.BaseStream;
406 Write(str.ToArray());
407 WriteZeros(NumToAlign((uint)str.Position,fileAlign));
410 internal void SetEntryPoint(uint entryPoint)
412 entryPointToken = entryPoint;
415 internal void AddInitData(DataConstant cVal)
418 sdata = new Section(sdataName,0xC0000040); // IMAGE_SCN_CNT INITIALIZED_DATA, READ, WRITE
419 data = new ArrayList();
422 cVal.DataOffset = sdata.Tide();
423 sdata.IncTide(cVal.GetSize());
426 internal void WriteZeros(uint numZeros)
428 for (int i=0; i < numZeros; i++) {
433 internal void WritePEHeader()
435 Write((ushort)0x014C); // Machine - always 0x14C for Managed PE Files (allow others??)
436 Write((ushort)numSections);
438 WriteZeros(8); // Pointer to Symbol Table and Number of Symbols (always zero for ECMA CLI files)
439 Write((ushort)0x00E0); // Size of Optional Header
440 Write(characteristics);
441 // PE Optional Header
442 Write((ushort)0x010B); // Magic
443 Write((byte)0x6); // LMajor pure-IL = 6 C++ = 7
444 Write((byte)0x0); // LMinor
447 Write(0); // Check other sections here!!
448 Write(text.RVA() + entryPointOffset);
451 if (sdata != null) dataBase = sdata.RVA();
452 else if (rsrc != null) dataBase = rsrc.RVA();
453 else dataBase = relocRVA;
456 Write(SectionAlignment);
458 Write((ushort)0x04); // OS Major
459 WriteZeros(6); // OS Minor, User Major, User Minor
460 Write((ushort)0x04); // SubSys Major
461 WriteZeros(6); // SybSys Minor, Reserved
464 Write((int)0); // File Checksum
465 Write((ushort)subSys);
466 Write((short)0); // DLL Flags
467 Write((uint)stackReserve); // Stack Reserve Size
468 Write((uint)0x1000); // Stack Commit Size
469 Write((uint)0x100000); // Heap Reserve Size
470 Write((uint)0x1000); // Heap Commit Size
471 Write(0); // Loader Flags
472 Write(0x10); // Number of Data Directories
473 WriteZeros(8); // Export Table
474 Write(importTableOffset + text.RVA());
475 Write(totalImportTableSize);
476 WriteZeros(24); // Resource, Exception and Certificate Tables
479 WriteZeros(48); // Debug, Copyright, Global Ptr, TLS, Load Config and Bound Import Tables
480 Write(text.RVA()); // IATRVA - IAT is at start of .text Section
482 WriteZeros(8); // Delay Import Descriptor
483 Write(text.RVA()+IATSize); // CLIHeader immediately follows IAT
484 Write(CLIHeaderSize);
485 WriteZeros(8); // Reserved
488 internal void WriteRelocSectionHeader()
490 Write(relocName.ToCharArray());
499 private void Align (MemoryStream str, int val)
501 if ((str.Position % val) != 0) {
502 for (int i=val - (int)(str.Position % val); i > 0; i--) {
508 private uint Align(uint val, uint alignVal)
510 if ((val % alignVal) != 0) {
511 val += alignVal - (val % alignVal);
516 private uint NumToAlign(uint val, uint alignVal)
518 if ((val % alignVal) == 0) return 0;
519 return alignVal - (val % alignVal);
522 internal void StringsIndex(uint ix)
524 if (largeStrings) Write(ix);
525 else Write((ushort)ix);
528 internal void GUIDIndex(uint ix)
530 if (largeGUID) Write(ix);
531 else Write((ushort)ix);
534 internal void USIndex(uint ix)
536 if (largeUS) Write(ix);
537 else Write((ushort)ix);
540 internal void BlobIndex(uint ix)
542 if (largeBlob) Write(ix);
543 else Write((ushort)ix);
546 internal void WriteIndex(MDTable tabIx,uint ix)
548 if (metaData.LargeIx(tabIx)) Write(ix);
549 else Write((ushort)ix);
552 internal void WriteCodedIndex(CIx code, MetaDataElement elem)
554 metaData.WriteCodedIndex(code,elem,this);
557 internal void WriteCodeRVA(uint offs)
559 Write(text.RVA() + offs);
562 internal void WriteDataRVA(uint offs)
564 Write(sdata.RVA() + offs);
567 internal void Write3Bytes(uint val)
569 byte b3 = (byte)((val & FileImage.iByteMask[2]) >> 16);
570 byte b2 = (byte)((val & FileImage.iByteMask[1]) >> 8);;
571 byte b1 = (byte)(val & FileImage.iByteMask[0]);
577 internal bool ReserveStrongNameSignatureSpace {
578 get { return reserveStrongNameSignatureSpace; }
579 set { reserveStrongNameSignatureSpace = value; }
584 /**************************************************************************/
586 /// Base class for the PEFile (starting point)
588 public class PEFile {
590 private static readonly string mscorlibName = "mscorlib";
591 private Module thisMod;
592 private ClassDef moduleClass;
593 private ArrayList resources = new ArrayList ();
594 private Assembly thisAssembly;
595 private static bool isMSCorlib;
596 private int corFlags = 1;
601 /// Create a new PEFile. Each PEFile is a module.
603 /// <param name="name">module name, also used for the file name</param>
604 /// <param name="isDLL">create a .dll or .exe file</param>
605 /// <param name="hasAssembly">this file is an assembly and
606 /// will contain the assembly manifest. The assembly name is the
607 /// same as the module name</param>
608 public PEFile(string name, bool isDLL, bool hasAssembly)
609 : this (name, null, isDLL, hasAssembly, null, null)
611 // Console.WriteLine(Hex.Byte(0x12));
612 // Console.WriteLine(Hex.Short(0x1234));
613 // Console.WriteLine(Hex.Int(0x12345678));
617 /// Create a new PEFile. Each PEFile is a module.
619 /// <param name="name">module name, also used for the file name</param>
620 /// <param name="isDLL">create a .dll or .exe file</param>
621 /// <param name="hasAssembly">this file is an assembly and
622 /// will contain the assembly manifest. The assembly name is the
623 /// same as the module name</param>
624 /// <param name="outputDir">write the PEFile to this directory. If this
625 /// string is null then the output will be to the current directory</param>
626 public PEFile(string name, bool isDLL, bool hasAssembly, string outputDir)
627 : this (name, null, isDLL, hasAssembly, outputDir, null)
629 // Console.WriteLine(Hex.Byte(0x12));
630 // Console.WriteLine(Hex.Short(0x1234));
631 // Console.WriteLine(Hex.Int(0x12345678));
635 /// Create a new PEFile
637 /// <param name="name">module name</param>
638 /// <param name="isDLL">create a .dll or .exe</param>
639 /// <param name="hasAssembly">this PEfile is an assembly and
640 /// will contain the assemly manifest. The assembly name is the
641 /// same as the module name</param>
642 /// <param name="outStream">write the PEFile to this stream instead
643 /// of to a new file</param>
644 public PEFile(string name, bool isDLL, bool hasAssembly, Stream outStream)
645 : this (name, null, isDLL, hasAssembly, null, outStream)
649 public PEFile(string name, string module_name, bool isDLL, bool hasAssembly, Stream outStream)
650 : this (name, module_name, isDLL, hasAssembly, null, outStream)
654 public PEFile(string name, string module_name, bool isDLL, bool hasAssembly, string outputDir, Stream outStream)
657 string fname = module_name == null ? MakeFileName (outputDir, name, isDLL) : module_name;
658 if (outStream == null)
659 fileImage = new FileImage (isDLL, fname);
661 fileImage = new FileImage (isDLL, outStream);
663 InitPEFile (name, fname, hasAssembly);
666 private void SetName (string name)
668 if (name == "mscorlib")
672 private void InitPEFile(string name, string fName, bool hasAssembly)
674 metaData = fileImage.GetMetaData();
675 thisMod = new Module(fName,metaData);
677 thisAssembly = new Assembly(name,metaData);
678 metaData.AddToTable(MDTable.Assembly,thisAssembly);
680 moduleClass = AddClass(TypeAttr.Private,"","<Module>");
681 moduleClass.SpecialNoSuper();
682 metaData.AddToTable(MDTable.Module,thisMod);
685 internal static bool IsMSCorlib {
686 get { return isMSCorlib; }
689 public ClassDef ModuleClass {
690 get { return moduleClass; }
694 /// Set the subsystem (.subsystem) (Default is Windows Console mode)
696 /// <param name="subS">subsystem value</param>
697 public void SetSubSystem(SubSystem subS)
699 fileImage.subSys = subS;
703 /// Set the flags (.corflags)
705 /// <param name="flags">the flags value</param>
706 public void SetCorFlags(int flags)
711 public void SetStackReserve (long stackReserve)
713 fileImage.stackReserve = stackReserve;
716 private string MakeFileName(string dirName, string name, bool isDLL)
719 if ((dirName != null) && (dirName.CompareTo("") != 0)) {
721 if (!dirName.EndsWith("\\")) result += "\\";
725 // if (isDLL) result += ".dll"; else result += ".exe";
731 /// Add an external assembly to this PEFile (.assembly extern)
733 /// <param name="assemName">the external assembly name</param>
734 /// <returns>a descriptor for this external assembly</returns>
735 public AssemblyRef AddExternAssembly(string assemName)
737 if (assemName.CompareTo(mscorlibName) == 0) return metaData.mscorlib;
738 AssemblyRef anAssem = new AssemblyRef(metaData,assemName);
739 metaData.AddToTable(MDTable.AssemblyRef,anAssem);
740 // Console.WriteLine("Adding assembly " + assemName);
745 /// Add an external module to this PEFile (.module extern)
747 /// <param name="name">the external module name</param>
748 /// <returns>a descriptor for this external module</returns>
749 public ModuleRef AddExternModule(string name)
751 ModuleRef modRef = new ModuleRef(metaData,name);
752 metaData.AddToTable(MDTable.ModuleRef,modRef);
757 /// Add a "global" method to this module
759 /// <param name="name">method name</param>
760 /// <param name="retType">return type</param>
761 /// <param name="pars">method parameters</param>
762 /// <returns>a descriptor for this new "global" method</returns>
763 public MethodDef AddMethod (string name, Param ret_param, Param [] pars)
765 return moduleClass.AddMethod (name, ret_param, pars);
768 public MethodDef AddMethod(string name, Type retType, Param[] pars)
770 return AddMethod (name, new Param (ParamAttr.Default, "", retType), pars);
774 /// Add a "global" method to this module
776 /// <param name="mAtts">method attributes</param>
777 /// <param name="iAtts">method implementation attributes</param>
778 /// <param name="name">method name</param>
779 /// <param name="retType">return type</param>
780 /// <param name="pars">method parameters</param>
781 /// <returns>a descriptor for this new "global" method</returns>
782 public MethodDef AddMethod (MethAttr mAtts, ImplAttr iAtts, string name, Param ret_param, Param [] pars)
784 return moduleClass.AddMethod (mAtts, iAtts, name, ret_param, pars);
787 public MethodDef AddMethod(MethAttr mAtts, ImplAttr iAtts, string name, Type retType, Param[] pars)
789 return AddMethod (mAtts, iAtts, name, new Param (ParamAttr.Default, "", retType), pars);
792 public MethodRef AddMethodToTypeSpec (Type item, string name, Type retType, Type[] pars)
794 return AddMethodToTypeSpec (item, name, retType, pars, 0);
797 public MethodRef AddMethodToTypeSpec (Type item, string name, Type retType, Type[] pars, int gen_param_count)
799 MethodRef meth = new MethodRef (item.GetTypeSpec (metaData), name, retType, pars, false, null, gen_param_count);
800 metaData.AddToTable (MDTable.MemberRef,meth);
804 public MethodRef AddVarArgMethodToTypeSpec (Type item, string name, Type retType,
805 Type[] pars, Type[] optPars) {
806 MethodRef meth = new MethodRef(item.GetTypeSpec (metaData), name,retType,pars,true,optPars, 0);
807 metaData.AddToTable(MDTable.MemberRef,meth);
811 public FieldRef AddFieldToTypeSpec (Type item, string name, Type fType)
813 FieldRef field = new FieldRef (item.GetTypeSpec (metaData), name,fType);
814 metaData.AddToTable (MDTable.MemberRef,field);
818 public Method AddMethodSpec (Method m, GenericMethodSig g_sig)
820 MethodSpec ms = new MethodSpec (m, g_sig);
821 metaData.AddToTable (MDTable.MethodSpec, ms);
826 /// Add a "global" field to this module
828 /// <param name="name">field name</param>
829 /// <param name="fType">field type</param>
830 /// <returns>a descriptor for this new "global" field</returns>
831 public FieldDef AddField(string name, Type fType)
833 return moduleClass.AddField(name,fType);
837 /// Add a "global" field to this module
839 /// <param name="attrSet">attributes of this field</param>
840 /// <param name="name">field name</param>
841 /// <param name="fType">field type</param>
842 /// <returns>a descriptor for this new "global" field</returns>
843 public FieldDef AddField(FieldAttr attrSet, string name, Type fType)
845 return moduleClass.AddField(attrSet,name,fType);
849 /// Add a class to this module
851 /// <param name="attrSet">attributes of this class</param>
852 /// <param name="nsName">name space name</param>
853 /// <param name="name">class name</param>
854 /// <returns>a descriptor for this new class</returns>
855 public ClassDef AddClass(TypeAttr attrSet, string nsName, string name)
857 return AddClass (attrSet, nsName, name, null);
861 /// Add a class which extends System.ValueType to this module
863 /// <param name="attrSet">attributes of this class</param>
864 /// <param name="nsName">name space name</param>
865 /// <param name="name">class name</param>
866 /// <returns>a descriptor for this new class</returns>
867 public ClassDef AddValueClass(TypeAttr attrSet, string nsName, string name, ValueClass vClass)
869 ClassDef aClass = new ClassDef(attrSet,nsName,name,metaData);
870 if (!ClassDef.IsValueType (nsName, name) && !ClassDef.IsEnum (nsName, name)) {
871 aClass.MakeValueClass(vClass);
873 if (ClassDef.IsEnum (nsName, name))
874 aClass.SetSuper (metaData.mscorlib.ValueType ());
876 aClass.SetSuper (metaData.mscorlib.GetSpecialSystemClass (PrimitiveType.Object));
878 metaData.mscorlib.SetSpecialSystemClass (nsName, name, aClass);
880 aClass.SetTypeIndex (PrimitiveType.ValueType.GetTypeIndex ());
881 metaData.AddToTable(MDTable.TypeDef,aClass);
886 /// Add a class to this module
888 /// <param name="attrSet">attributes of this class</param>
889 /// <param name="nsName">name space name</param>
890 /// <param name="name">class name</param>
891 /// <param name="superType">super type of this class (extends)</param>
892 /// <returns>a descriptor for this new class</returns>
893 public ClassDef AddClass(TypeAttr attrSet, string nsName, string name, Class superType)
895 ClassDef aClass = new ClassDef(attrSet,nsName,name,metaData);
896 if (superType != null)
897 aClass.SetSuper(superType);
898 if (PEFile.IsMSCorlib)
899 metaData.mscorlib.SetSpecialSystemClass (nsName, name, aClass);
900 metaData.AddToTable(MDTable.TypeDef,aClass);
904 public void AddGenericClass (GenericTypeInst gti)
906 metaData.AddToTable (MDTable.TypeSpec, gti);
909 public void AddGenericParam (GenParam param)
911 metaData.AddToTable (MDTable.TypeSpec, param);
914 public FileRef AddFile(string fName, byte[] hashBytes, bool hasMetaData, bool entryPoint)
916 FileRef file = new FileRef(fName,hashBytes,hasMetaData,entryPoint,metaData);
917 metaData.AddToTable(MDTable.File,file);
922 /// Add a manifest resource to this PEFile NOT YET IMPLEMENTED
924 /// <param name="mr"></param>
925 public void AddManifestResource(ManifestResource mr)
927 metaData.AddToTable(MDTable.ManifestResource,mr);
929 //mr.FixName(metaData);
932 public void AddCustomAttribute (Method meth, byte [] data, MetaDataElement element)
934 metaData.AddCustomAttribute (new CustomAttribute (element, meth, data));
935 element.HasCustomAttr = true;
938 public void AddDeclSecurity (SecurityAction sec_action, byte [] data, MetaDataElement element)
940 metaData.AddDeclSecurity (new DeclSecurity (element, (ushort) sec_action, data));
943 public void AddDeclSecurity (SecurityAction sec_action, PEAPI.PermissionSet ps, MetaDataElement element)
945 metaData.AddDeclSecurity (new DeclSecurity_20 (element, (ushort) sec_action, ps));
949 /// Add a managed resource from another assembly.
951 /// <param name="resName">The name of the resource</param>
952 /// <param name="assem">The assembly where the resource is</param>
953 /// <param name="isPublic">Access for the resource</param>
954 public void AddExternalManagedResource (string resName, AssemblyRef assem, uint flags)
956 resources.Add (new ManifestResource (resName, flags, assem));
960 /// Add a managed resource from another assembly.
962 /// <param name="mr"></param>
963 /// <param name="isPublic"></param>
964 public void AddExternalManagedResource (ManifestResource mr)
966 resources.Add (new ManifestResource (mr));
971 /// <param name="name">The name of the resource</param>
972 /// <returns>The resource with the name "name" or null </returns>
973 public ManifestResource GetResource (string name)
975 for (int i = 0; i < resources.Count; i ++) {
976 if (((ManifestResource) resources [i]).Name == name)
977 return (ManifestResource) resources [i];
982 public ManifestResource [] GetResources()
984 return (ManifestResource []) resources.ToArray (typeof (ManifestResource));
988 /// Write out the PEFile (the "bake" function)
990 public void WritePEFile() { /* the "bake" function */
991 if (thisAssembly != null)
992 fileImage.ReserveStrongNameSignatureSpace = thisAssembly.HasPublicKey;
993 fileImage.MakeFile();
997 /// Get the descriptor of this module
999 /// <returns>the descriptor for this module</returns>
1000 public Module GetThisModule()
1006 /// Get the descriptor for this assembly. The PEFile must have been
1007 /// created with hasAssembly = true
1009 /// <returns>the descriptor for this assembly</returns>
1010 public Assembly GetThisAssembly()
1012 return thisAssembly;
1017 /**************************************************************************/
1019 /// Descriptor for a Section in a PEFile eg .text, .sdata
1021 internal class Section {
1022 private static readonly uint relocPageSize = 4096; // 4K pages for fixups
1025 uint offset = 0, tide = 0, size = 0, rva = 0, relocTide = 0;
1026 //uint relocOff = 0;
1027 uint flags = 0, padding = 0;
1030 internal Section(string sName, uint sFlags)
1032 name = sName.ToCharArray();
1036 internal uint Tide() { return tide; }
1038 internal void IncTide(uint incVal) { tide += incVal; }
1040 internal uint Padding() { return padding; }
1042 internal uint Size() { return size; }
1044 internal void SetSize(uint pad)
1047 size = tide + padding;
1050 internal uint RVA() { return rva; }
1052 internal void SetRVA(uint rva) { this.rva = rva; }
1054 internal uint Offset() { return offset; }
1056 internal void SetOffset(uint offs) { offset = offs; }
1058 internal void DoBlock(BinaryWriter reloc, uint page, int start, int end)
1060 //Console.WriteLine("rva = " + rva + " page = " + page);
1061 reloc.Write(rva + page);
1062 reloc.Write((uint)(((end-start+1)*2) + 8));
1063 for (int j=start; j < end; j++) {
1064 //Console.WriteLine("reloc offset = " + relocs[j]);
1065 reloc.Write((ushort)((0x3 << 12) | (relocs[j] - page)));
1067 reloc.Write((ushort)0);
1070 internal void DoRelocs(BinaryWriter reloc)
1072 if (relocTide > 0) {
1073 //relocOff = (uint)reloc.Seek(0,SeekOrigin.Current);
1074 uint block = (relocs[0]/relocPageSize + 1) * relocPageSize;
1076 for (int i=1; i < relocTide; i++) {
1077 if (relocs[i] >= block) {
1078 DoBlock(reloc,block-relocPageSize,start,i);
1080 block = (relocs[i]/relocPageSize + 1) * relocPageSize;
1083 DoBlock(reloc,block-relocPageSize,start,(int)relocTide);
1087 internal void AddReloc(uint offs)
1090 if (relocs == null) {
1091 relocs = new uint[5];
1093 if (relocTide >= relocs.Length) {
1094 uint[] tmp = relocs;
1095 relocs = new uint[tmp.Length + 5];
1096 for (int i=0; i < relocTide; i++) {
1100 while ((pos < relocTide) && (relocs[pos] < offs)) pos++;
1101 for (int i=pos; i < relocTide; i++) {
1102 relocs[i+1] = relocs[i];
1109 internal void WriteHeader(BinaryWriter output, uint relocRVA)
1115 output.Write(offset);
1117 //output.Write(relocRVA + relocOff);
1120 //output.Write((ushort)relocTide);
1121 //output.Write((ushort)0);
1122 output.Write(flags);
1128 readonly static char[] hexDigit = {'0','1','2','3','4','5','6','7',
1129 '8','9','A','B','C','D','E','F'};
1130 readonly static uint[] iByteMask = {0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000};
1131 readonly static ulong[] lByteMask = {0x00000000000000FF, 0x000000000000FF00,
1132 0x0000000000FF0000, 0x00000000FF000000,
1133 0x000000FF00000000, 0x0000FF0000000000,
1134 0x00FF000000000000, 0xFF00000000000000 };
1135 readonly static uint nibble0Mask = 0x0000000F;
1136 readonly static uint nibble1Mask = 0x000000F0;
1138 public static String Byte(int b)
1140 char[] str = new char[2];
1142 uint b1 = num & nibble0Mask;
1143 uint b2 = (num & nibble1Mask) >> 4;
1144 str[0] = hexDigit[b2];
1145 str[1] = hexDigit[b1];
1146 return new String(str);
1149 public static String Short(int b)
1151 char[] str = new char[4];
1152 uint num1 = (uint)b & iByteMask[0];
1153 uint num2 = ((uint)b & iByteMask[1]) >> 8;
1154 uint b1 = num1 & nibble0Mask;
1155 uint b2 = (num1 & nibble1Mask) >> 4;
1156 uint b3 = num2 & nibble0Mask;
1157 uint b4 = (num2 & nibble1Mask) >> 4;
1158 str[0] = hexDigit[b4];
1159 str[1] = hexDigit[b3];
1160 str[2] = hexDigit[b2];
1161 str[3] = hexDigit[b1];
1162 return new String(str);
1165 public static String Int(int val)
1167 char[] str = new char[8];
1168 uint num = (uint)val;
1170 for (int i=0; i < iByteMask.Length; i++) {
1171 uint b = num & iByteMask[i];
1173 uint b1 = b & nibble0Mask;
1174 uint b2 = (b & nibble1Mask) >> 4;
1175 str[strIx--] = hexDigit[b1];
1176 str[strIx--] = hexDigit[b2];
1178 return new String(str);
1181 public static String Int(uint num)
1183 char[] str = new char[8];
1185 for (int i=0; i < iByteMask.Length; i++) {
1186 uint b = num & iByteMask[i];
1188 uint b1 = b & nibble0Mask;
1189 uint b2 = (b & nibble1Mask) >> 4;
1190 str[strIx--] = hexDigit[b1];
1191 str[strIx--] = hexDigit[b2];
1193 return new String(str);
1196 public static String Long(long lnum)
1198 ulong num = (ulong)lnum;
1199 char[] str = new char[16];
1201 for (int i=0; i < lByteMask.Length; i++) {
1202 ulong b = num & lByteMask[i];
1204 ulong b1 = b & nibble0Mask;
1205 ulong b2 = (b & nibble1Mask) >> 4;
1206 str[strIx--] = hexDigit[b1];
1207 str[strIx--] = hexDigit[b2];
1209 return new String(str);
1214 /// Error for invalid PE file
1216 public class PEFileException : System.Exception {
1217 public PEFileException(string msg) : base(msg) { }
1220 public class NotYetImplementedException : System.Exception {
1221 public NotYetImplementedException(string msg) : base(msg + " Not Yet Implemented") { }
1224 public class TypeSignatureException : System.Exception {
1225 public TypeSignatureException(string msg) : base(msg) { }