我正在开发一个客户端/服务器应用程序,需要根据硬盘序列号和物理适配器MAC地址为每个注册的客户端分配一个唯一的标识符...但我不想使用ManagementObjectSearcher或任何WMI解决方案,因为它们很慢。如何使用本机方法获取这些值?
答案 0 :(得分:5)
如果您想从硬件值中获取唯一标识符,则必须记住,对每个注册客户端应用始终相同的方法非常重要。我的意思是,如果一台机器有多个硬盘驱动器,并且它很常见,那么对于每个人来说,你将始终必须从第一个或最后一个中取出序列。 除非您仅为了许可目的而这样做,否则您还必须实现容差算法,该算法能够理解用户是否更改了其计算机的一个或多个组件。 我将向您展示我通常用于从硬件值创建唯一标识符的代码...它可能有点过时,特别是对于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()即可获得所需内容。