C#/Native: Reading HDD Serial Using SCSI PassThrough

放肆的年华 提交于 2019-12-02 02:41:39

问题


I have written three different methods that make use of native CreateFile and DeviceIoControl calls in order to retrieve the HDD Serial Number (not the Model Number). The first one uses S.M.A.R.T., the second one uses Storage Query and the third one uses SCSI PassThrough. Most of my code is based on the content of this thread (with some fixes and improvements).

Here are the results I get using diskid32 utility:

Trying to read the drive IDs using physical access with admin rights

Drive Model Number________________: [ST975XXXXX]
Drive Serial Number_______________: [            6WS2XXXX]

Trying to read the drive IDs using physical access with zero rights

Product Id = [ST975XXXXX]
Serial Number = [6WS2XXXX]

Trying to read the drive IDs using Smart

Drive Model Number________________: [ST975XXXXX]
Drive Serial Number_______________: [            6WS2XXXX]

Now, here are the results using my methods:

S.M.A.R.T. = 6WS2XXXX
Storage Query = 6WS2XXXX
SCSI PassThrough = ST975XXXXX

Well... Houston we have a problem here. With the first two methods I get the correct Serial Number. With the last one I get the Model Number which is very bad. Now, here is my code:

--- METHOD ---

internal static String GetHardDiskSerialSCSIPassthrough(SafeFileHandle deviceHandle)
{
    IntPtr bufferPointer = IntPtr.Zero;
    String serial = String.Empty;
    UInt32 bytesReturned;

    SCSIPassthroughBuffered bspt = new SCSIPassthroughBuffered();
    bspt.SPT.Length = (UInt16)Marshal.SizeOf(bspt.SPT);
    bspt.SPT.CommandDescriptorBlockLength = 16;
    bspt.SPT.DataIn = 0x1;
    bspt.SPT.DataTransferLength = 64;
    bspt.SPT.DataBufferOffset = new IntPtr(Marshal.SizeOf(bspt) - 64);
    bspt.SPT.TimeOutValue = 60;
    bspt.SPT.CommandDescriptorBlock = new Byte[] { 0x12, 0x1, 0x80, 0x0, 64, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };

    Int32 bufferSize = Marshal.SizeOf(bspt);

    try
    {
        bufferPointer = Marshal.AllocHGlobal(bufferSize);

        Marshal.StructureToPtr(bspt, bufferPointer, true);

        if (DeviceIoControl(deviceHandle, 0x4D004, bufferPointer, (UInt32)bufferSize, bufferPointer, (UInt32)bufferSize, out bytesReturned, IntPtr.Zero) && (bytesReturned > 0))
        {
            SCSIPassthroughBuffered result = (SCSIPassthroughBuffered)Marshal.PtrToStructure(bufferPointer, typeof(SCSIPassthroughBuffered));
            serial = Encoding.ASCII.GetString(result.Buffer, 0, result.Buffer.Length).Replace("\0", String.Empty).Trim();
        }
    }
    finally
    {
        Marshal.FreeHGlobal(bufferPointer);
    }

    return serial;
}

--- STRUCTURES ---

[StructLayout(LayoutKind.Sequential)]
private struct SCSIPassthrough
{
    public UInt16 Length;
    public Byte SCSIStatus;
    public Byte PathID;
    public Byte TargetID;
    public Byte LogicalUnitNumber;
    public Byte CommandDescriptorBlockLength;
    public Byte SenseInfoLength;
    public Byte DataIn;
    public UInt32 DataTransferLength;
    public UInt32 TimeOutValue;
    public IntPtr DataBufferOffset;
    public UInt32 SenseInfoOffset;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
    public Byte[] CommandDescriptorBlock;
}

[StructLayout(LayoutKind.Sequential)]
private struct SCSIPassthroughBuffered
{
    public SCSIPassthrough SPT;
    public UInt32 Filler;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
    public Byte[] Buffer;
}

What am I doing wrong? Maybe using a wrong CDB?


回答1:


Your code actually runs OK for me, i.e. it returns the same data as the other methods described in the referenced thread. The only change I had to make was from:

serial = Encoding.ASCII.GetString(result.Buffer, 0, result.Buffer.Length)
                       .Replace("\0", String.Empty)
                       .Trim();

To:

serial = Encoding.ASCII.GetString(result.Buffer, 0, result.Buffer.Length)
                       .Substring(IntPtr.Size)
                       .Replace("\0", String.Empty)
                       .Trim();


来源:https://stackoverflow.com/questions/16443215/c-native-reading-hdd-serial-using-scsi-passthrough

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!