简体   繁体   English

Java获取断开连接卡的mac地址

[英]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. 我想获得以太网卡的MAC(对于产品密钥)我尝试使用这种解决方案并在这里搜索,问题是当所有网络断开连接(以太网和wifi)时,它返回空MAC地址。 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. 使用InetAddress绑定您查看IP地址列表。 If you have none because the interfaces are all disconnected, then you can't loop over such interfaces. 如果没有,因为接口都已断开连接,那么就无法遍历这些接口。

You should try with NetworkInterface class. 您应该尝试使用NetworkInterface类。

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. 如果您希望使用某些唯一的硬件标识符来验证许可证,那么我建议您使用OSHI (操作系统和硬件信息)来获取所需的硬件信息。

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. 一般原则是将硬件标识符编码为客户端许可证字符串,然后当客户端运行时,它将从许可证字符串中解码该ID,并确保存在硬件以验证许可证。 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. 如果你的许可证本身只是普通的MAC地址,那么人们很容易只需查看他们的MAC并给自己一个有效的许可证。 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. 即使您将MAC编码/加密到许可证中,他们也可以查看反编译代码并找到解码(以及编码)的工作方式,以便他们可以编码自己的有效许可证。 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. 除MAC地址外,另一个选项是绑定到磁盘。 Disk serial number is not as easy to change as MAC address. 磁盘序列号不像MAC地址那样容易更改。 With this you could bind the license to a USB key which is kinda fun. 有了这个,您可以将许可证绑定到USB密钥,这很有趣。 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 的pom.xml

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

ClientLicense.java 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); 另外,请参阅oshi oshi-demo示例类(如Daniel Widdis所述); The ComputerID.java example contains the following method: ComputerID.java示例包含以下方法:

/**
 * 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. 似乎Java标准库没有提供枚举所有网络接口的方法。

  • The InetAddress is clearly not suitable, as it represents an IP address. InetAddress显然不合适,因为它代表IP地址。
  • 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. NetworkInterface也不合适,因为它“代表一个由名称组成的网络接口,以及分配给该接口的IP地址列表” ,这意味着如果网络接口没有IP地址,则NetworkInterface是不适合代表它。 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. 当然,尽管NetworkInterface.getNetworkInterfaces()的javadoc说“返回此机器上的所有接口” ,但事实上它只返回具有IP地址的网络接口。

Note that the official tutorial to retrieve "all" network interfaces also produces a list of only the network interfaces having IP addresses. 请注意,检索“所有”网络接口的官方教程还会生成仅包含IP地址的网络接口的列表。

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. 根据操作系统的不同,您可以通过解析文件系统中的文件(如 Linux的答案 ),或通过解析系统命令的输出(如* NIX中的ifconfig或Windows中的ipconfig )来查找网络接口。 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. 想到的一个好的候选者是Go:它可以本地获取网络接口列表,并且很容易编译到所有必需的目标平台,并且二进制文件可以在不依赖于其他运行时环境的情况下使用。

Here's a simple implementation to print a list of network interfaces, one per line, the name, MAC, and IP addresses separated by tabs: 这是一个简单的实现,用于打印网络接口列表,每行一个,由制表符分隔的名称,MAC和IP地址:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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