Get HDD Serial by SCSI MINIPORT

0

Getting Real hdd serial with out admin right is hard.

I've found this small piece of software, which does exactly that what I want to implement in C#.net. Luckily, the source code is also available.

Basically I would like to implement the function ReadIdeDriveAsScsiDriveInNT from diskid32 in C#.

How I communicate with the device:

public class HDDSerial
{


    public const int FILE_DEVICE_SCSI = 0x0000001b;
    public const int IOCTL_SCSI_MINIPORT_IDENTIFY = ((FILE_DEVICE_SCSI <<        16) + 0x0501);
    public const int IOCTL_SCSI_MINIPORT = 0x0004D008;
    public const int ATA_IDENTIFY = 0xEC;



    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    private static extern bool DeviceIoControl(
        SafeFileHandle device,
        int inputOutputControlCode,
        ref byte[] inputBuffer,
        int inputBufferSize,
        ref byte[] outputBuffer,
        int outputBufferSize,
        ref uint bytesCount,
        int overlapped);




    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    internal static extern SafeFileHandle CreateFile(string lpFileName,
        FileAccess dwDesiredAccess,
        FileShare dwShareMode,
        uint lpSecurityAttributes,
        FileMode dwCreationDisposition,
        int flagsAndAttributes,
        uint hTemplateFile);


    [StructLayout(LayoutKind.Sequential, Size = 8)]
    private class IDEREGS
    {
        public byte Features;
        public byte SectorCount;
        public byte SectorNumber;
        public byte CylinderLow;
        public byte CylinderHigh;
        public byte DriveHead;
        public byte Command;
        public byte Reserved;
    }

    [StructLayout(LayoutKind.Sequential, Size = 32)]
    private class SENDCMDINPARAMS
    {
        public int BufferSize;
        public IDEREGS DriveRegs;
        public byte DriveNumber;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
        public byte[] Reserved;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
        public int[] Reserved2;
        public SENDCMDINPARAMS()
        {
            DriveRegs = new IDEREGS();
            Reserved = new byte[3];
            Reserved2 = new int[4];
        }
    }
    [StructLayout(LayoutKind.Sequential, Size = 12)]
    private class DRIVERSTATUS
    {
        public byte DriveError;
        public byte IDEStatus;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
        public byte[] Reserved;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
        public int[] Reserved2;
        public DRIVERSTATUS()
        {
            Reserved = new byte[2];
            Reserved2 = new int[2];
        }
    }

    [StructLayout(LayoutKind.Sequential)]
    private class IDSECTOR
    {
        public short GenConfig;
        public short NumberCylinders;
        public short Reserved;
        public short NumberHeads;
        public short BytesPerTrack;
        public short BytesPerSector;
        public short SectorsPerTrack;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
        public short[] VendorUnique;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
        public char[] SerialNumber;
        public short BufferClass;
        public short BufferSize;
        public short ECCSize;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
        public char[] FirmwareRevision;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]
        public char[] ModelNumber;
        public short MoreVendorUnique;
        public short DoubleWordIO;
        public short Capabilities;
        public short Reserved1;
        public short PIOTiming;
        public short DMATiming;
        public short BS;
        public short NumberCurrentCyls;
        public short NumberCurrentHeads;
        public short NumberCurrentSectorsPerTrack;
        public int CurrentSectorCapacity;
        public short MultipleSectorCapacity;
        public short MultipleSectorStuff;
        public int TotalAddressableSectors;
        public short SingleWordDMA;
        public short MultiWordDMA;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 382)]
        public byte[] Reserved2;
        public IDSECTOR()
        {
            VendorUnique = new short[3];
            Reserved2 = new byte[382];
            FirmwareRevision = new char[8];
            SerialNumber = new char[20];
            ModelNumber = new char[40];
        }
    }

    [StructLayout(LayoutKind.Sequential)]
    private class SENDCMDOUTPARAMS
    {
        public int BufferSize;
        public DRIVERSTATUS Status;
        public IDSECTOR IDS;
        public SENDCMDOUTPARAMS()
        {
            Status = new DRIVERSTATUS();
            IDS = new IDSECTOR();
        }
    }


    [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 512)]
    public struct IDENTIFY_DATA
    {
        public ushort wGenConfig;
        public ushort wNumCyls;
        public ushort wReserved;
        public ushort wNumHeads;
        public ushort wBytesPerTrack;
        public ushort wBytesPerSector;
        public ushort wSectorsPerTrack;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
        public ushort[] wVendorUnique;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
        public byte[] sSerialNumber;
        public ushort wBufferType;
        public ushort wBufferSize;
        public ushort wECCSize;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
        public byte[] sFirmwareRev;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]
        public byte[] sModelNumber;
        public ushort wMoreVendorUnique;
        public ushort wDoubleWordIO;
        public ushort wCapabilities;
        public ushort wReservedl;
        public ushort wPIOTiming;
        public ushort wDMATiming;
        public ushort wBS;
        public ushort wNumCurrentCyls;
        public ushort wNumCurrentHeads;
        public ushort wNumCurrentSectorsPerTrack;
        public uint ulCurrentSectorCapacity;
        public ushort wMultSectorStuff;
        public uint ulTotalAddressableSectors;
        public ushort wSingleWordDMA;
        public ushort wMultiWordDMA;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
        public byte[] bReserved;
    }
    [StructLayout(LayoutKind.Sequential)]
    internal struct SRB_IO_CONTROL
    {
        public uint HeaderLength;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
        public byte[] Signature;
        public uint Timeout;
        public uint ControlCode;
        public uint ReturnCode;
        public uint Length;
    }

    private SafeFileHandle OpenScsi(int scsiNumber)
    {
        var device = CreateFile(
            string.Format(@"\\.\Scsi{0}:", scsiNumber),
            FileAccess.Read | FileAccess.Write,
            FileShare.ReadWrite,
            0,
            FileMode.Open,
            0,
            0);
        if (device.IsInvalid)
        {
            throw new Exception(string.Format(@"Error during the creation of a safe file handle for \\.\Scsi{0}:", scsiNumber));
        }
        return device;
    }
    public string Swap(string input)
    {
        var characters = input.ToCharArray();
        var returnValue = new StringBuilder();
        for (var i = 0; i < characters.Length; i++)
        {
            if (i % 2 != 0)
            {
                continue;
            }
            if ((i + 1) < characters.Length)
            {
                returnValue.Append(characters[i + 1]);
            }
            returnValue.Append(characters[i]);
        }
        return returnValue.ToString();
    }




    public string GetSerialNumberUsingMiniportDriver(int busNumber, byte deviceNumber = 0)
    {

        using (var device = OpenScsi(busNumber))
        {
            var bytesReturned = default(uint);
            var sic = new SRB_IO_CONTROL();
            var sop = new SENDCMDOUTPARAMS();
            var sip = new SENDCMDINPARAMS();
            var id = new IDENTIFY_DATA();
            var buffer = new byte[Marshal.SizeOf(sic) + Marshal.SizeOf(sop) + Marshal.SizeOf(id)];

            sic.HeaderLength = (uint)Marshal.SizeOf(sic);
            sic.Timeout = 10000;
            sic.Length = (uint)(Marshal.SizeOf(sop) + Marshal.SizeOf(id));
            sic.ControlCode = IOCTL_SCSI_MINIPORT_IDENTIFY;


            sic.Signature = Encoding.ASCII.GetBytes("SCSIDISK".ToCharArray());

            var ptr = Marshal.AllocHGlobal(Marshal.SizeOf(sic));
            Marshal.StructureToPtr(sic, ptr, true);
            Marshal.Copy(ptr, buffer, 0, Marshal.SizeOf(sic));

            sip.DriveRegs.Command = (byte)ATA_IDENTIFY; 
            sip.DriveNumber = deviceNumber;

            ptr = Marshal.AllocHGlobal(Marshal.SizeOf(sip));
            Marshal.StructureToPtr(sip, ptr, true);
            Marshal.Copy(ptr, buffer, Marshal.SizeOf(sic), Marshal.SizeOf(sip));

            if (
                        !DeviceIoControl(
                            device,
                            IOCTL_SCSI_MINIPORT,
                            ref buffer,
                            (int)(Marshal.SizeOf(sic) + Marshal.SizeOf(sip) - 1),
                            ref buffer,
                            (int)(Marshal.SizeOf(sic) + Marshal.SizeOf(sop) + Marshal.SizeOf(id)),
                            ref bytesReturned,
                            0))
            {
                throw new Exception("Device Io Error");
            }

            var resultPtr = Marshal.AllocHGlobal(Marshal.SizeOf(id));
            Marshal.Copy(buffer, Marshal.SizeOf(sic) + Marshal.SizeOf(sop), resultPtr, Marshal.SizeOf(id));

            id = (IDENTIFY_DATA)Marshal.PtrToStructure(resultPtr, typeof(IDENTIFY_DATA));

            var model = Encoding.ASCII.GetString(id.sSerialNumber).Replace('\0', ' ').Trim();
            model = Swap(model);

            return model.Trim();
        }
    }
}

I found "Device Io Error" here. Please, Any suggestion or link that will help to solve this problem. Thank you...

c#
asked on Stack Overflow Mar 22, 2018 by Ripon Ali

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0