1 using System;
2 using System.IO;
3 using System.Collections;
4 using System.Text;
5 
6 namespace PEAPI {
7 
8 	/**************************************************************************/
9 	/// <summary>
10 	/// Image for a PEFile
11 	/// File Structure
12 	///     DOS Header (128 bytes)
13 	///     PE Signature ("PE\0\0")
14 	///     PEFileHeader (20 bytes)
15 	///     PEOptionalHeader (224 bytes)
16 	///     SectionHeaders (40 bytes * NumSections)
17 	///
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
23 	///
24 	/// .text layout
25 	///     IAT (single entry 8 bytes for pure CIL)
26 	///     CLIHeader (72 bytes)
27 	///     CIL instructions for all methods (variable size)
28 	///     MetaData
29 	///       Root (20 bytes + UTF-8 Version String + quad align padding)
30 	///       StreamHeaders (8 bytes + null terminated name string + quad align padding)
31 	///       Streams
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)
42 	///
43 	///  #~ stream structure
44 	///    Header (24 bytes)
45 	///    Rows   (4 bytes * numTables)
46 	///    Tables
47 	/// </summary>
48 	internal class FileImage : BinaryWriter {
49 
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;
57 
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,
74 			0x50,0x45,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
81 		};
82 
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;
96 
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";
108 
109 		private Section text, sdata;
110 		static readonly Section rsrc = null;
111 		ArrayList data;
112 		BinaryWriter reloc = new BinaryWriter(new MemoryStream());
113 		uint dateStamp = 0;
114 		DateTime origin = new DateTime(1970,1,1);
115 		uint numSections = 2; // always have .text  and .reloc sections
116 		internal SubSystem subSys = SubSystem.Windows_CUI;  // default is Windows Console mode
117 		internal long stackReserve = 0x100000; // default is 1Mb
118 		internal uint fileAlign = minFileAlign;
119 		uint entryPointOffset, entryPointPadding, imageSize, headerSize, headerPadding, entryPointToken = 0;
120 		uint relocOffset, relocRVA, relocSize, relocPadding, relocTide, hintNameTableOffset;
121 		uint metaDataOffset, runtimeEngineOffset, initDataSize = 0, importTablePadding;
122 		uint resourcesSize, resourcesOffset;
123 		uint strongNameSigOffset;
124 		uint importTableOffset, importLookupTableOffset, totalImportTableSize;
125 		MetaData metaData;
126 		char[] runtimeEngine = runtimeEngineName.ToCharArray(), hintNameTable;
127 		bool doDLL, largeStrings, largeGUID, largeUS, largeBlob;
128 		ushort characteristics;
129 
FileImage(bool makeDLL, string fileName)130 		internal FileImage(bool makeDLL, string fileName) : base(new FileStream(fileName,FileMode.Create))
131 		{
132 			InitFileImage(makeDLL);
133 			TimeSpan tmp = System.IO.File.GetCreationTime(fileName).Subtract(origin);
134 			dateStamp = Convert.ToUInt32(tmp.TotalSeconds);
135 		}
136 
FileImage(bool makeDLL, Stream str)137 		internal FileImage(bool makeDLL, Stream str) : base(str)
138 		{
139 			InitFileImage(makeDLL);
140 			TimeSpan tmp = DateTime.Now.Subtract(origin);
141 			dateStamp = Convert.ToUInt32(tmp.TotalSeconds);
142 		}
143 
InitFileImage(bool makeDLL)144 		private void InitFileImage(bool makeDLL)
145 		{
146 			doDLL = makeDLL;
147 			if (doDLL) {
148 				hintNameTable = dllHintNameTable.ToCharArray();
149 				characteristics = dllCharacteristics;
150 			} else {
151 				hintNameTable = exeHintNameTable.ToCharArray();
152 				characteristics = exeCharacteristics;
153 			}
154 			text = new Section(textName,0x60000020);     // IMAGE_SCN_CNT  CODE, EXECUTE, READ
155 			//                      rsrc = new Section(rsrcName,0x40000040);     // IMAGE_SCN_CNT  INITIALIZED_DATA, READ
156 			metaData = new MetaData(this);
157 		}
158 
GetMetaData()159 		internal MetaData GetMetaData()
160 		{
161 			return metaData;
162 		}
163 
GetNextSectStart(uint rva, uint tide)164 		private uint GetNextSectStart(uint rva, uint tide)
165 		{
166 			uint c = tide / SectionAlignment;
167 			if ((tide % SectionAlignment) != 0)
168 				c++;
169 			return rva + (c * SectionAlignment);
170 		}
171 
BuildTextSection()172 		private void BuildTextSection()
173 		{
174 			// .text layout
175 			//    IAT (single entry 8 bytes for pure CIL)
176 			//    CLIHeader (72 bytes)
177 			//    CIL instructions for all methods (variable size)
178 			//    MetaData
179 			//    ImportTable (40 bytes)
180 			//    ImportLookupTable(8 bytes) (same as IAT for standard CIL files)
181 			//    Hint/Name Tables with entry "_CorExeMain" for .exe file and "_CorDllMain" for .dll (14 bytes)
182 			//    ASCII string "mscoree.dll" referenced in ImportTable (+ padding = 16 bytes)
183 			//    Entry Point  (0xFF25 followed by 4 bytes 0x400000 + RVA of .text)
184 			metaData.BuildMetaData(IATSize + CLIHeaderSize);
185 			metaDataOffset = IATSize + CLIHeaderSize;
186 			// Console.WriteLine("Code starts at " + metaDataOffset);
187 			metaDataOffset += metaData.CodeSize();
188 			// resourcesStart =
189 			resourcesOffset = metaDataOffset + metaData.Size ();
190 			resourcesSize = metaData.GetResourcesSize ();
191 			if (reserveStrongNameSignatureSpace) {
192 				strongNameSigOffset = resourcesOffset + resourcesSize;
193 				// fixUps = RVA for vtable
194 				importTableOffset = strongNameSigOffset + StrongNameSignatureSize;
195 			} else {
196 				strongNameSigOffset = 0;
197 				// fixUps = RVA for vtable
198 				importTableOffset = resourcesOffset + resourcesSize;
199 			}
200 			importTablePadding = NumToAlign(importTableOffset,16);
201 			importTableOffset += importTablePadding;
202 			importLookupTableOffset = importTableOffset + ImportTableSize;
203 			hintNameTableOffset = importLookupTableOffset + IATSize;
204 			runtimeEngineOffset = hintNameTableOffset + (uint)hintNameTable.Length;
205 			entryPointOffset = runtimeEngineOffset + (uint)runtimeEngine.Length;
206 			totalImportTableSize = entryPointOffset - importTableOffset;
207 			// Console.WriteLine("total import table size = " + totalImportTableSize);
208 			// Console.WriteLine("entrypoint offset = " + entryPointOffset);
209 			entryPointPadding = NumToAlign(entryPointOffset,4) + 2;
210 			entryPointOffset += entryPointPadding;
211 			text.AddReloc(entryPointOffset+2);
212 			text.IncTide(entryPointOffset + 6);
213 			//if (text.Tide() < fileAlign) fileAlign = minFileAlign;
214 			text.SetSize(NumToAlign(text.Tide(),fileAlign));
215 			// Console.WriteLine("text size = " + text.Size() + " text tide = " + text.Tide() + " text padding = " + text.Padding());
216 			// Console.WriteLine("metaDataOffset = " + Hex.Int(metaDataOffset));
217 			// Console.WriteLine("importTableOffset = " + Hex.Int(importTableOffset));
218 			// Console.WriteLine("importLookupTableOffset = " + Hex.Int(importLookupTableOffset));
219 			// Console.WriteLine("hintNameTableOffset = " + Hex.Int(hintNameTableOffset));
220 			// Console.WriteLine("runtimeEngineOffset = " + Hex.Int(runtimeEngineOffset));
221 			// Console.WriteLine("entryPointOffset = " + Hex.Int(entryPointOffset));
222 			// Console.WriteLine("entryPointPadding = " + Hex.Int(entryPointPadding));
223 
224 		}
225 
BuildRelocSection()226 		internal void BuildRelocSection()
227 		{
228 			text.DoRelocs(reloc);
229 			if (sdata != null) sdata.DoRelocs(reloc);
230 			if (rsrc != null) rsrc.DoRelocs(reloc);
231 			relocTide = (uint)reloc.Seek(0,SeekOrigin.Current);
232 			relocPadding = NumToAlign(relocTide,fileAlign);
233 			relocSize = relocTide + relocPadding;
234 			imageSize = relocRVA + SectionAlignment;
235 			initDataSize += relocSize;
236 		}
237 
CalcOffsets()238 		private void CalcOffsets()
239 		{
240 			if (sdata != null)
241 				numSections++;
242 			if (rsrc != null)
243 				numSections++;
244 			headerSize = fileHeaderSize + (numSections * sectionHeaderSize);
245 			headerPadding = NumToAlign(headerSize,fileAlign);
246 			headerSize += headerPadding;
247 			uint offset = headerSize;
248 			uint rva = SectionAlignment;
249 			text.SetOffset(offset);
250 			text.SetRVA(rva);
251 			offset += text.Size();
252 			rva  = GetNextSectStart(rva,text.Tide());
253 			// Console.WriteLine("headerSize = " + headerSize);
254 			// Console.WriteLine("headerPadding = " + headerPadding);
255 			// Console.WriteLine("textOffset = " + Hex.Int(text.Offset()));
256 			if (sdata != null) {
257 				sdata.SetSize(NumToAlign(sdata.Tide(),fileAlign));
258 				sdata.SetOffset(offset);
259 				sdata.SetRVA(rva);
260 				offset += sdata.Size();
261 				rva = GetNextSectStart(rva,sdata.Tide());
262 				initDataSize += sdata.Size();
263 			}
264 			if (rsrc != null) {
265 				rsrc.SetSize(NumToAlign(rsrc.Tide(),fileAlign));
266 				rsrc.SetOffset(offset);
267 				rsrc.SetRVA(rva);
268 				offset += rsrc.Size();
269 				rva = GetNextSectStart(rva,rsrc.Tide());
270 				initDataSize += rsrc.Size();
271 			}
272 			relocOffset = offset;
273 			relocRVA = rva;
274 		}
275 
MakeFile()276 		internal void MakeFile()
277 		{
278 			if (doDLL) hintNameTable = dllHintNameTable.ToCharArray();
279 			else hintNameTable = exeHintNameTable.ToCharArray();
280 			BuildTextSection();
281 			CalcOffsets();
282 			BuildRelocSection();
283 			// now write it out
284 			WriteHeader();
285 			WriteSections();
286 			Flush();
287 			Close();
288 		}
289 
WriteHeader()290 		private void WriteHeader()
291 		{
292 			Write(DOSHeader);
293 			// Console.WriteLine("Writing PEHeader at offset " + Seek(0,SeekOrigin.Current));
294 			WritePEHeader();
295 			// Console.WriteLine("Writing text section header at offset " + Hex.Long(Seek(0,SeekOrigin.Current)));
296 			text.WriteHeader(this,relocRVA);
297 			if (sdata != null) sdata.WriteHeader(this,relocRVA);
298 			if (rsrc != null) rsrc.WriteHeader(this,relocRVA);
299 			// Console.WriteLine("Writing reloc section header at offset " + Seek(0,SeekOrigin.Current));
300 			WriteRelocSectionHeader();
301 			// Console.WriteLine("Writing padding at offset " + Seek(0,SeekOrigin.Current));
302 			WriteZeros(headerPadding);
303 		}
304 
WriteSections()305 		private void WriteSections()
306 		{
307 			// Console.WriteLine("Writing text section at offset " + Seek(0,SeekOrigin.Current));
308 			WriteTextSection();
309 			if (sdata != null) WriteSDataSection();
310 			if (rsrc != null) WriteRsrcSection();
311 			WriteRelocSection();
312 		}
313 
WriteIAT()314 		private void WriteIAT()
315 		{
316 			Write(text.RVA() + hintNameTableOffset);
317 			Write(0);
318 		}
319 
WriteImportTables()320 		private void WriteImportTables()
321 		{
322 			// Import Table
323 			WriteZeros(importTablePadding);
324 			// Console.WriteLine("Writing import tables at offset " + Hex.Long(Seek(0,SeekOrigin.Current)));
325 			Write(importLookupTableOffset + text.RVA());
326 			WriteZeros(8);
327 			Write(runtimeEngineOffset + text.RVA());
328 			Write(text.RVA());    // IAT is at the beginning of the text section
329 			WriteZeros(20);
330 			// Import Lookup Table
331 			WriteIAT();                // lookup table and IAT are the same
332 			// Hint/Name Table
333 			// Console.WriteLine("Writing hintname table at " + Hex.Long(Seek(0,SeekOrigin.Current)));
334 			Write(hintNameTable);
335 			Write(runtimeEngineName.ToCharArray());
336 		}
337 
WriteTextSection()338 		private void WriteTextSection()
339 		{
340 			WriteIAT();
341 			WriteCLIHeader();
342 			// Console.WriteLine("Writing code at " + Hex.Long(Seek(0,SeekOrigin.Current)));
343 			metaData.WriteByteCodes(this);
344 			// Console.WriteLine("Finished writing code at " + Hex.Long(Seek(0,SeekOrigin.Current)));
345 			largeStrings = metaData.LargeStringsIndex();
346 			largeGUID = metaData.LargeGUIDIndex();
347 			largeUS = metaData.LargeUSIndex();
348 			largeBlob = metaData.LargeBlobIndex();
349 			metaData.WriteMetaData(this);
350 			metaData.WriteResources (this);
351 			if (reserveStrongNameSignatureSpace) {
352 				WriteZeros(StrongNameSignatureSize);
353 			}
354 			WriteImportTables();
355 			WriteZeros(entryPointPadding);
356 			Write((ushort)0x25FF);
357 			Write(ImageBase + text.RVA());
358 			WriteZeros(text.Padding());
359 		}
360 
WriteCLIHeader()361 		private void WriteCLIHeader()
362 		{
363 			Write(CLIHeaderSize);       // Cb
364 			Write((short)2);            // Major runtime version
365 			Write((short)0);            // Minor runtime version
366 			Write(text.RVA() + metaDataOffset);
367 			Write(metaData.Size());
368 			Write(runtimeFlags);
369 			Write(entryPointToken);
370 			if (resourcesSize > 0) {
371 				Write (text.RVA () + resourcesOffset);
372 				Write (resourcesSize);
373 			} else {
374 				WriteZeros (8);
375 			}
376 			// Strong Name Signature (RVA, size)
377 			if (reserveStrongNameSignatureSpace) {
378 				Write(text.RVA() + strongNameSigOffset);
379 				Write(StrongNameSignatureSize);
380 			} else {
381 				WriteZeros(8);
382 			}
383 			WriteZeros(8);                     // CodeManagerTable
384 			WriteZeros(8);                     // VTableFixups NYI
385 			WriteZeros(16);                    // ExportAddressTableJumps, ManagedNativeHeader
386 		}
387 
WriteSDataSection()388 		private void WriteSDataSection()
389 		{
390 			long size = sdata.Size ();
391 			long start = BaseStream.Position;
392 			for (int i=0; i < data.Count; i++) {
393 				((DataConstant)data[i]).Write(this);
394 			}
395 			while (BaseStream.Position < (start + size))
396 				Write ((byte) 0);
397 		}
398 
WriteRsrcSection()399 		private void WriteRsrcSection()
400 		{
401 		}
402 
WriteRelocSection()403 		private void WriteRelocSection()
404 		{
405 			// Console.WriteLine("Writing reloc section at " + Seek(0,SeekOrigin.Current) + " = " + relocOffset);
406 			MemoryStream str = (MemoryStream)reloc.BaseStream;
407 			Write(str.ToArray());
408 			WriteZeros(NumToAlign((uint)str.Position,fileAlign));
409 		}
410 
SetEntryPoint(uint entryPoint)411 		internal void SetEntryPoint(uint entryPoint)
412 		{
413 			entryPointToken = entryPoint;
414 		}
415 
AddInitData(DataConstant cVal)416 		internal void AddInitData(DataConstant cVal)
417 		{
418 			if (sdata == null) {
419 				sdata = new Section(sdataName,0xC0000040);   // IMAGE_SCN_CNT  INITIALIZED_DATA, READ, WRITE
420 				data = new ArrayList();
421 			}
422 			data.Add(cVal);
423 			cVal.DataOffset = sdata.Tide();
424 			sdata.IncTide(cVal.GetSize());
425 		}
426 
WriteZeros(uint numZeros)427 		internal void WriteZeros(uint numZeros)
428 		{
429 			for (int i=0; i < numZeros; i++) {
430 				Write((byte)0);
431 			}
432 		}
433 
WritePEHeader()434 		internal void WritePEHeader()
435 		{
436 			Write((ushort)0x014C);  // Machine - always 0x14C for Managed PE Files (allow others??)
437 			Write((ushort)numSections);
438 			Write(dateStamp);
439 			WriteZeros(8); // Pointer to Symbol Table and Number of Symbols (always zero for ECMA CLI files)
440 			Write((ushort)0x00E0);  // Size of Optional Header
441 			Write(characteristics);
442 			// PE Optional Header
443 			Write((ushort)0x010B);   // Magic
444 			Write((byte)0x6);        // LMajor pure-IL = 6   C++ = 7
445 			Write((byte)0x0);        // LMinor
446 			Write(text.Size());
447 			Write(initDataSize);
448 			Write(0);                // Check other sections here!!
449 			Write(text.RVA() + entryPointOffset);
450 			Write(text.RVA());
451 			uint dataBase = 0;
452 			if (sdata != null) dataBase = sdata.RVA();
453 			else if (rsrc != null) dataBase = rsrc.RVA();
454 			else dataBase = relocRVA;
455 			Write(dataBase);
456 			Write(ImageBase);
457 			Write(SectionAlignment);
458 			Write(fileAlign);
459 			Write((ushort)0x04);     // OS Major
460 			WriteZeros(6);                  // OS Minor, User Major, User Minor
461 			Write((ushort)0x04);     // SubSys Major
462 			WriteZeros(6);           // SybSys Minor, Reserved
463 			Write(imageSize);
464 			Write(headerSize);
465 			Write((int)0);           // File Checksum
466 			Write((ushort)subSys);
467 			Write((short)0);         // DLL Flags
468 			Write((uint)stackReserve);   // Stack Reserve Size
469 			Write((uint)0x1000);     // Stack Commit Size
470 			Write((uint)0x100000);   // Heap Reserve Size
471 			Write((uint)0x1000);     // Heap Commit Size
472 			Write(0);                // Loader Flags
473 			Write(0x10);             // Number of Data Directories
474 			WriteZeros(8);                  // Export Table
475 			Write(importTableOffset + text.RVA());
476 			Write(totalImportTableSize);
477 			WriteZeros(24);            // Resource, Exception and Certificate Tables
478 			Write(relocRVA);
479 			Write(relocTide);
480 			WriteZeros(48);            // Debug, Copyright, Global Ptr, TLS, Load Config and Bound Import Tables
481 			Write(text.RVA());         // IATRVA - IAT is at start of .text Section
482 			Write(IATSize);
483 			WriteZeros(8);             // Delay Import Descriptor
484 			Write(text.RVA()+IATSize); // CLIHeader immediately follows IAT
485 			Write(CLIHeaderSize);
486 			WriteZeros(8);             // Reserved
487 		}
488 
WriteRelocSectionHeader()489 		internal void WriteRelocSectionHeader()
490 		{
491 			Write(relocName.ToCharArray());
492 			Write(relocTide);
493 			Write(relocRVA);
494 			Write(relocSize);
495 			Write(relocOffset);
496 			WriteZeros(12);
497 			Write(relocFlags);
498 		}
499 
Align(MemoryStream str, int val)500 		private void Align (MemoryStream str, int val)
501 		{
502 			if ((str.Position % val) != 0) {
503 				for (int i=val - (int)(str.Position % val); i > 0; i--) {
504 					str.WriteByte(0);
505 				}
506 			}
507 		}
508 
Align(uint val, uint alignVal)509 		private uint Align(uint val, uint alignVal)
510 		{
511 			if ((val % alignVal) != 0) {
512 				val += alignVal - (val % alignVal);
513 			}
514 			return val;
515 		}
516 
NumToAlign(uint val, uint alignVal)517 		private uint NumToAlign(uint val, uint alignVal)
518 		{
519 			if ((val % alignVal) == 0) return 0;
520 			return alignVal - (val % alignVal);
521 		}
522 
StringsIndex(uint ix)523 		internal void StringsIndex(uint ix)
524 		{
525 			if (largeStrings) Write(ix);
526 			else Write((ushort)ix);
527 		}
528 
GUIDIndex(uint ix)529 		internal void GUIDIndex(uint ix)
530 		{
531 			if (largeGUID) Write(ix);
532 			else Write((ushort)ix);
533 		}
534 
USIndex(uint ix)535 		internal void USIndex(uint ix)
536 		{
537 			if (largeUS) Write(ix);
538 			else Write((ushort)ix);
539 		}
540 
BlobIndex(uint ix)541 		internal void BlobIndex(uint ix)
542 		{
543 			if (largeBlob) Write(ix);
544 			else Write((ushort)ix);
545 		}
546 
WriteIndex(MDTable tabIx,uint ix)547 		internal void WriteIndex(MDTable tabIx,uint ix)
548 		{
549 			if (metaData.LargeIx(tabIx)) Write(ix);
550 			else Write((ushort)ix);
551 		}
552 
WriteCodedIndex(CIx code, MetaDataElement elem)553 		internal void WriteCodedIndex(CIx code, MetaDataElement elem)
554 		{
555 			metaData.WriteCodedIndex(code,elem,this);
556 		}
557 
WriteCodeRVA(uint offs)558 		internal void WriteCodeRVA(uint offs)
559 		{
560 			Write(text.RVA() + offs);
561 		}
562 
WriteDataRVA(uint offs)563 		internal void WriteDataRVA(uint offs)
564 		{
565 			Write(sdata.RVA() + offs);
566 		}
567 
Write3Bytes(uint val)568 		internal void Write3Bytes(uint val)
569 		{
570 			byte b3 = (byte)((val & FileImage.iByteMask[2]) >> 16);
571 			byte b2 = (byte)((val & FileImage.iByteMask[1]) >> 8);;
572 			byte b1 = (byte)(val & FileImage.iByteMask[0]);
573 			Write(b1);
574 			Write(b2);
575 			Write(b3);
576 		}
577 
578 		internal bool ReserveStrongNameSignatureSpace {
579 			get { return reserveStrongNameSignatureSpace; }
580 			set { reserveStrongNameSignatureSpace = value; }
581 		}
582 
583 	}
584 
585 	/**************************************************************************/
586 	/// <summary>
587 	/// Base class for the PEFile (starting point)
588 	/// </summary>
589 	public class PEFile {
590 
591 		private static readonly string mscorlibName = "mscorlib";
592 		private Module thisMod;
593 		private ClassDef moduleClass;
594 		private ArrayList resources = new ArrayList ();
595 		private Assembly thisAssembly;
596 		private static bool isMSCorlib;
597 		private int corFlags = 1;
598 		FileImage fileImage;
599 		MetaData metaData;
600 
601 		/// <summary>
602 		/// Create a new PEFile.  Each PEFile is a module.
603 		/// </summary>
604 		/// <param name="name">module name, also used for the file name</param>
605 		/// <param name="isDLL">create a .dll or .exe file</param>
606 		/// <param name="hasAssembly">this file is an assembly and
607 		/// will contain the assembly manifest.  The assembly name is the
608 		/// same as the module name</param>
PEFile(string name, bool isDLL, bool hasAssembly)609 		public PEFile(string name, bool isDLL, bool hasAssembly)
610 			: this (name, null, isDLL, hasAssembly, null, null)
611 		{
612 			// Console.WriteLine(Hex.Byte(0x12));
613 			// Console.WriteLine(Hex.Short(0x1234));
614 			// Console.WriteLine(Hex.Int(0x12345678));
615 		}
616 
617 		/// <summary>
618 		/// Create a new PEFile.  Each PEFile is a module.
619 		/// </summary>
620 		/// <param name="name">module name, also used for the file name</param>
621 		/// <param name="isDLL">create a .dll or .exe file</param>
622 		/// <param name="hasAssembly">this file is an assembly and
623 		/// will contain the assembly manifest.  The assembly name is the
624 		/// same as the module name</param>
625 		/// <param name="outputDir">write the PEFile to this directory.  If this
626 		/// string is null then the output will be to the current directory</param>
PEFile(string name, bool isDLL, bool hasAssembly, string outputDir)627 		public PEFile(string name, bool isDLL, bool hasAssembly, string outputDir)
628 			: this (name, null, isDLL, hasAssembly, outputDir, null)
629 		{
630 			// Console.WriteLine(Hex.Byte(0x12));
631 			// Console.WriteLine(Hex.Short(0x1234));
632 			// Console.WriteLine(Hex.Int(0x12345678));
633 		}
634 
635 		/// <summary>
636 		/// Create a new PEFile
637 		/// </summary>
638 		/// <param name="name">module name</param>
639 		/// <param name="isDLL">create a .dll or .exe</param>
640 		/// <param name="hasAssembly">this PEfile is an assembly and
641 		/// will contain the assemly manifest.  The assembly name is the
642 		/// same as the module name</param>
643 		/// <param name="outStream">write the PEFile to this stream instead
644 		/// of to a new file</param>
PEFile(string name, bool isDLL, bool hasAssembly, Stream outStream)645 		public PEFile(string name, bool isDLL, bool hasAssembly, Stream outStream)
646 			: this (name, null, isDLL, hasAssembly, null, outStream)
647 		{
648 		}
649 
PEFile(string name, string module_name, bool isDLL, bool hasAssembly, Stream outStream)650 		public PEFile(string name, string module_name, bool isDLL, bool hasAssembly, Stream outStream)
651 			: this (name, module_name, isDLL, hasAssembly, null, outStream)
652 		{
653 		}
654 
PEFile(string name, string module_name, bool isDLL, bool hasAssembly, string outputDir, Stream outStream)655 		public PEFile(string name, string module_name, bool isDLL, bool hasAssembly, string outputDir, Stream outStream)
656 		{
657 			SetName (name);
658 			string fname = module_name == null ? MakeFileName (outputDir, name, isDLL) : module_name;
659 			if (outStream == null)
660 				fileImage = new FileImage (isDLL, fname);
661 			else
662 				fileImage = new FileImage (isDLL, outStream);
663 
664 			InitPEFile (name, fname, hasAssembly);
665 		}
666 
SetName(string name)667 		private void SetName (string name)
668 		{
669 			if (name == "mscorlib")
670 				isMSCorlib = true;
671 		}
672 
InitPEFile(string name, string fName, bool hasAssembly)673 		private void InitPEFile(string name, string fName, bool hasAssembly)
674 		{
675 			metaData = fileImage.GetMetaData();
676 			thisMod = new Module(fName,metaData);
677 			if (hasAssembly) {
678 				thisAssembly = new Assembly(name,metaData);
679 				metaData.AddToTable(MDTable.Assembly,thisAssembly);
680 			}
681 			moduleClass = AddClass(TypeAttr.Private,"","<Module>");
682 			moduleClass.SpecialNoSuper();
683 			metaData.AddToTable(MDTable.Module,thisMod);
684 		}
685 
686 		internal static bool IsMSCorlib {
687 			get { return isMSCorlib; }
688 		}
689 
690 		public ClassDef ModuleClass {
691 			get { return moduleClass; }
692 		}
693 
694 		/// <summary>
695 		/// Set the subsystem (.subsystem) (Default is Windows Console mode)
696 		/// </summary>
697 		/// <param name="subS">subsystem value</param>
SetSubSystem(SubSystem subS)698 		public void SetSubSystem(SubSystem subS)
699 		{
700 			fileImage.subSys = subS;
701 		}
702 
703 		/// <summary>
704 		/// Set the flags (.corflags)
705 		/// </summary>
706 		/// <param name="flags">the flags value</param>
SetCorFlags(int flags)707 		public void SetCorFlags(int flags)
708 		{
709 			corFlags = flags;
710 		}
711 
SetStackReserve(long stackReserve)712 		public void SetStackReserve (long stackReserve)
713 		{
714 			fileImage.stackReserve = stackReserve;
715 		}
716 
MakeFileName(string dirName, string name, bool isDLL)717 		private string MakeFileName(string dirName, string name, bool isDLL)
718 		{
719 			string result = "";
720 			if ((dirName != null) && (dirName.CompareTo("") != 0)) {
721 				result = dirName;
722 				if (!dirName.EndsWith("\\")) result += "\\";
723 			}
724 			result += name;
725 
726 			// if (isDLL) result += ".dll";  else result += ".exe";
727 
728 			return result;
729 		}
730 
731 		/// <summary>
732 		/// Add an external assembly to this PEFile (.assembly extern)
733 		/// </summary>
734 		/// <param name="assemName">the external assembly name</param>
735 		/// <returns>a descriptor for this external assembly</returns>
AddExternAssembly(string assemName)736 		public AssemblyRef AddExternAssembly(string assemName)
737 		{
738 			if (assemName.CompareTo(mscorlibName) == 0) return metaData.mscorlib;
739 			AssemblyRef anAssem = new AssemblyRef(metaData,assemName);
740 			metaData.AddToTable(MDTable.AssemblyRef,anAssem);
741 			// Console.WriteLine("Adding assembly " + assemName);
742 			return anAssem;
743 		}
744 
745 		/// <summary>
746 		/// Add an external module to this PEFile (.module extern)
747 		/// </summary>
748 		/// <param name="name">the external module name</param>
749 		/// <returns>a descriptor for this external module</returns>
AddExternModule(string name)750 		public ModuleRef AddExternModule(string name)
751 		{
752 			ModuleRef modRef = new ModuleRef(metaData,name);
753 			metaData.AddToTable(MDTable.ModuleRef,modRef);
754 			return modRef;
755 		}
756 
AddExternClass(string ns, string name, TypeAttr attrs, MetaDataElement declRef)757 		public ClassRef AddExternClass(string ns, string name, TypeAttr attrs, MetaDataElement declRef)
758 		{
759 			return new ExternClassRef (attrs, ns, name, declRef, metaData);
760 		}
761 
762 		/// <summary>
763 		/// Add a "global" method to this module
764 		/// </summary>
765 		/// <param name="name">method name</param>
766 		/// <param name="retType">return type</param>
767 		/// <param name="pars">method parameters</param>
768 		/// <returns>a descriptor for this new "global" method</returns>
AddMethod(string name, Param ret_param, Param [] pars)769 		public MethodDef AddMethod (string name, Param ret_param, Param [] pars)
770 		{
771 			return moduleClass.AddMethod (name, ret_param, pars);
772 		}
773 
AddMethod(string name, Type retType, Param[] pars)774 		public MethodDef AddMethod(string name, Type retType, Param[] pars)
775 		{
776 			return AddMethod (name, new Param (ParamAttr.Default, "", retType), pars);
777 		}
778 
779 		/// <summary>
780 		/// Add a "global" method to this module
781 		/// </summary>
782 		/// <param name="mAtts">method attributes</param>
783 		/// <param name="iAtts">method implementation attributes</param>
784 		/// <param name="name">method name</param>
785 		/// <param name="retType">return type</param>
786 		/// <param name="pars">method parameters</param>
787 		/// <returns>a descriptor for this new "global" method</returns>
AddMethod(MethAttr mAtts, ImplAttr iAtts, string name, Param ret_param, Param [] pars)788 		public MethodDef AddMethod (MethAttr mAtts, ImplAttr iAtts, string name, Param ret_param, Param [] pars)
789 		{
790 			return moduleClass.AddMethod (mAtts, iAtts, name, ret_param, pars);
791 		}
792 
AddMethod(MethAttr mAtts, ImplAttr iAtts, string name, Type retType, Param[] pars)793 		public MethodDef AddMethod(MethAttr mAtts, ImplAttr iAtts, string name, Type retType, Param[] pars)
794 		{
795 			return AddMethod (mAtts, iAtts, name, new Param (ParamAttr.Default, "", retType), pars);
796 		}
797 
AddMethodToTypeSpec(Type item, string name, Type retType, Type[] pars)798 		public MethodRef AddMethodToTypeSpec (Type item, string name, Type retType, Type[] pars)
799 		{
800 			return AddMethodToTypeSpec (item, name, retType, pars, 0);
801 		}
802 
AddMethodToTypeSpec(Type item, string name, Type retType, Type[] pars, int gen_param_count)803 		public MethodRef AddMethodToTypeSpec (Type item, string name, Type retType, Type[] pars, int gen_param_count)
804 		{
805 			MethodRef meth = new MethodRef (item.GetTypeSpec (metaData), name, retType, pars, false, null, gen_param_count);
806 			metaData.AddToTable (MDTable.MemberRef,meth);
807 			return meth;
808 		}
809 
AddVarArgMethodToTypeSpec(Type item, string name, Type retType, Type[] pars, Type[] optPars)810 		public MethodRef AddVarArgMethodToTypeSpec (Type item, string name, Type retType,
811 				Type[] pars, Type[] optPars) {
812 			MethodRef meth = new MethodRef(item.GetTypeSpec (metaData), name,retType,pars,true,optPars, 0);
813 			metaData.AddToTable(MDTable.MemberRef,meth);
814 			return meth;
815 		}
816 
AddFieldToTypeSpec(Type item, string name, Type fType)817 		public FieldRef AddFieldToTypeSpec (Type item, string name, Type fType)
818 		{
819 			FieldRef field = new FieldRef (item.GetTypeSpec (metaData), name,fType);
820 			metaData.AddToTable (MDTable.MemberRef,field);
821 			return field;
822 		}
823 
AddMethodSpec(Method m, GenericMethodSig g_sig)824 		public Method AddMethodSpec (Method m, GenericMethodSig g_sig)
825 		{
826 			MethodSpec ms = new MethodSpec (m, g_sig);
827 			metaData.AddToTable (MDTable.MethodSpec, ms);
828 			return ms;
829 		}
830 
831 		/// <summary>
832 		/// Add a "global" field to this module
833 		/// </summary>
834 		/// <param name="name">field name</param>
835 		/// <param name="fType">field type</param>
836 		/// <returns>a descriptor for this new "global" field</returns>
AddField(string name, Type fType)837 		public FieldDef AddField(string name, Type fType)
838 		{
839 			return moduleClass.AddField(name,fType);
840 		}
841 
842 		/// <summary>
843 		/// Add a "global" field to this module
844 		/// </summary>
845 		/// <param name="attrSet">attributes of this field</param>
846 		/// <param name="name">field name</param>
847 		/// <param name="fType">field type</param>
848 		/// <returns>a descriptor for this new "global" field</returns>
AddField(FieldAttr attrSet, string name, Type fType)849 		public FieldDef AddField(FieldAttr attrSet, string name, Type fType)
850 		{
851 			return moduleClass.AddField(attrSet,name,fType);
852 		}
853 
854 		/// <summary>
855 		/// Add a class to this module
856 		/// </summary>
857 		/// <param name="attrSet">attributes of this class</param>
858 		/// <param name="nsName">name space name</param>
859 		/// <param name="name">class name</param>
860 		/// <returns>a descriptor for this new class</returns>
AddClass(TypeAttr attrSet, string nsName, string name)861 		public ClassDef AddClass(TypeAttr attrSet, string nsName, string name)
862 		{
863 			return AddClass (attrSet, nsName, name, null);
864 		}
865 
866 		/// <summary>
867 		/// Add a class which extends System.ValueType to this module
868 		/// </summary>
869 		/// <param name="attrSet">attributes of this class</param>
870 		/// <param name="nsName">name space name</param>
871 		/// <param name="name">class name</param>
872 		/// <returns>a descriptor for this new class</returns>
AddValueClass(TypeAttr attrSet, string nsName, string name, ValueClass vClass)873 		public ClassDef AddValueClass(TypeAttr attrSet, string nsName, string name, ValueClass vClass)
874 		{
875 			ClassDef aClass = new ClassDef(attrSet,nsName,name,metaData);
876 			if (!ClassDef.IsValueType (nsName, name) && !ClassDef.IsEnum (nsName, name)) {
877 				aClass.MakeValueClass(vClass);
878 			} else {
879 				if (ClassDef.IsEnum (nsName, name))
880 					aClass.SetSuper (metaData.mscorlib.ValueType ());
881 				else
882 					aClass.SetSuper (metaData.mscorlib.GetSpecialSystemClass (PrimitiveType.Object));
883 
884 				metaData.mscorlib.SetSpecialSystemClass (nsName, name, aClass);
885 			}
886 			aClass.SetTypeIndex (PrimitiveType.ValueType.GetTypeIndex ());
887 			metaData.AddToTable(MDTable.TypeDef,aClass);
888 			return aClass;
889 		}
890 
891 		/// <summary>
892 		/// Add a class to this module
893 		/// </summary>
894 		/// <param name="attrSet">attributes of this class</param>
895 		/// <param name="nsName">name space name</param>
896 		/// <param name="name">class name</param>
897 		/// <param name="superType">super type of this class (extends)</param>
898 		/// <returns>a descriptor for this new class</returns>
AddClass(TypeAttr attrSet, string nsName, string name, Class superType)899 		public ClassDef AddClass(TypeAttr attrSet, string nsName, string name, Class superType)
900 		{
901 			ClassDef aClass = new ClassDef(attrSet,nsName,name,metaData);
902 			if (superType != null)
903 				aClass.SetSuper(superType);
904 			if (PEFile.IsMSCorlib)
905 				metaData.mscorlib.SetSpecialSystemClass (nsName, name, aClass);
906 			metaData.AddToTable(MDTable.TypeDef,aClass);
907 			return aClass;
908 		}
909 
AddGenericClass(GenericTypeInst gti)910 		public void  AddGenericClass (GenericTypeInst gti)
911 		{
912 			metaData.AddToTable (MDTable.TypeSpec, gti);
913 		}
914 
AddGenericParam(GenParam param)915 		public void AddGenericParam (GenParam param)
916 		{
917 			metaData.AddToTable (MDTable.TypeSpec, param);
918 		}
919 
AddFile(string fName, byte[] hashBytes, bool hasMetaData, bool entryPoint)920 		public FileRef AddFile(string fName, byte[] hashBytes, bool hasMetaData, bool entryPoint)
921 		{
922 			FileRef file = new FileRef(fName,hashBytes,hasMetaData,entryPoint,metaData);
923 			metaData.AddToTable(MDTable.File,file);
924 			return file;
925 		}
926 
AddPrimitiveType(PrimitiveType type)927 		public PrimitiveTypeRef AddPrimitiveType (PrimitiveType type)
928 		{
929 			return new PrimitiveTypeRef (type, metaData);
930 		}
931 
932 		/// <summary>
933 		/// Add a manifest resource to this PEFile NOT YET IMPLEMENTED
934 		/// </summary>
935 		/// <param name="mr"></param>
AddManifestResource(ManifestResource mr)936 		public void AddManifestResource(ManifestResource mr)
937 		{
938 			metaData.AddToTable(MDTable.ManifestResource,mr);
939 			resources.Add (mr);
940 			//mr.FixName(metaData);
941 		}
942 
AddCustomAttribute(Method meth, byte [] data, MetaDataElement element)943 		public void AddCustomAttribute (Method meth, byte [] data, MetaDataElement element)
944 		{
945 			metaData.AddCustomAttribute (new CustomAttribute (element, meth, data));
946 			element.HasCustomAttr = true;
947 		}
948 
AddCustomAttribute(Method meth, Constant constant, MetaDataElement element)949 		public void AddCustomAttribute (Method meth, Constant constant, MetaDataElement element)
950 		{
951 			metaData.AddCustomAttribute (new CustomAttribute (element, meth, constant));
952 			element.HasCustomAttr = true;
953 		}
954 
AddDeclSecurity(SecurityAction sec_action, byte [] data, MetaDataElement element)955 		public void AddDeclSecurity (SecurityAction sec_action, byte [] data, MetaDataElement element)
956 		{
957 			metaData.AddDeclSecurity (new DeclSecurity (element, (ushort) sec_action, data));
958 		}
959 
AddDeclSecurity(SecurityAction sec_action, PEAPI.PermissionSet ps, MetaDataElement element)960 		public void AddDeclSecurity (SecurityAction sec_action, PEAPI.PermissionSet ps, MetaDataElement element)
961 		{
962 			metaData.AddDeclSecurity (new DeclSecurity_20 (element, (ushort) sec_action, ps));
963 		}
964 
965 		/// <summary>
966 		/// Add a managed resource from another assembly.
967 		/// </summary>
968 		/// <param name="resName">The name of the resource</param>
969 		/// <param name="assem">The assembly where the resource is</param>
970 		/// <param name="isPublic">Access for the resource</param>
AddExternalManagedResource(string resName, AssemblyRef assem, uint flags)971 		public void AddExternalManagedResource (string resName, AssemblyRef assem, uint flags)
972 		{
973 			resources.Add (new ManifestResource (resName, flags, assem));
974 		}
975 
976 		/// <summary>
977 		/// Add a managed resource from another assembly.
978 		/// </summary>
979 		/// <param name="mr"></param>
980 		/// <param name="isPublic"></param>
AddExternalManagedResource(ManifestResource mr)981 		public void AddExternalManagedResource (ManifestResource mr)
982 		{
983 			resources.Add (new ManifestResource (mr));
984 		}
985 		/// <summary>
986 		/// Find a resource
987 		/// </summary>
988 		/// <param name="name">The name of the resource</param>
989 		/// <returns>The resource with the name "name" or null </returns>
GetResource(string name)990 		public ManifestResource GetResource (string name)
991 		{
992 			for (int i = 0; i < resources.Count; i ++) {
993 				if (((ManifestResource) resources [i]).Name == name)
994 					return (ManifestResource) resources [i];
995 			}
996 			return null;
997 		}
998 
GetResources()999 		public ManifestResource [] GetResources()
1000 		{
1001 			return (ManifestResource []) resources.ToArray (typeof (ManifestResource));
1002 		}
1003 
1004 		/// <summary>
1005 		/// Write out the PEFile (the "bake" function)
1006 		/// </summary>
WritePEFile()1007 		public void WritePEFile() { /* the "bake" function */
1008 			if (thisAssembly != null)
1009 				fileImage.ReserveStrongNameSignatureSpace = thisAssembly.HasPublicKey;
1010 			fileImage.MakeFile();
1011 		}
1012 
1013 		/// <summary>
1014 		/// Get the descriptor of this module
1015 		/// </summary>
1016 		/// <returns>the descriptor for this module</returns>
GetThisModule()1017 		public Module GetThisModule()
1018 		{
1019 			return thisMod;
1020 		}
1021 
1022 		/// <summary>
1023 		/// Get the descriptor for this assembly.  The PEFile must have been
1024 		/// created with hasAssembly = true
1025 		/// </summary>
1026 		/// <returns>the descriptor for this assembly</returns>
GetThisAssembly()1027 		public Assembly GetThisAssembly()
1028 		{
1029 			return thisAssembly;
1030 		}
1031 
1032 	}
1033 
1034 	/**************************************************************************/
1035 	/// <summary>
1036 	/// Descriptor for a Section in a PEFile  eg .text, .sdata
1037 	/// </summary>
1038 	internal class Section {
1039 		private static readonly uint relocPageSize = 4096;  // 4K pages for fixups
1040 
1041 		char[] name;
1042 		uint offset = 0, tide = 0, size = 0, rva = 0, relocTide = 0;
1043 		//uint relocOff = 0;
1044 		uint flags = 0, padding = 0;
1045 		uint[] relocs;
1046 
Section(string sName, uint sFlags)1047 		internal Section(string sName, uint sFlags)
1048 		{
1049 			name = sName.ToCharArray();
1050 			flags = sFlags;
1051 		}
1052 
Tide()1053 		internal uint Tide() { return tide; }
1054 
IncTide(uint incVal)1055 		internal void IncTide(uint incVal) { tide += incVal; }
1056 
Padding()1057 		internal uint Padding() { return padding; }
1058 
Size()1059 		internal uint Size() { return size; }
1060 
SetSize(uint pad)1061 		internal void SetSize(uint pad)
1062 		{
1063 			padding = pad;
1064 			size = tide + padding;
1065 		}
1066 
RVA()1067 		internal uint RVA() { return rva; }
1068 
SetRVA(uint rva)1069 		internal void SetRVA(uint rva) { this.rva = rva; }
1070 
Offset()1071 		internal uint Offset() { return offset; }
1072 
SetOffset(uint offs)1073 		internal void SetOffset(uint offs) { offset = offs; }
1074 
DoBlock(BinaryWriter reloc, uint page, int start, int end)1075 		internal void DoBlock(BinaryWriter reloc, uint page, int start, int end)
1076 		{
1077 			//Console.WriteLine("rva = " + rva + "  page = " + page);
1078 			reloc.Write(rva + page);
1079 			reloc.Write((uint)(((end-start+1)*2) + 8));
1080 			for (int j=start; j < end; j++) {
1081 				//Console.WriteLine("reloc offset = " + relocs[j]);
1082 				reloc.Write((ushort)((0x3 << 12) | (relocs[j] - page)));
1083 			}
1084 			reloc.Write((ushort)0);
1085 		}
1086 
DoRelocs(BinaryWriter reloc)1087 		internal void DoRelocs(BinaryWriter reloc)
1088 		{
1089 			if (relocTide > 0) {
1090 				//relocOff = (uint)reloc.Seek(0,SeekOrigin.Current);
1091 				uint block = (relocs[0]/relocPageSize + 1) * relocPageSize;
1092 				int start = 0;
1093 				for (int i=1; i < relocTide; i++) {
1094 					if (relocs[i] >= block) {
1095 						DoBlock(reloc,block-relocPageSize,start,i);
1096 						start = i;
1097 						block = (relocs[i]/relocPageSize + 1) * relocPageSize;
1098 					}
1099 				}
1100 				DoBlock(reloc,block-relocPageSize,start,(int)relocTide);
1101 			}
1102 		}
1103 
AddReloc(uint offs)1104 		internal void AddReloc(uint offs)
1105 		{
1106 			int pos = 0;
1107 			if (relocs == null) {
1108 				relocs = new uint[5];
1109 			} else {
1110 				if (relocTide >= relocs.Length) {
1111 					uint[] tmp = relocs;
1112 					relocs = new uint[tmp.Length + 5];
1113 					for (int i=0; i < relocTide; i++) {
1114 						relocs[i] = tmp[i];
1115 					}
1116 				}
1117 				while ((pos < relocTide) && (relocs[pos] < offs)) pos++;
1118 				for (int i=pos; i < relocTide; i++) {
1119 					relocs[i+1] = relocs[i];
1120 				}
1121 			}
1122 			relocs[pos] = offs;
1123 			relocTide++;
1124 		}
1125 
WriteHeader(BinaryWriter output, uint relocRVA)1126 		internal void WriteHeader(BinaryWriter output, uint relocRVA)
1127 		{
1128 			output.Write(name);
1129 			output.Write(tide);
1130 			output.Write(rva);
1131 			output.Write(size);
1132 			output.Write(offset);
1133 			output.Write(0);
1134 			//output.Write(relocRVA + relocOff);
1135 			output.Write(0);
1136 			output.Write(0);
1137 			//output.Write((ushort)relocTide);
1138 			//output.Write((ushort)0);
1139 			output.Write(flags);
1140 		}
1141 
1142 	}
1143 
1144 	public class Hex {
1145 		readonly static char[] hexDigit = {'0','1','2','3','4','5','6','7',
1146 			'8','9','A','B','C','D','E','F'};
1147 		readonly static uint[] iByteMask = {0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000};
1148 		readonly static ulong[] lByteMask = {0x00000000000000FF, 0x000000000000FF00,
1149 			0x0000000000FF0000, 0x00000000FF000000,
1150 			0x000000FF00000000, 0x0000FF0000000000,
1151 			0x00FF000000000000, 0xFF00000000000000 };
1152 		readonly static uint nibble0Mask = 0x0000000F;
1153 		readonly static uint nibble1Mask = 0x000000F0;
1154 
Byte(int b)1155 		public static String Byte(int b)
1156 		{
1157 			char[] str = new char[2];
1158 			uint num = (uint)b;
1159 			uint b1 = num & nibble0Mask;
1160 			uint b2 = (num & nibble1Mask) >> 4;
1161 			str[0] = hexDigit[b2];
1162 			str[1] = hexDigit[b1];
1163 			return new String(str);
1164 		}
1165 
Short(int b)1166 		public static String Short(int b)
1167 		{
1168 			char[] str = new char[4];
1169 			uint num1 = (uint)b & iByteMask[0];
1170 			uint num2 = ((uint)b & iByteMask[1]) >> 8;
1171 			uint b1 = num1 & nibble0Mask;
1172 			uint b2 = (num1 & nibble1Mask) >> 4;
1173 			uint b3 = num2 & nibble0Mask;
1174 			uint b4 = (num2 & nibble1Mask) >> 4;
1175 			str[0] = hexDigit[b4];
1176 			str[1] = hexDigit[b3];
1177 			str[2] = hexDigit[b2];
1178 			str[3] = hexDigit[b1];
1179 			return new String(str);
1180 		}
1181 
Int(int val)1182 		public static String Int(int val)
1183 		{
1184 			char[] str = new char[8];
1185 			uint num = (uint)val;
1186 			int strIx = 7;
1187 			for (int i=0; i < iByteMask.Length; i++) {
1188 				uint b = num & iByteMask[i];
1189 				b >>= (i*8);
1190 				uint b1 = b & nibble0Mask;
1191 				uint b2 = (b & nibble1Mask) >> 4;
1192 				str[strIx--] = hexDigit[b1];
1193 				str[strIx--] = hexDigit[b2];
1194 			}
1195 			return new String(str);
1196 		}
1197 
Int(uint num)1198 		public static String Int(uint num)
1199 		{
1200 			char[] str = new char[8];
1201 			int strIx = 7;
1202 			for (int i=0; i < iByteMask.Length; i++) {
1203 				uint b = num & iByteMask[i];
1204 				b >>= (i*8);
1205 				uint b1 = b & nibble0Mask;
1206 				uint b2 = (b & nibble1Mask) >> 4;
1207 				str[strIx--] = hexDigit[b1];
1208 				str[strIx--] = hexDigit[b2];
1209 			}
1210 			return new String(str);
1211 		}
1212 
Long(long lnum)1213 		public static String Long(long lnum)
1214 		{
1215 			ulong num = (ulong)lnum;
1216 			char[] str = new char[16];
1217 			int strIx = 15;
1218 			for (int i=0; i < lByteMask.Length; i++) {
1219 				ulong b = num & lByteMask[i];
1220 				b >>= (i*8);
1221 				ulong b1 = b & nibble0Mask;
1222 				ulong b2 = (b & nibble1Mask) >> 4;
1223 				str[strIx--] = hexDigit[b1];
1224 				str[strIx--] = hexDigit[b2];
1225 			}
1226 			return new String(str);
1227 		}
1228 	}
1229 
1230 	/// <summary>
1231 	/// Error for invalid PE file
1232 	/// </summary>
1233 	public class PEFileException : System.Exception {
PEFileException(string msg)1234 		public PEFileException(string msg) : base(msg) { }
1235 	}
1236 
1237 	public class NotYetImplementedException : System.Exception  {
NotYetImplementedException(string msg)1238 		public NotYetImplementedException(string msg) : base(msg + " Not Yet Implemented") { }
1239 	}
1240 
1241 	public class TypeSignatureException : System.Exception {
TypeSignatureException(string msg)1242 		public TypeSignatureException(string msg) : base(msg) { }
1243 	}
1244 
1245 }
1246