Packet.dll получить MAC-адрес (JNR-FFI) - PullRequest
0 голосов
/ 09 сентября 2018

Как можно сопоставить приведенную ниже функцию с Java с помощью jnr-ffi?

BOOLEAN PacketRequest (LPADAPTER AdapterObject, BOOLEAN Set, PPACKET_OID_DATA OidData);

Пример (C): https://github.com/patmarion/winpcap/blob/master/WpcapSrc_4_1_3/Examples/PacketDriver/GetMacAddress/GetMacAddress.c

public interface NativeMappings {

    public static class PPACKET_OID_DATA extends Struct {

        public final UnsignedLong Oid = new UnsignedLong();
        public final UnsignedLong Length = new UnsignedLong();
        public final byte[] Data = new byte[6];

        public PPACKET_OID_DATA(Runtime runtime) {
           super(runtime);
        }

    }

    Pointer PacketOpenAdapter(String AdapterName);

    int PacketRequest(Pointer AdapterObject, int set, @Out PPACKET_OID_DATA OidData);

    void PacketCloseAdapter(Pointer lpAdapter);

    public static class Main {
        public static void main(String[] args) {
            NativeMappings mappings = LibraryLoader.create(NativeMappings.class).load("Packet");
            Runtime runtime = Runtime.getRuntime(mappings);
            Pointer adapterObject = mappings.PacketOpenAdapter("\\Device\\NPF_{53152A2F-39F7-458E-BD58-24D17099256A}");
            PPACKET_OID_DATA oid_data = new PPACKET_OID_DATA(runtime);
            oid_data.Oid.set(0x01010102L);
            oid_data.Length.set(6L);
            int status = mappings.PacketRequest(adapterObject, 0, oid_data);
            if (status == 0) {
                System.out.println("Fail.");
            } else {
                System.out.println("Success.");
            }
            mappings.PacketCloseAdapter(adapterObject);
        }
    }

}

1 Ответ

0 голосов
/ 10 сентября 2018

Прежде всего, чтобы сделать раскладку пропппера, вы должны взглянуть на определения типов, которые вы отображаете. Функция PacketRequest возвращает переменную BOOLEAN. Согласно описанию типа данных windows , BOOLEAN объявлено как typedef BYTE BOOLEAN;. Это означает, что вы можете использовать тип byte как тип функции в Java. Но JNR также поддерживает отображение типа boolean в / из собственного byte. Итак, оба определения верны:

  • byte PacketRequest (...)
  • boolean PacketRequest (...)

Далее необходимо сопоставить параметры. То же самое здесь, посмотрите на определения, и вы будете знать, какие типы использовать. Результат будет:

boolean PacketRequest(Pointer AdapterObject, boolean set, PPACKET_OID_DATA OidData);

Параметр set был неправильно объявлен как int. Более того, аннотация @Out последнего поля указывает JNR передавать пустую структуру без копирования значений в собственную память. Таким образом, предварительно заданные значения не будут переданы.

Последний параметр имеет тип PPACKET_OID_DATA - структура .

struct _PACKET_OID_DATA {
   ULONG Oid;                   ///< OID code. See the Microsoft DDK documentation or the file ntddndis.h
                                ///< for a complete list of valid codes.
   ULONG Length;                ///< Length of the data field
   UCHAR Data[1];               ///< variable-lenght field that contains the information passed to or received 
                                ///< from the adapter.
}; 

Отображение структуры немного сложнее, чем для нативных типов. Вы не можете использовать типы Java здесь. Вместо этого вы должны использовать jnr.ffi.Struct внутренние классы для определения структурных полей. Это правило включает определения массивов. Правильное определение вашей структуры будет выглядеть так:

class PPACKET_OID_DATA extends Struct {

    public final UnsignedLong Oid = new UnsignedLong();
    public final UnsignedLong Length = new UnsignedLong();
    public final Unsigned8[] Data = array(new Unsigned8[6]);

    public PPACKET_OID_DATA(Runtime runtime) {
        super(runtime);
    }

}

Обратите внимание на это UCHAR определение массива. Собственно, этот тип определяется как unsigned char, поэтому для структуры JNR он будет отображаться в jnr.ffi.Strunc.Unsigned8 class или jnr.ffi.Struct.BYTE (что в значительной степени совпадает).

Чтобы объявить поле массива, вы должны инициализировать массив во время построения. Вам нужно использовать функции jnr.ffi.Struct#array(...), чтобы сделать это правильно. Это также означает, что вы должны знать размер массива. Пример показан выше.

Почему мы должны определять это так? Во время инициализации Struct является своего рода указателем переменной длины. Каждое поле внутреннего класса, инициализированное в нем, резервирует свое собственное пространство, увеличивает максимальный размер этого указателя. Таким образом, каждое поле представляет собой «представление» некоторого фрагмента памяти со своим собственным способом взаимодействия с этой памятью (публичные методы). Но чтобы создать массив таких представлений, вам нужно заполнить пустой массив экземплярами представлений. Это именно то, что делает функция array.

...