WlanAPI WlanGetNetworkBssList返回无效数据

时间:2017-01-25 21:11:02

标签: delphi wlanapi

我通过调用WlanGetNetworkBssList来调试我的调试工作,并希望得到一些指示。我的最终目标是构建一个Wifi扫描仪/分析器工具,以帮助我解决远程站点上的网络问题。

我在Windows 10(VCL)下使用Delphi Berlin 10.1 Update 2使用Windows Native Wifi API(link)和Delphi / Pascal接口here

我从一个简单粗暴的测试应用程序(VCL)开始,以了解API并遇到调用WlanGetNetworkBssList的问题,因此我创建了一个专注于该问题的小型控制台应用程序。问题是它适用于在命令提示符下运行的控制台应用程序,但不适用于我的VCL测试应用程序。这些函数非常类似于复制粘贴,并且逐步执行代码显示数据是相同的,除了来自WlanGetNetworkBssList调用的返回数据(pWlanBssList)

问题:由于调用外部DLL,我可以采取哪些步骤来进一步调试此操作并了解VCL和控制台应用程序之间的区别。

注意:WlanGetNetworkBssList有两种操作模式,其中可以提供SSID以获取该特定SSID的BSSID(接入点的MAC)。通过传递NULL而不是SSID,API将返回所有AP的BSSID。传递NULL适用于VLC和控制台应用程序。当请求特定SSID时会发生什么中断。验证后,两个应用程序中的SSID数据结构相同,但返回的数据缓冲区对VCL应用程序无效。怎么会这样?

控制台应用:

program CWifiScan;

{$APPTYPE CONSOLE}

uses
  Windows,
  System.SysUtils,
  nduWlanAPI,
  nduWlanTypes;
const
  WLAN_AVAILABLE_NETWORK_INCLUDE_ALL_ADHOC_PROFILES = $00000001;
var
  hWlan: THandle;
  guid : TGUID;
  dwSupportedVersion: DWORD = 0;
  dwClientVersion: DWORD = 1;
  i,j                   : integer;
  pInterfaceInfo        : Pndu_WLAN_INTERFACE_INFO;
  pInterfaceList        : Pndu_WLAN_INTERFACE_INFO_LIST;
  pAvailableNetworkList : Pndu_WLAN_AVAILABLE_NETWORK_LIST;

procedure GetBSSIDList(clientHandle  : THandle;
                          interfaceGUID : TGUID;
                          pSSID         : Pndu_DOT11_SSID = nil;
                          SSID_Type     : Tndu_DOT11_BSS_Type = dot11_BSS_type_any;
                          SecurityEnabled : BOOL = True);
var
  //to check if interface is connected
  pData         : Pndu_WLAN_INTERFACE_STATE;
  pdwDataSize   : DWORD;
  isConnected   : Boolean;
  //to get list of BSSids from available APs
  pWlanBssList : Pndu_WLAN_BSS_LIST;
  items         : integer;
  itemIndex     : integer;
  SSID          : string;
  MAC           : string;
begin
  //check if interface is connected
  isConnected := False;
  if WlanQueryInterface(clientHandle,
                        @interfaceGUID,
                        wlan_intf_opcode_interface_state,
                        nil,
                        @pdwDataSize,
                        @pData,
                        nil) = ERROR_SUCCESS then
  begin
    isConnected := (pData^ = Tndu_WLAN_INTERFACE_STATE.wlan_interface_state_connected);
  end;

  //get the list of BSSids for the provided interface
  if isConnected then
  begin
    if WlanGetNetworkBssList(clientHandle,
                             @interfaceGUID,
                             pSSID,
                             SSID_Type,
                             SecurityEnabled,
                             nil,
                             @pWlanBssList) = ERROR_SUCCESS then
    begin
      items := pWlanBssList^.dwNumberOfItems;
      for itemIndex := 0 to items - 1 do
      begin

        SSID := String(PAnsiChar(@pWlanBssList^.wlanBssEntries[itemIndex].dot11Ssid.ucSSID));

        MAC := Format('%.2x:%.2x:%.2x:%.2x:%.2x:%.2x', [
                     pWlanBssList^.wlanBssEntries[itemIndex].dot11Bssid[0],
                     pWlanBssList^.wlanBssEntries[itemIndex].dot11Bssid[1],
                     pWlanBssList^.wlanBssEntries[itemIndex].dot11Bssid[2],
                     pWlanBssList^.wlanBssEntries[itemIndex].dot11Bssid[3],
                     pWlanBssList^.wlanBssEntries[itemIndex].dot11Bssid[4],
                     pWlanBssList^.wlanBssEntries[itemIndex].dot11Bssid[5]]);

        Writeln('');
        Writeln('SSID: ................ '+SSID);
        Writeln('Physical Address: .... '+MAC);
      end; {for itemIndex}
      Writeln(#10+#13+'Done.');
    end; {WlanGetNetworkBssList succeeds}

  end; {isConnected}
end;

begin
  hWlan := 0;

  if WlanOpenHandle(2, nil,@dwSupportedVersion, @hWlan)= ERROR_SUCCESS then
  begin
    if WlanEnumInterfaces(hWlan, nil, @pInterfaceList) = ERROR_SUCCESS then
    begin
      try
        for i := 0 to pInterfaceList^.dwNumberOfItems-1 do
          begin
            Writeln('Wifi Adapter - '+GUIDToString( pInterfaceList^.InterfaceInfo[i].InterfaceGuid ) );
            Writeln('Scanning: .... '+pInterfaceList^.InterfaceInfo[i].strInterfaceDescription);
            guid := pInterfaceList^.InterfaceInfo[i].InterfaceGuid;

            //Get all BSSids for this interface
            GetBSSIDList(hWlan, guid);

            if WlanGetAvailableNetworkList(hWlan,
                                           @guid,
                                           WLAN_AVAILABLE_NETWORK_INCLUDE_ALL_ADHOC_PROFILES,
                                           nil,
                                           pAvailableNetworkList) = ERROR_SUCCESS then
            begin
              try
                for j := 0 to pAvailableNetworkList^.dwNumberOfItems - 1 do
                  begin

                    //Get BSSid for this specific SSID
                    GetBSSIDList(hWlan,
                                 guid,
                                 @pAvailableNetworkList^.Network[j].dot11Ssid,
                                 pAvailableNetworkList^.Network[j].dot11BssType,
                                 pAvailableNetworkList^.Network[j].bSecurityEnabled);

                  end;
              finally
                if pAvailableNetworkList<>nil then
                  WlanFreeMemory(pAvailableNetworkList);
              end;
            end;

          end;
      finally
        if pInterfaceList<>nil then
          WlanFreeMemory(pInterfaceList);
      end;
    end;

    WlanCloseHandle(hWlan, nil);

    readln;

  end;
end.

VCL应用程序的相关部分是:

uses
  ... nduWlanAPI, nduWlanTypes, nduWinDot11;


function TForm1.GetBSSID(clientHandle: THandle;
                         interfaceGuid: TGUID;
                         pSSID: Pndu_DOT11_SSID = nil;
                         SSID_Type : Tndu_DOT11_BSS_TYPE = dot11_BSS_type_any;
                         SecurityEnabled: boolean = true): string;
var
  //used to determin if the interface is connected
  pData       : Pndu_WLAN_INTERFACE_STATE;
  isConnected : boolean;
  //used to extract a list of BSSIDs for a given interface
  pWlanBssList : Pndu_WLAN_BSS_LIST;

  lastError     : DWORD;
  pdwDataSize   : DWORD;
  items,
  itemIndex:    Integer;
begin
  pData := nil;
  pdwDataSize := 0;
  isConnected := False;

  //check if the interface is connected
  lastError := WlanQueryInterface(clientHandle,
                                 @interfaceGuid,
                                 wlan_intf_opcode_interface_state,
                                 nil,
                                 @pdwDataSize,
                                 @pData,
                                 nil);
    if (lastError = ERROR_SUCCESS) then
    begin
     //isConnected := (Tndu_WLAN_INTERFACE_STATE(pData^.isState) = Tndu_WLAN_INTERFACE_STATE.wlan_interface_state_connected);
     isConnected := (pData^ = Tndu_WLAN_INTERFACE_STATE.wlan_interface_state_connected);
    end
    else
      DisplayError('Error in WlanQueryInterface() function', lastError);

  if isConnected then
  begin
    pWlanBssList := nil;

    lastError := WlanGetNetworkBssList(clientHandle,
                                       @interfaceGuid,
                                       pSSID,
                                       SSID_Type,
                                       SecurityEnabled,
                                       nil,
                                       @pWlanBssList);

    try

      if (lastError = ERROR_SUCCESS) then
      begin

        items := pWlanBssList^.dwNumberOfItems;
        for itemIndex := 0 to items-1 do
        begin

          Result := (Format('%.2x:%.2x:%.2x:%.2x:%.2x:%.2x', [
                   pWlanBssList^.wlanBssEntries[itemIndex].dot11Bssid[0],
                   pWlanBssList^.wlanBssEntries[itemIndex].dot11Bssid[1],
                   pWlanBssList^.wlanBssEntries[itemIndex].dot11Bssid[2],
                   pWlanBssList^.wlanBssEntries[itemIndex].dot11Bssid[3],
                   pWlanBssList^.wlanBssEntries[itemIndex].dot11Bssid[4],
                   pWlanBssList^.wlanBssEntries[itemIndex].dot11Bssid[5]]));

        end;
      end
      else
        DisplayError('Error in the WlanGetNetworkBssList() function call', lastError);

    finally
      if pData<>nil then
        WlanFreeMemory(pData);

      if pWlanBssList<>nil then
        WlanFreeMemory(pWlanBssList);
    end;
  end;
end;

其名称如下:

function TForm1.ScanWifi(): THandle;
const
  WLAN_AVAILABLE_NETWORK_INCLUDE_ALL_ADHOC_PROFILES = $00000001;
var
  hClient              : THandle;
  dwVersion            : DWORD;
  lastError            : DWORD;
  pInterface           : Pndu_WLAN_INTERFACE_INFO_LIST;
  i                    : Integer;
  j                    : Integer;
  pAvailableNetworkList: Pndu_WLAN_AVAILABLE_NETWORK_LIST;
  interfaceGuid        : TGUID;
  BSSID                : string;
begin
  lastError:=WlanOpenHandle(NDU_WLAN_API_VERSION, nil, @dwVersion, @hClient);
  if  lastError<> ERROR_SUCCESS then
  begin
     //DisplayError('Error in the WlanOpenHandle() function call', lastError);
     Result := 0;
     Exit;
  end;

  //L(Format('Requested WLAN interface version [%d], negotiated version [%d]', [NDU_WLAN_API_VERSION, dwVersion]));
  Result := hClient;

  try

      lastError:=WlanEnumInterfaces(hClient, nil, @pInterface);

      try
        if  lastError<> ERROR_SUCCESS then
        begin
           //DisplayError('Errorin the WlanEnumInterfaces() function call', lastError);
           Exit;
        end;

        for i := 0 to pInterface^.dwNumberOfItems - 1 do
        begin
          interfaceGuid:= pInterface^.InterfaceInfo[i].InterfaceGuid;

          lastError:=WlanGetAvailableNetworkList(hClient,
                                                 @interfaceGuid,
                                                 WLAN_AVAILABLE_NETWORK_INCLUDE_ALL_ADHOC_PROFILES,
                                                 nil,
                                                 pAvailableNetworkList);

          try
            if  lastError<> ERROR_SUCCESS then
            begin
               //DisplayError('Error WlanGetAvailableNetworkList', lastError);

               Exit;
            end
            else
            begin
              for j := 0 to pAvailableNetworkList^.dwNumberOfItems - 1 do
              Begin

                 BSSID := GetBssid(hClient,
                                   interfaceGuid,
                                   @pAvailableNetworkList^.Network[j].dot11Ssid,
                                   pAvailableNetworkList^.Network[j].dot11BssType,
                                   pAvailableNetworkList^.Network[j].bSecurityEnabled
                 );

                 //FAPList.AddOrSetValue(BSSID,J);

              end;
            end;

          finally
            if pAvailableNetworkList <> nil then
              WlanFreeMemory(pAvailableNetworkList);
          end;

        end;
      finally
        if pInterface <> nil then
          WlanFreeMemory(pInterface);
      end;


  finally
    WlanCloseHandle(FhClient, nil);
  end;

end;

比较两个应用程序之间的数据唯一的区别是此处显示的结果(pWlanBssList)(left = console,right = VCL): enter image description here

1 个答案:

答案 0 :(得分:2)

在布尔转换中看起来像编译器错误,问题是在VCL代码中跟随行

SecurityEnabled: boolean = true

您需要将其更改为

SecurityEnabled: bool = true