How to detect the original MAC address after it has been spoofed?

We are using the following code for retrieving active MAC address of a windows pc.

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;
}

It works fine to retrieve the MAC address. The problem is when the MAC address is spoofed then it returns the spoofed MAC address. We want to somehow retrieve the original MAC address which is unique and assigned at the factory. Is there any way to do so?


I wish to give an alternative. I don't know if it really answer to 'a way to uniquely identify any computer'.
However, this method query the Win32_BIOS class in System.Management and return a string with high chances to be unique. (Waiting to be disavowed!!)

/// <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();
}

There can be two alternatives.

  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
    

(( I found it here http://snipplr.com/view/23006/ ))


I had to write something similar a little while ago because I was using a number of hardware parameters for "activation" of my software.

Have a look at, DeviceIoControl & OID_802_3_PERMANENT_ADDRESS. Its a lot of interop code (my class for handling it is approximatley 200 lines), but it gets me the hardware code guaranteed.

Some code snippets to get you going,

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);
    }
}

Well, I wouldn't bet all my money on the order in which NetworkInterface class lists NetworkInterfaces. My mainboard has 2 adapters and the order seems to switch every time I reboot.

So here is a suggestion, which worked for me (BTW : credits goes probably to another awesome stackoverflow contributer, ty) :

    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;
    }