PERWAPI.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. /*
  2. * PERWAPI - An API for Reading and Writing PE Files
  3. *
  4. * Copyright (c) Diane Corney, Queensland University of Technology, 2004-2010.
  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. * Contributions Made By:
  18. *
  19. * Douglas Stockwell - Developed support for PDB files.
  20. * Andrew Bacon - Integrated PDB file support and developed automatic
  21. * stack depth calculations.
  22. *
  23. */
  24. // The conditional compilation on the CORAPI symbol has been
  25. // deleted from this version. Go back to version 1 in the QUT SVN
  26. // repository to get the conditional code if needed.
  27. using System;
  28. using System.IO;
  29. using System.Collections;
  30. using System.Text;
  31. using System.Diagnostics;
  32. using System.Reflection; // For the assembly attributes
  33. //
  34. // The assembly version is managed manually here.
  35. // 1.1.* are versions with the PDB handling built
  36. // Version 1.1.1+ uses System.Security.Crytography
  37. // to provide public key token methods
  38. //
  39. namespace QUT.PERWAPI {
  40. internal class MetaDataTables {
  41. private TableRow[][] tables;
  42. internal MetaDataTables(TableRow[][] tabs) {
  43. tables = tabs;
  44. }
  45. internal MetaDataElement GetTokenElement(uint token) {
  46. uint tabIx = (token & FileImage.TableMask) >> 24;
  47. uint elemIx = (token & FileImage.ElementMask) - 1;
  48. return (MetaDataElement)tables[tabIx][(int)elemIx];
  49. }
  50. }
  51. /**************************************************************************/
  52. // Streams for PE File Reader
  53. /**************************************************************************/
  54. /// <summary>
  55. /// Stream in the Meta Data (#Strings, #US, #Blob and #GUID)
  56. /// </summary>
  57. ///
  58. internal class MetaDataInStream : BinaryReader {
  59. //protected bool largeIx = false;
  60. protected byte[] data;
  61. public MetaDataInStream(byte[] streamBytes)
  62. : base(new MemoryStream(streamBytes)) {
  63. data = streamBytes;
  64. }
  65. public uint ReadCompressedNum() {
  66. //int pos = (int)BaseStream.Position;
  67. //Console.WriteLine("Position = " + BaseStream.Position);
  68. byte b = ReadByte();
  69. //pos++;
  70. uint num = 0;
  71. if (b <= 0x7F) {
  72. num = b;
  73. }
  74. else if (b >= 0xC0) {
  75. num = (uint)(((b - 0xC0) << 24) + (ReadByte() << 16) + (ReadByte() << 8) + ReadByte());
  76. }
  77. else { // (b >= 0x80) && (b < 0xC0)
  78. num = (uint)((b - 0x80) << 8) + ReadByte();
  79. }
  80. return num;
  81. }
  82. public int ReadCompressedInt() {
  83. // This code is based on a revised version of the
  84. // (incorrect) ECMA-335 spec which clarifies the
  85. // encoding of array lower bounds. (kjg 2008-Feb-22 )
  86. //
  87. uint rawBits = ReadCompressedNum();
  88. uint magnitude = (rawBits >> 1);
  89. if ((rawBits & 1) != 1)
  90. return (int)magnitude;
  91. else if (magnitude <= 0x3f)
  92. return (int)(magnitude | 0xffffffc0);
  93. else if (magnitude <= 0x1fff)
  94. return (int)(magnitude | 0xffffe000);
  95. else
  96. return (int)(magnitude | 0xf0000000);
  97. }
  98. internal bool AtEnd() {
  99. long pos = BaseStream.Position;
  100. long len = BaseStream.Length;
  101. //if (pos >= len-1)
  102. // Console.WriteLine("At end of stream");
  103. return BaseStream.Position == BaseStream.Length - 1;
  104. }
  105. internal byte[] GetBlob(uint ix) {
  106. if (ix == 0) return new byte[0];
  107. BaseStream.Seek(ix, SeekOrigin.Begin);
  108. //Console.WriteLine("Getting blob size at index " + buff.GetPos());
  109. //if (Diag.CADiag) Console.WriteLine("Getting blob size at " + (BaseStream.Position+PEReader.blobStreamStartOffset));
  110. uint bSiz = ReadCompressedNum();
  111. //byte[] blobBytes = new byte[ReadCompressedNum()];
  112. //if (Diag.CADiag) Console.WriteLine("Blob size = " + bSiz);
  113. byte[] blobBytes = new byte[bSiz];
  114. for (int i = 0; i < blobBytes.Length; i++) {
  115. blobBytes[i] = ReadByte();
  116. }
  117. return blobBytes;
  118. }
  119. internal byte[] GetBlob(uint ix, int len) {
  120. //Console.WriteLine("Getting blob size at index " + buffer.GetPos());
  121. byte[] blobBytes = new byte[len];
  122. for (int i = 0; i < len; i++) {
  123. blobBytes[i] = data[ix++];
  124. }
  125. return blobBytes;
  126. }
  127. internal string GetString(uint ix) {
  128. uint end;
  129. for (end = ix; data[end] != '\0'; end++) ;
  130. char[] str = new char[end - ix];
  131. for (int i = 0; i < str.Length; i++) {
  132. str[i] = (char)data[ix + i];
  133. }
  134. return new string(str, 0, str.Length);
  135. }
  136. internal string GetBlobString(uint ix) {
  137. if (ix == 0) return "";
  138. BaseStream.Seek(ix, SeekOrigin.Begin);
  139. return GetBlobString();
  140. }
  141. internal string GetBlobString() {
  142. uint strLen = ReadCompressedNum();
  143. char[] str = new char[strLen];
  144. uint readpos = (uint)this.BaseStream.Position;
  145. for (int i = 0; i < strLen; i++) {
  146. str[i] = ReadChar();
  147. uint newpos = (uint)this.BaseStream.Position;
  148. if (newpos > readpos + 1)
  149. strLen -= newpos - (readpos + 1);
  150. readpos = newpos;
  151. }
  152. return new string(str, 0, (int)strLen);
  153. }
  154. internal void GoToIndex(uint ix) {
  155. BaseStream.Seek(ix, SeekOrigin.Begin);
  156. }
  157. }
  158. /**************************************************************************/
  159. internal class MetaDataStringStream : BinaryReader {
  160. //BinaryReader br;
  161. internal MetaDataStringStream(byte[] bytes)
  162. : base(new MemoryStream(bytes), Encoding.Unicode) {
  163. //br = new BinaryReader(new MemoryStream(bytes)/*,Encoding.Unicode*/);
  164. }
  165. private uint GetStringLength() {
  166. uint b = ReadByte();
  167. uint num = 0;
  168. if (b <= 0x7F) {
  169. num = b;
  170. }
  171. else if (b >= 0xC0) {
  172. num = (uint)(((b - 0xC0) << 24) + (ReadByte() << 16) + (ReadByte() << 8) + ReadByte());
  173. }
  174. else { // (b >= 0x80) && (b < 0xC0)
  175. num = (uint)((b - 0x80) << 8) + ReadByte();
  176. }
  177. return num;
  178. }
  179. internal string GetUserString(uint ix) {
  180. BaseStream.Seek(ix, SeekOrigin.Begin);
  181. uint strLen = GetStringLength() / 2;
  182. char[] strArray = new char[strLen];
  183. for (int i = 0; i < strLen; i++) {
  184. //strArray[i] = ReadChar(); // works for everett but not whidbey
  185. strArray[i] = (char)ReadUInt16();
  186. }
  187. return new String(strArray);
  188. }
  189. }
  190. /**************************************************************************/
  191. // Streams for generated MetaData
  192. /**************************************************************************/
  193. /// <summary>
  194. /// Stream in the generated Meta Data (#Strings, #US, #Blob and #GUID)
  195. /// </summary>
  196. internal class MetaDataStream : BinaryWriter {
  197. private static readonly uint StreamHeaderSize = 8;
  198. private static uint maxSmlIxSize = 0xFFFF;
  199. private uint start = 0;
  200. uint size = 0, tide = 1;
  201. bool largeIx = false;
  202. uint sizeOfHeader;
  203. internal char[] name;
  204. Hashtable htable = new Hashtable();
  205. internal MetaDataStream(char[] name, bool addInitByte)
  206. : base(new MemoryStream()) {
  207. if (addInitByte) { Write((byte)0); size = 1; }
  208. this.name = name;
  209. sizeOfHeader = StreamHeaderSize + (uint)name.Length;
  210. }
  211. internal MetaDataStream(char[] name, System.Text.Encoding enc, bool addInitByte)
  212. : base(new MemoryStream(), enc) {
  213. if (addInitByte) { Write((byte)0); size = 1; }
  214. this.name = name;
  215. sizeOfHeader = StreamHeaderSize + (uint)name.Length;
  216. }
  217. public uint Start {
  218. get {
  219. return start;
  220. }
  221. set {
  222. start = value;
  223. }
  224. }
  225. internal uint headerSize() {
  226. // Console.WriteLine(name + " stream has headersize of " + sizeOfHeader);
  227. return sizeOfHeader;
  228. }
  229. //internal void SetSize(uint siz) {
  230. // size = siz;
  231. //}
  232. internal uint Size() {
  233. return size;
  234. }
  235. internal bool LargeIx() {
  236. return largeIx;
  237. }
  238. internal void WriteDetails() {
  239. // Console.WriteLine(name + " - size = " + size);
  240. }
  241. internal uint Add(string str, bool prependSize) {
  242. Object val = htable[str];
  243. uint index = 0;
  244. if (val == null) {
  245. index = size;
  246. htable[str] = index;
  247. char[] arr = str.ToCharArray();
  248. if (prependSize)
  249. CompressNum((uint)arr.Length * 2 + 1);
  250. Write(arr);
  251. Write((byte)0);
  252. size = (uint)Seek(0, SeekOrigin.Current);
  253. }
  254. else {
  255. index = (uint)val;
  256. }
  257. return index;
  258. }
  259. internal uint Add(Guid guid) {
  260. Write(guid.ToByteArray());
  261. size = (uint)Seek(0, SeekOrigin.Current);
  262. return tide++;
  263. }
  264. internal uint Add(byte[] blob) {
  265. uint ix = size;
  266. CompressNum((uint)blob.Length);
  267. Write(blob);
  268. size = (uint)Seek(0, SeekOrigin.Current);
  269. return ix;
  270. }
  271. internal uint Add(long val, uint numBytes) {
  272. uint ix = size;
  273. Write((byte)numBytes);
  274. switch (numBytes) {
  275. case 1: Write((byte)val); break;
  276. case 2: Write((short)val); break;
  277. case 4: Write((int)val); break;
  278. default: Write(val); break;
  279. }
  280. size = (uint)Seek(0, SeekOrigin.Current);
  281. return ix;
  282. }
  283. internal uint Add(ulong val, uint numBytes) {
  284. uint ix = size;
  285. Write((byte)numBytes);
  286. switch (numBytes) {
  287. case 1: Write((byte)val); break;
  288. case 2: Write((ushort)val); break;
  289. case 4: Write((uint)val); break;
  290. default: Write(val); break;
  291. }
  292. size = (uint)Seek(0, SeekOrigin.Current);
  293. return ix;
  294. }
  295. internal uint Add(char ch) {
  296. uint ix = size;
  297. Write((byte)2); // size of blob to follow
  298. Write(ch);
  299. size = (uint)Seek(0, SeekOrigin.Current);
  300. return ix;
  301. }
  302. internal uint Add(float val) {
  303. uint ix = size;
  304. Write((byte)4); // size of blob to follow
  305. Write(val);
  306. size = (uint)Seek(0, SeekOrigin.Current);
  307. return ix;
  308. }
  309. internal uint Add(double val) {
  310. uint ix = size;
  311. Write((byte)8); // size of blob to follow
  312. Write(val);
  313. size = (uint)Seek(0, SeekOrigin.Current);
  314. return ix;
  315. }
  316. private void CompressNum(uint val) {
  317. if (val <= 0x7F) {
  318. Write((byte)val);
  319. }
  320. else if (val <= 0x3FFF) {
  321. byte b1 = (byte)((val >> 8) | 0x80);
  322. byte b2 = (byte)(val & FileImage.iByteMask[0]);
  323. Write(b1);
  324. Write(b2);
  325. }
  326. else {
  327. byte b1 = (byte)((val >> 24) | 0xC0);
  328. byte b2 = (byte)((val & FileImage.iByteMask[2]) >> 16);
  329. byte b3 = (byte)((val & FileImage.iByteMask[1]) >> 8); ;
  330. byte b4 = (byte)(val & FileImage.iByteMask[0]);
  331. Write(b1);
  332. Write(b2);
  333. Write(b3);
  334. Write(b4);
  335. }
  336. }
  337. private void QuadAlign() {
  338. if ((size % 4) != 0) {
  339. uint pad = 4 - (size % 4);
  340. size += pad;
  341. for (int i = 0; i < pad; i++) {
  342. Write((byte)0);
  343. }
  344. }
  345. }
  346. internal void EndStream() {
  347. QuadAlign();
  348. if (size > maxSmlIxSize) {
  349. largeIx = true;
  350. }
  351. }
  352. internal void WriteHeader(BinaryWriter output) {
  353. output.Write(start);
  354. output.Write(size);
  355. output.Write(name);
  356. }
  357. internal virtual void Write(BinaryWriter output) {
  358. // Console.WriteLine("Writing " + name + " stream at " + output.Seek(0,SeekOrigin.Current) + " = " + start);
  359. MemoryStream str = (MemoryStream)BaseStream;
  360. output.Write(str.ToArray());
  361. }
  362. }
  363. }