SectionClass.cs 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  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.Collections;
  20. namespace QUT.PERWAPI
  21. {
  22. /**************************************************************************/
  23. // PE File Section Descriptor
  24. /**************************************************************************/
  25. /// <summary>
  26. /// Descriptor for a Section in a PEFile eg .text, .sdata
  27. /// </summary>
  28. internal class Section
  29. {
  30. internal static readonly uint relocPageSize = 4096; // 4K pages for fixups
  31. /// <summary>
  32. /// Eight characters exactly, null padded if necessary.
  33. /// </summary>
  34. char[] name;
  35. string nameString;
  36. /// <summary>
  37. /// Total size of the section in bytes. If this value is
  38. /// greater than SizeOFRawData the section is zero-padded.
  39. /// </summary>
  40. uint loadedSize = 0;
  41. /// <summary>
  42. /// Position in memory when loaded, relative to image base.
  43. /// </summary>
  44. uint loadedRVA = 0;
  45. /// <summary>
  46. /// Size of raw data in the section. Must be multiple of file alignment size.
  47. /// Can be smaller than loadedSize, or larger (as a result of alignment).
  48. /// </summary>
  49. uint sizeOnDisk = 0;
  50. /// <summary>
  51. /// Offset to section's page within the PE file. Must be multiple
  52. /// of file alignment constant.
  53. /// </summary>
  54. uint fileOffset = 0;
  55. // These are all zero mostly.
  56. uint relocRVA, lineRVA, relocOff, numRelocs, numLineNums = 0;
  57. /// <summary>
  58. /// Flags of section: code = 0x20, init-data = 0x40, un-init-data = 0x80,
  59. /// execute = 0x20000000, read = 0x40000000, write = 0x80000000.
  60. /// </summary>
  61. uint flags;
  62. uint relocTide = 0;
  63. uint padding = 0;
  64. uint[] relocs;
  65. internal Section(string sName, uint sFlags)
  66. {
  67. nameString = sName;
  68. name = sName.ToCharArray();
  69. flags = sFlags;
  70. }
  71. internal Section(PEReader input)
  72. {
  73. name = new char[8];
  74. for (int i = 0; i < name.Length; i++)
  75. name[i] = (char)input.ReadByte();
  76. nameString = new String(name);
  77. loadedSize = input.ReadUInt32();
  78. loadedRVA = input.ReadUInt32();
  79. sizeOnDisk = input.ReadUInt32();
  80. fileOffset = input.ReadUInt32();
  81. relocRVA = input.ReadUInt32();
  82. lineRVA = input.ReadUInt32();
  83. numRelocs = input.ReadUInt16();
  84. numLineNums = input.ReadUInt16();
  85. flags = input.ReadUInt32();
  86. if (Diag.DiagOn)
  87. {
  88. Console.WriteLine(" " + nameString + " RVA = " + Hex.Int(loadedRVA) + " vSize = " + Hex.Int(loadedSize));
  89. Console.WriteLine(" FileOffset = " + Hex.Int(fileOffset) + " aSize = " + Hex.Int(sizeOnDisk));
  90. }
  91. }
  92. internal bool ContainsRVA(uint rvaPos)
  93. {
  94. return (loadedRVA <= rvaPos) && (rvaPos <= loadedRVA + loadedSize);
  95. }
  96. internal uint GetOffset(uint inRVA)
  97. {
  98. uint offs = 0;
  99. if ((loadedRVA <= inRVA) && (inRVA <= loadedRVA + loadedSize))
  100. offs = fileOffset + (inRVA - loadedRVA);
  101. return offs;
  102. }
  103. internal uint Tide() { return loadedSize; }
  104. internal void IncTide(uint incVal) { loadedSize += incVal; }
  105. internal uint Padding() { return padding; }
  106. internal uint Size() { return sizeOnDisk; }
  107. internal void SetSize(uint pad)
  108. {
  109. padding = pad;
  110. sizeOnDisk = loadedSize + padding;
  111. }
  112. internal uint RVA() { return loadedRVA; }
  113. internal void SetRVA(uint loadedRVA) { this.loadedRVA = loadedRVA; }
  114. internal uint Offset() { return fileOffset; }
  115. internal void SetOffset(uint offs) { fileOffset = offs; }
  116. internal void DoBlock(BinaryWriter reloc, uint page, int start, int end)
  117. {
  118. //Console.WriteLine("rva = " + rva + " page = " + page);
  119. if (Diag.DiagOn) Console.WriteLine("writing reloc block at " + reloc.BaseStream.Position);
  120. reloc.Write(loadedRVA + page);
  121. uint blockSize = (uint)(((end - start + 1) * 2) + 8);
  122. reloc.Write(blockSize);
  123. if (Diag.DiagOn) Console.WriteLine("Block size = " + blockSize);
  124. for (int j = start; j < end; j++)
  125. {
  126. //Console.WriteLine("reloc offset = " + relocs[j]);
  127. reloc.Write((ushort)((0x3 << 12) | (relocs[j] - page)));
  128. }
  129. reloc.Write((ushort)0);
  130. if (Diag.DiagOn) Console.WriteLine("finished reloc block at " + reloc.BaseStream.Position);
  131. }
  132. internal void DoRelocs(BinaryWriter reloc)
  133. {
  134. if (relocTide > 0)
  135. {
  136. // align block to 32 bit boundary
  137. relocOff = (uint)reloc.Seek(0, SeekOrigin.Current);
  138. if ((relocOff % 32) != 0)
  139. {
  140. uint padding = 32 - (relocOff % 32);
  141. for (int i = 0; i < padding; i++)
  142. reloc.Write((byte)0);
  143. relocOff += padding;
  144. }
  145. uint block = (relocs[0] / relocPageSize + 1) * relocPageSize;
  146. int start = 0;
  147. for (int i = 1; i < relocTide; i++)
  148. {
  149. if (relocs[i] >= block)
  150. {
  151. DoBlock(reloc, block - relocPageSize, start, i);
  152. start = i;
  153. block = (relocs[i] / relocPageSize + 1) * relocPageSize;
  154. }
  155. }
  156. DoBlock(reloc, block - relocPageSize, start, (int)relocTide);
  157. }
  158. }
  159. internal void AddReloc(uint offs)
  160. {
  161. if (Diag.DiagOn) Console.WriteLine("Adding a reloc to " + nameString + " section");
  162. int pos = 0;
  163. if (relocs == null)
  164. {
  165. relocs = new uint[5];
  166. }
  167. else
  168. {
  169. if (relocTide >= relocs.Length)
  170. {
  171. uint[] tmp = relocs;
  172. relocs = new uint[tmp.Length + 5];
  173. for (int i = 0; i < relocTide; i++)
  174. {
  175. relocs[i] = tmp[i];
  176. }
  177. }
  178. while ((pos < relocTide) && (relocs[pos] < offs)) pos++;
  179. for (int i = pos; i < relocTide; i++)
  180. {
  181. relocs[i + 1] = relocs[i];
  182. }
  183. }
  184. relocs[pos] = offs;
  185. relocTide++;
  186. if (Diag.DiagOn) Console.WriteLine("relocTide = " + relocTide);
  187. }
  188. internal void WriteHeader(BinaryWriter output, uint relocRVA)
  189. {
  190. if (Diag.DiagOn) Console.WriteLine("relocTide = " + relocTide);
  191. output.Write(name);
  192. output.Write(loadedSize); // Virtual size
  193. output.Write(loadedRVA); // Virtual address
  194. output.Write(sizeOnDisk); // SizeOfRawData
  195. output.Write(fileOffset); // PointerToRawData
  196. if (relocTide > 0)
  197. {
  198. output.Write(relocRVA + relocOff);
  199. }
  200. else
  201. {
  202. if (Diag.DiagOn) Console.WriteLine(nameString + " section has no relocs");
  203. output.Write(0);
  204. } // PointerToRelocations
  205. output.Write(0); // PointerToLineNumbers
  206. output.Write((ushort)relocTide); // NumberOfRelocations
  207. output.Write((ushort)0); // NumberOfLineNumbers
  208. output.Write(flags); // Characteristics
  209. }
  210. }
  211. }