123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417 |
- /*
- * PERWAPI - An API for Reading and Writing PE Files
- *
- * Copyright (c) Diane Corney, Queensland University of Technology, 2004-2010.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the PERWAPI Copyright as included with this
- * distribution in the file PERWAPIcopyright.rtf.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY as is explained in the copyright notice.
- *
- * The author may be contacted at d.corney@qut.edu.au
- *
- * Version Date: 26/01/07
- *
- * Contributions Made By:
- *
- * Douglas Stockwell - Developed support for PDB files.
- * Andrew Bacon - Integrated PDB file support and developed automatic
- * stack depth calculations.
- *
- */
- // The conditional compilation on the CORAPI symbol has been
- // deleted from this version. Go back to version 1 in the QUT SVN
- // repository to get the conditional code if needed.
- using System;
- using System.IO;
- using System.Collections;
- using System.Text;
- using System.Diagnostics;
- using System.Reflection; // For the assembly attributes
- //
- // The assembly version is managed manually here.
- // 1.1.* are versions with the PDB handling built
- // Version 1.1.1+ uses System.Security.Crytography
- // to provide public key token methods
- //
- namespace QUT.PERWAPI {
- internal class MetaDataTables {
- private TableRow[][] tables;
- internal MetaDataTables(TableRow[][] tabs) {
- tables = tabs;
- }
- internal MetaDataElement GetTokenElement(uint token) {
- uint tabIx = (token & FileImage.TableMask) >> 24;
- uint elemIx = (token & FileImage.ElementMask) - 1;
- return (MetaDataElement)tables[tabIx][(int)elemIx];
- }
- }
- /**************************************************************************/
- // Streams for PE File Reader
- /**************************************************************************/
- /// <summary>
- /// Stream in the Meta Data (#Strings, #US, #Blob and #GUID)
- /// </summary>
- ///
- internal class MetaDataInStream : BinaryReader {
- //protected bool largeIx = false;
- protected byte[] data;
- public MetaDataInStream(byte[] streamBytes)
- : base(new MemoryStream(streamBytes)) {
- data = streamBytes;
- }
- public uint ReadCompressedNum() {
- //int pos = (int)BaseStream.Position;
- //Console.WriteLine("Position = " + BaseStream.Position);
- byte b = ReadByte();
- //pos++;
- uint num = 0;
- if (b <= 0x7F) {
- num = b;
- }
- else if (b >= 0xC0) {
- num = (uint)(((b - 0xC0) << 24) + (ReadByte() << 16) + (ReadByte() << 8) + ReadByte());
- }
- else { // (b >= 0x80) && (b < 0xC0)
- num = (uint)((b - 0x80) << 8) + ReadByte();
- }
- return num;
- }
- public int ReadCompressedInt() {
- // This code is based on a revised version of the
- // (incorrect) ECMA-335 spec which clarifies the
- // encoding of array lower bounds. (kjg 2008-Feb-22 )
- //
- uint rawBits = ReadCompressedNum();
- uint magnitude = (rawBits >> 1);
- if ((rawBits & 1) != 1)
- return (int)magnitude;
- else if (magnitude <= 0x3f)
- return (int)(magnitude | 0xffffffc0);
- else if (magnitude <= 0x1fff)
- return (int)(magnitude | 0xffffe000);
- else
- return (int)(magnitude | 0xf0000000);
- }
- internal bool AtEnd() {
- long pos = BaseStream.Position;
- long len = BaseStream.Length;
- //if (pos >= len-1)
- // Console.WriteLine("At end of stream");
- return BaseStream.Position == BaseStream.Length - 1;
- }
- internal byte[] GetBlob(uint ix) {
- if (ix == 0) return new byte[0];
- BaseStream.Seek(ix, SeekOrigin.Begin);
- //Console.WriteLine("Getting blob size at index " + buff.GetPos());
- //if (Diag.CADiag) Console.WriteLine("Getting blob size at " + (BaseStream.Position+PEReader.blobStreamStartOffset));
- uint bSiz = ReadCompressedNum();
- //byte[] blobBytes = new byte[ReadCompressedNum()];
- //if (Diag.CADiag) Console.WriteLine("Blob size = " + bSiz);
- byte[] blobBytes = new byte[bSiz];
- for (int i = 0; i < blobBytes.Length; i++) {
- blobBytes[i] = ReadByte();
- }
- return blobBytes;
- }
- internal byte[] GetBlob(uint ix, int len) {
- //Console.WriteLine("Getting blob size at index " + buffer.GetPos());
- byte[] blobBytes = new byte[len];
- for (int i = 0; i < len; i++) {
- blobBytes[i] = data[ix++];
- }
- return blobBytes;
- }
- internal string GetString(uint ix) {
- uint end;
- for (end = ix; data[end] != '\0'; end++) ;
- char[] str = new char[end - ix];
- for (int i = 0; i < str.Length; i++) {
- str[i] = (char)data[ix + i];
- }
- return new string(str, 0, str.Length);
- }
- internal string GetBlobString(uint ix) {
- if (ix == 0) return "";
- BaseStream.Seek(ix, SeekOrigin.Begin);
- return GetBlobString();
- }
- internal string GetBlobString() {
- uint strLen = ReadCompressedNum();
- char[] str = new char[strLen];
- uint readpos = (uint)this.BaseStream.Position;
- for (int i = 0; i < strLen; i++) {
- str[i] = ReadChar();
- uint newpos = (uint)this.BaseStream.Position;
- if (newpos > readpos + 1)
- strLen -= newpos - (readpos + 1);
- readpos = newpos;
- }
- return new string(str, 0, (int)strLen);
- }
- internal void GoToIndex(uint ix) {
- BaseStream.Seek(ix, SeekOrigin.Begin);
- }
- }
- /**************************************************************************/
- internal class MetaDataStringStream : BinaryReader {
- //BinaryReader br;
- internal MetaDataStringStream(byte[] bytes)
- : base(new MemoryStream(bytes), Encoding.Unicode) {
- //br = new BinaryReader(new MemoryStream(bytes)/*,Encoding.Unicode*/);
- }
- private uint GetStringLength() {
- uint b = ReadByte();
- uint num = 0;
- if (b <= 0x7F) {
- num = b;
- }
- else if (b >= 0xC0) {
- num = (uint)(((b - 0xC0) << 24) + (ReadByte() << 16) + (ReadByte() << 8) + ReadByte());
- }
- else { // (b >= 0x80) && (b < 0xC0)
- num = (uint)((b - 0x80) << 8) + ReadByte();
- }
- return num;
- }
- internal string GetUserString(uint ix) {
- BaseStream.Seek(ix, SeekOrigin.Begin);
- uint strLen = GetStringLength() / 2;
- char[] strArray = new char[strLen];
- for (int i = 0; i < strLen; i++) {
- //strArray[i] = ReadChar(); // works for everett but not whidbey
- strArray[i] = (char)ReadUInt16();
- }
- return new String(strArray);
- }
- }
- /**************************************************************************/
- // Streams for generated MetaData
- /**************************************************************************/
- /// <summary>
- /// Stream in the generated Meta Data (#Strings, #US, #Blob and #GUID)
- /// </summary>
- internal class MetaDataStream : BinaryWriter {
- private static readonly uint StreamHeaderSize = 8;
- private static uint maxSmlIxSize = 0xFFFF;
- private uint start = 0;
- uint size = 0, tide = 1;
- bool largeIx = false;
- uint sizeOfHeader;
- internal char[] name;
- Hashtable htable = new Hashtable();
- internal MetaDataStream(char[] name, bool addInitByte)
- : base(new MemoryStream()) {
- if (addInitByte) { Write((byte)0); size = 1; }
- this.name = name;
- sizeOfHeader = StreamHeaderSize + (uint)name.Length;
- }
- internal MetaDataStream(char[] name, System.Text.Encoding enc, bool addInitByte)
- : base(new MemoryStream(), enc) {
- if (addInitByte) { Write((byte)0); size = 1; }
- this.name = name;
- sizeOfHeader = StreamHeaderSize + (uint)name.Length;
- }
- public uint Start {
- get {
- return start;
- }
- set {
- start = value;
- }
- }
- internal uint headerSize() {
- // Console.WriteLine(name + " stream has headersize of " + sizeOfHeader);
- return sizeOfHeader;
- }
- //internal void SetSize(uint siz) {
- // size = siz;
- //}
- internal uint Size() {
- return size;
- }
- internal bool LargeIx() {
- return largeIx;
- }
- internal void WriteDetails() {
- // Console.WriteLine(name + " - size = " + size);
- }
- internal uint Add(string str, bool prependSize) {
- Object val = htable[str];
- uint index = 0;
- if (val == null) {
- index = size;
- htable[str] = index;
- char[] arr = str.ToCharArray();
- if (prependSize)
- CompressNum((uint)arr.Length * 2 + 1);
- Write(arr);
- Write((byte)0);
- size = (uint)Seek(0, SeekOrigin.Current);
- }
- else {
- index = (uint)val;
- }
- return index;
- }
- internal uint Add(Guid guid) {
- Write(guid.ToByteArray());
- size = (uint)Seek(0, SeekOrigin.Current);
- return tide++;
- }
- internal uint Add(byte[] blob) {
- uint ix = size;
- CompressNum((uint)blob.Length);
- Write(blob);
- size = (uint)Seek(0, SeekOrigin.Current);
- return ix;
- }
- internal uint Add(long val, uint numBytes) {
- uint ix = size;
- Write((byte)numBytes);
- switch (numBytes) {
- case 1: Write((byte)val); break;
- case 2: Write((short)val); break;
- case 4: Write((int)val); break;
- default: Write(val); break;
- }
- size = (uint)Seek(0, SeekOrigin.Current);
- return ix;
- }
- internal uint Add(ulong val, uint numBytes) {
- uint ix = size;
- Write((byte)numBytes);
- switch (numBytes) {
- case 1: Write((byte)val); break;
- case 2: Write((ushort)val); break;
- case 4: Write((uint)val); break;
- default: Write(val); break;
- }
- size = (uint)Seek(0, SeekOrigin.Current);
- return ix;
- }
- internal uint Add(char ch) {
- uint ix = size;
- Write((byte)2); // size of blob to follow
- Write(ch);
- size = (uint)Seek(0, SeekOrigin.Current);
- return ix;
- }
- internal uint Add(float val) {
- uint ix = size;
- Write((byte)4); // size of blob to follow
- Write(val);
- size = (uint)Seek(0, SeekOrigin.Current);
- return ix;
- }
- internal uint Add(double val) {
- uint ix = size;
- Write((byte)8); // size of blob to follow
- Write(val);
- size = (uint)Seek(0, SeekOrigin.Current);
- return ix;
- }
- private void CompressNum(uint val) {
- if (val <= 0x7F) {
- Write((byte)val);
- }
- else if (val <= 0x3FFF) {
- byte b1 = (byte)((val >> 8) | 0x80);
- byte b2 = (byte)(val & FileImage.iByteMask[0]);
- Write(b1);
- Write(b2);
- }
- else {
- byte b1 = (byte)((val >> 24) | 0xC0);
- byte b2 = (byte)((val & FileImage.iByteMask[2]) >> 16);
- byte b3 = (byte)((val & FileImage.iByteMask[1]) >> 8); ;
- byte b4 = (byte)(val & FileImage.iByteMask[0]);
- Write(b1);
- Write(b2);
- Write(b3);
- Write(b4);
- }
- }
- private void QuadAlign() {
- if ((size % 4) != 0) {
- uint pad = 4 - (size % 4);
- size += pad;
- for (int i = 0; i < pad; i++) {
- Write((byte)0);
- }
- }
- }
- internal void EndStream() {
- QuadAlign();
- if (size > maxSmlIxSize) {
- largeIx = true;
- }
- }
- internal void WriteHeader(BinaryWriter output) {
- output.Write(start);
- output.Write(size);
- output.Write(name);
- }
- internal virtual void Write(BinaryWriter output) {
- // Console.WriteLine("Writing " + name + " stream at " + output.Seek(0,SeekOrigin.Current) + " = " + start);
- MemoryStream str = (MemoryStream)BaseStream;
- output.Write(str.ToArray());
- }
- }
- }
|