PEWriter.cs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636
  1. /*
  2. * PERWAPI - An API for Reading and Writing PE Files
  3. *
  4. * Copyright (c) Diane Corney, Queensland University of Technology, 2004.
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the PERWAPI Copyright as included with this
  8. * distribution in the file PERWAPIcopyright.rtf.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY as is explained in the copyright notice.
  12. *
  13. * The author may be contacted at d.corney@qut.edu.au
  14. *
  15. * Version Date: 26/01/07
  16. */
  17. using System;
  18. using System.IO;
  19. using System.Diagnostics;
  20. using System.Collections;
  21. namespace QUT.PERWAPI
  22. {
  23. /**************************************************************************/
  24. // Class to Write PE File
  25. /**************************************************************************/
  26. internal class PEWriter : BinaryWriter
  27. {
  28. private Section text, sdata, rsrc = null;
  29. ArrayList data; // Used for accumulating data for the .sdata Section.
  30. PEResourceDirectory unmanagedResourceRoot;
  31. BinaryWriter reloc = new BinaryWriter(new MemoryStream());
  32. uint dateStamp = 0, codeStart = 0;
  33. uint numSections = 2; // always have .text and .reloc sections
  34. internal PEFileVersionInfo verInfo;
  35. //internal bool delaySign;
  36. uint entryPointOffset, entryPointPadding, imageSize, headerSize, headerPadding, entryPointToken = 0;
  37. uint relocOffset, relocRVA, relocSize, relocPadding, relocTide, hintNameTableOffset, resourcesSize = 0;
  38. uint metaDataOffset, runtimeEngineOffset, initDataSize = 0, resourcesOffset, importTablePadding;
  39. uint importTableOffset, importLookupTableOffset, totalImportTableSize, entryPointReloc = 0; //, delaySignOffset;
  40. uint debugOffset = 0, debugSize = 0, debugRVA = 0;
  41. long debugBytesStartOffset = 0;
  42. MetaDataOut metaData;
  43. char[] runtimeEngine = FileImage.runtimeEngineName.ToCharArray(), hintNameTable;
  44. bool closeStream = true;
  45. int debugBytesSize = 25; // NOTE: I don't know that this should be 25 but the debug bytes size seems to be 25 plus the size of the PDB filename. AKB 06-01-2007
  46. internal PDBWriter pdbWriter;
  47. /*-------------------- Constructors ---------------------------------*/
  48. internal PEWriter(PEFileVersionInfo verInfo, string fileName, MetaDataOut md, bool writePDB)
  49. : base(new FileStream(fileName, FileMode.Create))
  50. {
  51. InitPEWriter(verInfo, md, writePDB, fileName);
  52. TimeSpan tmp = System.IO.File.GetCreationTime(fileName).Subtract(FileImage.origin);
  53. dateStamp = Convert.ToUInt32(tmp.TotalSeconds);
  54. }
  55. internal PEWriter(PEFileVersionInfo verInfo, Stream str, MetaDataOut md)
  56. : base(str)
  57. {
  58. // NOTE: Can not write a PDB file if using a stream.
  59. InitPEWriter(verInfo, md, false, null);
  60. TimeSpan tmp = DateTime.Now.Subtract(FileImage.origin);
  61. dateStamp = Convert.ToUInt32(tmp.TotalSeconds);
  62. closeStream = false;
  63. }
  64. /*----------------------------- Writing -----------------------------------------*/
  65. private void InitPEWriter(PEFileVersionInfo verInfo, MetaDataOut md, bool writePDB, string fileName)
  66. {
  67. this.verInfo = verInfo;
  68. if (!verInfo.fromExisting)
  69. verInfo.lMajor = MetaData.LMajors[(int)verInfo.netVersion];
  70. if (verInfo.isDLL)
  71. {
  72. hintNameTable = FileImage.dllHintNameTable.ToCharArray();
  73. if (!verInfo.fromExisting) verInfo.characteristics = FileImage.dllCharacteristics;
  74. }
  75. else
  76. {
  77. hintNameTable = FileImage.exeHintNameTable.ToCharArray();
  78. if (!verInfo.fromExisting) verInfo.characteristics = FileImage.exeCharacteristics;
  79. }
  80. text = new Section(FileImage.textName, 0x60000020); // IMAGE_SCN_CNT CODE, EXECUTE, READ
  81. metaData = md;
  82. metaData.InitMetaDataOut(this);
  83. // Check if we should include a PDB file
  84. if (writePDB)
  85. {
  86. // Work out the PDB filename from the PE files filename
  87. if ((fileName == null) || (fileName == "")) fileName = "default";
  88. // Setup the PDB Writer object
  89. pdbWriter = new PDBWriter(fileName);
  90. // Set the amount of space required for the debug information
  91. debugBytesSize += pdbWriter.PDBFilename.Length;
  92. }
  93. }
  94. private uint GetNextSectStart(uint rva, uint tide)
  95. {
  96. if (tide < FileImage.SectionAlignment) return rva + FileImage.SectionAlignment;
  97. return rva + ((tide / FileImage.SectionAlignment) + 1) * FileImage.SectionAlignment;
  98. }
  99. private void BuildTextSection()
  100. {
  101. // .text layout
  102. // IAT (single entry 8 bytes for pure CIL)
  103. // CLIHeader (72 bytes)
  104. // CIL instructions for all methods (variable size)
  105. // Strong Name Signature
  106. // MetaData
  107. // ManagedResources
  108. // ImportTable (40 bytes)
  109. // ImportLookupTable(8 bytes) (same as IAT for standard CIL files)
  110. // Hint/Name Tables with entry "_CorExeMain" for .exe file and "_CorDllMain" for .dll (14 bytes)
  111. // ASCII string "mscoree.dll" referenced in ImportTable (+ padding = 16 bytes)
  112. // Entry Point (0xFF25 followed by 4 bytes 0x400000 + RVA of .text)
  113. codeStart = FileImage.IATSize + FileImage.CLIHeaderSize;
  114. if (Diag.DiagOn) Console.WriteLine("Code starts at " + Hex.Int(codeStart));
  115. metaData.BuildMetaData();
  116. // strongNameSig = metaData.GetStrongNameSig();
  117. metaDataOffset = FileImage.IATSize + FileImage.CLIHeaderSize + metaData.CodeSize();
  118. if (pdbWriter != null)
  119. {
  120. debugSize = 0x1C; // or size of debugBytes??
  121. debugOffset = metaDataOffset;
  122. metaDataOffset += (uint)debugBytesSize + debugSize + NumToAlign((uint)debugBytesSize, 4);
  123. }
  124. resourcesOffset = metaDataOffset + metaData.Size();
  125. resourcesSize = metaData.GetResourcesSize();
  126. importTableOffset = resourcesOffset + resourcesSize;
  127. importTablePadding = NumToAlign(importTableOffset, 16);
  128. importTableOffset += importTablePadding;
  129. importLookupTableOffset = importTableOffset + FileImage.ImportTableSize;
  130. hintNameTableOffset = importLookupTableOffset + FileImage.IATSize;
  131. runtimeEngineOffset = hintNameTableOffset + (uint)hintNameTable.Length;
  132. entryPointOffset = runtimeEngineOffset + (uint)runtimeEngine.Length;
  133. totalImportTableSize = entryPointOffset - importTableOffset;
  134. if (Diag.DiagOn)
  135. {
  136. Console.WriteLine("total import table size = " + totalImportTableSize);
  137. Console.WriteLine("entrypoint offset = " + Hex.Int(entryPointOffset));
  138. }
  139. entryPointPadding = NumToAlign(entryPointOffset, 4) + 2;
  140. entryPointOffset += entryPointPadding;
  141. entryPointReloc = entryPointOffset + 2;
  142. text.IncTide(entryPointOffset + 6);
  143. // The following lines may have some benefit for speed,
  144. // but can increase the PE file size by up to 10k in
  145. // some circumstances. Can be commented out safely.
  146. if (text.Tide() > 8 * FileImage.maxFileAlign)
  147. verInfo.fileAlign = FileImage.maxFileAlign;
  148. else if (text.Tide() > 2 * FileImage.maxFileAlign)
  149. verInfo.fileAlign = FileImage.midFileAlign;
  150. text.SetSize(NumToAlign(text.Tide(), verInfo.fileAlign));
  151. if (Diag.DiagOn)
  152. {
  153. Console.WriteLine("text size = " + text.Size() + " text tide = " + text.Tide() + " text padding = " + text.Padding());
  154. Console.WriteLine("metaDataOffset = " + Hex.Int(metaDataOffset));
  155. Console.WriteLine("importTableOffset = " + Hex.Int(importTableOffset));
  156. Console.WriteLine("importLookupTableOffset = " + Hex.Int(importLookupTableOffset));
  157. Console.WriteLine("hintNameTableOffset = " + Hex.Int(hintNameTableOffset));
  158. Console.WriteLine("runtimeEngineOffset = " + Hex.Int(runtimeEngineOffset));
  159. Console.WriteLine("entryPointOffset = " + Hex.Int(entryPointOffset));
  160. Console.WriteLine("entryPointPadding = " + Hex.Int(entryPointPadding));
  161. }
  162. }
  163. internal void BuildRelocSection()
  164. {
  165. // do entry point reloc
  166. uint relocPage = entryPointReloc / Section.relocPageSize;
  167. uint pageOff = relocPage * Section.relocPageSize;
  168. reloc.Write(text.RVA() + pageOff);
  169. reloc.Write(12);
  170. uint fixUpOff = entryPointReloc - pageOff;
  171. reloc.Write((ushort)((0x3 << 12) | fixUpOff));
  172. reloc.Write((ushort)0);
  173. // text.DoRelocs(reloc);
  174. if (sdata != null) sdata.DoRelocs(reloc);
  175. if (rsrc != null) rsrc.DoRelocs(reloc);
  176. relocTide = (uint)reloc.Seek(0, SeekOrigin.Current);
  177. //reloc.Write((uint)0);
  178. if (Diag.DiagOn) Console.WriteLine("relocTide = " + relocTide);
  179. relocPadding = NumToAlign(relocTide, verInfo.fileAlign);
  180. relocSize = relocTide + relocPadding;
  181. imageSize = relocRVA + FileImage.SectionAlignment;
  182. initDataSize += relocSize;
  183. }
  184. private void CalcOffsets()
  185. {
  186. if (sdata != null) numSections++;
  187. if (rsrc != null) numSections++;
  188. headerSize = FileImage.fileHeaderSize + (numSections * FileImage.sectionHeaderSize);
  189. headerPadding = NumToAlign(headerSize, verInfo.fileAlign);
  190. headerSize += headerPadding;
  191. uint offset = headerSize;
  192. uint rva = FileImage.SectionAlignment;
  193. text.SetOffset(offset);
  194. text.SetRVA(rva);
  195. if (pdbWriter != null) debugRVA = rva + debugOffset;
  196. offset += text.Size();
  197. rva = GetNextSectStart(rva, text.Tide());
  198. // Console.WriteLine("headerSize = " + headerSize);
  199. // Console.WriteLine("headerPadding = " + headerPadding);
  200. // Console.WriteLine("textOffset = " + Hex.Int(text.Offset()));
  201. if (sdata != null)
  202. {
  203. sdata.SetOffset(offset);
  204. sdata.SetRVA(rva);
  205. for (int i = 0; i < data.Count; i++)
  206. {
  207. DataConstant cVal = (DataConstant)data[i];
  208. cVal.DataOffset = sdata.Tide();
  209. sdata.IncTide(cVal.GetSize());
  210. }
  211. sdata.SetSize(NumToAlign(sdata.Tide(), verInfo.fileAlign));
  212. offset += sdata.Size();
  213. rva = GetNextSectStart(rva, sdata.Tide());
  214. initDataSize += sdata.Size();
  215. }
  216. if (rsrc != null)
  217. {
  218. //Console.WriteLine("Resource section is not null");
  219. rsrc.SetSize(NumToAlign(rsrc.Tide(), verInfo.fileAlign));
  220. rsrc.SetOffset(offset);
  221. rsrc.SetRVA(rva);
  222. offset += rsrc.Size();
  223. rva = GetNextSectStart(rva, rsrc.Tide());
  224. initDataSize += rsrc.Size();
  225. }
  226. relocOffset = offset;
  227. relocRVA = rva;
  228. }
  229. internal void MakeFile(PEFileVersionInfo verInfo)
  230. {
  231. this.verInfo = verInfo;
  232. if (this.verInfo.isDLL) hintNameTable = FileImage.dllHintNameTable.ToCharArray();
  233. else hintNameTable = FileImage.exeHintNameTable.ToCharArray();
  234. BuildTextSection();
  235. CalcOffsets();
  236. BuildRelocSection();
  237. // now write it out
  238. WriteHeader();
  239. WriteSections();
  240. Flush();
  241. if (closeStream) Close();
  242. if (pdbWriter != null)
  243. {
  244. // Write the PDB file
  245. pdbWriter.WritePDBFile();
  246. // Check to make sure the DebugInfo is the length we expected.
  247. if (pdbWriter.DebugInfo.Length != debugBytesSize)
  248. throw new Exception("DebugInfo for the new PDB file is incompatible with the PE file. This is most likely an internal error. Please consult your vendor if you continue to have this problem.");
  249. // Write the debug info to the PE file
  250. using (FileStream fs = new FileStream(pdbWriter.PEFilename, FileMode.Open, FileAccess.ReadWrite))
  251. {
  252. using (BinaryWriter bw = new BinaryWriter(fs))
  253. {
  254. // Get to the DebugInfo section
  255. bw.Seek((int)debugBytesStartOffset, SeekOrigin.Begin);
  256. bw.Write(pdbWriter.DebugInfo, 0, pdbWriter.DebugInfo.Length);
  257. }
  258. }
  259. }
  260. }
  261. private void WriteHeader()
  262. {
  263. Write(FileImage.DOSHeader);
  264. // Console.WriteLine("Writing PEHeader at offset " + Seek(0,SeekOrigin.Current));
  265. WritePEHeader();
  266. // Console.WriteLine("Writing text section header at offset " + Hex.Long(Seek(0,SeekOrigin.Current)));
  267. text.WriteHeader(this, relocRVA);
  268. if (sdata != null) sdata.WriteHeader(this, relocRVA);
  269. if (rsrc != null) rsrc.WriteHeader(this, relocRVA);
  270. // Console.WriteLine("Writing reloc section header at offset " + Seek(0,SeekOrigin.Current));
  271. WriteRelocSectionHeader();
  272. // Console.WriteLine("Writing padding at offset " + Seek(0,SeekOrigin.Current));
  273. WriteZeros(headerPadding);
  274. }
  275. private void WriteSections()
  276. {
  277. // Console.WriteLine("Writing text section at offset " + Seek(0,SeekOrigin.Current));
  278. WriteTextSection();
  279. if (sdata != null) WriteSDataSection();
  280. if (rsrc != null) WriteRsrcSection();
  281. WriteRelocSection();
  282. }
  283. private void WriteIAT()
  284. {
  285. Write(text.RVA() + hintNameTableOffset);
  286. Write(0);
  287. }
  288. private void WriteImportTables()
  289. {
  290. // Import Table
  291. WriteZeros(importTablePadding);
  292. //Console.WriteLine("Writing import tables at offset " + Hex.Long(Seek(0,SeekOrigin.Current)));
  293. //Console.WriteLine("Should be at offset " + Hex.Long(importTableOffset + text.Offset()));
  294. Write(importLookupTableOffset + text.RVA());
  295. WriteZeros(8);
  296. Write(runtimeEngineOffset + text.RVA());
  297. Write(text.RVA()); // IAT is at the beginning of the text section
  298. WriteZeros(20);
  299. // Import Lookup Table
  300. WriteIAT(); // lookup table and IAT are the same
  301. // Hint/Name Table
  302. // Console.WriteLine("Writing hintname table at " + Hex.Long(Seek(0,SeekOrigin.Current)));
  303. Write(hintNameTable);
  304. Write(FileImage.runtimeEngineName.ToCharArray());
  305. }
  306. private void WriteTextSection()
  307. {
  308. WriteIAT();
  309. WriteCLIHeader();
  310. if (Diag.DiagOn)
  311. Console.WriteLine("Writing code at " + Hex.Long(Seek(0, SeekOrigin.Current)));
  312. metaData.WriteByteCodes(this);
  313. if (Diag.DiagOn)
  314. Console.WriteLine("Finished writing code at " + Hex.Long(Seek(0, SeekOrigin.Current)));
  315. WriteDebugInfo();
  316. metaData.WriteMetaData(this);
  317. metaData.WriteResources(this);
  318. WriteImportTables();
  319. WriteZeros(entryPointPadding);
  320. Write((ushort)0x25FF);
  321. Write(FileImage.ImageBase + text.RVA());
  322. WriteZeros(text.Padding());
  323. }
  324. /// <summary>
  325. /// Write out the debug infro required for PDB files to the PE file.
  326. /// </summary>
  327. private void WriteDebugInfo()
  328. {
  329. if (pdbWriter != null)
  330. { // WINNT.h IMAGE_DEBUG_DIRECTORY
  331. WriteZeros(4); // Characteristics
  332. Write(dateStamp); // Date stamp
  333. WriteZeros(4); // Major Version, Minor Version
  334. Write(2); // Type (Code View???)
  335. Write(debugBytesSize); // Size of Data
  336. WriteZeros(4); // Address of Raw Data
  337. Write(text.Offset() + debugOffset + debugSize); // Pointer to Raw Data
  338. if (Diag.DiagOn)
  339. Debug.WriteLine("Debug Bytes Offset: " + BaseStream.Length.ToString());
  340. // Remember where the debug bytes need to be written to
  341. debugBytesStartOffset = BaseStream.Length;
  342. // For now don't write the real debug bytes.
  343. // Just fill the space so we can come and write them later.
  344. // Write(debugBytes);
  345. WriteZeros((uint)debugBytesSize);
  346. WriteZeros(NumToAlign((uint)debugBytesSize, 4));
  347. }
  348. }
  349. private void WriteCLIHeader()
  350. {
  351. Write(FileImage.CLIHeaderSize); // Cb
  352. Write(verInfo.cliMajVer); // Major runtime version
  353. Write(verInfo.cliMinVer); // Minor runtime version
  354. Write(text.RVA() + metaDataOffset);
  355. if (Diag.DiagOn) Console.WriteLine("MetaDataOffset = " + metaDataOffset);
  356. Write(metaData.Size());
  357. Write((uint)verInfo.corFlags);
  358. Write(entryPointToken);
  359. if (resourcesSize > 0)
  360. { // managed resources
  361. Write(text.RVA() + resourcesOffset);
  362. Write(resourcesSize);
  363. }
  364. else
  365. {
  366. WriteZeros(8);
  367. }
  368. WriteZeros(8); // Strong Name stuff here!! NYI
  369. WriteZeros(8); // CodeManagerTable
  370. WriteZeros(8); // VTableFixups NYI
  371. WriteZeros(16); // ExportAddressTableJumps, ManagedNativeHeader
  372. }
  373. private void WriteSDataSection()
  374. {
  375. long pos = BaseStream.Position;
  376. for (int i = 0; i < data.Count; i++)
  377. {
  378. ((DataConstant)data[i]).Write(this);
  379. }
  380. pos = BaseStream.Position - pos;
  381. WriteZeros(NumToAlign((uint)pos, verInfo.fileAlign));
  382. }
  383. private void WriteRsrcSection()
  384. {
  385. //Console.WriteLine("Trying to write rsrc section !!!");
  386. long pos = BaseStream.Position;
  387. this.unmanagedResourceRoot.Write(this, rsrc.RVA());
  388. pos = BaseStream.Position - pos;
  389. WriteZeros(NumToAlign((uint)pos, verInfo.fileAlign));
  390. }
  391. private void WriteRelocSection()
  392. {
  393. // Console.WriteLine("Writing reloc section at " + Seek(0,SeekOrigin.Current) + " = " + relocOffset);
  394. MemoryStream str = (MemoryStream)reloc.BaseStream;
  395. Write(str.ToArray());
  396. WriteZeros(NumToAlign((uint)str.Position, verInfo.fileAlign));
  397. }
  398. internal void SetEntryPoint(uint entryPoint)
  399. {
  400. entryPointToken = entryPoint;
  401. }
  402. internal void AddInitData(DataConstant cVal)
  403. {
  404. if (sdata == null)
  405. {
  406. sdata = new Section(FileImage.sdataName, 0xC0000040); // IMAGE_SCN_CNT INITIALIZED_DATA, READ, WRITE
  407. data = new ArrayList();
  408. }
  409. data.Add(cVal);
  410. }
  411. internal void AddUnmanagedResourceDirectory(PEResourceDirectory directory) {
  412. if (rsrc == null)
  413. rsrc = new Section(FileImage.rsrcName, 0x40000040);
  414. rsrc.IncTide(directory.Size());
  415. unmanagedResourceRoot = directory;
  416. }
  417. internal void WriteZeros(uint numZeros)
  418. {
  419. for (int i = 0; i < numZeros; i++)
  420. {
  421. Write((byte)0);
  422. }
  423. }
  424. internal void WritePEHeader()
  425. {
  426. Write((ushort)0x014C); // Machine - always 0x14C for Managed PE Files (allow others??)
  427. Write((ushort)numSections);
  428. Write(dateStamp);
  429. WriteZeros(8); // Pointer to Symbol Table and Number of Symbols (always zero for ECMA CLI files)
  430. Write((ushort)0x00E0); // Size of Optional Header
  431. Write(verInfo.characteristics);
  432. // PE Optional Header
  433. Write((ushort)0x010B); // Magic
  434. Write(verInfo.lMajor); // LMajor pure-IL = 6 C++ = 7
  435. Write(verInfo.lMinor);
  436. Write(text.Size());
  437. Write(initDataSize);
  438. Write(0); // Check other sections here!!
  439. Write(text.RVA() + entryPointOffset);
  440. Write(text.RVA());
  441. uint dataBase = 0;
  442. if (sdata != null) dataBase = sdata.RVA();
  443. else if (rsrc != null) dataBase = rsrc.RVA();
  444. else dataBase = relocRVA;
  445. Write(dataBase);
  446. Write(FileImage.ImageBase);
  447. Write(FileImage.SectionAlignment);
  448. Write(verInfo.fileAlign);
  449. Write(verInfo.osMajor);
  450. Write(verInfo.osMinor);
  451. Write(verInfo.userMajor);
  452. Write(verInfo.userMinor);
  453. Write(verInfo.subSysMajor); // OS Major
  454. Write(verInfo.subSysMinor);
  455. WriteZeros(4); // Reserved
  456. Write(imageSize);
  457. Write(headerSize);
  458. Write((int)0); // File Checksum
  459. Write((ushort)verInfo.subSystem);
  460. Write(verInfo.DLLFlags);
  461. Write(FileImage.StackReserveSize);
  462. Write(FileImage.StackCommitSize);
  463. Write(FileImage.HeapReserveSize);
  464. Write(FileImage.HeapCommitSize);
  465. Write(FileImage.LoaderFlags);
  466. Write(FileImage.NumDataDirectories); // Data Directories
  467. WriteZeros(8); // Export Table
  468. Write(importTableOffset + text.RVA());
  469. Write(totalImportTableSize);
  470. if (rsrc != null) {
  471. Write(rsrc.RVA());
  472. Write(rsrc.Tide()); // Tide() is loadedSize, Size() is sizeOnDisk.
  473. }
  474. else
  475. WriteZeros(8);
  476. WriteZeros(16); // Exception and Certificate Tables
  477. Write(relocRVA);
  478. Write(relocTide);
  479. Write(debugRVA);
  480. Write(debugSize);
  481. WriteZeros(40); // Copyright, Global Ptr, TLS, Load Config and Bound Import Tables
  482. Write(text.RVA()); // IATRVA - IAT is at start of .text Section
  483. Write(FileImage.IATSize);
  484. WriteZeros(8); // Delay Import Descriptor
  485. Write(text.RVA() + FileImage.IATSize); // CLIHeader immediately follows IAT
  486. Write(FileImage.CLIHeaderSize);
  487. WriteZeros(8); // Reserved
  488. }
  489. internal void WriteRelocSectionHeader()
  490. {
  491. Write(FileImage.relocName.ToCharArray());
  492. Write(relocTide);
  493. Write(relocRVA);
  494. Write(relocSize);
  495. Write(relocOffset);
  496. WriteZeros(12);
  497. Write(FileImage.relocFlags);
  498. }
  499. private void Align(MemoryStream str, int val)
  500. {
  501. if ((str.Position % val) != 0)
  502. {
  503. for (int i = val - (int)(str.Position % val); i > 0; i--)
  504. {
  505. str.WriteByte(0);
  506. }
  507. }
  508. }
  509. private uint Align(uint val, uint alignVal)
  510. {
  511. if ((val % alignVal) != 0)
  512. {
  513. val += alignVal - (val % alignVal);
  514. }
  515. return val;
  516. }
  517. private uint NumToAlign(uint val, uint alignVal)
  518. {
  519. if ((val % alignVal) == 0) return 0;
  520. return alignVal - (val % alignVal);
  521. }
  522. internal void StringsIndex(uint ix)
  523. {
  524. if (metaData.largeStrings) Write(ix);
  525. else Write((ushort)ix);
  526. }
  527. internal void GUIDIndex(uint ix)
  528. {
  529. if (metaData.largeGUID) Write(ix);
  530. else Write((ushort)ix);
  531. }
  532. internal void USIndex(uint ix)
  533. {
  534. if (metaData.largeUS) Write(ix);
  535. else Write((ushort)ix);
  536. }
  537. internal void BlobIndex(uint ix)
  538. {
  539. if (metaData.largeBlob) Write(ix);
  540. else Write((ushort)ix);
  541. }
  542. internal void WriteIndex(MDTable tabIx, uint ix)
  543. {
  544. if (metaData.LargeIx(tabIx)) Write(ix);
  545. else Write((ushort)ix);
  546. }
  547. internal void WriteCodedIndex(CIx code, MetaDataElement elem)
  548. {
  549. metaData.WriteCodedIndex(code, elem, this);
  550. }
  551. internal void WriteCodeRVA(uint offs)
  552. {
  553. Write(text.RVA() + codeStart + offs);
  554. }
  555. internal void WriteDataRVA(uint offs)
  556. {
  557. Write(sdata.RVA() + offs);
  558. }
  559. internal void Write3Bytes(uint val)
  560. {
  561. byte b3 = (byte)((val & FileImage.iByteMask[2]) >> 16);
  562. byte b2 = (byte)((val & FileImage.iByteMask[1]) >> 8); ;
  563. byte b1 = (byte)(val & FileImage.iByteMask[0]);
  564. Write(b1);
  565. Write(b2);
  566. Write(b3);
  567. }
  568. }
  569. }