Wi-Fi a llawer o fyrfoddau eraill. Sut i gael data am nodau Wi-Fi mewn cymhwysiad Android heb chwyddo

Un diwrnod roedd angen i mi sganio rhwydweithiau Wi-Fi o gymwysiadau Android a chael data manwl am bwyntiau mynediad.

Yma bu'n rhaid i ni wynebu sawl anhawster: dogfennaeth off.Android aeth llawer o'r dosbarthiadau a ddisgrifiwyd yn anghymeradwy (lefel API > 26), nad oedd yn cael ei adlewyrchu ynddo; mae'r disgrifiad o rai pethau yn y ddogfennaeth yn fach iawn (er enghraifft, maes galluoedd y dosbarth Canlyniad Scan ar adeg ysgrifennu, nid oes bron dim yn cael ei ddisgrifio, er ei fod yn cynnwys llawer o ddata pwysig). Efallai mai'r trydydd anhawster yw'r ffaith, pan fyddwch chi'n agosáu at Wi-Fi am y tro cyntaf, heblaw darllen y theori a sefydlu'r llwybrydd trwy localhost, mae'n rhaid i chi ddelio â nifer o fyrfoddau sy'n ymddangos yn ddealladwy yn unigol. Ond efallai na fydd yn amlwg sut i'w cysylltu a'u strwythuro (mae'r farn yn oddrychol ac yn dibynnu ar brofiad blaenorol).

Mae'r erthygl hon yn trafod sut i gael data cynhwysfawr am yr amgylchedd Wi-Fi o god Android heb NDK, haciau, ond dim ond defnyddio'r API Android a deall sut i'w ddehongli.

Gadewch i ni beidio ag oedi a dechrau ysgrifennu cod.

1. Creu prosiect

Mae'r nodyn hwn wedi'i fwriadu ar gyfer y rhai sydd wedi creu prosiect Android fwy nag unwaith, felly rydym yn hepgor manylion yr eitem hon. Bydd y cod isod yn cael ei gyflwyno yn Kotlin, minSdkVersion=23.

2. Caniatâd mynediad

I weithio gyda Wi-Fi o'r rhaglen, bydd angen i chi gael sawl caniatâd gan y defnyddiwr. Yn unol â dogfennaeth, er mwyn sganio'r rhwydwaith ar ddyfeisiau gyda fersiynau OS ar ôl 8.0, yn ogystal â mynediad i weld cyflwr amgylchedd y rhwydwaith, mae angen naill ai mynediad i newid cyflwr modiwl Wi-Fi y ddyfais, neu fynediad at gyfesurynnau (bras neu yn union). Gan ddechrau gyda fersiwn 9.0, rhaid i chi annog y defnyddiwr am y ddau, a hefyd ofyn yn benodol i'r defnyddiwr droi gwasanaethau lleoliad ymlaen. Peidiwch ag anghofio esbonio'n ddewr i'r defnyddiwr mai mympwy Google yw hyn, ac nid ein dymuniad i ysbïo arno :)

Felly, yn AndroidManifest.xml byddwn yn ychwanegu:

    <uses-permission android_name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android_name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android_name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android_name="android.permission.ACCESS_FINE_LOCATION"/>

Ac yn y cod sy'n cynnwys dolen i'r Gweithgaredd cyfredol:

import android.app.Activity
import android.content.Context
import android.location.LocationManager
import androidx.core.app.ActivityCompat

....

if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            ActivityCompat.requestPermissions(
                activity,
                arrayOf(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.CHANGE_WIFI_STATE),
                1
            )
            makeEnableLocationServices(activity.applicationContext)
        } else {
            ActivityCompat.requestPermissions(
                activity,
                arrayOf(Manifest.permission.CHANGE_WIFI_STATE),
                1
            )
        }

    /* включает экран включения службы по определению местоположения */
    fun makeEnableLocationServices(context: Context) {
        // TODO: перед вызовом этой функции надо рассказать пользователю, зачем Вам доступ к местоположению
        val lm: LocationManager =
            context.applicationContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager

        val gpsEnabled: Boolean = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
        val networkEnabled: Boolean = lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER);

        if (!gpsEnabled && !networkEnabled) {
            context.startActivity(Intent(ACTION_LOCATION_SOURCE_SETTINGS));
        }
    }

3. Creu BroadcastReceiver a thanysgrifio i ddigwyddiadau diweddaru data am sganio'r amgylchedd rhwydwaith Wi-Fi

val wifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager

val wifiScanReceiver = object : BroadcastReceiver() {

  override fun onReceive(context: Context, intent: Intent) {
    val success = intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false)
    if (success) {
      scanSuccess()
    } 
  }
}

val intentFilter = IntentFilter()
/* подписываемся на сообщения о получении новых результатов сканирования */
intentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)
context.registerReceiver(wifiScanReceiver, intentFilter)

val success = wifiManager.startScan()
if (!success) {
  /* что-то не получилось при запуске сканирования, проверьте выданые разрешения */
}

....

private fun scanSuccess() {
 /* вот они, результаты сканирования */
  val results: List<ScanResult> = wifiManager.scanResults
}

Mae'r dull WiFiManager.startScan yn y ddogfennaeth wedi'i nodi fel un sydd wedi'i amddifadu ers fersiwn API 28, ond i ffwrdd. arwain yn awgrymu ei ddefnyddio.

Yn gyfan gwbl, cawsom restr o wrthrychau Canlyniad Scan.

4. Edrychwch ar ScanResult a deall y termau

Edrychwn ar rai meysydd o'r dosbarth hwn a disgrifio'r hyn y maent yn ei olygu:

SSID — Dynodwr Set Gwasanaeth yw enw'r rhwydwaith

BSSID - Dynodwr Set Gwasanaeth Sylfaenol - cyfeiriad MAC addasydd y rhwydwaith (pwynt Wi-Fi)

lefel — Dangosydd Cryfder Signalau a Dderbyniwyd [dBm (dBm Rwsiaidd) — Decibel, pŵer cyfeirio 1 mW.] — Dangosydd o gryfder y signal a dderbyniwyd. Yn cymryd gwerth o 0 i -100, po bellaf o 0, y mwyaf o bŵer signal a gollwyd ar hyd y ffordd o'r pwynt Wi-Fi i'ch dyfais. Ceir rhagor o fanylion, er enghraifft, yn Wikipedia. Yma dywedaf wrthych hynny gan ddefnyddio'r dosbarth Android Rheolwr Wifi gallwch raddnodi lefel y signal ar raddfa o ardderchog i ofnadwy yn y cam a ddewiswch:

        val wifiManager = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
        val numberOfLevels = 5
        val level = WifiManager.calculateSignalLevel(level, numberOfLevels)

amledd — amledd gweithredu'r pwynt Wi-Fi [Hz]. Yn ychwanegol at yr amlder ei hun, efallai y bydd gennych ddiddordeb yn y sianel fel y'i gelwir. Mae gan bob pwynt ei burdeb gweithredu ei hun. Ar adeg ysgrifennu, yr ystod fwyaf poblogaidd o bwyntiau Wi-Fi yw 2.4 GHz. Ond, i fod yn fwy manwl gywir, mae'r pwynt yn trosglwyddo gwybodaeth i'ch ffôn ar amlder wedi'i rifo yn agos at yr un a enwir. Nifer y sianeli ac amleddau cyfatebol safonedig. Gwneir hyn fel bod pwyntiau cyfagos yn gweithredu ar wahanol amleddau, a thrwy hynny beidio ag ymyrryd â'i gilydd a pheidio â lleihau cyflymder ac ansawdd y trosglwyddiad ar y cyd. Yn yr achos hwn, mae'r pwyntiau'n gweithredu nid ar un amledd, ond dros ystod o amleddau (paramedr sianelWidth), a elwir yn lled y sianel. Hynny yw, mae pwyntiau sy'n gweithredu ar sianeli cyfagos (ac nid yn unig yn gyfagos, ond hyd yn oed 3 ohonynt eu hunain) yn ymyrryd â'i gilydd. Efallai y bydd y cod syml hwn yn ddefnyddiol i chi, sy'n eich galluogi i gyfrifo rhif y sianel o'r gwerth amledd ar gyfer pwyntiau ag amledd o 2.4 a 5 Ghz:


    /* по частоте определяем номер канала */
    val channel: Int
        get() {
            return if (frequency in 2412..2484) {
                (frequency - 2412) / 5 + 1
            } else if (frequency in 5170..5825) {
                (frequency - 5170) / 5 + 34
            } else {
                -1
            }
        }

galluoedd - y maes mwyaf diddorol ar gyfer dadansoddi, gwaith yr oedd angen llawer o amser ag ef. Yma mae “galluoedd” y pwynt wedi'u hysgrifennu yn y llinell. Yn yr achos hwn, nid oes rhaid i chi edrych am fanylion dehongli llinynnol yn y ddogfennaeth. Dyma rai enghreifftiau o'r hyn a allai fod yn y llinell hon:

[WPA-PSK-TKIP+CCMP][WPA2-PSK-TKIP+CCMP][WPS][ESS]
[WPA2-PSK-CCMP][ESS]
[WPA2-PSK-CCMP+TKIP][ESS]
[WPA-PSK-CCMP+TKIP][WPA2-PSK-CCMP+TKIP][ESS]
[ESS][WPS]

5. Deall byrfoddau a galluoedd dosrannu

Mae'n werth nodi bod dosbarthiadau'r pecyn android.net.wifi.* yn cael eu defnyddio o dan y cwfl gan gyfleustodau Linux wpa_supplicant a'r canlyniad allbwn yn y maes galluoedd yw copi o'r maes baneri wrth sganio.

Byddwn yn gweithredu’n gyson. Yn gyntaf, gadewch i ni ystyried allbwn fformat lle mae elfennau y tu mewn i gromfachau yn cael eu gwahanu gan arwydd “-“:

[WPA-PSK-TKIP+CCMP]
[WPA2-PSK-CCMP]

Mae'r ystyr cyntaf yn disgrifio'r hyn a elwir. dull dilysu. Hynny yw, pa ddilyniant o gamau gweithredu y mae'n rhaid i'r ddyfais a'r pwynt mynediad eu perfformio er mwyn i'r pwynt mynediad ganiatáu iddo'i hun gael ei ddefnyddio a sut i amgryptio'r llwyth tâl. Ar adeg ysgrifennu'r swydd hon, yr opsiynau mwyaf cyffredin yw WPA a WPA2, lle mae naill ai pob dyfais gysylltiedig yn uniongyrchol neu drwy'r hyn a elwir. Mae'r gweinydd RADIUS (WPA-Enterprice) yn darparu'r cyfrinair dros sianel wedi'i hamgryptio. Yn fwyaf tebygol, mae'r pwynt mynediad yn eich cartref yn darparu cysylltiad yn unol â'r cynllun hwn. Y gwahaniaeth rhwng yr ail fersiwn a'r cyntaf yw bod ganddo seiffr cryfach: AES yn erbyn y TKIP ansicr. Mae WPA3, sy'n fwy cymhleth a datblygedig, hefyd yn cael ei gyflwyno'n raddol. Yn ddamcaniaethol, efallai y bydd opsiwn gyda'r datrysiad enterprice CCKM (Cisco Centralized Key Management), ond nid wyf erioed wedi dod ar ei draws.

Mae'n bosibl bod y pwynt mynediad wedi'i ffurfweddu i ddilysu yn ôl cyfeiriad MAC. Neu, os yw'r pwynt mynediad yn darparu data gan ddefnyddio'r algorithm WEP sydd wedi dyddio, yna nid oes unrhyw ddilysu mewn gwirionedd (yr allwedd gyfrinachol yma yw'r allwedd amgryptio). Rydym yn dosbarthu opsiynau o'r fath fel ARALL.
Mae yna hefyd ddull sy'n boblogaidd mewn wi-fi cyhoeddus gyda Canfod Porth Caethus cudd - cais dilysu trwy borwr. Mae pwyntiau mynediad o'r fath yn ymddangos i'r sganiwr fel rhai agored (y maent o safbwynt y cysylltiad ffisegol). Felly, rydym yn eu dosbarthu fel AGORED.

Gellir dynodi'r ail werth fel algorithm rheoli allweddol. Mae hwn yn baramedr o'r dull dilysu a ddisgrifir uchod. Sôn am yn union sut mae allweddi amgryptio yn cael eu cyfnewid. Gadewch i ni ystyried yr opsiynau posibl. Mae EAP - a ddefnyddir yn y WPA-Enterprice y soniwyd amdano, yn defnyddio cronfa ddata i wirio'r data dilysu a gofnodwyd. SAE - a ddefnyddir mewn WPA3 datblygedig, yn fwy gwrthsefyll grym 'n ysgrublaidd. PSK - yr opsiwn mwyaf cyffredin, sy'n golygu mynd i mewn i gyfrinair a'i drosglwyddo ar ffurf wedi'i amgryptio. IEEE8021X - yn unol â safon ryngwladol (yn wahanol i'r hyn a gefnogir gan deulu WPA). Mae OWE (Amgryptio Di-wifr Opportunistic) yn estyniad o safon IEEE 802.11 ar gyfer pwyntiau a ddosbarthwyd gennym fel AGORED. Mae OWE yn sicrhau diogelwch data a drosglwyddir dros rwydwaith anniogel trwy ei amgryptio. Mae opsiwn hefyd yn bosibl pan nad oes allweddi mynediad, gadewch i ni alw'r opsiwn hwn DIM.

Y trydydd paramedr yw'r hyn a elwir. cynlluniau amgryptio — sut yn union y defnyddir y seiffr i ddiogelu'r data a drosglwyddir. Gadewch i ni restru'r opsiynau. WEP - yn defnyddio cipher ffrwd RC4, yr allwedd gyfrinachol yw'r allwedd amgryptio, a ystyrir yn annerbyniol ym myd cryptograffeg modern. TKIP - a ddefnyddir yn WPA, CKIP - yn WPA2. TKIP + CKIP - gellir ei nodi mewn pwyntiau sy'n gallu WPA a WPA2 ar gyfer cydweddoldeb yn ôl.

Yn lle tair elfen, gallwch ddod o hyd i farc WEP unig:

[WEP]

Fel y trafodwyd uchod, mae hyn yn ddigon i beidio â nodi'r algorithm ar gyfer defnyddio allweddi, nad yw'n bodoli, a'r dull amgryptio, sydd yr un peth yn ddiofyn.

Nawr ystyriwch y braced hwn:

[ESS]

Mae'n Modd gweithredu Wi-Fi neu Topoleg rhwydwaith Wi-Fi. Efallai y byddwch yn dod ar draws modd BSS (Set Gwasanaeth Sylfaenol) - pan fydd un pwynt mynediad y mae dyfeisiau cysylltiedig yn cyfathrebu drwyddo. Gellir dod o hyd iddo ar rwydweithiau lleol. Fel rheol, mae angen pwyntiau mynediad i gysylltu dyfeisiau o wahanol rwydweithiau lleol, felly maent yn rhan o Setiau Gwasanaeth Estynedig - ESS. Mae'r math IBSSs (Setiau Gwasanaeth Sylfaenol Annibynnol) yn nodi bod y ddyfais yn rhan o rwydwaith Cyfoedion i Gyfoedion.

Efallai y byddwch hefyd yn gweld baner WPS:

[WPS]

Protocol ar gyfer cychwyn rhwydwaith Wi-Fi yn lled-awtomatig yw WPS (Gosodiad Gwarchodedig Wi-Fi). I gychwyn, mae'r defnyddiwr naill ai'n mynd i mewn i gyfrinair 8-cymeriad neu'n pwyso botwm ar y llwybrydd. Os yw'ch pwynt mynediad o'r math cyntaf a bod y blwch ticio hwn yn ymddangos wrth ymyl enw eich pwynt mynediad, fe'ch cynghorir yn gryf i fynd i'r panel gweinyddol ac analluogi mynediad WPS. Y ffaith yw y gellir dod o hyd i'r PIN 8 digid yn aml wrth y cyfeiriad MAC, neu gellir ei ddatrys mewn amser rhagweladwy, y gall rhywun yn anonest fanteisio arno.

6. Creu model a swyddogaeth dosrannu

Yn seiliedig ar yr hyn a ddarganfuwyd uchod, byddwn yn disgrifio beth ddigwyddodd gan ddefnyddio dosbarthiadau data:

/* схема аутентификации */
enum class AuthMethod {
    WPA3,
    WPA2,
    WPA, // Wi-Fi Protected Access
    OTHER, // включает в себя Shared Key Authentication и др. использующие mac-address-based и WEP
    CCKM, // Cisco
    OPEN // Open Authentication. Может быть со скрытым Captive Portal Detection - запрос аутентификации через браузер
}

/* алгоритм ввода ключей */
enum class KeyManagementAlgorithm {
    IEEE8021X, // по стандарту
    EAP, // Extensible Authentication Protocol, расширяемый протокол аутентификации
    PSK, // Pre-Shared Key — каждый узел вводит пароль для доступа к сети
    WEP, // в WEP пароль является ключом шифрования (No auth key)
    SAE, // Simultaneous Authentication of Equals - может быть в WPA3
    OWE, // Opportunistic Wireless Encryption - в роутерах новых поколений, публичных сетях типа OPEN
    NONE // может быть без шифрования в OPEN, OTHER
}

/* метод шифрования */
enum class CipherMethod {
    WEP, // Wired Equivalent Privacy, Аналог шифрования трафика в проводных сетях
    TKIP, // Temporal Key Integrity Protocol
    CCMP, // Counter Mode with Cipher Block Chaining Message Authentication Code Protocol,
    // протокол блочного шифрования с кодом аутентичности сообщения и режимом сцепления блоков и счетчика
    // на основе AES
    NONE // может быть без шифрования в OPEN, OTHER
}

/* набор методов шифрования и протоколов, по которым может работать точка */
data class Capability(
    var authScheme: AuthMethod? = null,
    var keyManagementAlgorithm: KeyManagementAlgorithm? = null,
    var cipherMethod: CipherMethod? = null
)

/* Режим работы WiFi (или топология сетей WiFi) */
enum class TopologyMode {
    IBSS, // Эпизодическая сеть (Ad-Hoc или IBSS – Independent Basic Service Set).
    BSS, // Основная зона обслуживания Basic Service Set (BSS) или Infrastructure Mode.
    ESS // Расширенная зона обслуживания ESS – Extended Service Set.
}

Nawr, gadewch i ni ysgrifennu swyddogaeth a fydd yn dosrannu'r maes galluoedd:


private fun parseCapabilities(capabilitiesString: String): List < Capability > {
    val capabilities: List < Capability > = capabilitiesString
        .splitByBrackets()
        .filter {
            !it.isTopology() && !it.isWps()
        }
        .flatMap {
            parseCapability(it)
        }
    return
        if (!capabilities.isEmpty()) {
            capabilities
        } else {
            listOf(Capability(AuthMethod.OPEN, KeyManagementAlgorithm.NONE, CipherMethod.NONE))
        }
}

private fun parseCapability(part: String): List < Capability > {
    if (part.contains("WEP")) {
        return listOf(Capability(
            AuthMethod.OTHER,
            KeyManagementAlgorithm.WEP,
            CipherMethod.WEP
        ))
    }

    val authScheme = when {
        part.contains("WPA3") - > AuthMethod.WPA3
        part.contains("WPA2") - > AuthMethod.WPA2
        part.contains("WPA") - > AuthMethod.WPA
        else - > null
    }

    val keyManagementAlgorithm = when {
        part.contains("OWE") - > KeyManagementAlgorithm.OWE
        part.contains("SAE") - > KeyManagementAlgorithm.SAE
        part.contains("IEEE802.1X") - > KeyManagementAlgorithm.IEEE8021X
        part.contains("EAP") - > KeyManagementAlgorithm.EAP
        part.contains("PSK") - > KeyManagementAlgorithm.PSK
        else - > null
    }

    val capabilities = ArrayList < Capability > ()
    if (part.contains("TKIP") || part.contains("CCMP")) {
        if (part.contains("TKIP")) {
            capabilities.add(Capability(
                authScheme ? : AuthMethod.OPEN,
                keyManagementAlgorithm ? : KeyManagementAlgorithm.NONE,
                CipherMethod.TKIP
            ))
        }
        if (part.contains("CCMP")) {
            capabilities.add(Capability(
                authScheme ? : AuthMethod.OPEN,
                keyManagementAlgorithm ? : KeyManagementAlgorithm.NONE,
                CipherMethod.CCMP
            ))
        }
    } else if (authScheme != null || keyManagementAlgorithm != null) {
        capabilities.add(Capability(
            authScheme ? : AuthMethod.OPEN,
            keyManagementAlgorithm ? : KeyManagementAlgorithm.NONE,
            CipherMethod.NONE
        ))
    }

    return capabilities
}

private fun parseTopologyMode(capabilitiesString: String): TopologyMode ? {
    return capabilitiesString
        .splitByBrackets()
        .mapNotNull {
            when {
                it.contains("ESS") - > TopologyMode.ESS
                it.contains("BSS") - > TopologyMode.BSS
                it.contains("IBSS") - > TopologyMode.IBSS
                else - > null
            }
        }
        .firstOrNull()
}

private fun parseWPSAvailable(capabilitiesString: String): Boolean {
    return capabilitiesString
        .splitByBrackets()
        .any {
            it.isWps()
        }
}

private fun String.splitByBrackets(): List < String > {
    val m = Pattern.compile("[(.*?)]").matcher(this)
    val parts = ArrayList < String > ()
    while (m.find()) {
        parts.add(m.group().replace("[", "").replace("]", ""))
    }
    return parts
}

private fun String.isTopology(): Boolean {
    return TopologyMode.values().any {
        this == it.name
    }
}

private fun String.isWps(): Boolean {
    return this == "WPS"
}

8. Gweler y canlyniad

Byddaf yn sganio'r rhwydwaith ac yn dangos i chi yr hyn a ddarganfyddais. Dangosir canlyniadau allbwn syml trwy Log.d:

Capability of Home-Home [WPA2-PSK-CCMP][ESS][WPS]
...
capabilities=[Capability(authScheme=WPA2, keyManagementAlgorithm=PSK, cipherMethod=CCMP)], topologyMode=ESS, availableWps=true

Roedd y mater o gysylltu â'r rhwydwaith o'r cod cais yn parhau heb ei archwilio. Ni fyddaf ond yn dweud, er mwyn darllen cyfrineiriau sydd wedi'u cadw o OS dyfais symudol, bod angen hawliau gwraidd arnoch a pharodrwydd i chwilota trwy'r system ffeiliau i ddarllen wpa_supplicant.conf. Os yw rhesymeg y cais yn gofyn am fewnbynnu cyfrinair o'r tu allan, gellir gwneud y cysylltiad trwy'r dosbarth android.net.wifi.WifiManager.

Diolch Egor Ponomarev am ychwanegiadau gwerthfawr.

Os ydych chi'n meddwl bod angen ychwanegu neu gywiro rhywbeth, ysgrifennwch y sylwadau :)

Ffynhonnell: hab.com

Ychwanegu sylw