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 MethodRef meth = new MethodRef (item.GetTypeSpec (metaData), name, retType, pars, false, null);
785 metaData.AddToTable (MDTable.MemberRef,meth);
789 public MethodRef AddVarArgMethodToTypeSpec (Type item, string name, Type retType,
790 Type[] pars, Type[] optPars) {
791 MethodRef meth = new MethodRef(item.GetTypeSpec (metaData), name,retType,pars,true,optPars);
792 metaData.AddToTable(MDTable.MemberRef,meth);
796 public FieldRef AddFieldToTypeSpec (Type item, string name, Type fType)
798 FieldRef field = new FieldRef (item.GetTypeSpec (metaData), name,fType);
799 metaData.AddToTable (MDTable.MemberRef,field);
803 public void AddMethodSpec (Method m, GenericMethodSig g_sig)
805 MethodSpec ms = new MethodSpec (m, g_sig);
806 metaData.AddToTable (MDTable.MethodSpec, ms);
810 /// Add a "global" field to this module
812 /// <param name="name">field name</param>
813 /// <param name="fType">field type</param>
814 /// <returns>a descriptor for this new "global" field</returns>
815 public FieldDef AddField(string name, Type fType)
817 return moduleClass.AddField(name,fType);
821 /// Add a "global" field to this module
823 /// <param name="attrSet">attributes of this field</param>
824 /// <param name="name">field name</param>
825 /// <param name="fType">field type</param>
826 /// <returns>a descriptor for this new "global" field</returns>
827 public FieldDef AddField(FieldAttr attrSet, string name, Type fType)
829 return moduleClass.AddField(attrSet,name,fType);
833 /// Add a class to this module
835 /// <param name="attrSet">attributes of this class</param>
836 /// <param name="nsName">name space name</param>
837 /// <param name="name">class name</param>
838 /// <returns>a descriptor for this new class</returns>
839 public ClassDef AddClass(TypeAttr attrSet, string nsName, string name)
841 return AddClass (attrSet, nsName, name, null);
845 /// Add a class which extends System.ValueType to this module
847 /// <param name="attrSet">attributes of this class</param>
848 /// <param name="nsName">name space name</param>
849 /// <param name="name">class name</param>
850 /// <returns>a descriptor for this new class</returns>
851 public ClassDef AddValueClass(TypeAttr attrSet, string nsName, string name, ValueClass vClass)
853 ClassDef aClass = new ClassDef(attrSet,nsName,name,metaData);
854 if (!ClassDef.IsValueType (nsName, name) && !ClassDef.IsEnum (nsName, name)) {
855 aClass.MakeValueClass(vClass);
857 if (ClassDef.IsEnum (nsName, name))
858 aClass.SetSuper (metaData.mscorlib.ValueType ());
860 aClass.SetSuper (metaData.mscorlib.GetSpecialSystemClass (PrimitiveType.Object));
862 metaData.mscorlib.SetSpecialSystemClass (nsName, name, aClass);
864 aClass.SetTypeIndex (PrimitiveType.ValueType.GetTypeIndex ());
865 metaData.AddToTable(MDTable.TypeDef,aClass);
870 /// Add a class to this module
872 /// <param name="attrSet">attributes of this class</param>
873 /// <param name="nsName">name space name</param>
874 /// <param name="name">class name</param>
875 /// <param name="superType">super type of this class (extends)</param>
876 /// <returns>a descriptor for this new class</returns>
877 public ClassDef AddClass(TypeAttr attrSet, string nsName, string name, Class superType)
879 ClassDef aClass = new ClassDef(attrSet,nsName,name,metaData);
880 if (superType != null)
881 aClass.SetSuper(superType);
882 if (PEFile.IsMSCorlib)
883 metaData.mscorlib.SetSpecialSystemClass (nsName, name, aClass);
884 metaData.AddToTable(MDTable.TypeDef,aClass);
888 public FileRef AddFile(string fName, byte[] hashBytes, bool hasMetaData, bool entryPoint)
890 FileRef file = new FileRef(fName,hashBytes,hasMetaData,entryPoint,metaData);
891 metaData.AddToTable(MDTable.File,file);
896 /// Add a manifest resource to this PEFile NOT YET IMPLEMENTED
898 /// <param name="mr"></param>
899 public void AddManifestResource(ManifestResource mr)
901 metaData.AddToTable(MDTable.ManifestResource,mr);
903 //mr.FixName(metaData);
906 public void AddCustomAttribute (Method meth, byte [] data, MetaDataElement element)
908 metaData.AddCustomAttribute (new CustomAttribute (element, meth, data));
911 public void AddDeclSecurity (SecurityAction sec_action, byte [] data, MetaDataElement element)
913 metaData.AddDeclSecurity (new DeclSecurity (element, (ushort) sec_action, data));
917 /// Add a managed resource from another assembly.
919 /// <param name="resName">The name of the resource</param>
920 /// <param name="assem">The assembly where the resource is</param>
921 /// <param name="isPublic">Access for the resource</param>
922 public void AddExternalManagedResource (string resName, AssemblyRef assem, uint flags)
924 resources.Add (new ManifestResource (resName, flags, assem));
928 /// Add a managed resource from another assembly.
930 /// <param name="mr"></param>
931 /// <param name="isPublic"></param>
932 public void AddExternalManagedResource (ManifestResource mr)
934 resources.Add (new ManifestResource (mr));
939 /// <param name="name">The name of the resource</param>
940 /// <returns>The resource with the name "name" or null </returns>
941 public ManifestResource GetResource (string name)
943 for (int i = 0; i < resources.Count; i ++) {
944 if (((ManifestResource) resources [i]).Name == name)
945 return (ManifestResource) resources [i];
950 public ManifestResource [] GetResources()
952 return (ManifestResource []) resources.ToArray (typeof (ManifestResource));
956 /// Write out the PEFile (the "bake" function)
958 public void WritePEFile() { /* the "bake" function */
959 fileImage.ReserveStrongNameSignatureSpace = thisAssembly.HasPublicKey;
960 fileImage.MakeFile();
964 /// Get the descriptor of this module
966 /// <returns>the descriptor for this module</returns>
967 public Module GetThisModule()
973 /// Get the descriptor for this assembly. The PEFile must have been
974 /// created with hasAssembly = true
976 /// <returns>the descriptor for this assembly</returns>
977 public Assembly GetThisAssembly()
984 /**************************************************************************/
986 /// Descriptor for a Section in a PEFile eg .text, .sdata
988 internal class Section {
989 private static readonly uint relocPageSize = 4096; // 4K pages for fixups
992 uint offset = 0, tide = 0, size = 0, rva = 0, relocTide = 0;
994 uint flags = 0, padding = 0;
997 internal Section(string sName, uint sFlags)
999 name = sName.ToCharArray();
1003 internal uint Tide() { return tide; }
1005 internal void IncTide(uint incVal) { tide += incVal; }
1007 internal uint Padding() { return padding; }
1009 internal uint Size() { return size; }
1011 internal void SetSize(uint pad)
1014 size = tide + padding;
1017 internal uint RVA() { return rva; }
1019 internal void SetRVA(uint rva) { this.rva = rva; }
1021 internal uint Offset() { return offset; }
1023 internal void SetOffset(uint offs) { offset = offs; }
1025 internal void DoBlock(BinaryWriter reloc, uint page, int start, int end)
1027 //Console.WriteLine("rva = " + rva + " page = " + page);
1028 reloc.Write(rva + page);
1029 reloc.Write((uint)(((end-start+1)*2) + 8));
1030 for (int j=start; j < end; j++) {
1031 //Console.WriteLine("reloc offset = " + relocs[j]);
1032 reloc.Write((ushort)((0x3 << 12) | (relocs[j] - page)));
1034 reloc.Write((ushort)0);
1037 internal void DoRelocs(BinaryWriter reloc)
1039 if (relocTide > 0) {
1040 //relocOff = (uint)reloc.Seek(0,SeekOrigin.Current);
1041 uint block = (relocs[0]/relocPageSize + 1) * relocPageSize;
1043 for (int i=1; i < relocTide; i++) {
1044 if (relocs[i] >= block) {
1045 DoBlock(reloc,block-relocPageSize,start,i);
1047 block = (relocs[i]/relocPageSize + 1) * relocPageSize;
1050 DoBlock(reloc,block-relocPageSize,start,(int)relocTide);
1054 internal void AddReloc(uint offs)
1057 if (relocs == null) {
1058 relocs = new uint[5];
1060 if (relocTide >= relocs.Length) {
1061 uint[] tmp = relocs;
1062 relocs = new uint[tmp.Length + 5];
1063 for (int i=0; i < relocTide; i++) {
1067 while ((pos < relocTide) && (relocs[pos] < offs)) pos++;
1068 for (int i=pos; i < relocTide; i++) {
1069 relocs[i+1] = relocs[i];
1076 internal void WriteHeader(BinaryWriter output, uint relocRVA)
1082 output.Write(offset);
1084 //output.Write(relocRVA + relocOff);
1087 //output.Write((ushort)relocTide);
1088 //output.Write((ushort)0);
1089 output.Write(flags);
1095 readonly static char[] hexDigit = {'0','1','2','3','4','5','6','7',
1096 '8','9','A','B','C','D','E','F'};
1097 readonly static uint[] iByteMask = {0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000};
1098 readonly static ulong[] lByteMask = {0x00000000000000FF, 0x000000000000FF00,
1099 0x0000000000FF0000, 0x00000000FF000000,
1100 0x000000FF00000000, 0x0000FF0000000000,
1101 0x00FF000000000000, 0xFF00000000000000 };
1102 readonly static uint nibble0Mask = 0x0000000F;
1103 readonly static uint nibble1Mask = 0x000000F0;
1105 public static String Byte(int b)
1107 char[] str = new char[2];
1109 uint b1 = num & nibble0Mask;
1110 uint b2 = (num & nibble1Mask) >> 4;
1111 str[0] = hexDigit[b2];
1112 str[1] = hexDigit[b1];
1113 return new String(str);
1116 public static String Short(int b)
1118 char[] str = new char[4];
1119 uint num1 = (uint)b & iByteMask[0];
1120 uint num2 = ((uint)b & iByteMask[1]) >> 8;
1121 uint b1 = num1 & nibble0Mask;
1122 uint b2 = (num1 & nibble1Mask) >> 4;
1123 uint b3 = num2 & nibble0Mask;
1124 uint b4 = (num2 & nibble1Mask) >> 4;
1125 str[0] = hexDigit[b4];
1126 str[1] = hexDigit[b3];
1127 str[2] = hexDigit[b2];
1128 str[3] = hexDigit[b1];
1129 return new String(str);
1132 public static String Int(int val)
1134 char[] str = new char[8];
1135 uint num = (uint)val;
1137 for (int i=0; i < iByteMask.Length; i++) {
1138 uint b = num & iByteMask[i];
1140 uint b1 = b & nibble0Mask;
1141 uint b2 = (b & nibble1Mask) >> 4;
1142 str[strIx--] = hexDigit[b1];
1143 str[strIx--] = hexDigit[b2];
1145 return new String(str);
1148 public static String Int(uint num)
1150 char[] str = new char[8];
1152 for (int i=0; i < iByteMask.Length; i++) {
1153 uint b = num & iByteMask[i];
1155 uint b1 = b & nibble0Mask;
1156 uint b2 = (b & nibble1Mask) >> 4;
1157 str[strIx--] = hexDigit[b1];
1158 str[strIx--] = hexDigit[b2];
1160 return new String(str);
1163 public static String Long(long lnum)
1165 ulong num = (ulong)lnum;
1166 char[] str = new char[16];
1168 for (int i=0; i < lByteMask.Length; i++) {
1169 ulong b = num & lByteMask[i];
1171 ulong b1 = b & nibble0Mask;
1172 ulong b2 = (b & nibble1Mask) >> 4;
1173 str[strIx--] = hexDigit[b1];
1174 str[strIx--] = hexDigit[b2];
1176 return new String(str);
1181 /// Error for invalid PE file
1183 public class PEFileException : System.Exception {
1184 public PEFileException(string msg) : base("Error in PE File: " + msg) { }
1187 public class NotYetImplementedException : System.Exception {
1188 public NotYetImplementedException(string msg) : base(msg + " Not Yet Implemented") { }
1191 public class TypeSignatureException : System.Exception {
1192 public TypeSignatureException(string msg) : base(msg) { }