2020-10-20 16:20:38 +03:00
|
|
|
using System;
|
|
|
|
using System.Diagnostics;
|
|
|
|
using System.IO;
|
|
|
|
using System.Linq;
|
|
|
|
using System.Text.RegularExpressions;
|
|
|
|
using System.Threading;
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
|
|
|
|
namespace MalwareMultiScan.Backends.Backends.Abstracts
|
|
|
|
{
|
|
|
|
public abstract class AbstractLocalProcessScanBackend : AbstractScanBackend
|
|
|
|
{
|
|
|
|
private readonly ILogger _logger;
|
2020-10-20 17:08:40 +03:00
|
|
|
|
|
|
|
protected AbstractLocalProcessScanBackend(ILogger logger)
|
|
|
|
{
|
|
|
|
_logger = logger;
|
|
|
|
}
|
|
|
|
|
2020-10-26 17:06:29 +02:00
|
|
|
protected abstract Regex MatchRegex { get; }
|
|
|
|
protected abstract string BackendPath { get; }
|
2020-10-20 16:20:38 +03:00
|
|
|
protected virtual bool ParseStdErr { get; }
|
2020-10-22 09:28:28 +03:00
|
|
|
protected virtual bool ThrowOnNonZeroExitCode { get; } = true;
|
2020-10-20 16:20:38 +03:00
|
|
|
|
2020-10-26 17:06:29 +02:00
|
|
|
protected abstract string GetBackendArguments(string path);
|
2020-10-20 16:20:38 +03:00
|
|
|
|
|
|
|
public override async Task<string[]> ScanAsync(string path, CancellationToken cancellationToken)
|
|
|
|
{
|
|
|
|
var process = new Process
|
|
|
|
{
|
|
|
|
StartInfo = new ProcessStartInfo(BackendPath, GetBackendArguments(path))
|
|
|
|
{
|
|
|
|
RedirectStandardError = true,
|
|
|
|
RedirectStandardOutput = true,
|
|
|
|
WorkingDirectory = Path.GetDirectoryName(BackendPath) ?? Directory.GetCurrentDirectory()
|
|
|
|
}
|
|
|
|
};
|
2020-10-20 17:08:40 +03:00
|
|
|
|
2020-10-20 16:20:38 +03:00
|
|
|
_logger.LogInformation(
|
|
|
|
$"Starting process {process.StartInfo.FileName} " +
|
|
|
|
$"with arguments {process.StartInfo.Arguments} " +
|
|
|
|
$"in working directory {process.StartInfo.WorkingDirectory}");
|
2020-10-20 17:08:40 +03:00
|
|
|
|
2020-10-20 16:20:38 +03:00
|
|
|
process.Start();
|
|
|
|
|
|
|
|
cancellationToken.Register(() =>
|
|
|
|
{
|
|
|
|
if (!process.HasExited)
|
|
|
|
process.Kill(true);
|
|
|
|
});
|
2020-10-20 17:08:40 +03:00
|
|
|
|
2020-10-20 16:20:38 +03:00
|
|
|
process.WaitForExit();
|
|
|
|
|
|
|
|
_logger.LogInformation($"Process has exited with code {process.ExitCode}");
|
2020-10-23 11:11:19 +03:00
|
|
|
|
2020-10-20 16:20:38 +03:00
|
|
|
var standardOutput = await process.StandardOutput.ReadToEndAsync();
|
|
|
|
var standardError = await process.StandardError.ReadToEndAsync();
|
2020-10-20 17:08:40 +03:00
|
|
|
|
2020-10-20 16:20:38 +03:00
|
|
|
_logger.LogDebug($"Process standard output: {standardOutput}");
|
|
|
|
_logger.LogDebug($"Process standard error: {standardError}");
|
2020-10-23 11:11:19 +03:00
|
|
|
|
2020-10-22 09:28:28 +03:00
|
|
|
if (ThrowOnNonZeroExitCode && process.ExitCode != 0)
|
|
|
|
throw new ApplicationException($"Process has terminated with an exit code {process.ExitCode}");
|
2020-10-20 16:20:38 +03:00
|
|
|
|
|
|
|
return MatchRegex
|
|
|
|
.Matches(ParseStdErr ? standardError : standardOutput)
|
|
|
|
.Where(x => x.Success)
|
|
|
|
.Select(x => x.Groups["threat"].Value)
|
|
|
|
.ToArray();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|