Java Получить mac-адрес отключенной карты

Я хочу получить MAC-адрес Ethernet-карты (для ключа продукта) Я пробовал использовать такое решение и искал здесь, проблема в том, что когда все сети отключены (ethernet и wifi), он возвращает пустой MAC-адрес. Я скорее получаю адрес ethernet, даже если он отключен.

Спасибо!!

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

Ответ 1

Использование 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);
    }
  }
}

Ответ 2

Если вы хотите использовать какой-то уникальный идентификатор оборудования для проверки лицензии, я рекомендую использовать OSHI (Информация об операционной системе и оборудовании) для получения необходимой вам информации об оборудовании.

Основным принципалом будет кодирование идентификатора оборудования в строку клиентской лицензии, затем при запуске клиента он будет декодировать этот идентификатор из строки лицензии и удостовериться в наличии оборудования для проверки лицензии. Не зависите от индексов, потому что зачастую нет гарантии порядка оборудования, просто переберите список оборудования, о котором идет речь, и посмотрите, присутствует ли тот, к которому привязан ключ.

Примечание. Когда проверка лицензии выполняется локально, ее всегда можно взломать; Дело в том, чтобы сделать его раздражающим, чтобы взломать. Если бы ваша лицензия сама по себе была простым 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 (как упомянуто Дэниелом Виддисом); Пример 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;
}

Ответ 3

Кажется, стандартная библиотека Java не обеспечивает способ перечисления всех сетевых интерфейсов.

  • InetAddress явно не подходит, поскольку представляет IP-адрес.
  • NetworkInterface также не подходит, потому что он "представляет сетевой интерфейс, состоящий из имени и списка IP-адресов, назначенных этому интерфейсу", что подразумевает, что если сетевой интерфейс не имеет IP-адреса, то NetworkInterface не подходит для представления. И, конечно же, несмотря на javadoc NetworkInterface.getNetworkInterfaces() говорящий "возвращает все интерфейсы на этом компьютере", фактически он возвращает только сетевые интерфейсы, которые имеют IP-адреса.

Обратите внимание, что официальный учебник по извлечению "всех" сетевых интерфейсов также создает список только сетевых интерфейсов, имеющих IP-адреса.

Так что ты можешь сделать?

Я думаю, что у вас нет выбора, кроме как искать другие способы поиска этой информации в среде выполнения. В зависимости от операционной системы вы можете найти сетевые интерфейсы, анализируя файлы в файловой системе (как в этом ответе для Linux), или анализируя выходные данные системных команд, таких как ifconfig в * NIX или ipconfig в Windows. Но я не думаю, что это было бы очень надежно, так как вам, возможно, придется иметь дело с неприятными проблемами, такими как различное поведение в зависимости от версии операционной системы или доступности и версии системных команд.

Другой вариант может заключаться в разработке переносимого кроссплатформенного инструмента на языке, который способен изначально получать список сетевых интерфейсов и создавать его в согласованном формате, который легко анализировать. Затем вы можете объединить этот инструмент в своем решении.

Хорошим кандидатом, который приходит на ум, является 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()
}