9

I wrote the below code to write 0xFF to all bytes on my USB storeage device. For some reason the WriteFile() calls begin to error out at sector 242. I have done this on two separate USB storage devices and then examined the devices in a hex editor. Sector 242 appears to be the start of the file allocation table on a FAT16 formated device and the start of the boot area on an NTFS device. I'm sure it is no conincidence that it is erroring out at these exact locations, however I do not know how to alter this behavior. The HRESULT I am receiving when the WriteFile fails is -2147024891 which is E_ACCESSDENIED. Does anyone know what could be causing the problem?

NOTE: IF you are going to run this code on your local system BE VERY CAREFUL as I have hardcoded the physical device ID for my USB device. Please be sure to update the deviceId variable with the device you are attempting to write to. You do not want to destroy your hard drive.

    public enum EMoveMethod : uint
    {
        Begin = 0,
        Current = 1,
        End = 2
    }

    [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    static extern uint SetFilePointer([In] SafeFileHandle hFile, [In] long lDistanceToMove, [Out] out int lpDistanceToMoveHigh, [In] EMoveMethod dwMoveMethod);

    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    static extern SafeFileHandle CreateFile(string lpFileName, uint dwDesiredAccess, uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile);

    [DllImport("kernel32", SetLastError = true)]
    internal extern static int ReadFile(SafeFileHandle handle, byte[] bytes, int numBytesToRead, out int numBytesRead, IntPtr overlapped_MustBeZero);

    [DllImport("kernel32.dll", SetLastError = true)]
    internal extern static int WriteFile(SafeFileHandle handle, byte[] bytes, int numBytesToWrite, out int numBytesWritten, IntPtr overlapped_MustBeZero);

    [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
    private static extern bool DeviceIoControl(SafeFileHandle hDevice, uint dwIoControlCode, byte[] lpInBuffer, int nInBufferSize, byte[] lpOutBuffer, int nOutBufferSize, out int lpBytesReturned, IntPtr lpOverlapped);

    [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
    private static extern bool CloseHandle(SafeFileHandle handle);

public void wipeDisk()
{
        const uint OPEN_EXISTING = 3;
        const uint GENERIC_WRITE = (0x40000000);
        const uint FSCTL_LOCK_VOLUME = 0x00090018;
        const uint FSCTL_UNLOCK_VOLUME = 0x0009001c;
        const uint FSCTL_DISMOUNT_VOLUME = 0x00090020;

        bool success = false;
        int intOut;
        string deviceId = @"\\.\PHYSICALDRIVE2";
        long DiskSize = 2056320000;

        SafeFileHandle diskHandle = CreateFile(deviceId, GENERIC_WRITE, 0, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
        if (diskHandle.IsInvalid)
        {
            Console.WriteLine(deviceId + " open error.");
            return;
        }

        Console.WriteLine(deviceId + " " + Marshal.GetHRForLastWin32Error().ToString() + ": opened.");

        success = DeviceIoControl(diskHandle, FSCTL_LOCK_VOLUME, null, 0, null, 0, out intOut, IntPtr.Zero);
        if (!success)
        {
            Console.WriteLine(deviceId + " lock error.");
            CloseHandle(diskHandle);
            return;
        }

        Console.WriteLine(deviceId + " " + Marshal.GetHRForLastWin32Error().ToString() + ": locked.");

        success = DeviceIoControl(diskHandle, FSCTL_DISMOUNT_VOLUME, null, 0, null, 0, out intOut, IntPtr.Zero);
        if (!success)
        {
            Console.WriteLine(deviceId + " " + Marshal.GetHRForLastWin32Error().ToString() + ": dismount error.");
            DeviceIoControl(diskHandle, FSCTL_UNLOCK_VOLUME, null, 0, null, 0, out intOut, IntPtr.Zero);
            CloseHandle(diskHandle);
            return;
        }

        Console.WriteLine(deviceId + " " + Marshal.GetHRForLastWin32Error().ToString() + ": unmounted.");

        int numBytesPerSector = 512;
        long numTotalSectors = DiskSize / 512;

        byte[] junkBytes = new byte[512];
        for (int x = 0; x < 512; x++)
        {
            junkBytes[x] = 0xFF;
        }

        for (long sectorNum = 0; sectorNum < numTotalSectors; sectorNum++)
        {
            int numBytesWritten = 0;
            int moveToHigh;

            uint rvalsfp = SetFilePointer(diskHandle, sectorNum * numBytesPerSector, out moveToHigh, EMoveMethod.Begin);

            Console.WriteLine("File pointer set " + Marshal.GetHRForLastWin32Error().ToString() + ": " + (sectorNum * numBytesPerSector).ToString());

            int rval = WriteFile(diskHandle, junkBytes, junkBytes.Length, out numBytesWritten, IntPtr.Zero);

            if (numBytesWritten != junkBytes.Length)
            {
                Console.WriteLine("Write error on track " + sectorNum.ToString() + " from " + (sectorNum * numBytesPerSector).ToString() + "-" + moveToHigh.ToString() + " " + Marshal.GetHRForLastWin32Error().ToString() + ": Only " + numBytesWritten.ToString() + "/" + junkBytes.Length.ToString() + " bytes written.");
                break;
            }
            else
            {
                Console.WriteLine("Write success " + Marshal.GetHRForLastWin32Error().ToString() + ": " + numBytesWritten.ToString() + "/" + junkBytes.Length.ToString() + " bytes written.");
            }
        }

        success = DeviceIoControl(diskHandle, FSCTL_UNLOCK_VOLUME, null, 0, null, 0, out intOut, IntPtr.Zero);
        if (success)
        {
            Console.WriteLine(deviceId + " " + Marshal.GetHRForLastWin32Error().ToString() + ": unlocked.");
        }
        else
        {
            Console.WriteLine(deviceId + " " + Marshal.GetHRForLastWin32Error().ToString() + ": unlock error: " + Marshal.GetHRForLastWin32Error().ToString());
        }

        success = CloseHandle(diskHandle);
        if (success)
        {
            Console.WriteLine(deviceId + " " + Marshal.GetHRForLastWin32Error().ToString() + ": handle closed.");
        }
        else
        {
            Console.WriteLine(deviceId + " " + Marshal.GetHRForLastWin32Error().ToString() + ": close handle error: " + Marshal.GetHRForLastWin32Error().ToString());
        }
}

EDIT/UPDATE

I was able to get this to work successfully after doing a low level wipe of the USB device using a third-party tool. After the drive was completely zeroed out I was able to write to the device successfully. It seems as if windows is locking the device as soon as it recognizes a valid fat or ntfs file system and the usage of

    const uint FSCTL_LOCK_VOLUME = 0x00090018;
    const uint FSCTL_DISMOUNT_VOLUME = 0x00090020;

paired with DeviceIoControl does not seem to override the lock windows has on the device.

Does anyone know how to successfully lock a removable USB Device in windows using DeviceIoControl on a drive that has a valid file system?

I have used several third-party tools that do what I am trying to do and they work successfully. I know that it is possible but all of the MSDN documentation that I have read has not helped to solve the problem.

EDIT/UPDATE 2

This is taken from https://web.archive.org/web/20130507212546/http://msdn.microsoft.com/en-us/library/ff551353.aspx

The application needs to lock the volume, dismount the volume, or both, before it can issue DASD I/O. This is new to Windows Vista and was done to address potentially malicious techniques.

  1. The file system will block all write operations to reserved sections of the disk. In this case, those reserved sections include the MBR and the two FAT areas. To block these areas, you need to lock the volume by sending FSCTL_LOCK_VOLUME. You must issue this structure on the same volume handle that performs the actual write operations. This request can fail if there are open file handles. In this case, the application can force a dismount of the file system by issuing FSCTL_DISMOUNT_VOLUME. However, the volume is not actually dismounted until the file handle is closed. Until then, the application can continue to issue DASD I/O by using the same file handle that is currently open.

  2. There is an extended region beyond the volume space that is known to the file system where write operations will be blocked. To allow write operations to this region, you must issue FSCTL_ALLOW_EXTENDED_DASD_IO on the volume handle.

You can use the Win32 API routine DeviceIoControl to issue all the previous FSCTSs.

I believe this is exactly what we are implementing in the above code but it does not appear to be working correctly. We are getting a handle and are locking and dismounting the device so we should be able to write to the protected area correct?

EDIT/UPDATE 3

Ok this is the current order of opening disks and volumns.. The methods for locking, dismounting, etc work just the order we think is wrong..

SafeFileHandle volumeHandle = CreateFile("\\.\E:",...);
LockVolume(volumeHandle);
DismountVolume(volumeHandle);
SafeFileHandle diskHandle = CreateFile("\\.\PHYSICALDRIVE1"...);
WriteStuff(diskHandle);
//Fails...
UnlockVolume(volumeHandle);
CloseVolume(volumeHandle);
CloseDisk(diskHandle);

I am still getting the same results, it only works whenever the disk is trashed.

riQQ
  • 9,878
  • 7
  • 49
  • 66
Brandon Stout
  • 359
  • 10
  • 22
  • I know it doesn't answer the question, but I believe there are disk utilities out there that will set all the bits on a drive to 1 or 0. Is this an academic/fun thing or is there a business need for such a utility? PS Upvoted the question because it is intriguing even though I haven't the foggiest how you are going to solve it. – Duncan Howe Aug 22 '12 at 21:12
  • Eventually I will use an approach similar to this to "dd" a binary disk image file back onto a physical device. This particular example was just used to test the capability of C# to write binary data to a physical device. I have several tools that can do this for me, but I need a C# interface for code I am working on. – Brandon Stout Aug 22 '12 at 21:18
  • 1
    I will have a play myself purely out of interest and let you know if I manage anything - I have a few USB sticks that I can try it out on. – Duncan Howe Aug 22 '12 at 21:36
  • 1
    If you have a virus scanner, it may be denying access to the boot sector. Are you able to write to any sectors past 242? – nneonneo Aug 22 '12 at 22:30
  • It doesn't appear to let me write to any sector past 242. The drive flashes for the first 241 sectors and I have verified in a hex editor that all 241 are populated with 0xFF. THere is just something odd about 242... – Brandon Stout Aug 23 '12 at 12:29
  • Note that you can't implement a secure wipe using such high level operations. Wear leveling&co will leave some remnants. – CodesInChaos Aug 24 '12 at 21:18

5 Answers5

5

There is a confusion between disk and drive here.

If you want full access to a disk (which is your case as you're using \\.\PHYSICALDRIVE), you must lock all mounted volumes, which are basically all partitions (i.e. drives) of your physical disk.

Instead of using FSCTL_LOCK_VOLUME on the handle returned by CreateFile("\\.\PHYSICALDRIVE"...), get a handle to each mounted volume (which is a drive, not a physical disk) using the string.Replace("\\\\.\\{0}:", DriveLetter) pattern.

You can get the list of mounted volumes (ultimately, you want a list of letters) for a given physical disk using IOCTL_DISK_GET_DRIVE_LAYOUT.


EDIT:

From MSDN :

A write on a disk handle will succeed if one of the following conditions is true:

The sectors to be written to do not fall within a volume's extents.

The sectors to be written to fall within a mounted volume, but you have explicitly locked or dismounted the volume by using FSCTL_LOCK_VOLUME or FSCTL_DISMOUNT_VOLUME.

The sectors to be written to fall within a volume that has no mounted file system other than RAW.

So basically, what you should do is:

  • get a handle to each of the volumes
  • use FSCTL_LOCK_VOLUME or FSCTL_DISMOUNT_VOLUME on each volume. If no file is being used in the volume (i.e. no opened handle by any process to any file), FSCTL_LOCK_VOLUME is enough
  • get a handle to the physical disk
  • write to the physical disk
  • close both handles. Closing the volume handle will release the lock.

Also make sure you're running your application with admin rights (elevated process).

ken2k
  • 48,145
  • 10
  • 116
  • 176
  • Ok, this makes sense. But do I also lock the disk using FSCTL_LOCK_VOLUME? I altered my code to get handle on the volume, lock the volume, dismount the volume, unlock the volume, close handle. Then open a handle on the disk, lock the disk, dismount the disk, write to the disk [which fails], unlock the disk, close handle. – Brandon Stout Aug 24 '12 at 18:32
  • @BrandonStout FSCTL_LOCK_VOLUME/FSCTL_DISMOUNT_VOLUME on the volumes should be enough. Then write to the disk. Then unlock. Don't close handle to the volumes until you finished to wrote to the disk. Closing the handle would release the lock. – ken2k Aug 24 '12 at 18:43
  • Please look at edit 3 on my post and let me know if that is the correct order that you are suggesting. – Brandon Stout Aug 24 '12 at 21:00
  • Your answer helped me get to the solution although I had to end up doing it a different way. For some reason I still could not write to the entire disk, still only the first 242 sectors until the FAT entry. But with your suggestion I came up with a work-around. I will post my way of doing it in an answer. Thank you again for the help! – Brandon Stout Aug 27 '12 at 16:28
1

I'm guessing that you're using Windows Vista or later. The OS will block any attempts to direct write to those sectors, so you need to do a lock first. More on this here:

http://msdn.microsoft.com/en-us/library/ff551353.aspx

Also just checking in SO brought this post up:

CreateFile: direct write operation to raw disk "Access is denied" - Vista, Win7

The investigative information there might be helpful, HTH...

Community
  • 1
  • 1
code4life
  • 15,655
  • 7
  • 50
  • 82
  • 2
    I am already locking and dismounting the USB device, as stated in the above code. The page you linked explains everything that we are already doing, although now I am going back and double checking all of my locking and dismounting etc. Ill check back with you after I am 100% sure that is not the issue. – Brandon Stout Aug 24 '12 at 15:55
1

EDIT

I have edited this answer to reflect ken2k's suggestions.

ken2k's suggestion did in fact fix the problem I was having. I am not sure why my previous attempts using that approach were unsuccessful, however I have just revisited/tweaked my code and that approach does appear to work correctly.

Here are the steps I used in order to solve this problem:

  • Obtain a handle to physical disk
  • Obtain a handle to each logical drive on the physical disk
  • Lock each drive on the physical disk
  • Dismount each drive on the physical disk
  • Lock the physical disk (Optional)
  • Dismount the physical disk (Optional)
  • Use the physical disk handle to zero out the entire physical disk
  • Unlock each logical drive
  • Unlock the physical disk (Only if you choose to lock the Disk)
  • Close the logical drive handles
  • Close the physical disk handle

NOTE: If you wish to do back-to-back disk operations without terminating your program and you have used the FSCTL_DISMOUNT_VOLUME functionality you will need to "remount" the disk using something similar to the following:

ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM Win32_DiskDrive");

or

System.IO.DriveInfo.GetDrives();

To map the logical drive ID's to the physical disk ID when you are attempting to lock each individual logical drive use the following piece of code to link the logical drive labels to the physical disk labels:

    List<string> driveLetters = new List<string>();
    string deviceId = @"\\.\PHYSICALDRIVE1";
    string queryString = "ASSOCIATORS OF {Win32_DiskDrive.DeviceID='" + deviceId + "'} WHERE AssocClass = Win32_DiskDriveToDiskPartition";
    ManagementObjectSearcher diskSearcher = new ManagementObjectSearcher("root\\CIMV2", queryString);
    ManagementObjectCollection diskMoc = diskSearcher.Get();
    foreach (ManagementObject diskMo in diskMoc)
    {
        queryString = "ASSOCIATORS OF {Win32_DiskPartition.DeviceID='" + diskMo["DeviceID"] + "'} WHERE AssocClass = Win32_LogicalDiskToPartition";
        ManagementObjectSearcher driveSearcher = new ManagementObjectSearcher("root\\CIMV2", queryString);

        ManagementObjectCollection driveMoc = driveSearcher.Get();
        foreach (ManagementObject driveMo in driveMoc)
        {
            driveLetters.Add("\\\\.\\" + driveMo["DeviceID"].ToString());
        }
    }

So for example, if the physical disk label is \\.\PHYSICALDRIVE1 and it contains one logical drive with the drive letter "E" the above code will map \\.\E: to \\.\PHYSICALDRIVE1.

As per ken2k's suggestion this mapping can also be done using the IOCTL_DISK_GET_DRIVE_LAYOUT functionality.

riQQ
  • 9,878
  • 7
  • 49
  • 66
Brandon Stout
  • 359
  • 10
  • 22
  • Great to see you found a solution, but I do not understand why you couldn't write to your FAT disk after having locked partitions. To be honest, I wrote some .Net hex/disk editor software I didn't released yet, and I can successfully write to my disks (Windows 7) using the described method. I can't copy/paste my code (unknown license/pricing model for now), but I did pretty much the same as I described previously. Strange you couldn't make it work. – ken2k Aug 27 '12 at 16:54
  • It's not the individual logical drives/partitions that we ultimately need access to, we need to eventually be able to access the entire physical disk to restore a binary image from a file. I would think at some point you would have to lock the physical disk to do this and not just the drives. – Brandon Stout Aug 28 '12 at 14:29
  • No, that's not required. A physical disk doesn't require to be locked itself. For example, if no partition is mounted, there is no access restriction to the disk. That's also why you can write from sector 0 to sector 242: it's possible to write to any offset of a disk if either the offset is not part of a partition with a filesystem, or is part of a partition that is locked. – ken2k Aug 28 '12 at 14:40
  • ken2k - I was able to get your method to work, see my above edit. Thanks for all the help! – Brandon Stout Aug 28 '12 at 15:43
0

for this command i did run and check it. SafeFileHandle diskHandle = CreateFile(deviceId, GENERIC_WRITE, 0/*Here*/ , IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);

change first zero next of GENERIC_WRITE parameters to 3 by mean FILE_SHARE_READ |FILE_SHARE_WRITE (1|2) to get good result. i changed that and device id to drive name same \.\f: for my usb drive name. at end i used this code replace than: SafeFileHandle diskHandle = CreateFile(deviceId, GENERIC_WRITE, 3 , IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero); good luck

  • Please format your code properly, [click here to learn how](https://stackoverflow.com/help/formatting). – rizerphe Jun 28 '20 at 07:46
0

im test follow code and need to repair my usb disk to hide rootkit viruse. so write this code:

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

namespace RootKeyremover
{
    public partial class Form1 : Form
    {
        public enum EMoveMethod : uint
        {
            Begin = 0,
            Current = 1,
            End = 2
        }

        [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern uint SetFilePointer([In] SafeFileHandle hFile, [In] long lDistanceToMove, [Out] out int lpDistanceToMoveHigh, [In] EMoveMethod dwMoveMethod);

        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        static extern SafeFileHandle CreateFile(string lpFileName, uint dwDesiredAccess, uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile);

        [DllImport("kernel32", SetLastError = true)]
        internal extern static int ReadFile(SafeFileHandle handle, byte[] bytes, int numBytesToRead, out int numBytesRead, IntPtr overlapped_MustBeZero);

        [DllImport("kernel32.dll", SetLastError = true)]
        internal extern static int WriteFile(SafeFileHandle handle, byte[] bytes, int numBytesToWrite, out int numBytesWritten, IntPtr overlapped_MustBeZero);

        [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
        private static extern bool DeviceIoControl(SafeFileHandle hDevice, uint dwIoControlCode, byte[] lpInBuffer, int nInBufferSize, byte[] lpOutBuffer, int nOutBufferSize, out int lpBytesReturned, IntPtr lpOverlapped);

        [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
        private static extern bool CloseHandle(SafeFileHandle handle);

        public Form1()
        {
            InitializeComponent();
        }

                   
        public void wipeDisk()
        {
            const short FILE_ATTRIBUTE_NORMAL = 0x80;
            const short INVALID_HANDLE_VALUE = -1;
            const uint GENERIC_READ = 0x80000000;
            const uint OPEN_EXISTING = 3;
            const uint GENERIC_WRITE = (0x40000000);
            const uint FSCTL_LOCK_VOLUME = 0x00090018;
            const uint FSCTL_UNLOCK_VOLUME = 0x0009001c;
            const uint FSCTL_DISMOUNT_VOLUME = 0x00090020;

            bool success = false;
            int intOut;
            //@"\\.\PHYSICALDRIVE2"
            string deviceId = @"\\.\" + comboBox1.Text.Substring(0,2);
            long DiskSize = 2056320000;

            SafeFileHandle diskHandle = CreateFile(deviceId, GENERIC_READ | GENERIC_WRITE, 3, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
            if (diskHandle.IsInvalid)
            {
                Console.WriteLine(deviceId + " open error.");
                return;
            }

            Console.WriteLine(deviceId + " " + Marshal.GetHRForLastWin32Error().ToString() + ": opened.");

            success = DeviceIoControl(diskHandle, FSCTL_LOCK_VOLUME, null, 0, null, 0, out intOut, IntPtr.Zero);
            if (!success)
            {
                Console.WriteLine(deviceId + " lock error.");
                CloseHandle(diskHandle);
                return;
            }

            Console.WriteLine(deviceId + " " + Marshal.GetHRForLastWin32Error().ToString() + ": locked.");

            success = DeviceIoControl(diskHandle, FSCTL_DISMOUNT_VOLUME, null, 0, null, 0, out intOut, IntPtr.Zero);
            if (!success)
            {
                Console.WriteLine(deviceId + " " + Marshal.GetHRForLastWin32Error().ToString() + ": dismount error.");
                DeviceIoControl(diskHandle, FSCTL_UNLOCK_VOLUME, null, 0, null, 0, out intOut, IntPtr.Zero);
                CloseHandle(diskHandle);
                return;
            }

            Console.WriteLine(deviceId + " " + Marshal.GetHRForLastWin32Error().ToString() + ": unmounted.");

            int numBytesPerSector = 512;
            long numTotalSectors = DiskSize / 512;

            byte[] junkBytes = new byte[512];

            
            int k =0 ;
            IntPtr l= (IntPtr)0 ;
            SetFilePointer(diskHandle, 0, out k, EMoveMethod.Begin);
            ReadFile(diskHandle, junkBytes, (int)512,out k,l);
            //3e 17e 1f1-1fb
            //for (int x = 0x3e; x < 0x17e; x++)
            //{
            //    junkBytes[x] = 0x00;
            //}
            //for (int x = 0x1f1; x < 0x1fb; x++)
            //{
            //    junkBytes[x] = 0x00;
            //}
            for (int x = 0x1e1; x < 0x1ee; x++)
            {
                junkBytes[x] = 0x00;
            }

            //diskHandle = CreateFile(deviceId, GENERIC_WRITE, 3, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
            for (long sectorNum = 0; sectorNum < 1; sectorNum++)
            {
                int numBytesWritten = 0;
                int moveToHigh;

                uint rvalsfp = SetFilePointer(diskHandle, sectorNum * numBytesPerSector, out moveToHigh, EMoveMethod.Begin);

                Console.WriteLine("File pointer set " + Marshal.GetHRForLastWin32Error().ToString() + ": " + (sectorNum * numBytesPerSector).ToString());

                int rval = WriteFile(diskHandle, junkBytes, junkBytes.Length, out numBytesWritten, IntPtr.Zero);

                if (numBytesWritten != junkBytes.Length)
                {
                    Console.WriteLine("Write error on track " + sectorNum.ToString() + " from " + (sectorNum * numBytesPerSector).ToString() + "-" + moveToHigh.ToString() + " " + Marshal.GetHRForLastWin32Error().ToString() + ": Only " + numBytesWritten.ToString() + "/" + junkBytes.Length.ToString() + " bytes written.");
                    break;
                }
                else
                {
                    Console.WriteLine("Write success " + Marshal.GetHRForLastWin32Error().ToString() + ": " + numBytesWritten.ToString() + "/" + junkBytes.Length.ToString() + " bytes written.");
                }
            }

            success = DeviceIoControl(diskHandle, FSCTL_UNLOCK_VOLUME, null, 0, null, 0, out intOut, IntPtr.Zero);
            if (success)
            {
                Console.WriteLine(deviceId + " " + Marshal.GetHRForLastWin32Error().ToString() + ": unlocked.");
            }
            else
            {
                Console.WriteLine(deviceId + " " + Marshal.GetHRForLastWin32Error().ToString() + ": unlock error: " + Marshal.GetHRForLastWin32Error().ToString());
            }

            success = CloseHandle(diskHandle);
            if (success)
            {
                Console.WriteLine(deviceId + " " + Marshal.GetHRForLastWin32Error().ToString() + ": handle closed.");
            }
            else
            {
                Console.WriteLine(deviceId + " " + Marshal.GetHRForLastWin32Error().ToString() + ": close handle error: " + Marshal.GetHRForLastWin32Error().ToString());
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            wipeDisk();
            MessageBox.Show("اتمام عملیات پاک سازی");
        }

        private void comboBox1_Click(object sender, EventArgs e)
        {
            comboBox1.Items.Clear();
            foreach (DriveInfo drive in DriveInfo.GetDrives())
            {
                if (drive.DriveType == DriveType.Removable)
                {
                    comboBox1.Items.Add(drive.Name);
                }
            }
            if (comboBox1.Items.Count <= 0)
                button2.Enabled = false;
            else
            {
                button2.Enabled = true;
                comboBox1.SelectedIndex = 0;
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            comboBox1_Click(null, null);

        }
    }
}