简体   繁体   中英

Java Get mac address of disconnected card

I want to get the MAC of the ethernet card (for product key) I tried using this kind of solution and searched here, the problem is that when all the networking is disconnected (ethernet and wifi) it returns empty MAC adress. I rather get the adress of the ethernet even if it's disconnected.

Thanks!!

   public static void main(String[] args)
    {
        InetAddress ip;
        try {
            ip = InetAddress.getLocalHost();

            System.out.println("The mac Address of this machine is :" + ip.getHostAddress());

            NetworkInterface network = NetworkInterface.getByInetAddress(ip);

            byte[] mac = network.getHardwareAddress();

            System.out.print("The mac address is : ");

            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < mac.length; i++){
                sb.append(String.format("%02X%s", mac[i],(i< mac.length - 1)?"-":""));
            }

            System.out.println(sb.toString());

        } 
        catch (UnknownHostException e) {
            e.printStackTrace();
        } 
        catch (SocketException e) {
            e.printStackTrace();
        }
    }
}

Using InetAddress binds you to look in a list of IP addresses. If you have none because the interfaces are all disconnected, then you can't loop over such interfaces.

You should try with NetworkInterface class.

public class MacAddressTest
{
  public static void main(String[] args) throws Exception
  {
    Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();

    while (interfaces.hasMoreElements())
    {
      NetworkInterface nif = interfaces.nextElement();
      byte[] lBytes = nif.getHardwareAddress();
      StringBuffer lStringBuffer = new StringBuffer();

      if (lBytes != null)
      {
        for (byte b : lBytes)
        {
          lStringBuffer.append(String.format("%1$02X ", new Byte(b)));
        }
      }

      System.out.println(lStringBuffer);
    }
  }
}

If you are looking to use some unique hardware identifier to validate a license then I recommend using OSHI (Operating System and Hardware Information) to get the hardware information you need.

The general principal would be encode the hardware identifier into the client license string then when the client runs it would decode that id from the license string and make sure that hardware is present to validate the license. Don't depend on indices because there's often no guarantee of hardware order, just iterate through the list of hardware in question and see if the one the key is bound to is present.

Note: When license validation is done locally it can always be cracked; The point is just to make it annoying to crack. If your license were just the plain MAC address by itself then it would be very easy for people to just look up their MAC and give themselves a valid license. Even if you encode/encrypt the MAC into the license, they could look at the decompiled code and find the how the decoding (and hence encoding) works so that they could encode their own valid license. You need to encrypt and obfuscate as much as possible to make it hard for people to generate their own licenses but in the end it only makes it more annoying to crack but not impossible.

Another option, aside from MAC address, is binding to a disk. Disk serial number is not as easy to change as MAC address. With this you could bind the license to a USB key which is kinda fun. The only thing to worry about is people changing out disks but if the software license is bound to the disk it's stored on then that's hardly a problem.

pom.xml

...
<dependencies>
    <dependency>
        <groupId>com.github.oshi</groupId>
        <artifactId>oshi-core</artifactId>
        <version>3.13.2</version>
    </dependency>
</dependencies>
...

ClientLicense.java

import oshi.SystemInfo;
import oshi.hardware.HWDiskStore;
import oshi.hardware.HardwareAbstractionLayer;
import oshi.hardware.NetworkIF;

/**
 * This class would be loaded with the client license and validate that the license is for the machine running this code.
 */
public class ClientLicense {
    final String clientLicenseString;

    public ClientLicense(String clientLicenseString) {
        this.clientLicenseString = clientLicenseString;
    }

    public final boolean validateByDisk() {
        int expectedModelSerialHash = decodeExpectedModelSerialHash(clientLicenseString);
        for (HWDiskStore disk : new SystemInfo().getHardware().getDiskStores()) {
            if (expectedModelSerialHash == Objects.hash(disk.getModel(), disk.getSerial())) {
                return true;
            }
        }
        return false;
    }

    public final boolean validateByMAC() {
        String expectedMac = decodeExpectedMac(clientLicenseString);
        for (NetworkIF netIF : new SystemInfo().getHardware().getNetworkIFs()) {
            if (expectedMac.equals(netIF.getMacaddr())) {
                return true;
            }
        }
        return false;
    }

    private int decodeExpectedModelSerialHash(String clientLicenseString) {
        // obfuscate license decoding, inverse of license encoding/encrypting
        return 0; // return the expected hash of model and serial
    }

    private String decodeExpectedMac(String clientLicenseString) {
        // obfuscate license decoding, inverse of license encoding/encrypting
        return ""; // return the expected MAC address
    }
}

Alternatively, you can see a lot of the hardware information that you can get in this example file .


Additionally, see example classes at oshi-demo (as mentioned by Daniel Widdis); The ComputerID.java example contains the following method:

/**
 * Generates a Computer Identifier, which may be part of a strategy to
 * construct a licence key. (The identifier may not be unique as in one case
 * hashcode could be same for multiple values, and the result may differ
 * based on whether the program is running with sudo/root permission.) The
 * identifier string is based upon the processor serial number, vendor,
 * processor identifier, and total processor count.
 * 
 * @return A string containing four hyphen-delimited fields representing the
 *         processor; the first 3 are 32-bit hexadecimal values and the last
 *         one is an integer value.
 */
public static String getComputerIdentifier() {
    SystemInfo systemInfo = new SystemInfo();
    OperatingSystem operatingSystem = systemInfo.getOperatingSystem();
    HardwareAbstractionLayer hardwareAbstractionLayer = systemInfo.getHardware();
    CentralProcessor centralProcessor = hardwareAbstractionLayer.getProcessor();
    ComputerSystem computerSystem = hardwareAbstractionLayer.getComputerSystem();

    String vendor = operatingSystem.getManufacturer();
    String processorSerialNumber = computerSystem.getSerialNumber();
    String processorIdentifier = centralProcessor.getIdentifier();
    int processors = centralProcessor.getLogicalProcessorCount();

    String delimiter = "-";

    return String.format("%08x", vendor.hashCode()) + delimiter
            + String.format("%08x", processorSerialNumber.hashCode()) + delimiter
            + String.format("%08x", processorIdentifier.hashCode()) + delimiter + processors;
}

It seems the Java standard library doesn't provide a way to enumerate all the network interfaces.

  • The InetAddress is clearly not suitable, as it represents an IP address.
  • The NetworkInterface is also not suitable, because it "represents a Network Interface made up of a name, and a list of IP addresses assigned to this interface" , which implies that if a network interface doesn't have an IP address, then NetworkInterface is not a good fit to represent it. And sure enough, despite the javadoc of NetworkInterface.getNetworkInterfaces() saying "returns all the interfaces on this machine" , in fact it returns only the network interfaces that have IP addresses.

Note that the official tutorial to retrieve "all" network interfaces also produces a list of only the network interfaces having IP addresses.

So what can you do?

I think you have no choice but to look for other ways to find this information in the runtime environment. Depending on the operating system, you may be able to find the network interfaces by parsing through files in the filesystem (as in this answer for Linux), or by parsing the output of system commands such as ifconfig in *NIX or ipconfig in Windows. But I don't think this would be very robust, as you may need to deal with unpleasant problems such as different behaviors depending on operating system version or the availability and version of system commands.

Another option could be to develop a portable cross-platform tool in a language that is able to get the list of network interfaces natively, and produce it in consistent format that's easy to parse. Then, you could bundle that tool in your solution.

A good candidate that comes to mind is Go: it can get the list of network interfaces natively, and it's easy to compile to all required target platforms, and the binaries are ready to use without depending on additional runtime environments.

Here's a simple implementation to print a list of network interfaces, one per line, the name, MAC, and IP addresses separated by tabs:

package main

import (
    "fmt"
    "net"
    "strings"
)

func macsAndIps() {
    ifaces, err := net.Interfaces()
    if err != nil {
        fmt.Print(fmt.Errorf("could not get interfaces: %+v\n", err.Error()))
        return
    }

    for _, iface := range ifaces {
        addresses, err := iface.Addrs()
        if err != nil {
            fmt.Print(fmt.Errorf("could not get addresses for interface %v: %v\n", iface, err.Error()))
        }

        ips := []string{}
        for _, address := range addresses {
            // fmt.Printf("%#v\n", address)
            switch address.(type) {
                case *net.IPNet:
                    ips = append(ips, address.String())
            }
        }

        name := iface.Name
        mac := iface.HardwareAddr
        fmt.Printf("%v\t%v\t%s\n", name, mac, strings.Join(ips, "\t"))
    }
}

func main() {
    macsAndIps()
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM