17

我想获取以太网卡的 MAC(用于产品密钥)我尝试使用这种解决方案并在此处搜索,问题是当所有网络断开连接(以太网和 wifi)时,它返回空 MAC 地址。我宁愿得到以太网的地址,即使它已断开连接。

谢谢!!

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

3 回答 3

5

使用InetAddress绑定您查看 IP 地址列表。如果你没有,因为接口都断开了,那么你不能循环这些接口。

你应该尝试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);
    }
  }
}
于 2012-08-27T16:31:49.853 回答
3

如果您希望使用一些唯一的硬件标识符来验证许可证,那么我建议您使用OSHI(操作系统和硬件信息)来获取您需要的硬件信息。

一般主体会将硬件标识符编码到客户端许可证字符串中,然后当客户端运行时,它将从许可证字符串中解码该 ID,并确保存在硬件以验证许可证。不要依赖索引,因为通常无法保证硬件顺序,只需遍历有问题的硬件列表并查看键绑定的硬件是否存在。

注意:在本地完​​成许可证验证时,总是可以破解;关键是让破解变得烦人。如果您的许可证本身只是普通的 MAC 地址,那么人们很容易查找他们的 MAC 并给自己一个有效的许可证。即使您将 MAC 编码/加密到许可证中,他们也可以查看反编译的代码并找到解码(以及因此编码)的工作原理,以便他们可以对自己的有效许可证进行编码。您需要尽可能多地加密和混淆,以使人们难以生成自己的许可证,但最终它只会使破解变得更加烦人,但并非不可能。

除了 MAC 地址之外,另一个选项是绑定到磁盘。磁盘序列号不像MAC地址那样容易更改。有了这个,您可以将许可证绑定到 USB 密钥,这很有趣。唯一需要担心的是人们更换磁盘,但如果软件许可证绑定到存储它的磁盘,那么这几乎不是问题。

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

或者,您可以在此示例文件中看到很多硬件信息。


此外,请参阅oshi-demo(如 Daniel Widdis 所述)的示例类;该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;
}
于 2019-05-28T20:17:34.620 回答
1

Java 标准库似乎没有提供枚举所有网络接口的方法。

  • InetAddress显然不合适,因为它代表一个 IP 地址。
  • NetworkInterface也不合适,因为它“表示由名称和分配给该接口的 IP 地址列表组成的网络接口”,这意味着如果网络接口没有 IP 地址,则NetworkInterface不是很适合代表它。果然,尽管 javadocNetworkInterface.getNetworkInterfaces()“返回这台机器上的所有接口”,但实际上它只返回具有 IP 地址的网络接口。

请注意,检索“所有”网络接口的官方教程还会生成仅具有 IP 地址的网络接口的列表。

所以,你可以做什么?

我认为您别无选择,只能在运行时环境中寻找其他方法来查找此信息。根据操作系统的不同,您可以通过解析文件系统中的文件(如 Linux 的这个答案)或解析系统命令的输出(如ifconfig*NIX 或ipconfigWindows)来找到网络接口。但我不认为这会非常健壮,因为您可能需要处理不愉快的问题,例如取决于操作系统版本或系统命令的可用性和版本的不同行为。

另一种选择可能是开发一种可移植的跨平台工具,该工具能够以一种能够本地获取网络接口列表的语言,并以易于解析的一致格式生成它。然后,您可以将该工具捆绑到您的解决方案中。

想到的一个很好的候选者是 Go:它可以本地获取网络接口列表,并且很容易编译到所有需要的目标平台,并且二进制文件可以立即使用,而无需依赖额外的运行时环境。

这是一个打印网络接口列表的简单实现,每行一个,名称、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()
}
于 2019-05-23T06:30:37.017 回答