Wi-Fi sareng seueur singgetan sanésna. Kumaha kéngingkeun data ngeunaan titik Wi-Fi dina aplikasi Android tanpa ngabareuhan

Hiji poé kuring diperlukeun pikeun nyeken jaringan Wi-Fi tina aplikasi Android sarta meunangkeun data lengkep ngeunaan titik aksés.

Di dieu urang kedah nyanghareupan sababaraha kasusah: dokuméntasi off.Android loba kelas digambarkeun jadi deprecated (tingkat API> 26), nu teu reflected di dinya; katerangan ngeunaan sababaraha hal dina dokuméntasi minimal (contona, widang kamampuan kelas Hasil Scan dina waktu nulis, ampir euweuh anu dijelaskeun, sanajan ngandung loba data penting). Kasusah katilu bisa jadi perenahna di kanyataan yén nalika anjeun mimiti deukeut ka Wi-Fi, lian ti maca téori jeung nyetel router via localhost, Anjeun kudu nungkulan sababaraha singkatan nu sigana kaharti individual. Tapi bisa jadi teu jelas kumaha pakaitna jeung struktur aranjeunna (judgment nyaeta subjektif jeung gumantung kana pangalaman saméméhna).

Tulisan ieu ngabahas kumaha carana kéngingkeun data komprehensif ngeunaan lingkungan Wi-Fi tina kode Android tanpa NDK, hacks, tapi ngan ukur nganggo API Android sareng ngartos kumaha napsirkeunana.

Hayu urang teu reureuh tur mimitian nulis kode.

1. Jieun proyék

Catetan ieu dimaksudkeun pikeun jalma anu parantos nyiptakeun proyék Android langkung ti sakali, janten urang ngaleungitkeun detil barang ieu. Kodeu di handap bakal dibere dina Kotlin, minSdkVersion = 23.

2. Idin aksés

Pikeun damel sareng Wi-Fi tina aplikasi, anjeun kedah nampi sababaraha idin ti pangguna. Dumasarkeun kana dokuméntasi, pikeun nyeken jaringan dina alat sareng versi OS saatos 8.0, salian ti aksés pikeun ningali kaayaan lingkungan jaringan, anjeun peryogi aksés pikeun ngarobih kaayaan modul Wi-Fi alat, atanapi aksés ka koordinat (kira-kira. atawa pasti). Dimimitian ku vérsi 9.0, anjeun kedah naroskeun pangguna pikeun duanana, sareng ogé sacara eksplisit nyuhunkeun pangguna pikeun ngaktipkeun jasa lokasi. Tong hilap sacara gampil ngajelaskeun ka pangguna yén ieu mangrupikeun karep Google, sareng sanés kahayang urang pikeun nénjo anjeunna :)

Janten, dina AndroidManifest.xml kami bakal nambihan:

    <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"/>

Sareng dina kode anu ngandung tautan kana Kagiatan ayeuna:

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. Jieun BroadcastReceiver sarta ngalanggan acara update data ngeunaan scanning lingkungan jaringan 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
}

Metodeu WiFiManager.startScan dina dokuméntasi ditandaan salaku depricated saprak versi API 28, tapi pareum. mere beja nyarankeun ngagunakeun éta.

Dina total, kami nampi daptar objék Hasil Scan.

4. Tingali di ScanResult tur ngartos istilah

Hayu urang tingali sababaraha widang kelas ieu sareng ngajelaskeun naon hartosna:

SSID — Service Set Identifier nyaéta ngaran jaringan

BSSID - Identifier Set Layanan Dasar - Alamat MAC tina adaptor jaringan (titik Wi-Fi)

tingkat - Indikator Kakuatan Sinyal Ditampi [dBm (dBm Rusia) - Decibel, kakuatan rujukan 1 mW.] - Indikator kakuatan sinyal anu ditampi. Butuh nilai ti 0 nepi ka -100, beuki jauh ti 0, kakuatan sinyal beuki leungit sapanjang jalan ti titik Wi-Fi ka alat Anjeun. Leuwih rinci bisa kapanggih, contona, di Wikipédia. Di dieu kuring gé ngabejaan Anjeun yen ngagunakeun kelas Android WifiManager Anjeun tiasa calibrate tingkat sinyal dina skala ti alus teuing pikeun dahsyat dina hambalan anjeun milih:

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

prekuensi — frékuénsi operasi titik Wi-Fi [Hz]. Salian frékuénsi sorangan, Anjeun bisa jadi kabetot dina disebut saluran. Unggal titik boga purity operasi sorangan. Dina waktos nyerat, rentang titik Wi-Fi anu paling populér nyaéta 2.4 GHz. Tapi, langkung tepatna, titik ngirimkeun inpormasi ka telepon anjeun dina frékuénsi wilangan anu caket sareng anu namina. Jumlah saluran jeung frékuénsi pakait standarisasi. Hal ieu dilakukeun ku kituna titik caket dieu beroperasi dina frékuénsi béda, kukituna teu interfering saling sarta teu saling ngurangan laju sarta kualitas transmisi. Dina hal ieu, titik beroperasi henteu dina hiji frékuénsi, tapi dina rentang frékuénsi (parameter saluranWidth), disebut lebar saluran. Hartina, titik operasi dina padeukeut (jeung teu ngan padeukeut, tapi malah 3 ti sorangan) saluran ngaganggu silih. Anjeun tiasa mendakan kode basajan ieu mangpaat, anu ngamungkinkeun anjeun ngitung jumlah saluran tina nilai frékuénsi pikeun titik kalayan frékuénsi 2.4 sareng 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
            }
        }

kamampuhan - widang paling metot pikeun analisis, gawé bareng nu diperlukeun loba waktu. Di dieu "kamampuan" titik ditulis dina garis. Dina hal ieu, anjeun teu kudu néangan wincik interpretasi string dina dokuméntasi. Ieu sababaraha conto naon anu aya dina garis ieu:

[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. Ngartos singketan sareng kamampuan parsing

Perlu disebatkeun yén kelas tina pakét android.net.wifi.* dianggo di handapeun tiung ku utilitas Linux. wpa_supplicant sareng hasil kaluaran dina widang kamampuan mangrupikeun salinan lapangan bendera nalika nyeken.

Urang bakal meta konsistén. Hayu urang mimiti nganggap kaluaran format dimana elemen dina jero kurung dipisahkeun ku tanda "-":

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

Harti kahiji nerangkeun nu disebut. métode auténtikasi. Nyaéta, naon urutan tindakan anu kedah dilakukeun ku alat sareng titik aksés supados titik aksés tiasa dianggo sareng kumaha cara énkripsi payload. Dina waktos nyerat tulisan ieu, pilihan anu paling umum nyaéta WPA sareng WPA2, dimana unggal alat anu disambungkeun langsung atanapi ngalangkungan anu disebut. Server RADIUS (WPA-Enterprice) nyadiakeun kecap akses dina saluran énkripsi. Paling dipikaresep, titik aksés di imah anjeun nyadiakeun sambungan nurutkeun skéma ieu. Beda antara versi kadua sareng anu kahiji nyaéta yén éta gaduh cipher anu langkung kuat: AES versus TKIP anu teu aman. WPA3, anu langkung kompleks sareng canggih, ogé laun-laun diwanohkeun. Sacara téoritis, meureun aya pilihan sareng solusi enterprice CCKM (Cisco Centralized Key Management), tapi kuring henteu pernah mendakan éta.

Titik aksés meureun geus ngonpigurasi pikeun auténtikasi ku alamat MAC. Atawa, lamun titik aksés nyadiakeun data ngagunakeun algoritma WEP luntur, lajeng aya sabenerna euweuh auténtikasi (konci rusiah didieu nyaeta konci enkripsi). Urang mengklasifikasikan pilihan sapertos LAIN.
Aya ogé metode anu populer di wi-fi umum sareng Deteksi Portal Captive disumputkeun - pamundut auténtikasi ngalangkungan browser. Titik aksés sapertos kitu muncul dina scanner salaku muka (anu aranjeunna tina sudut pandang sambungan fisik). Ku alatan éta, urang mengklasifikasikan aranjeunna salaku OPEN.

Nilai kadua bisa dilambangkeun salaku algoritma manajemén konci. Ieu mangrupikeun parameter tina metodeu auténtikasi anu dijelaskeun di luhur. Talks ngeunaan persis kumaha konci enkripsi disilihtukeurkeun. Hayu urang nganggap pilihan mungkin. EAP - dipaké dina WPA-Enterprice disebutkeun, ngagunakeun database pikeun pariksa data auténtikasi diasupkeun. SAE - dipaké dina WPA3 canggih, leuwih tahan ka gaya BRUTE. PSK - pilihan anu paling umum, kalebet ngalebetkeun kecap konci sareng ngirimkeunana dina bentuk énkripsi. IEEE8021X - numutkeun standar internasional (béda sareng anu dirojong ku kulawarga WPA). OWE (Opportunistic Wireless Encryption) mangrupikeun penyuluhan standar IEEE 802.11 pikeun titik anu kami digolongkeun kana OPEN. OWE mastikeun kaamanan data anu dikirimkeun kana jaringan anu teu aman ku cara énkripsi. Hiji pilihan oge mungkin lamun euweuh kenop aksés, hayu urang nelepon pilihan ieu NONE.

Parameter katilu anu disebut. skéma énkripsi — kumaha kahayang cipher dipaké pikeun ngajaga data dikirimkeun. Hayu urang daptar pilihan. WEP - ngagunakeun cipher stream RC4, konci rusiah nyaéta konci enkripsi, nu dianggap unacceptable di dunya kriptografi modern. TKIP - dipaké dina WPA, CKIP - dina WPA2. TKIP+CKIP - tiasa disaluyukeun dina titik anu tiasa WPA sareng WPA2 pikeun kasaluyuan mundur.

Gantina tilu elemen, anjeun tiasa mendakan tanda WEP anu sepi:

[WEP]

Salaku urang bahas di luhur, ieu cukup teu nangtukeun algoritma pikeun pamakéan konci, nu teu aya, sarta metoda enkripsi, nu sarua sacara standar.

Ayeuna mertimbangkeun bracket ieu:

[ESS]

ieu Modeu operasi Wi-Fi atawa Topologi jaringan Wi-Fi. Anjeun tiasa sapatemon mode BSS (Basic Service Set) - lamun aya hiji titik aksés ngaliwatan alat nu disambungkeun komunikasi. Bisa kapanggih dina jaringan lokal. Sakumaha aturan, titik aksés diperlukeun pikeun nyambungkeun alat ti jaringan lokal béda, jadi aranjeunna bagian tina Extended Service Sets - ESS. Jinis IBSSs (Set Layanan Dasar Independen) nunjukkeun yén alat éta bagian tina jaringan Peer-to-Peer.

Anjeun ogé tiasa ningali bandéra WPS:

[WPS]

WPS (Wi-Fi Protected Setup) nyaéta protokol pikeun inisialisasi semi-otomatis jaringan Wi-Fi. Pikeun initialize, pamaké boh ngasupkeun sandi 8 karakter atawa mencét hiji tombol dina router dina. Upami titik aksés anjeun tina jinis anu munggaran sareng kotak centang ieu nembongan di gigireun nami titik aksés anjeun, anjeun disarankeun pisan pikeun muka panel admin sareng nganonaktipkeun aksés WPS. Kanyataan yén PIN 8-angka sering tiasa dipendakan ku alamat MAC, atanapi tiasa diurutkeun dina waktos anu tiasa diramalkeun, anu tiasa dimanfaatkeun ku jalma anu teu jujur.

6. Jieun model jeung fungsi parsing

Dumasar naon anu urang mendakan di luhur, urang bakal ngajelaskeun naon anu kajantenan nganggo kelas 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.
}

Ayeuna hayu urang nulis hiji fungsi anu bakal parse widang kamampuhan:


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. Tempo hasilna

Kuring bakal nyeken jaringan sareng nunjukkeun ka anjeun naon anu kuring mendakan. Ditémbongkeun mangrupa hasil kaluaran basajan via Log.d:

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

Isu nyambungkeun ka jaringan tina kode aplikasi tetep unexamined. Kuring ngan bakal nyebutkeun yén dina urutan maca sandi disimpen tina OS tina alat mobile, anjeun peryogi hak root na kahayang rummage ngaliwatan sistem file maca wpa_supplicant.conf. Lamun logika aplikasi merlukeun ngasupkeun sandi ti luar, sambungan bisa dijieun ngaliwatan kelas android.net.wifi.WifiManager.

Спасибо Egor Ponomarev pikeun tambahan berharga.

Upami anjeun nyangka aya anu kedah ditambihan atanapi dilereskeun, tulis dina koméntar :)

sumber: www.habr.com

Tambahkeun komentar