diff --git a/PInvoke/AMSI/amsi.Interfaces.cs b/PInvoke/AMSI/amsi.Interfaces.cs index 643de402..befb8f1e 100644 --- a/PInvoke/AMSI/amsi.Interfaces.cs +++ b/PInvoke/AMSI/amsi.Interfaces.cs @@ -1,8 +1,4 @@ -using System; using System.IO; -using System.Runtime.InteropServices; -using Vanara.Extensions; -using Vanara.InteropServices; namespace Vanara.PInvoke; @@ -548,14 +544,14 @@ public static partial class AMSI /// Initializes a new instance of the class and inserts the contents of a buffer. /// The buffer to copy. /// if set to , the stream is read-write; if , it is read-only. - public AmsiStream(byte[] buffer, bool writable) : base(new SafeCoTaskMemHandle(buffer), access: writable ? FileAccess.ReadWrite : FileAccess.Read) + public AmsiStream(byte[]? buffer, bool writable) : base(buffer is null ? SafeCoTaskMemHandle.Null : new SafeCoTaskMemHandle(buffer), access: writable ? FileAccess.ReadWrite : FileAccess.Read) { } /// Initializes a new instance of the class with file information. /// The file information. /// if set to , the stream is read-write; if , it is read-only. - public AmsiStream(FileInfo file, bool writable) : this(file is null ? null : File.ReadAllBytes(file.FullName), writable) => ContentName = file.FullName; + public AmsiStream(FileInfo? file, bool writable) : this(file is null ? null : File.ReadAllBytes(file.FullName), writable) => ContentName = file?.FullName; /// Initializes a new instance of the class. /// The memory allocator used to create and extend the native memory. @@ -565,10 +561,10 @@ public static partial class AMSI } /// Gets or sets the name, version, or GUID string of the calling application. - public string AppName { get; set; } + public string? AppName { get; set; } /// Gets or sets the filename, URL, unique script ID, or similar of the content. - public string ContentName { get; set; } + public string? ContentName { get; set; } /// /// Gets or sets the session is used to associate different scan calls, such as if the contents to be scanned belong to the @@ -578,10 +574,10 @@ public static partial class AMSI HRESULT IAmsiStream.GetAttribute(AMSI_ATTRIBUTE attribute, uint dataSize, IntPtr data, out uint retData) { - byte[] bytes = attribute switch + byte[]? bytes = attribute switch { - AMSI_ATTRIBUTE.AMSI_ATTRIBUTE_APP_NAME => StringHelper.GetBytes(AppName, true, CharSet.Unicode), - AMSI_ATTRIBUTE.AMSI_ATTRIBUTE_CONTENT_NAME => StringHelper.GetBytes(ContentName, true, CharSet.Unicode), + AMSI_ATTRIBUTE.AMSI_ATTRIBUTE_APP_NAME => AppName is null ? null : StringHelper.GetBytes(AppName, true, CharSet.Unicode), + AMSI_ATTRIBUTE.AMSI_ATTRIBUTE_CONTENT_NAME => ContentName is null ? null : StringHelper.GetBytes(ContentName, true, CharSet.Unicode), AMSI_ATTRIBUTE.AMSI_ATTRIBUTE_CONTENT_SIZE => BitConverter.GetBytes((ulong)Length), AMSI_ATTRIBUTE.AMSI_ATTRIBUTE_CONTENT_ADDRESS => IntPtr.Size == 8 ? BitConverter.GetBytes(Pointer.ToInt64()) : BitConverter.GetBytes(Pointer.ToInt32()), AMSI_ATTRIBUTE.AMSI_ATTRIBUTE_SESSION => IntPtr.Size == 8 ? BitConverter.GetBytes(Session.ToInt64()) : BitConverter.GetBytes(Session.ToInt32()), diff --git a/PInvoke/AMSI/amsi.cs b/PInvoke/AMSI/amsi.cs index 8ba55809..0bc75285 100644 --- a/PInvoke/AMSI/amsi.cs +++ b/PInvoke/AMSI/amsi.cs @@ -1,5 +1,4 @@ -using System; -using System.Runtime.InteropServices; +using System.Diagnostics.CodeAnalysis; namespace Vanara.PInvoke; @@ -265,7 +264,7 @@ public static partial class AMSI public static bool operator ==(HAMSICONTEXT h1, HAMSICONTEXT h2) => h1.handle == h2.handle; /// - public override bool Equals(object? obj) => (obj is IHandle h && handle == h.DangerousGetHandle()) || (obj is IntPtr p && handle == p); + public override bool Equals(object? obj) => obj is IHandle h && handle == h.DangerousGetHandle() || obj is IntPtr p && handle == p; /// public override int GetHashCode() => handle.GetHashCode(); @@ -313,7 +312,7 @@ public static partial class AMSI public static bool operator ==(HAMSISESSION h1, HAMSISESSION h2) => h1.handle == h2.handle; /// - public override bool Equals(object? obj) => (obj is IHandle h && handle == h.DangerousGetHandle()) || (obj is IntPtr p && handle == p); + public override bool Equals(object? obj) => obj is IHandle h && handle == h.DangerousGetHandle() || obj is IntPtr p && handle == p; /// public override int GetHashCode() => handle.GetHashCode(); @@ -340,6 +339,9 @@ public static partial class AMSI /// The result of the conversion. public static implicit operator HAMSICONTEXT(SafeHAMSICONTEXT h) => h.handle; + /// Represents a NULL handle. + public static readonly SafeHAMSICONTEXT Null = new(IntPtr.Zero, false); + /// protected override bool InternalReleaseHandle() { AmsiUninitialize(handle); return true; } } @@ -354,11 +356,11 @@ public static partial class AMSI /// /// to reliably release the handle during the finalization phase; otherwise, (not recommended). /// - public SafeHAMSISESSION(IntPtr preexistingHandle, bool ownsHandle = true) : base(preexistingHandle, ownsHandle) { } + public SafeHAMSISESSION(IntPtr preexistingHandle, bool ownsHandle = true) : base(preexistingHandle, ownsHandle) => ctx = SafeHAMSICONTEXT.Null; /// Initializes a new instance of the class. /// The context. - public SafeHAMSISESSION(HAMSICONTEXT context) : base() => Open(Context = context); + public SafeHAMSISESSION(HAMSICONTEXT context) : base() => Open(ctx = new(context.DangerousGetHandle(), false)); /// Initializes a new instance of the class. /// The name, version, or GUID string of the app calling the AMSI API. @@ -369,7 +371,7 @@ public static partial class AMSI } /// Initializes a new instance of the class. - private SafeHAMSISESSION() : base() { } + private SafeHAMSISESSION() : base() => ctx = SafeHAMSICONTEXT.Null; /// Gets or sets the handle of type HAMSICONTEXT that was initially received from AmsiInitialize. /// The context handle. diff --git a/UnitTests/PInvoke/AMSI/AMSITests.cs b/UnitTests/PInvoke/AMSI/AMSITests.cs index 3e0e4ff8..de1c5b92 100644 --- a/UnitTests/PInvoke/AMSI/AMSITests.cs +++ b/UnitTests/PInvoke/AMSI/AMSITests.cs @@ -1,9 +1,6 @@ using NUnit.Framework; using NUnit.Framework.Internal; -using System; using System.IO; -using System.Runtime.InteropServices; -using Vanara.InteropServices; using static Vanara.PInvoke.AMSI; namespace Vanara.PInvoke.Tests; @@ -68,10 +65,10 @@ public class AMSITests { var fn = TestCaseSources.BmpFile; var app = "MyTestApp"; - AmsiStream str = null; + AmsiStream? str = null; Assert.That(() => str = new(new FileInfo(fn), false) { AppName = app }, Throws.Nothing); - var istr = str as IAmsiStream; + var istr = (IAmsiStream)str!; using var mem = new SafeCoTaskMemHandle(2048); Assert.That(istr.GetAttribute(AMSI_ATTRIBUTE.AMSI_ATTRIBUTE_APP_NAME, mem.Size, mem, out var sz), ResultIs.Successful); @@ -82,7 +79,7 @@ public class AMSITests Assert.That(istr.GetAttribute(AMSI_ATTRIBUTE.AMSI_ATTRIBUTE_CONTENT_SIZE, mem.Size, mem, out sz), ResultIs.Successful); Assert.That(sz, Is.EqualTo(sizeof(ulong))); - Assert.That(mem.ToStructure(), Is.EqualTo((ulong)str.Length)); + Assert.That(mem.ToStructure(), Is.EqualTo((ulong)str!.Length)); Assert.That(istr.GetAttribute(AMSI_ATTRIBUTE.AMSI_ATTRIBUTE_CONTENT_ADDRESS, mem.Size, mem, out sz), ResultIs.Successful); Assert.That(sz, Is.EqualTo(IntPtr.Size)); @@ -98,11 +95,11 @@ public class AMSITests { var fn = TestCaseSources.BmpFile; var app = "MyTestApp"; - AmsiStream str = null; + AmsiStream? str = null; Assert.That(() => str = new(new FileInfo(fn), false) { AppName = app }, Throws.Nothing); IAntimalware2 iam = new(); - Assert.That(iam.Scan(str, out var res, out var prov), ResultIs.Successful); + Assert.That(iam.Scan(str!, out var res, out var prov), ResultIs.Successful); TestContext.WriteLine(res); Assert.That(prov.DisplayName(out var pname), ResultIs.Successful); TestContext.WriteLine(pname);