最快的方式检索硬盘串行和物理MAC地址

本文关键字:MAC 地址 方式 检索 硬盘 | 更新日期: 2023-09-27 17:52:59

我正在开发一个客户端/服务器应用程序,需要根据硬盘序列号和物理适配器MAC地址为每个注册客户端分配唯一标识符…但我不喜欢使用managentobjectsearcher或任何WMI解决方案,因为它们很慢。如何使用本机方法获得这些值?

最快的方式检索硬盘串行和物理MAC地址

如果您想从硬件值中获得唯一标识符,您必须记住,对于每个已注册的客户端始终应用相同的方法非常重要。我的意思是,如果一台机器有多个硬盘(这很常见),那么您总是需要为每个人从第一个或最后一个硬盘中取出串行。除非您只是出于许可目的而这样做,否则您还必须实现能够理解用户是否更改了其计算机的一个或多个组件的容差算法。我将向您展示我通常用于从硬件值中创建唯一标识符的代码……它可能有点过时,特别是对于64x的支持(注册表项和指针,特别是),但它只是给你一个想法。指纹仅使用本地方法从第一个HDD串行、第一个适配器MAC地址和SMBIOS数据中创建。

public static class HardwareAnalyzer
{
#region Methods: Imports
[DllImport("Iphlpapi.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
internal static extern Int32 GetAdaptersInfo(IntPtr handle, ref UInt32 size);
[DllImport("Kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern Boolean CloseHandle([In] IntPtr handle);
[DllImport("Kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern Boolean DeviceIoControl([In] IntPtr handle, [In] UInt32 controlCode, [In, Optional] IntPtr bufferIn, [In] UInt32 bufferInSize, [Out, Optional] IntPtr bufferOut, [In] UInt32 bufferOutSize,  [Out] out UInt32 bytesReturned, [In, Out, Optional] IntPtr overlapped);
[DllImport("Kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = false, SetLastError = true)]
internal static extern IntPtr CreateFile([In] String fileName, [In] eFileAccess fileAccess, [In] EFileShare fileShare, [In, Optional] IntPtr fileSecurity, [In] eCreationDisposition creationDisposition, [In] UInt32 flags, [In, Optional] IntPtr handleTemplateFile);
#endregion
#region Methods: Functions
private static String RetrieveDiskSerial()
{
    String serial = String.Empty;
    try
    {
        IntPtr handle = IntPtr.Zero;
        for (Int32 i = 0; i < 16; ++i)
        {
            handle = CreateFile(String.Format("''''.''PhysicalDrive{0}", i), (eFileAccess.GenericRead | eFileAccess.GenericWrite), (EFileShare.Read | EFileShare.Write), IntPtr.Zero, eCreationDisposition.OpenExisting, 0, IntPtr.Zero);
            if (handle != IntPtr.Zero)
            {
                serial = RetrieveDiskSerialSmart(handle);
                if (serial.Length == 0)
                    serial = RetrieveDiskSerialStorageQuery(handle);
                if (serial.Length == 0)
                    continue;
                if (!CloseHandle(handle))
                    Console.WriteLine("WARNING: a file handle has not been correctly closed.");
                break;
            }
        }
    }
    catch { }
    return serial;
}
private static String RetrieveDiskSerialSmart(IntPtr handle)
{
    IntPtr bufferIn = Marshal.AllocHGlobal(32);
    IntPtr bufferOut = Marshal.AllocHGlobal(24);
    String serial = String.Empty;
    UInt32 bytesReturned = 0;
    try
    {
        if (DeviceIoControl(handle, 0x074080, IntPtr.Zero, 0, bufferOut, 24, out bytesReturned, IntPtr.Zero))
        {
            if ((Marshal.ReadInt32(bufferOut, 4) & 4) > 0)
            {
                SCInputParameters parameters = new SCInputParameters();
                bufferOut = Marshal.ReAllocHGlobal(bufferOut, (IntPtr)528);
                Marshal.StructureToPtr(parameters, bufferIn, true);
                if (DeviceIoControl(handle, 0x07C088, bufferIn, 32, bufferOut, 528, out bytesReturned, IntPtr.Zero))
                {
                    String serialANSI = Marshal.PtrToStringAnsi((IntPtr)(bufferOut.ToInt32() + 36), 20);
                    if (serialANSI.Length != 0)
                    {
                        Char[] serialANSICharacters = serialANSI.ToCharArray();
                        for (Int32 i = 0; i <= (serialANSICharacters.Length - 2); i += 2)
                        {
                            Char current = serialANSICharacters[i];
                            serialANSICharacters[i] = serialANSICharacters[(i + 1)];
                            serialANSICharacters[(i + 1)] = current;
                        }
                        serial = new String(serialANSICharacters).Trim();
                    }
                }
            }
        }
    }
    finally
    {
        Marshal.FreeHGlobal(bufferIn);
        Marshal.FreeHGlobal(bufferOut);
    }
    return serial;
}
private static String RetrieveDiskSerialStorageQuery(IntPtr handle)
{
    IntPtr bufferIn = Marshal.AllocHGlobal(12);
    IntPtr bufferOut = Marshal.AllocHGlobal(1024);
    StoragePropertyQuery query = new StoragePropertyQuery();
    String serial = String.Empty;
    UInt32 bytesReturned = 0;
    try
    {
        Marshal.StructureToPtr(query, bufferIn, true);
        if (DeviceIoControl(handle, 0x2D1400, bufferIn, 12, bufferOut, 1024, out bytesReturned, IntPtr.Zero))
        {
            Int32 address = bufferOut.ToInt32();
            Int32 offset = Marshal.ReadInt32(bufferOut, 24);
            if (offset != 0)
            {
                String serialANSI = Marshal.PtrToStringAnsi((IntPtr)(address + offset));
                if (serialANSI.Length != 0)
                {
                    StringBuilder builder = new StringBuilder();
                    for (Int32 i = 0; i < serialANSI.Length; i += 4)
                    {
                        for (Int32 j = 1; j >= 0; --j)
                        {
                            Int32 sum = 0;
                            for (Int32 y = 0; y < 2; ++y)
                            {
                                sum *= 16;
                                switch (serialANSI[(i + (j * 2) + y)])
                                {
                                    case '0':
                                        sum += 0;
                                        break;
                                    case '1':
                                        sum += 1;
                                        break;
                                    case '2':
                                        sum += 2;
                                        break;
                                    case '3':
                                        sum += 3;
                                        break;
                                    case '4':
                                        sum += 4;
                                        break;
                                    case '5':
                                        sum += 5;
                                        break;
                                    case '6':
                                        sum += 6;
                                        break;
                                    case '7':
                                        sum += 7;
                                        break;
                                    case '8':
                                        sum += 8;
                                        break;
                                    case '9':
                                        sum += 9;
                                        break;
                                    case 'a':
                                        sum += 10;
                                        break;
                                    case 'b':
                                        sum += 11;
                                        break;
                                    case 'c':
                                        sum += 12;
                                        break;
                                    case 'd':
                                        sum += 13;
                                        break;
                                    case 'e':
                                        sum += 14;
                                        break;
                                    case 'f':
                                        sum += 15;
                                        break;
                                }
                            }
                            if (sum > 0)
                                builder.Append((Char)sum);
                        }
                    }
                    serial = builder.ToString().Trim();
                }
            }
        }
    }
    finally
    {
        Marshal.FreeHGlobal(bufferIn);
        Marshal.FreeHGlobal(bufferOut);
    }
    return serial;
}
private static String RetrieveMACAddress()
{
    String address = String.Empty;
    try
    {
        UInt32 size = 0;
        Int32 result = GetAdaptersInfo(IntPtr.Zero, ref size);
        if ((result == 0) || (result == 111))
        {
            IntPtr buffer = Marshal.AllocHGlobal((IntPtr)size);
            result = GetAdaptersInfo(buffer, ref size);
            if (result == 0)
            {
                while (true)
                {
                    String adapterName = Marshal.PtrToStringAnsi((IntPtr)(buffer.ToInt32() + 8));
                    IntPtr handle = CreateFile(String.Format("''''.''{0}", adapterName), (eFileAccess.GenericRead | eFileAccess.GenericWrite), (EFileShare.Read | EFileShare.Write), IntPtr.Zero, eCreationDisposition.OpenExisting, 0, IntPtr.Zero);
                    if (handle != IntPtr.Zero)
                    {
                        IntPtr bufferIn = GCHandle.Alloc(0x1010101, GCHandleType.Pinned).AddrOfPinnedObject();
                        IntPtr bufferOut = Marshal.AllocHGlobal(6);
                        UInt32 bytesReturned = 0;
                        try
                        {
                            if (DeviceIoControl(handle, 0x170002, bufferIn, 4, bufferOut, 6, out bytesReturned, IntPtr.Zero))
                            {
                                String temporaryAddress = String.Empty;
                                for (Int32 i = 0; i < 6; ++i)
                                    temporaryAddress += Marshal.ReadByte(bufferOut, i).ToString("X2") + ((i == 5) ? "" : ":");
                                if (temporaryAddress != "00:00:00:00:00:00")
                                {
                                    address = temporaryAddress;
                                    break;
                                }
                            }
                        }
                        finally
                        {
                            if (!CloseHandle(handle))
                                Console.WriteLine("WARNING: a file handle has not been correctly closed.");
                            Marshal.FreeHGlobal(bufferOut);
                        }
                    }
                    Int32 nextAdapterOffset = Marshal.ReadInt32(buffer);
                    if (nextAdapterOffset != 0)
                        buffer = (IntPtr)nextAdapterOffset;
                    else
                        break;
                }
            }
        }
    }
    catch { }
    return address;
}
private static String RetrieveSMBiosData()
{
    String data = String.Empty;
    try
    {
        using (RegistryKey key = Registry.LocalMachine.OpenSubKey(@"System'CurrentControlSet'Services'MSSMBios'Data", false))
        {
            if (key != null)
            {
                Byte[] keyData = (Byte[])key.GetValue("SMBiosData");
                if (keyData != null)
                {
                    using (MD5CryptoServiceProvider provider = new MD5CryptoServiceProvider())
                        keyData = provider.ComputeHash(keyData);
                    for (Int32 i = 0; i < keyData.Length; ++i)
                        data += keyData[i].ToString("X2");
                }
            }
        }
    }
    catch { }
    return data;
}
public static String CreateFingerprint()
{
    String serial = RetrieveDiskSerial();
    String address = RetrieveMACAddress();
    String data = RetrieveSMBiosData();
    if ((serial.Length == 0) && (address.Length == 0) && (data.Length == 0))
        return "0000-0000-0000-0000-0000-0000-0000-0000";
    String fingerprint = String.Empty;
    using (MD5CryptoServiceProvider provider = new MD5CryptoServiceProvider())
    {
        Byte[] hash = provider.ComputeHash(Encoding.ASCII.GetBytes(serial + " - " + address + " - " + data));
        for (Int32 i = 0; i < 16; ++i)
        {
            fingerprint += hash[i].ToString("X2");
            if (((i & 1) != 0) && (i != 15))
                fingerprint += "-";
        }
    }
    return fingerprint;
}
#endregion
#region Nesting: Enumerators
public enum eCreationDisposition : uint
{
    New              = 1,
    CreateAlways     = 2,
    OpenExisting     = 3,
    OpenAlways       = 4,
    TruncateExisting = 5
}
[Flags]
public enum eFileAccess : uint
{
    Delete               = 0x00010000,
    ReadControl          = 0x00020000,
    WriteDAC             = 0x00040000,
    WriteOwner           = 0x00080000,
    Synchronize          = 0x00100000,
    AccessSystemSecurity = 0x01000000,
    MaximumAllowed       = 0x02000000,
    GenericAll           = 0x10000000,
    GenericExecute       = 0x20000000,
    GenericWrite         = 0x40000000,
    GenericRead          = 0x80000000
}
[Flags]
public enum EFileShare : uint
{
    None   = 0x00000000,
    Read   = 0x00000001,
    Write  = 0x00000002,
    Delete = 0x00000004
}
#endregion
#region Nesting: Structures
[StructLayout(LayoutKind.Sequential)]
private class SCInputParameters
{
    private int BufferSize = 528;
    private Byte Features = 0;
    private Byte SectorCount = 1;
    private Byte SectorNumber = 1;
    private Byte LowOrderCylinder = 0;
    private Byte HighOrderCylinder = 0;
    private Byte DriveHead = 160;
    private Byte Command = 236;
    private Byte Reserved = 0;
    private Byte DriveNumber = 0;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
    private Byte[] UselessData = new Byte[16];
}
[StructLayout(LayoutKind.Sequential)]
private class StoragePropertyQuery
{
    private Int32 PropertyID;
    private Int32 QueryType;
    private Int32 UselessData;
}
#endregion
}

你只需要调用HardwareAnalyzer.CreateFingerprint()来获得你需要的