如何在MAC地址被伪装后检测到原始的MAC地址?

20
我们正在使用以下代码来获取Windows电脑的活动MAC地址。
private static string macId()
{
    return identifier("Win32_NetworkAdapterConfiguration", "MACAddress", "IPEnabled");
}

private static string identifier(string wmiClass, string wmiProperty, string wmiMustBeTrue)
{
    string result = "";
    System.Management.ManagementClass mc = new System.Management.ManagementClass(wmiClass);
    System.Management.ManagementObjectCollection moc = mc.GetInstances();
    foreach (System.Management.ManagementObject mo in moc)
    {
        if (mo[wmiMustBeTrue].ToString() == "True")
        {
            //Only get the first one
            if (result == "")
            {
                try
                {
                    result = mo[wmiProperty].ToString();
                    break;
                }
                catch
                {
                }
            }
        }
    }
    return result;
}
//Return a hardware identifier
private static string identifier(string wmiClass, string wmiProperty)
{
    string result = "";
    System.Management.ManagementClass mc = new System.Management.ManagementClass(wmiClass);
    System.Management.ManagementObjectCollection moc = mc.GetInstances();
    foreach (System.Management.ManagementObject mo in moc)
    {
        //Only get the first one
        if (result == "")
        {
            try
            {
                result = mo[wmiProperty].ToString();
                break;
            }
            catch
            {
            }
        }
    }
    return result;
}

在检索MAC地址时,它运行良好。问题在于当MAC地址被欺骗时,它返回欺骗的MAC地址。我们希望以某种方式检索出原始的MAC地址,它是唯一的并在工厂分配。有什么方法可以做到这一点吗?


11
MAC地址欺骗的整个目的是让电脑(及其上面的软件)相信它是正确的MAC地址。 - Joe
@Joe,是的。我的最初问题是“是否真的有办法唯一地识别任何计算机”?我得到了一些建议,说MAC地址可以用作唯一标识符。这就引出了这个问题。 - Sajib Mahmood
1
这里还有一些其他的想法:https://dev59.com/B3RB5IYBdhLWcg3wSVcI - Joe
1
如果有人想尝试构建一个可行的解决方案,使用IOCTL_NDIS_QUERY_GLOBAL_STATS和OID_FDDI_LONG_PERMANENT_ADDR应该可以检索硬件MAC地址。 - Harry Johnston
@SajibMahmood 有一种方法可以做到。已在下面发布答案。 - M Afifi
显示剩余6条评论
4个回答

21

我希望提供一种替代方法。我不知道它是否真正回答了“唯一标识任何计算机的方法”。
但是,这种方法查询System.Management中的Win32_BIOS类,并返回一个高度可能是唯一的字符串。(等待否认!)

/// <summary>
/// BIOS IDentifier
/// </summary>
/// <returns></returns>
public static string BIOS_ID()
{
    return    GetFirstIdentifier("Win32_BIOS", "Manufacturer")
            + GetFirstIdentifier("Win32_BIOS", "SMBIOSBIOSVersion")
            + GetFirstIdentifier("Win32_BIOS", "IdentificationCode")
            + GetFirstIdentifier("Win32_BIOS", "SerialNumber")
            + GetFirstIdentifier("Win32_BIOS", "ReleaseDate")
            + GetFirstIdentifier("Win32_BIOS", "Version");
}

/// <summary>
/// ManagementClass used to read the first specific properties
/// </summary>
/// <param name="wmiClass">Object Class to query</param>
/// <param name="wmiProperty">Property to get info</param>
/// <returns></returns>
private static string GetFirstIdentifier(string wmiClass, string wmiProperty)
{
    string result = string.Empty;
    ManagementClass mc = new System.Management.ManagementClass(wmiClass);
    ManagementObjectCollection moc = mc.GetInstances();
    foreach (ManagementObject mo in moc)
    {
        //Only get the first one
        if (string.IsNullOrEmpty(result))
        {
            try
            {
                if (mo[wmiProperty] != null) result = mo[wmiProperty].ToString();
                break;
            }
            catch
            {
            }
        }
    }
    return result.Trim();
}

谢谢你提供的替代方案,虽然我已经有了这个想法。无论如何,我感激任何合理的建议。没有什么需要否认的。 :) - Sajib Mahmood
这些参数在系统格式化或新的Windows安装时会改变吗? - mrid
我会说不,因为它们与BIOS中的数据绑定在一起。但是我还没有测试过。 - Steve
唯一的问题是我们发现许多计算机BIOS只是填充了默认字符串,通常甚至没有输入序列号。这尤其适用于几乎在BIOS中填写任何细节的较小的无风扇盒子。 - Barry Andrews
这是我PC BIOS的一个例子。[系统] 制造商=待填写O.E.M. 产品=待填写O.E.M. 版本=待填写O.E.M. 序列号=待填写O.E.M. - Barry Andrews

8

有两种选择。

  1. You can get the MAC address using the code snippet you gave before and check if that MAC address belongs to any NIC (Network Interface Card). If it doesn't belong to one, then the MAC address is obviously spoofed. Here is the code that Locates the NIC using a MAC adress

    using System.Net.Sockets;
    using System.Net;
    using System.Net.NetworkInformation;
    
    string localNicMac = "00:00:00:11:22:33".Replace(":", "-"); // Parse doesn't like colons
    
    var mac = PhysicalAddress.Parse(localNicMac);
    var localNic =
    NetworkInterface.GetAllNetworkInterfaces()
        .Where(nic => nic.GetPhysicalAddress().Equals(mac)) // Must use .Equals, not ==
        .SingleOrDefault();
    if (localNic == null)
    {
        throw new ArgumentException("Local NIC with the specified MAC could not be found.");
    }
    
    var ips =
        localNic.GetIPProperties().UnicastAddresses
        .Select(x => x.Address);
    
  2. Get the network card address directly.

    a. NWIF = dotnetClass "System.Net.NetworkInformation.NetworkInterface"  
    b. the_Mac_array = NWIF.GetAllNetworkInterfaces() -- this is an array of all the Networks  
    c. the_PhysicalAddress_Array = #()  
    d. for net in the_Mac_array where (net.NetworkInterfaceType.toString()) == "Ethernet" do append   the_PhysicalAddress_Array ((net.GetPhysicalAddress()).toString())  
    e. print the_PhysicalAddress_Array
    
我在这里找到了它 http://snipplr.com/view/23006/

1
@Guvante,不是这样的。它会向您显示欺骗的MAC地址属于相应的NIC。事实上,到目前为止我所使用的每个代码都检索当前的MAC地址,而不是在工厂分配的原始地址。 - Sajib Mahmood
你的答案没有起作用,但是你是唯一一个尝试给出实际答案的人。因此,我决定把赏金给你。 :) - Abdur Rahman
非常抱歉,我应该提到我自己没有测试过这段代码。但是如果MAC地址被欺骗了,我认为操作系统将不会将其与NIC连接起来。必须在操作系统中运行某些方法,将欺骗的MAC地址链接到NIC上,并且必须在某处存储原始MAC地址。尝试找到它可能会太复杂了。这里有一篇关于MAC地址欺骗检测的精彩论文。http://www.net-security.org/article.php?id=364 但我不确定它是否有助于检测系统中的欺骗MAC地址。@Rahman。非常感谢。赏金非常感激。 :) - HUNKY_Monkey
@HUNKY_Monkey:可能有一种使用非标准API查找它的方法,但这将随着每个NIC制造商的变化而改变,甚至可能随着每个NIC类型的变化而改变。 - Guvante

7

我不久前也写过类似的东西,因为我使用了一些硬件参数来“激活”我的软件。

可以看看DeviceIoControlOID_802_3_PERMANENT_ADDRESS。这是一堆交互代码(我处理它的类大约有200行),但是它保证获取到硬件代码。

以下是一些代码片段,帮助你入门:

private const uint IOCTL_NDIS_QUERY_GLOBAL_STATS = 0x170002;

[DllImport("Kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool DeviceIoControl(
        SafeFileHandle hDevice,
        uint dwIoControlCode,
        ref int InBuffer,
        int nInBufferSize,
        byte[] OutBuffer,
        int nOutBufferSize,
        out int pBytesReturned,
        IntPtr lpOverlapped);

[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
internal static extern SafeFileHandle CreateFile(
    string lpFileName,
    EFileAccess dwDesiredAccess,
    EFileShare dwShareMode,
    IntPtr lpSecurityAttributes,
    ECreationDisposition dwCreationDisposition,
    EFileAttributes dwFlagsAndAttributes,
    IntPtr hTemplateFile);

[Flags]
internal enum EFileAccess : uint
{
    Delete = 0x10000,
    ReadControl = 0x20000,
    WriteDAC = 0x40000,
    WriteOwner = 0x80000,
    Synchronize = 0x100000,

    StandardRightsRequired = 0xF0000,
    StandardRightsRead = ReadControl,
    StandardRightsWrite = ReadControl,
    StandardRightsExecute = ReadControl,
    StandardRightsAll = 0x1F0000,
    SpecificRightsAll = 0xFFFF,

    AccessSystemSecurity = 0x1000000,       // AccessSystemAcl access type

    MaximumAllowed = 0x2000000,         // MaximumAllowed access type

    GenericRead = 0x80000000,
    GenericWrite = 0x40000000,
    GenericExecute = 0x20000000,
    GenericAll = 0x10000000
}

// Open a file handle to the interface
using (SafeFileHandle handle = FileInterop.CreateFile(deviceName,
    FileInterop.EFileAccess.GenericRead | FileInterop.EFileAccess.GenericWrite,
    0, IntPtr.Zero, FileInterop.ECreationDisposition.OpenExisting,
    0, IntPtr.Zero))
{
    int bytesReturned;
    // Set the OID to query the permanent address
    // http://msdn.microsoft.com/en-us/library/windows/hardware/ff569074(v=vs.85).aspx
    int OID_802_3_PERMANENT_ADDRESS = 0x01010101;

    // Array to capture the mac address
    var address = new byte[6];
    if (DeviceIoControl(handle, IOCTL_NDIS_QUERY_GLOBAL_STATS,
        ref OID_802_3_PERMANENT_ADDRESS, sizeof(uint),
        address, 6, out bytesReturned, IntPtr.Zero))
    {
        // Attempt to parse the MAC address into a string
        // any exceptions will be passed onto the caller
        return BitConverter.ToString(address, 0, 6);
    }
}

这看起来很有前途。谢谢 :) 我会测试并告诉你。 - Sajib Mahmood
1
@SajibMahmood 如果你遇到问题,请告诉我。我的软件已经在超过250种不同的计算机硬件上运行了超过150,000台机器。它总是捕获MAC地址。不幸的是,使用WMI你不会得到那样的成功率。 - M Afifi
@SajibMahmood 是的,已经测试过从 Windows XP 32 位升级到 Windows 7 64 位。 - M Afifi
那可能是我的错误。出于某种原因,我仍然没有在这个问题上找到任何成功的方法。不过,由于其他事情,我没能花太多时间来解决它。让我再试一次。感谢您的合作。 - Sajib Mahmood
没有 EFileShareECreationDispositionEFileAttributes - mrid

1

嗯,我不会把所有的钱都压在NetworkInterface类列出网络接口的顺序上。 我的主板有两个适配器,每次重新启动时顺序似乎都会变化。

所以这里是一个建议,对我有效(顺便说一句:这个想法可能来自于另一个很棒的stackoverflow贡献者,谢谢):

    public static string GetMACAddress()
    {
        NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces();
        //for each j you can get the MAC 
        PhysicalAddress address = nics[0].GetPhysicalAddress();
        byte[] bytes = address.GetAddressBytes();

        string macAddress = "";

        for (int i = 0; i < bytes.Length; i++)
        {
            // Format the physical address in hexadecimal. 
            macAddress += bytes[i].ToString("X2");
            // Insert a hyphen after each byte, unless we are at the end of the address. 
            if (i != bytes.Length - 1)
            {
                macAddress += "-";
            }
        }

        return macAddress;
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接