하드 디스크 일련 번호 및 물리적 어댑터 MAC 주소를 기반으로 등록 된 모든 클라이언트에 고유 한 식별자를 할당해야하는 클라이언트/서버 응용 프로그램을 개발 중입니다. ManagementObjectSearcher 또는 WMI 솔루션을 사용하는 것을 선호하지 않습니다. 원시 메소드를 사용하여 그 값을 얻으려면 어떻게해야합니까?하드 디스크 직렬 및 물리적 MAC 주소를 검색하는 가장 빠른 방법
답변
하드웨어 값에서 고유 한 식별자를 가져 오려면 등록 된 모든 클라이언트에 항상 동일한 방법을 적용하는 것이 중요하다는 사실을 명심해야합니다. 제 말은 컴퓨터에 여러 개의 HDD가 있고 아주 일반적이기 때문에 모든 사람이 첫 번째 또는 마지막 HDD를 꺼내야한다는 것입니다. 라이선스 목적으로 만이 작업을 수행하는 경우가 아니면 사용자가 컴퓨터의 하나 이상의 구성 요소를 변경했는지 이해할 수있는 허용 오차 알고리즘을 구현해야합니다. 하드웨어 값에서 고유 한 식별자를 생성하기 위해 일반적으로 사용하는 코드를 보여 드리겠습니다 ... 아마도 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()를 호출하기 만하면됩니다.
코드 스 니펫에 감사드립니다. 클라이언트가 VPN을 사용하고 있다면, MAC 주소를 조금 빗나가는 경향이 있습니다. 허용 오차 알고리즘이 그런 경우에 좋을까요? – user2979010
'ipconfig/all' – zerkms
사용자가 HD를 변경하면 어떻게 될까요? – spender
사용자가 여러 네트워크 어댑터 (유선 및 무선)를 사용하면 어떻습니까? –