Click here to Skip to main content
Click here to Skip to main content

Removing Strong-Signing from Assemblies at File Level (byte patching)

By , 9 Mar 2013
 
StrongNameRemove.zip
StrongNameRemove.exe
strongnameremove20.zip
StrongNameRemove20.exe
strongnameremove20_src.zip
alert.png
Asmex
decrypted.ico
decrypted.png
folder_blue.png
info.png
ok.png
Properties
Settings.settings
remove.png
vu.ch.argee.MemoryMapping
strongnameremove21.zip
StrongNameRemove.exe
strongnameremove21_src.zip
Settings.settings
Resources
alert.png
folder_explore.png
info.png
ok.png
remove.png
System_Locked.png
Sistema_Locked.ico
StrongNameRemove_src.zip
app.manifest
Other-Power-Lock-Metro.ico
alert.png
folder_explore.png
info.png
ok.png
Other-Power-Lock-Metro-icon.png
remove.png
using System;
using System.IO;
using System.Runtime.InteropServices;

namespace vu.ch.argee.MemoryMapping
{
	/// <summary>
	/// Implements a Stream wrapper for unmanaged memory, supporting synchronous read and write operations.
	/// </summary>
	public class UnmanagedMemoryStream: Stream
	{
		#region ------------ fields ------------

		private IUnmanagedMemoryResource unmanagedMemory;
		private IBufferedResource bufferedResource;
		private long position;
		private long length;
		private IntPtr baseAddress;

		#endregion

		#region ------------ contructors ------------

		/// <summary>
		/// Initializes a new instance of the UnmanagedMemoryStream class based on the specified unmanaged memory object.
		/// </summary>
		/// <param name="unmanagedMemorySource">The object which implements the IUnmanagedMemoryResource interface.</param>
		/// <example>
		/// The following example demonstrates this UnmanagedMemoryStream constructor
		/// <code>
		/// using(fileMapping = FileMapping.CreateReadOnlyFileMapping(@"..\..\TestData.txt"))
		///	{
		///		// We create a view that can be changed without changing the original file
		///		using(view = new FileMappingView(fileMapping, MappingAccess.WriteCopy))
		///		{
		///			stream = new UnmanagedMemoryStream(view);
		///			stream.Seek(1800, SeekOrigin.Current);
		///
		///			StreamWriter streamWriter = new StreamWriter(stream);
		///			streamWriter.Write("Hello World!");
		///			streamWriter.Flush(); // writes the changes to the in-memory-copy
		///		}
		///	}
		///	</code>
		/// </example>
		public UnmanagedMemoryStream(IUnmanagedMemoryResource unmanagedMemorySource)
		{
			this.unmanagedMemory = unmanagedMemorySource;
			bufferedResource = unmanagedMemorySource as IBufferedResource;
			this.length = unmanagedMemory.Length;
			this.baseAddress = unmanagedMemory.BaseAddress;
		}

		#endregion

		#region ------------ protected methods ------------

		/// <summary>
		/// Returns the address pointer to the unmanaged memory according to the stream's position
		/// </summary>
		/// <returns>The address pointer to the unmanaged memory according to the stream's position</returns>
		protected IntPtr GetCurrentAddress()
		{
			if (position >= length)
			{
				throw new ArgumentException("You cannot read beyond the end of stream.");
			}
			if (position < 0)
			{
				throw new ArgumentException("Invalid stream position.");
			}
			return (IntPtr)((int)baseAddress + position);
		}

		/// <summary>
		/// Determines the number of accessed bytes in a read or write operation.
		/// </summary>
		/// <param name="count">demanded number of bytes</param>
		/// <returns>demanded number of bytes or the number of bytes left till the end of the stream.</returns>
		/// <remarks>This method is used by the ReadBytes and WriteBytes method to determine the amount of bytes accessed.</remarks>
		protected int AdjustAccessedBytes(int count)
		{
			int result;

			result = count;
			if ((position + result) > length)
			{
				result = (int)(length - position);
			}

			return result;
		}

		#endregion

		#region ------------ public methods ------------

		/// <summary>
		/// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read.
		/// </summary>
		/// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array with the values between offset and (offset + count- 1) replaced by the bytes read from the current source. </param>
		/// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the current stream.</param>
		/// <param name="count">The maximum number of bytes to be read from the current stream.</param>
		/// <returns>The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached.</returns>
		/// <exception cref="ArgumentException">The sum of offset and count is greater than the buffer length.</exception>
		/// <exception cref="ArgumentNullException">buffer is a null reference (Nothing in Visual Basic).</exception>
		/// <exception cref="ArgumentOutOfRangeException">offset or count is negative.</exception>
		/// <exception cref="IOException">An I/O error occurs.</exception>
		/// <exception cref="NotSupportedException">The stream does not support reading.</exception>																																  
		/// ObjectDisposedException Methods were called after the stream was closed. 
		/// <exception cref="ObjectDisposedException">Methods were called after the stream was closed.</exception>
		public override int Read(byte[] buffer, int offset, int count)
		{
			int bytesRead;

			if (buffer == null)
			{
				throw new ArgumentNullException("buffer");
			}
			bytesRead = AdjustAccessedBytes(count);
			if (bytesRead > 0)
			{
				Marshal.Copy(GetCurrentAddress(), buffer, offset, bytesRead);
				Seek(bytesRead, SeekOrigin.Current);
			}

			return bytesRead;
		}

		/// <summary>
		/// Writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written.
		/// </summary>
		/// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</param>
		/// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current stream.</param>
		/// <param name="count">The number of bytes to be written to the current stream.</param>
		/// <exception cref="ArgumentException">The sum of offset and count is greater than the buffer length.</exception>
		/// <exception cref="ArgumentNullException">buffer is a null reference (Nothing in Visual Basic).</exception>
		/// <exception cref="ArgumentOutOfRangeException">offset or count is negative.</exception>
		/// <exception cref="IOException">An I/O error occurs.</exception>
		/// <exception cref="NotSupportedException">The stream does not support writing.</exception>																																  
		/// ObjectDisposedException Methods were called after the stream was closed. 
		public override void Write(byte[] buffer, int offset, int count)
		{
			int bytesWritten;

			if (!CanWrite)
			{
				throw new NotSupportedException("Writing is not supported by this stream");
			}
			if (buffer == null)
			{
				throw new ArgumentNullException("buffer");
			}
			bytesWritten = AdjustAccessedBytes(count);
			if (bytesWritten != count)
			{
				throw new ArgumentException("You cannot write beyond the end of the stream.");
			}
			Marshal.Copy(buffer, offset, GetCurrentAddress(), bytesWritten);
			Seek(bytesWritten, SeekOrigin.Current);
		}

		/// <summary>
		/// Reads a byte from the stream and advances the position within the stream by one byte, or returns -1 if at the end of the stream.
		/// </summary>
		/// <returns>The unsigned byte cast to an Int32, or -1 if at the end of the stream.</returns>
		/// <exception cref="NotSupportedException">The stream does not support reading.</exception>
		/// <exception cref="ObjectDisposedException">Methods were called after the stream was closed.</exception>
		public override int ReadByte()
		{	
			int result;

			if (Position < Length)
			{
				result = Marshal.ReadByte(GetCurrentAddress());
				Seek(1, SeekOrigin.Current);
			}
			else
			{
				result = -1;
			}

			return result;
		}

		/// <summary>
		/// Writes a byte to the current position in the stream and advances the position within the stream by one byte.
		/// </summary>
		/// <param name="value">The byte to write to the stream.</param>
		/// <exception cref="IOException">An I/O error occurs.</exception>
		/// <exception cref="NotSupportedException">The stream does not support writing, or the stream is already closed.</exception>
		/// <exception cref="ObjectDisposedException">Methods were called after the stream was closed.</exception>
		public override void WriteByte(byte value)
		{
			if (!CanWrite)
			{
				throw new NotSupportedException("Writing is not supported by this stream");
			}
			Marshal.WriteByte(GetCurrentAddress(), value);
			Seek(1, SeekOrigin.Current);
		}

		/// <summary>
		/// Flushes and closes the UnmanagedMemoryStream and the underlying unmanagedMemorySource and
		/// releases any system resources associated with the UnmanagedMemoryStream. 
		/// This method must not be called as long you want to continue using the underlying object.
		/// </summary>
		/// <remarks>
		/// A call to Close is required for proper operation of a stream. Following a call to Close, other operations on the stream could throw exceptions. If the stream is already closed, a call to Close throws no exceptions.<br/>
		/// <br/>
		/// Attempts to manipulate the stream after the stream has been closed might throw an ObjectDisposedException.
		/// </remarks>
        public override void Close()
		{
			Flush();
			base.Close ();
			unmanagedMemory.Dispose();
		}

		/// <summary>
		/// Clears all buffers for this stream and causes any buffered data to be written to the underlying unmanaged memory.
		/// </summary>
		/// <remarks>
		/// If the underlying object passed to the constuctor does not implement IBufferedResource this method does nothing.
		/// </remarks>
		public override void Flush()
		{
			// Flush if the underlying resource is buffered else ingore it.
			if (bufferedResource != null)
			{
				bufferedResource.Flush();
			}
		}

		/// <summary>
		/// Sets the position within the current stream.
		/// </summary>
		/// <param name="offset">A byte offset relative to the origin parameter.</param>
		/// <param name="origin">A value of type SeekOrigin indicating the reference point used to obtain the new position.</param>
		/// <returns>The new position within the current stream.</returns>
		public override long Seek(long offset, SeekOrigin origin)
		{
			switch(origin)
			{
				case SeekOrigin.Begin:
					position = offset;
					break;
				case SeekOrigin.Current:
					position += offset;
					break;
				case SeekOrigin.End:
					position = Length - offset; // corrected
					break;
			}

			return position;
		}

		/// <summary>
		/// sets the length of the current stream.
		/// </summary>
		/// <param name="value">The desired length of the current stream in bytes.</param>
		/// <exception cref="ArgumentOutOfRangeException">value exceeds the amount of allocated unmanaged memory.</exception>
		public override void SetLength(long value)
		{
			if (value > unmanagedMemory.Length)
			{
				throw new ArgumentOutOfRangeException("value", "Length must not exceed the amount of allocated memory");
			}
			length = value;
		}

		#endregion

		#region ------------ properties ------------

		/// <summary>
		/// Gets a value indicating whether the current stream supports seeking.
		/// </summary>
		/// <value>always <b>true</b></value>
		public override bool CanSeek
		{
			get
			{
				return true;
			}
		}

		/// <summary>
		/// Gets a value indicating whether the current stream supports writing.
		/// </summary>
		/// <value><b>true</b> if the IUnmanagedMemoryResource is writable.</value>
		public override bool CanWrite
		{
			get
			{
				return unmanagedMemory.CanWrite;
			}
		}

		/// <summary>
		/// Gets a value indicating whether the current stream supports reading.
		/// </summary>
		/// <value>always <b>true</b></value>
		public override bool CanRead
		{
			get
			{
				return true;
			}
		}

		/// <summary>
		/// Gets the length in bytes of the stream.
		/// </summary>
		/// <value>A long value representing the length of the stream in bytes.</value>
		public override long Length
		{
			get
			{
				return length;
			}
		}

		/// <summary>
		/// Gets or sets the position within the current stream.
		/// </summary>
		/// <value>The current position within the stream.</value>
		public override long Position
		{
			get
			{
				return position;
			}
			set
			{
				position = value;
			}
		}

		#endregion
	}
}

By viewing downloads associated with this article you agree to the Terms of use and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Andrea Bertolotto
Software Developer (Senior)
Italy Italy
Member
No Biography provided

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130516.1 | Last Updated 10 Mar 2013
Article Copyright 2006 by Andrea Bertolotto
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid