// Decompiled with JetBrains decompiler
// Type: Dolinay.DriveDetector
// Assembly: svchost, Version=3.2.4.0, Culture=neutral, PublicKeyToken=null
// MVID: 8F51F928-E1DB-4815-857F-7D580385B815
// Assembly location: C:\Users\Administrateur\Downloads\Virusshare-00000-msil\Backdoor.MSIL.IrcBot.lp-4dd7df88cffbf85a5894bc1b38660fa613c24b0e6c004ac00b2b119c03a35d3f.exe

using Microsoft.Win32.SafeHandles;
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace Dolinay
{
  internal class DriveDetector : IDisposable
  {
    private const int DBT_DEVTYP_DEVICEINTERFACE = 5;
    private const int DBT_DEVTYP_HANDLE = 6;
    private const int BROADCAST_QUERY_DENY = 1112363332;
    private const int WM_DEVICECHANGE = 537;
    private const int DBT_DEVICEARRIVAL = 32768;
    private const int DBT_DEVICEQUERYREMOVE = 32769;
    private const int DBT_DEVICEREMOVECOMPLETE = 32772;
    private const int DBT_DEVTYP_VOLUME = 2;
    private IntPtr mDirHandle = IntPtr.Zero;
    private FileStream mFileOnFlash;
    private string mFileToOpen;
    private IntPtr mDeviceNotifyHandle;
    private IntPtr mRecipientHandle;
    private string mCurrentDrive;

    public event DriveDetectorEventHandler DeviceArrived;

    public event DriveDetectorEventHandler DeviceRemoved;

    public event DriveDetectorEventHandler QueryRemove;

    public DriveDetector()
    {
      DetectorForm detectorForm = new DetectorForm(this);
      detectorForm.Show();
      this.Init((Control) detectorForm, (string) null);
    }

    public DriveDetector(Control control) => this.Init(control, (string) null);

    public DriveDetector(Control control, string FileToOpen) => this.Init(control, FileToOpen);

    private void Init(Control control, string fileToOpen)
    {
      this.mFileToOpen = fileToOpen;
      this.mFileOnFlash = (FileStream) null;
      this.mDeviceNotifyHandle = IntPtr.Zero;
      this.mRecipientHandle = control.Handle;
      this.mDirHandle = IntPtr.Zero;
      this.mCurrentDrive = "";
    }

    public bool IsQueryHooked => !(this.mDeviceNotifyHandle == IntPtr.Zero);

    public string HookedDrive => this.mCurrentDrive;

    public FileStream OpenedFile => this.mFileOnFlash;

    public bool EnableQueryRemove(string fileOnDrive)
    {
      switch (fileOnDrive)
      {
        case "":
        case null:
          throw new ArgumentException("Drive path must be supplied to register for Query remove.");
        default:
          if (fileOnDrive.Length == 2 && fileOnDrive[1] == ':')
            fileOnDrive += (string) (object) '\\';
          if (this.mDeviceNotifyHandle != IntPtr.Zero)
            this.RegisterForDeviceChange(false, (SafeFileHandle) null);
          this.mFileToOpen = Path.GetFileName(fileOnDrive).Length == 0 || !File.Exists(fileOnDrive) ? (string) null : fileOnDrive;
          this.RegisterQuery(Path.GetPathRoot(fileOnDrive));
          return !(this.mDeviceNotifyHandle == IntPtr.Zero);
      }
    }

    public void DisableQueryRemove()
    {
      if (!(this.mDeviceNotifyHandle != IntPtr.Zero))
        return;
      this.RegisterForDeviceChange(false, (SafeFileHandle) null);
    }

    public void Dispose() => this.RegisterForDeviceChange(false, (SafeFileHandle) null);

    public void WndProc(ref Message m)
    {
      if (m.Msg != 537)
        return;
      switch (m.WParam.ToInt32())
      {
        case 32768:
          if (Marshal.ReadInt32(m.LParam, 4) != 2)
            break;
          char letter1 = DriveDetector.DriveMaskToLetter(((DriveDetector.DEV_BROADCAST_VOLUME) Marshal.PtrToStructure(m.LParam, typeof (DriveDetector.DEV_BROADCAST_VOLUME))).dbcv_unitmask);
          DriveDetectorEventHandler deviceArrived = this.DeviceArrived;
          if (deviceArrived == null)
            break;
          DriveDetectorEventArgs e1 = new DriveDetectorEventArgs();
          e1.Drive = letter1.ToString() + ":\\";
          deviceArrived((object) this, e1);
          if (!e1.HookQueryRemove)
            break;
          if (this.mDeviceNotifyHandle != IntPtr.Zero)
            this.RegisterForDeviceChange(false, (SafeFileHandle) null);
          this.RegisterQuery(letter1.ToString() + ":\\");
          break;
        case 32769:
          if (Marshal.ReadInt32(m.LParam, 4) != 6)
            break;
          DriveDetectorEventHandler queryRemove = this.QueryRemove;
          if (queryRemove == null)
            break;
          DriveDetectorEventArgs e2 = new DriveDetectorEventArgs();
          e2.Drive = this.mCurrentDrive;
          queryRemove((object) this, e2);
          if (e2.Cancel)
          {
            m.Result = (IntPtr) 1112363332;
            break;
          }
          this.RegisterForDeviceChange(false, (SafeFileHandle) null);
          break;
        case 32772:
          if (Marshal.ReadInt32(m.LParam, 4) != 2 || Marshal.ReadInt32(m.LParam, 4) != 2)
            break;
          char letter2 = DriveDetector.DriveMaskToLetter(((DriveDetector.DEV_BROADCAST_VOLUME) Marshal.PtrToStructure(m.LParam, typeof (DriveDetector.DEV_BROADCAST_VOLUME))).dbcv_unitmask);
          DriveDetectorEventHandler deviceRemoved = this.DeviceRemoved;
          if (deviceRemoved == null)
            break;
          deviceRemoved((object) this, new DriveDetectorEventArgs()
          {
            Drive = letter2.ToString() + ":\\"
          });
          break;
      }
    }

    private void RegisterQuery(string drive)
    {
      bool flag = true;
      if (this.mFileToOpen != null)
      {
        if (this.mFileToOpen.Contains(":"))
        {
          string path2 = this.mFileToOpen.Substring(3);
          this.mFileToOpen = Path.Combine(Path.GetPathRoot(drive), path2);
        }
        else
          this.mFileToOpen = Path.Combine(drive, this.mFileToOpen);
      }
      try
      {
        this.mFileOnFlash = this.mFileToOpen != null ? new FileStream(this.mFileToOpen, FileMode.Open) : (FileStream) null;
      }
      catch (Exception ex)
      {
        flag = false;
      }
      if (!flag)
        return;
      if (this.mFileOnFlash == null)
        this.RegisterForDeviceChange(drive);
      else
        this.RegisterForDeviceChange(true, this.mFileOnFlash.SafeFileHandle);
      this.mCurrentDrive = drive;
    }

    private void RegisterForDeviceChange(string dirPath)
    {
      IntPtr num1 = DriveDetector.Native.OpenDirectory(dirPath);
      if (num1 == IntPtr.Zero)
      {
        this.mDeviceNotifyHandle = IntPtr.Zero;
      }
      else
      {
        this.mDirHandle = num1;
        DriveDetector.DEV_BROADCAST_HANDLE structure = new DriveDetector.DEV_BROADCAST_HANDLE();
        structure.dbch_devicetype = 6;
        structure.dbch_reserved = 0;
        structure.dbch_nameoffset = 0L;
        structure.dbch_handle = num1;
        structure.dbch_hdevnotify = (IntPtr) 0;
        int cb = Marshal.SizeOf((object) structure);
        structure.dbch_size = cb;
        IntPtr num2 = Marshal.AllocHGlobal(cb);
        Marshal.StructureToPtr((object) structure, num2, true);
        this.mDeviceNotifyHandle = DriveDetector.Native.RegisterDeviceNotification(this.mRecipientHandle, num2, 0U);
      }
    }

    private void RegisterForDeviceChange(bool register, SafeFileHandle fileHandle)
    {
      if (register)
      {
        DriveDetector.DEV_BROADCAST_HANDLE structure = new DriveDetector.DEV_BROADCAST_HANDLE();
        structure.dbch_devicetype = 6;
        structure.dbch_reserved = 0;
        structure.dbch_nameoffset = 0L;
        structure.dbch_handle = fileHandle.DangerousGetHandle();
        structure.dbch_hdevnotify = (IntPtr) 0;
        int cb = Marshal.SizeOf((object) structure);
        structure.dbch_size = cb;
        IntPtr num = Marshal.AllocHGlobal(cb);
        Marshal.StructureToPtr((object) structure, num, true);
        this.mDeviceNotifyHandle = DriveDetector.Native.RegisterDeviceNotification(this.mRecipientHandle, num, 0U);
      }
      else
      {
        if (this.mDirHandle != IntPtr.Zero)
          DriveDetector.Native.CloseDirectoryHandle(this.mDirHandle);
        if (this.mDeviceNotifyHandle != IntPtr.Zero)
        {
          int num = (int) DriveDetector.Native.UnregisterDeviceNotification(this.mDeviceNotifyHandle);
        }
        this.mDeviceNotifyHandle = IntPtr.Zero;
        this.mDirHandle = IntPtr.Zero;
        this.mCurrentDrive = "";
        if (this.mFileOnFlash == null)
          return;
        this.mFileOnFlash.Close();
        this.mFileOnFlash = (FileStream) null;
      }
    }

    private static char DriveMaskToLetter(int mask)
    {
      string str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
      int index = 0;
      int num = mask / 2;
      while (num != 0)
      {
        num /= 2;
        ++index;
      }
      return index >= str.Length ? '?' : str[index];
    }

    private class Native
    {
      private const uint GENERIC_READ = 2147483648;
      private const uint OPEN_EXISTING = 3;
      private const uint FILE_SHARE_READ = 1;
      private const uint FILE_SHARE_WRITE = 2;
      private const uint FILE_ATTRIBUTE_NORMAL = 128;
      private const uint FILE_FLAG_BACKUP_SEMANTICS = 33554432;
      private static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);

      [DllImport("user32.dll", CharSet = CharSet.Auto)]
      public static extern IntPtr RegisterDeviceNotification(
        IntPtr hRecipient,
        IntPtr NotificationFilter,
        uint Flags);

      [DllImport("user32.dll", CharSet = CharSet.Auto)]
      public static extern uint UnregisterDeviceNotification(IntPtr hHandle);

      [DllImport("kernel32", SetLastError = true)]
      private static extern IntPtr CreateFile(
        string FileName,
        uint DesiredAccess,
        uint ShareMode,
        uint SecurityAttributes,
        uint CreationDisposition,
        uint FlagsAndAttributes,
        int hTemplateFile);

      [DllImport("kernel32", SetLastError = true)]
      private static extern bool CloseHandle(IntPtr hObject);

      public static IntPtr OpenDirectory(string dirPath)
      {
        IntPtr file = DriveDetector.Native.CreateFile(dirPath, 2147483648U, 3U, 0U, 3U, 33554560U, 0);
        return file == DriveDetector.Native.INVALID_HANDLE_VALUE ? IntPtr.Zero : file;
      }

      public static bool CloseDirectoryHandle(IntPtr handle) => DriveDetector.Native.CloseHandle(handle);
    }

    public struct DEV_BROADCAST_HANDLE
    {
      public int dbch_size;
      public int dbch_devicetype;
      public int dbch_reserved;
      public IntPtr dbch_handle;
      public IntPtr dbch_hdevnotify;
      public Guid dbch_eventguid;
      public long dbch_nameoffset;
      public byte dbch_data;
      public byte dbch_data1;
    }

    public struct DEV_BROADCAST_VOLUME
    {
      public int dbcv_size;
      public int dbcv_devicetype;
      public int dbcv_reserved;
      public int dbcv_unitmask;
    }
  }
}
