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 if (tide < SectionAlignment) return rva + SectionAlignment;
166 return rva + ((tide / SectionAlignment) + 1) * SectionAlignment;
169 private void BuildTextSection()
172 // IAT (single entry 8 bytes for pure CIL)
173 // CLIHeader (72 bytes)
174 // CIL instructions for all methods (variable size)
176 // ImportTable (40 bytes)
177 // ImportLookupTable(8 bytes) (same as IAT for standard CIL files)
178 // Hint/Name Tables with entry "_CorExeMain" for .exe file and "_CorDllMain" for .dll (14 bytes)
179 // ASCII string "mscoree.dll" referenced in ImportTable (+ padding = 16 bytes)
180 // Entry Point (0xFF25 followed by 4 bytes 0x400000 + RVA of .text)
181 metaData.BuildMetaData(IATSize + CLIHeaderSize);
182 metaDataOffset = IATSize + CLIHeaderSize;
183 // Console.WriteLine("Code starts at " + metaDataOffset);
184 metaDataOffset += metaData.CodeSize();
186 resourcesOffset = metaDataOffset + metaData.Size ();
187 resourcesSize = metaData.GetResourcesSize ();
188 if (reserveStrongNameSignatureSpace) {
189 strongNameSigOffset = resourcesOffset + resourcesSize;
190 // fixUps = RVA for vtable
191 importTableOffset = strongNameSigOffset + StrongNameSignatureSize;
193 strongNameSigOffset = 0;
194 // fixUps = RVA for vtable
195 importTableOffset = resourcesOffset + resourcesSize;
197 importTablePadding = NumToAlign(importTableOffset,16);
198 importTableOffset += importTablePadding;
199 importLookupTableOffset = importTableOffset + ImportTableSize;
200 hintNameTableOffset = importLookupTableOffset + IATSize;
201 runtimeEngineOffset = hintNameTableOffset + (uint)hintNameTable.Length;
202 entryPointOffset = runtimeEngineOffset + (uint)runtimeEngine.Length;
203 totalImportTableSize = entryPointOffset - importTableOffset;
204 // Console.WriteLine("total import table size = " + totalImportTableSize);
205 // Console.WriteLine("entrypoint offset = " + entryPointOffset);
206 entryPointPadding = NumToAlign(entryPointOffset,4) + 2;
207 entryPointOffset += entryPointPadding;
208 text.AddReloc(entryPointOffset+2);
209 text.IncTide(entryPointOffset + 6);
210 //if (text.Tide() < fileAlign) fileAlign = minFileAlign;
211 text.SetSize(NumToAlign(text.Tide(),fileAlign));
212 // Console.WriteLine("text size = " + text.Size() + " text tide = " + text.Tide() + " text padding = " + text.Padding());
213 // Console.WriteLine("metaDataOffset = " + Hex.Int(metaDataOffset));
214 // Console.WriteLine("importTableOffset = " + Hex.Int(importTableOffset));
215 // Console.WriteLine("importLookupTableOffset = " + Hex.Int(importLookupTableOffset));
216 // Console.WriteLine("hintNameTableOffset = " + Hex.Int(hintNameTableOffset));
217 // Console.WriteLine("runtimeEngineOffset = " + Hex.Int(runtimeEngineOffset));
218 // Console.WriteLine("entryPointOffset = " + Hex.Int(entryPointOffset));
219 // Console.WriteLine("entryPointPadding = " + Hex.Int(entryPointPadding));
223 internal void BuildRelocSection()
225 text.DoRelocs(reloc);
226 if (sdata != null) sdata.DoRelocs(reloc);
227 if (rsrc != null) rsrc.DoRelocs(reloc);
228 relocTide = (uint)reloc.Seek(0,SeekOrigin.Current);
229 relocPadding = NumToAlign(relocTide,fileAlign);
230 relocSize = relocTide + relocPadding;
231 imageSize = relocRVA + SectionAlignment;
232 initDataSize += relocSize;
235 private void CalcOffsets()
241 headerSize = fileHeaderSize + (numSections * sectionHeaderSize);
242 headerPadding = NumToAlign(headerSize,fileAlign);
243 headerSize += headerPadding;
244 uint offset = headerSize;
245 uint rva = SectionAlignment;
246 text.SetOffset(offset);
248 offset += text.Size();
249 rva = GetNextSectStart(rva,text.Tide());
250 // Console.WriteLine("headerSize = " + headerSize);
251 // Console.WriteLine("headerPadding = " + headerPadding);
252 // Console.WriteLine("textOffset = " + Hex.Int(text.Offset()));
254 sdata.SetSize(NumToAlign(sdata.Tide(),fileAlign));
255 sdata.SetOffset(offset);
257 offset += sdata.Size();
258 rva = GetNextSectStart(rva,sdata.Tide());
259 initDataSize += sdata.Size();
262 rsrc.SetSize(NumToAlign(rsrc.Tide(),fileAlign));
263 rsrc.SetOffset(offset);
265 offset += rsrc.Size();
266 rva = GetNextSectStart(rva,rsrc.Tide());
267 initDataSize += rsrc.Size();
269 relocOffset = offset;
273 internal void MakeFile()
275 if (doDLL) hintNameTable = dllHintNameTable.ToCharArray();
276 else hintNameTable = exeHintNameTable.ToCharArray();
287 private void WriteHeader()
290 // Console.WriteLine("Writing PEHeader at offset " + Seek(0,SeekOrigin.Current));
292 // Console.WriteLine("Writing text section header at offset " + Hex.Long(Seek(0,SeekOrigin.Current)));
293 text.WriteHeader(this,relocRVA);
294 if (sdata != null) sdata.WriteHeader(this,relocRVA);
295 if (rsrc != null) rsrc.WriteHeader(this,relocRVA);
296 // Console.WriteLine("Writing reloc section header at offset " + Seek(0,SeekOrigin.Current));
297 WriteRelocSectionHeader();
298 // Console.WriteLine("Writing padding at offset " + Seek(0,SeekOrigin.Current));
299 WriteZeros(headerPadding);
302 private void WriteSections()
304 // Console.WriteLine("Writing text section at offset " + Seek(0,SeekOrigin.Current));
306 if (sdata != null) WriteSDataSection();
307 if (rsrc != null) WriteRsrcSection();
311 private void WriteIAT()
313 Write(text.RVA() + hintNameTableOffset);
317 private void WriteImportTables()
320 WriteZeros(importTablePadding);
321 // Console.WriteLine("Writing import tables at offset " + Hex.Long(Seek(0,SeekOrigin.Current)));
322 Write(importLookupTableOffset + text.RVA());
324 Write(runtimeEngineOffset + text.RVA());
325 Write(text.RVA()); // IAT is at the beginning of the text section
327 // Import Lookup Table
328 WriteIAT(); // lookup table and IAT are the same
330 // Console.WriteLine("Writing hintname table at " + Hex.Long(Seek(0,SeekOrigin.Current)));
331 Write(hintNameTable);
332 Write(runtimeEngineName.ToCharArray());
335 private void WriteTextSection()
339 // Console.WriteLine("Writing code at " + Hex.Long(Seek(0,SeekOrigin.Current)));
340 metaData.WriteByteCodes(this);
341 // Console.WriteLine("Finished writing code at " + Hex.Long(Seek(0,SeekOrigin.Current)));
342 largeStrings = metaData.LargeStringsIndex();
343 largeGUID = metaData.LargeGUIDIndex();
344 largeUS = metaData.LargeUSIndex();
345 largeBlob = metaData.LargeBlobIndex();
346 metaData.WriteMetaData(this);
347 metaData.WriteResources (this);
348 if (reserveStrongNameSignatureSpace) {
349 WriteZeros(StrongNameSignatureSize);
352 WriteZeros(entryPointPadding);
353 Write((ushort)0x25FF);
354 Write(ImageBase + text.RVA());
355 WriteZeros(text.Padding());
358 private void WriteCLIHeader()
360 Write(CLIHeaderSize); // Cb
361 Write((short)2); // Major runtime version
362 Write((short)0); // Minor runtime version
363 Write(text.RVA() + metaDataOffset);
364 Write(metaData.Size());
366 Write(entryPointToken);
367 if (resourcesSize > 0) {
368 Write (text.RVA () + resourcesOffset);
369 Write (resourcesSize);
373 // Strong Name Signature (RVA, size)
374 if (reserveStrongNameSignatureSpace) {
375 Write(text.RVA() + strongNameSigOffset);
376 Write(StrongNameSignatureSize);
380 WriteZeros(8); // CodeManagerTable
381 WriteZeros(8); // VTableFixups NYI
382 WriteZeros(16); // ExportAddressTableJumps, ManagedNativeHeader
385 private void WriteSDataSection()
387 long size = sdata.Size ();
388 long start = BaseStream.Position;
389 for (int i=0; i < data.Count; i++) {
390 ((DataConstant)data[i]).Write(this);
392 while (BaseStream.Position < (start + size))
396 private void WriteRsrcSection()
400 private void WriteRelocSection()
402 // Console.WriteLine("Writing reloc section at " + Seek(0,SeekOrigin.Current) + " = " + relocOffset);
403 MemoryStream str = (MemoryStream)reloc.BaseStream;
404 Write(str.ToArray());
405 WriteZeros(NumToAlign((uint)str.Position,fileAlign));
408 internal void SetEntryPoint(uint entryPoint)
410 entryPointToken = entryPoint;
413 internal void AddInitData(DataConstant cVal)
416 sdata = new Section(sdataName,0xC0000040); // IMAGE_SCN_CNT INITIALIZED_DATA, READ, WRITE
417 data = new ArrayList();
420 cVal.DataOffset = sdata.Tide();
421 sdata.IncTide(cVal.GetSize());
424 internal void WriteZeros(uint numZeros)
426 for (int i=0; i < numZeros; i++) {
431 internal void WritePEHeader()
433 Write((ushort)0x014C); // Machine - always 0x14C for Managed PE Files (allow others??)
434 Write((ushort)numSections);
436 WriteZeros(8); // Pointer to Symbol Table and Number of Symbols (always zero for ECMA CLI files)
437 Write((ushort)0x00E0); // Size of Optional Header
438 Write(characteristics);
439 // PE Optional Header
440 Write((ushort)0x010B); // Magic
441 Write((byte)0x6); // LMajor pure-IL = 6 C++ = 7
442 Write((byte)0x0); // LMinor
445 Write(0); // Check other sections here!!
446 Write(text.RVA() + entryPointOffset);
449 if (sdata != null) dataBase = sdata.RVA();
450 else if (rsrc != null) dataBase = rsrc.RVA();
451 else dataBase = relocRVA;
454 Write(SectionAlignment);
456 Write((ushort)0x04); // OS Major
457 WriteZeros(6); // OS Minor, User Major, User Minor
458 Write((ushort)0x04); // SubSys Major
459 WriteZeros(6); // SybSys Minor, Reserved
462 Write((int)0); // File Checksum
463 Write((ushort)subSys);
464 Write((short)0); // DLL Flags
465 Write((uint)stackReserve); // Stack Reserve Size
466 Write((uint)0x1000); // Stack Commit Size
467 Write((uint)0x100000); // Heap Reserve Size
468 Write((uint)0x1000); // Heap Commit Size
469 Write(0); // Loader Flags
470 Write(0x10); // Number of Data Directories
471 WriteZeros(8); // Export Table
472 Write(importTableOffset + text.RVA());
473 Write(totalImportTableSize);
474 WriteZeros(24); // Resource, Exception and Certificate Tables
477 WriteZeros(48); // Debug, Copyright, Global Ptr, TLS, Load Config and Bound Import Tables
478 Write(text.RVA()); // IATRVA - IAT is at start of .text Section
480 WriteZeros(8); // Delay Import Descriptor
481 Write(text.RVA()+IATSize); // CLIHeader immediately follows IAT
482 Write(CLIHeaderSize);
483 WriteZeros(8); // Reserved
486 internal void WriteRelocSectionHeader()
488 Write(relocName.ToCharArray());
497 private void Align (MemoryStream str, int val)
499 if ((str.Position % val) != 0) {
500 for (int i=val - (int)(str.Position % val); i > 0; i--) {
506 private uint Align(uint val, uint alignVal)
508 if ((val % alignVal) != 0) {
509 val += alignVal - (val % alignVal);
514 private uint NumToAlign(uint val, uint alignVal)
516 if ((val % alignVal) == 0) return 0;
517 return alignVal - (val % alignVal);
520 internal void StringsIndex(uint ix)
522 if (largeStrings) Write(ix);
523 else Write((ushort)ix);
526 internal void GUIDIndex(uint ix)
528 if (largeGUID) Write(ix);
529 else Write((ushort)ix);
532 internal void USIndex(uint ix)
534 if (largeUS) Write(ix);
535 else Write((ushort)ix);
538 internal void BlobIndex(uint ix)
540 if (largeBlob) Write(ix);
541 else Write((ushort)ix);
544 internal void WriteIndex(MDTable tabIx,uint ix)
546 if (metaData.LargeIx(tabIx)) Write(ix);
547 else Write((ushort)ix);
550 internal void WriteCodedIndex(CIx code, MetaDataElement elem)
552 metaData.WriteCodedIndex(code,elem,this);
555 internal void WriteCodeRVA(uint offs)
557 Write(text.RVA() + offs);
560 internal void WriteDataRVA(uint offs)
562 Write(sdata.RVA() + offs);
565 internal void Write3Bytes(uint val)
567 byte b3 = (byte)((val & FileImage.iByteMask[2]) >> 16);
568 byte b2 = (byte)((val & FileImage.iByteMask[1]) >> 8);;
569 byte b1 = (byte)(val & FileImage.iByteMask[0]);
575 internal bool ReserveStrongNameSignatureSpace {
576 get { return reserveStrongNameSignatureSpace; }
577 set { reserveStrongNameSignatureSpace = value; }
582 /**************************************************************************/
584 /// Base class for the PEFile (starting point)
586 public class PEFile {
588 private static readonly string mscorlibName = "mscorlib";
589 private Module thisMod;
590 private ClassDef moduleClass;
591 private ArrayList classRefList = new ArrayList();
592 private ArrayList classDefList = new ArrayList();
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, Type retType, Param[] pars)
765 return moduleClass.AddMethod(name,retType,pars);
769 /// Add a "global" method to this module
771 /// <param name="mAtts">method attributes</param>
772 /// <param name="iAtts">method implementation attributes</param>
773 /// <param name="name">method name</param>
774 /// <param name="retType">return type</param>
775 /// <param name="pars">method parameters</param>
776 /// <returns>a descriptor for this new "global" method</returns>
777 public MethodDef AddMethod(MethAttr mAtts, ImplAttr iAtts, string name, Type retType, Param[] pars)
779 return moduleClass.AddMethod(mAtts,iAtts,name,retType,pars);
782 public MethodRef AddMethodToTypeSpec (Type item, string name, Type retType, Type[] pars)
784 return AddMethodToTypeSpec (item, name, retType, pars, 0);
787 public MethodRef AddMethodToTypeSpec (Type item, string name, Type retType, Type[] pars, int gen_param_count)
789 MethodRef meth = new MethodRef (item.GetTypeSpec (metaData), name, retType, pars, false, null, gen_param_count);
790 metaData.AddToTable (MDTable.MemberRef,meth);
794 public MethodRef AddVarArgMethodToTypeSpec (Type item, string name, Type retType,
795 Type[] pars, Type[] optPars) {
796 MethodRef meth = new MethodRef(item.GetTypeSpec (metaData), name,retType,pars,true,optPars, 0);
797 metaData.AddToTable(MDTable.MemberRef,meth);
801 public FieldRef AddFieldToTypeSpec (Type item, string name, Type fType)
803 FieldRef field = new FieldRef (item.GetTypeSpec (metaData), name,fType);
804 metaData.AddToTable (MDTable.MemberRef,field);
808 public Method AddMethodSpec (Method m, GenericMethodSig g_sig)
810 MethodSpec ms = new MethodSpec (m, g_sig);
811 metaData.AddToTable (MDTable.MethodSpec, ms);
816 /// Add a "global" field to this module
818 /// <param name="name">field name</param>
819 /// <param name="fType">field type</param>
820 /// <returns>a descriptor for this new "global" field</returns>
821 public FieldDef AddField(string name, Type fType)
823 return moduleClass.AddField(name,fType);
827 /// Add a "global" field to this module
829 /// <param name="attrSet">attributes of this field</param>
830 /// <param name="name">field name</param>
831 /// <param name="fType">field type</param>
832 /// <returns>a descriptor for this new "global" field</returns>
833 public FieldDef AddField(FieldAttr attrSet, string name, Type fType)
835 return moduleClass.AddField(attrSet,name,fType);
839 /// Add a class to this module
841 /// <param name="attrSet">attributes of this class</param>
842 /// <param name="nsName">name space name</param>
843 /// <param name="name">class name</param>
844 /// <returns>a descriptor for this new class</returns>
845 public ClassDef AddClass(TypeAttr attrSet, string nsName, string name)
847 return AddClass (attrSet, nsName, name, null);
851 /// Add a class which extends System.ValueType to this module
853 /// <param name="attrSet">attributes of this class</param>
854 /// <param name="nsName">name space name</param>
855 /// <param name="name">class name</param>
856 /// <returns>a descriptor for this new class</returns>
857 public ClassDef AddValueClass(TypeAttr attrSet, string nsName, string name, ValueClass vClass)
859 ClassDef aClass = new ClassDef(attrSet,nsName,name,metaData);
860 if (!ClassDef.IsValueType (nsName, name) && !ClassDef.IsEnum (nsName, name)) {
861 aClass.MakeValueClass(vClass);
863 if (ClassDef.IsEnum (nsName, name))
864 aClass.SetSuper (metaData.mscorlib.ValueType ());
866 aClass.SetSuper (metaData.mscorlib.GetSpecialSystemClass (PrimitiveType.Object));
868 metaData.mscorlib.SetSpecialSystemClass (nsName, name, aClass);
870 aClass.SetTypeIndex (PrimitiveType.ValueType.GetTypeIndex ());
871 metaData.AddToTable(MDTable.TypeDef,aClass);
876 /// Add a class to this module
878 /// <param name="attrSet">attributes of this class</param>
879 /// <param name="nsName">name space name</param>
880 /// <param name="name">class name</param>
881 /// <param name="superType">super type of this class (extends)</param>
882 /// <returns>a descriptor for this new class</returns>
883 public ClassDef AddClass(TypeAttr attrSet, string nsName, string name, Class superType)
885 ClassDef aClass = new ClassDef(attrSet,nsName,name,metaData);
886 if (superType != null)
887 aClass.SetSuper(superType);
888 if (PEFile.IsMSCorlib)
889 metaData.mscorlib.SetSpecialSystemClass (nsName, name, aClass);
890 metaData.AddToTable(MDTable.TypeDef,aClass);
894 public void AddGenericClass (GenericTypeInst gti)
896 metaData.AddToTable (MDTable.TypeSpec, gti);
899 public void AddGenericParam (GenParam param)
901 metaData.AddToTable (MDTable.TypeSpec, param);
904 public FileRef AddFile(string fName, byte[] hashBytes, bool hasMetaData, bool entryPoint)
906 FileRef file = new FileRef(fName,hashBytes,hasMetaData,entryPoint,metaData);
907 metaData.AddToTable(MDTable.File,file);
912 /// Add a manifest resource to this PEFile NOT YET IMPLEMENTED
914 /// <param name="mr"></param>
915 public void AddManifestResource(ManifestResource mr)
917 metaData.AddToTable(MDTable.ManifestResource,mr);
919 //mr.FixName(metaData);
922 public void AddCustomAttribute (Method meth, byte [] data, MetaDataElement element)
924 metaData.AddCustomAttribute (new CustomAttribute (element, meth, data));
927 public void AddDeclSecurity (SecurityAction sec_action, byte [] data, MetaDataElement element)
929 metaData.AddDeclSecurity (new DeclSecurity (element, (ushort) sec_action, data));
933 /// Add a managed resource from another assembly.
935 /// <param name="resName">The name of the resource</param>
936 /// <param name="assem">The assembly where the resource is</param>
937 /// <param name="isPublic">Access for the resource</param>
938 public void AddExternalManagedResource (string resName, AssemblyRef assem, uint flags)
940 resources.Add (new ManifestResource (resName, flags, assem));
944 /// Add a managed resource from another assembly.
946 /// <param name="mr"></param>
947 /// <param name="isPublic"></param>
948 public void AddExternalManagedResource (ManifestResource mr)
950 resources.Add (new ManifestResource (mr));
955 /// <param name="name">The name of the resource</param>
956 /// <returns>The resource with the name "name" or null </returns>
957 public ManifestResource GetResource (string name)
959 for (int i = 0; i < resources.Count; i ++) {
960 if (((ManifestResource) resources [i]).Name == name)
961 return (ManifestResource) resources [i];
966 public ManifestResource [] GetResources()
968 return (ManifestResource []) resources.ToArray (typeof (ManifestResource));
972 /// Write out the PEFile (the "bake" function)
974 public void WritePEFile() { /* the "bake" function */
975 if (thisAssembly != null)
976 fileImage.ReserveStrongNameSignatureSpace = thisAssembly.HasPublicKey;
977 fileImage.MakeFile();
981 /// Get the descriptor of this module
983 /// <returns>the descriptor for this module</returns>
984 public Module GetThisModule()
990 /// Get the descriptor for this assembly. The PEFile must have been
991 /// created with hasAssembly = true
993 /// <returns>the descriptor for this assembly</returns>
994 public Assembly GetThisAssembly()
1001 /**************************************************************************/
1003 /// Descriptor for a Section in a PEFile eg .text, .sdata
1005 internal class Section {
1006 private static readonly uint relocPageSize = 4096; // 4K pages for fixups
1009 uint offset = 0, tide = 0, size = 0, rva = 0, relocTide = 0;
1010 //uint relocOff = 0;
1011 uint flags = 0, padding = 0;
1014 internal Section(string sName, uint sFlags)
1016 name = sName.ToCharArray();
1020 internal uint Tide() { return tide; }
1022 internal void IncTide(uint incVal) { tide += incVal; }
1024 internal uint Padding() { return padding; }
1026 internal uint Size() { return size; }
1028 internal void SetSize(uint pad)
1031 size = tide + padding;
1034 internal uint RVA() { return rva; }
1036 internal void SetRVA(uint rva) { this.rva = rva; }
1038 internal uint Offset() { return offset; }
1040 internal void SetOffset(uint offs) { offset = offs; }
1042 internal void DoBlock(BinaryWriter reloc, uint page, int start, int end)
1044 //Console.WriteLine("rva = " + rva + " page = " + page);
1045 reloc.Write(rva + page);
1046 reloc.Write((uint)(((end-start+1)*2) + 8));
1047 for (int j=start; j < end; j++) {
1048 //Console.WriteLine("reloc offset = " + relocs[j]);
1049 reloc.Write((ushort)((0x3 << 12) | (relocs[j] - page)));
1051 reloc.Write((ushort)0);
1054 internal void DoRelocs(BinaryWriter reloc)
1056 if (relocTide > 0) {
1057 //relocOff = (uint)reloc.Seek(0,SeekOrigin.Current);
1058 uint block = (relocs[0]/relocPageSize + 1) * relocPageSize;
1060 for (int i=1; i < relocTide; i++) {
1061 if (relocs[i] >= block) {
1062 DoBlock(reloc,block-relocPageSize,start,i);
1064 block = (relocs[i]/relocPageSize + 1) * relocPageSize;
1067 DoBlock(reloc,block-relocPageSize,start,(int)relocTide);
1071 internal void AddReloc(uint offs)
1074 if (relocs == null) {
1075 relocs = new uint[5];
1077 if (relocTide >= relocs.Length) {
1078 uint[] tmp = relocs;
1079 relocs = new uint[tmp.Length + 5];
1080 for (int i=0; i < relocTide; i++) {
1084 while ((pos < relocTide) && (relocs[pos] < offs)) pos++;
1085 for (int i=pos; i < relocTide; i++) {
1086 relocs[i+1] = relocs[i];
1093 internal void WriteHeader(BinaryWriter output, uint relocRVA)
1099 output.Write(offset);
1101 //output.Write(relocRVA + relocOff);
1104 //output.Write((ushort)relocTide);
1105 //output.Write((ushort)0);
1106 output.Write(flags);
1112 readonly static char[] hexDigit = {'0','1','2','3','4','5','6','7',
1113 '8','9','A','B','C','D','E','F'};
1114 readonly static uint[] iByteMask = {0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000};
1115 readonly static ulong[] lByteMask = {0x00000000000000FF, 0x000000000000FF00,
1116 0x0000000000FF0000, 0x00000000FF000000,
1117 0x000000FF00000000, 0x0000FF0000000000,
1118 0x00FF000000000000, 0xFF00000000000000 };
1119 readonly static uint nibble0Mask = 0x0000000F;
1120 readonly static uint nibble1Mask = 0x000000F0;
1122 public static String Byte(int b)
1124 char[] str = new char[2];
1126 uint b1 = num & nibble0Mask;
1127 uint b2 = (num & nibble1Mask) >> 4;
1128 str[0] = hexDigit[b2];
1129 str[1] = hexDigit[b1];
1130 return new String(str);
1133 public static String Short(int b)
1135 char[] str = new char[4];
1136 uint num1 = (uint)b & iByteMask[0];
1137 uint num2 = ((uint)b & iByteMask[1]) >> 8;
1138 uint b1 = num1 & nibble0Mask;
1139 uint b2 = (num1 & nibble1Mask) >> 4;
1140 uint b3 = num2 & nibble0Mask;
1141 uint b4 = (num2 & nibble1Mask) >> 4;
1142 str[0] = hexDigit[b4];
1143 str[1] = hexDigit[b3];
1144 str[2] = hexDigit[b2];
1145 str[3] = hexDigit[b1];
1146 return new String(str);
1149 public static String Int(int val)
1151 char[] str = new char[8];
1152 uint num = (uint)val;
1154 for (int i=0; i < iByteMask.Length; i++) {
1155 uint b = num & iByteMask[i];
1157 uint b1 = b & nibble0Mask;
1158 uint b2 = (b & nibble1Mask) >> 4;
1159 str[strIx--] = hexDigit[b1];
1160 str[strIx--] = hexDigit[b2];
1162 return new String(str);
1165 public static String Int(uint num)
1167 char[] str = new char[8];
1169 for (int i=0; i < iByteMask.Length; i++) {
1170 uint b = num & iByteMask[i];
1172 uint b1 = b & nibble0Mask;
1173 uint b2 = (b & nibble1Mask) >> 4;
1174 str[strIx--] = hexDigit[b1];
1175 str[strIx--] = hexDigit[b2];
1177 return new String(str);
1180 public static String Long(long lnum)
1182 ulong num = (ulong)lnum;
1183 char[] str = new char[16];
1185 for (int i=0; i < lByteMask.Length; i++) {
1186 ulong b = num & lByteMask[i];
1188 ulong b1 = b & nibble0Mask;
1189 ulong b2 = (b & nibble1Mask) >> 4;
1190 str[strIx--] = hexDigit[b1];
1191 str[strIx--] = hexDigit[b2];
1193 return new String(str);
1198 /// Error for invalid PE file
1200 public class PEFileException : System.Exception {
1201 public PEFileException(string msg) : base(msg) { }
1204 public class NotYetImplementedException : System.Exception {
1205 public NotYetImplementedException(string msg) : base(msg + " Not Yet Implemented") { }
1208 public class TypeSignatureException : System.Exception {
1209 public TypeSignatureException(string msg) : base(msg) { }