#nullable enable
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace IPA.AntiMalware.ComAPI
|
|
{
|
|
internal class AmsiFileStream : IAmsiStream, IDisposable
|
|
{
|
|
private readonly FileInfo file;
|
|
private readonly IntPtr session;
|
|
|
|
public AmsiFileStream(FileInfo file, IntPtr session)
|
|
{
|
|
this.file = file;
|
|
this.session = session;
|
|
}
|
|
|
|
public unsafe void GetAttribute([In] AmsiAttribute attribute, [In] uint dataSize, [Out] byte* buffer, out uint writtenData)
|
|
{
|
|
switch (attribute)
|
|
{
|
|
case AmsiAttribute.AppName:
|
|
writtenData = WriteWString(AmsiConstants.AppName, dataSize, buffer);
|
|
return;
|
|
case AmsiAttribute.Session:
|
|
*(IntPtr*)buffer = session;
|
|
writtenData = (uint)sizeof(IntPtr);
|
|
return;
|
|
|
|
case AmsiAttribute.ContentName:
|
|
writtenData = WriteWString(file.FullName, dataSize, buffer);
|
|
return;
|
|
|
|
case AmsiAttribute.ContentSize:
|
|
*(ulong*)buffer = (ulong)file.Length;
|
|
writtenData = sizeof(ulong);
|
|
return;
|
|
|
|
default:
|
|
throw new NotImplementedException(); // return e_notimpl
|
|
}
|
|
|
|
static unsafe uint WriteWString(string str, uint dataSize, byte* buffer)
|
|
{
|
|
fixed (char* name = str)
|
|
{
|
|
return (uint)Encoding.Unicode.GetBytes(name, str.Length, buffer, (int)dataSize);
|
|
}
|
|
}
|
|
}
|
|
|
|
private FileStream? stream;
|
|
private bool disposedValue;
|
|
private readonly byte[] readBuffer = new byte[1024];
|
|
|
|
public unsafe void Read([In] ulong position, [In] uint dataSize, [Out] byte* buffer, out uint readSize)
|
|
{
|
|
stream ??= file.OpenRead();
|
|
|
|
stream.Position = (long)position;
|
|
|
|
var bytesToRead = dataSize;
|
|
readSize = 0;
|
|
|
|
while (bytesToRead > 0)
|
|
{
|
|
var bytesRead = stream.Read(readBuffer, 0, (int)Math.Min(readBuffer.Length, bytesToRead));
|
|
if (bytesRead == 0)
|
|
{
|
|
break;
|
|
}
|
|
fixed (byte* readBufferPtr = readBuffer)
|
|
{
|
|
Buffer.MemoryCopy(readBufferPtr, buffer + readSize, dataSize - readSize, bytesRead);
|
|
}
|
|
bytesToRead -= (uint)bytesRead;
|
|
readSize += (uint)bytesRead;
|
|
}
|
|
}
|
|
|
|
protected virtual void Dispose(bool disposing)
|
|
{
|
|
if (!disposedValue)
|
|
{
|
|
if (disposing)
|
|
{
|
|
stream?.Dispose();
|
|
}
|
|
|
|
disposedValue = true;
|
|
}
|
|
}
|
|
|
|
// This does not have unmanagd resources, so it doesn't need to exist
|
|
// ~AmsiFileStream()
|
|
// {
|
|
// // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
|
// Dispose(disposing: false);
|
|
// }
|
|
|
|
public void Dispose()
|
|
{
|
|
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
|
Dispose(disposing: true);
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
}
|
|
}
|