Ühel päeval pidin Androidi rakendustest WiFi-võrke skannima ja pääsupunktide kohta üksikasjalikke andmeid hankima.
Siin pidime silmitsi seisma mitmete raskustega:
Selles artiklis käsitletakse, kuidas hankida kõikehõlmavaid andmeid Wi-Fi keskkonna kohta Androidi koodist ilma NDK-ta, häkkideta, kuid ainult Android API-d kasutades, ja mõista, kuidas seda tõlgendada.
Ärgem viivitagem ja hakakem koodi kirjutama.
1. Loo projekt
See märkus on mõeldud neile, kes on Androidi projekti loonud rohkem kui korra, seega jätame selle üksuse üksikasjad välja. Allolev kood esitatakse Kotlinis, minSdkVersion=23.
2. Juurdepääsuload
Rakenduse Wi-Fi-ga töötamiseks peate hankima kasutajalt mitu luba. Kooskõlas
Seega lisame faili AndroidManifest.xml:
<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"/>
Ja koodis, mis sisaldab linki praegusele tegevusele:
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. Looge BroadcastReceiver ja tellige andmete värskendamise sündmused Wi-Fi võrgukeskkonna skannimise kohta
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
}
Meetod WiFiManager.startScan dokumentatsioonis on alates API versioonist 28 märgitud kehtetuks, kuid välja lülitatud.
Kokku saime objektide nimekirja
4. Vaadake ScanResultit ja mõistke tingimusi
Vaatame mõnda selle klassi välja ja kirjeldame, mida need tähendavad:
SSID — Service Set Identifier on võrgu nimi
BSSID – Basic Service Set Identifier – võrguadapteri MAC-aadress (Wi-Fi-punkt)
tase — Vastuvõetud signaali tugevuse indikaator [dBm (Vene dBm) — Detsibell, võrdlusvõimsus 1 mW.] — Vastuvõetud signaali tugevuse indikaator. Võtab väärtuse vahemikus 0 kuni –100, mida kaugemal 0-st, seda rohkem signaali võimsust kadus teel Wi-Fi-punktist teie seadmesse. Täpsemalt leiab näiteks aadressilt
val wifiManager = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
val numberOfLevels = 5
val level = WifiManager.calculateSignalLevel(level, numberOfLevels)
sagedus — Wi-Fi-punkti töösagedus [Hz]. Lisaks sagedusele endale võib huvi pakkuda nn kanal. Igal punktil on oma tööpuhtus. Selle artikli kirjutamise ajal on kõige populaarsem WiFi-punktide vahemik 2.4 GHz. Kuid täpsemini edastab punkt teavet teie telefoni nummerdatud sagedusega, mis on lähedal nimetatud sagedusele. Kanalite arv ja vastavad sagedused
/* по частоте определяем номер канала */
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
}
}
võimeid - kõige huvitavam analüüsivaldkond, millega töötamine nõudis palju aega. Siin on reale kirjas punkti “võimalused”. Sel juhul ei pea te dokumentatsioonist stringi tõlgendamise üksikasju otsima. Siin on mõned näited selle kohta, mis sellel real olla võib:
[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. Lühendite mõistmine ja parsimise võimalused
Tasub mainida, et paketi android.net.wifi.* klasse kasutab kapoti all Linuxi utiliit
Tegutseme järjekindlalt. Vaatleme esmalt sellise vormingu väljundit, milles sulgudes olevad elemendid on eraldatud märgiga "-":
[WPA-PSK-TKIP+CCMP]
[WPA2-PSK-CCMP]
Esimene tähendus kirjeldab nn. autentimismeetod. See tähendab, millist toimingute jada peavad seade ja pääsupunkt tegema, et pääsupunkt lubaks end kasutada ja kuidas krüpteerida kasulikku koormust. Selle postituse kirjutamise hetkel on levinumad valikud WPA ja WPA2, milles kas iga ühendatud seade otse või läbi nn. RADIUS-server (WPA-Enterprice) annab parooli krüptitud kanali kaudu. Tõenäoliselt pakub teie kodu pöörduspunkt selle skeemi järgi ühendust. Erinevus teise versiooni ja esimese vahel seisneb selles, et sellel on tugevam šifr: AES versus ebaturvaline TKIP. Tasapisi võetakse kasutusele ka WPA3, mis on keerulisem ja arenenum. Teoreetiliselt võib ettevõtte lahendusega CCKM (Cisco Centralized Key Management) olla võimalus, kuid ma pole sellega kunagi kokku puutunud.
Pöörduspunkt võib olla konfigureeritud MAC-aadressi järgi autentima. Või kui pääsupunkt edastab andmeid vananenud WEP-algoritmi abil, siis autentimist tegelikult ei toimu (salajane võti on siin krüpteerimisvõti). Me liigitame sellised valikud kategooriasse MUU.
Samuti on avalikus wi-fis populaarne meetod peidetud Captive Portal Detectioniga – autentimistaotlus läbi brauseri. Sellised pääsupunktid tunduvad skannerile avatud (mida nad füüsilise ühenduse seisukohast on). Seetõttu klassifitseerime need AVATUD.
Teist väärtust saab tähistada kui võtmehaldusalgoritm. See on ülalkirjeldatud autentimismeetodi parameeter. Räägib täpselt sellest, kuidas krüpteerimisvõtmeid vahetatakse. Vaatleme võimalikke valikuid. EAP - kasutatakse mainitud WPA-Enterprice'is, kasutab sisestatud autentimisandmete kontrollimiseks andmebaasi. SAE – kasutatakse täiustatud WPA3-s, vastupidavam toorele jõule. PSK - kõige levinum valik, hõlmab parooli sisestamist ja selle krüpteeritud kujul edastamist. IEEE8021X - vastavalt rahvusvahelisele standardile (erineb WPA perekonna toetatud standardist). OWE (Opportunistic Wireless Encryption) on IEEE 802.11 standardi laiendus punktidele, mille klassifitseerisime AVATUD. OWE tagab turvamata võrgu kaudu edastatavate andmete turvalisuse neid krüpteerides. Valik on võimalik ka siis, kui juurdepääsuklahve pole, nimetagem seda valikut EI OLE.
Kolmas parameeter on nn. krüpteerimisskeemid — kuidas täpselt šifrit edastatud andmete kaitsmiseks kasutatakse. Loetleme valikud. WEP - kasutab RC4 voošifrit, salajaseks võtmeks on krüpteerimisvõti, mida peetakse kaasaegse krüptograafia maailmas vastuvõetamatuks. TKIP - kasutatakse WPA-s, CKIP - WPA2-s. TKIP+CKIP – tagasiühilduvuse tagamiseks saab määrata WPA- ja WPA2-võimelistes punktides.
Kolme elemendi asemel võite leida üksiku WEP-märgi:
[WEP]
Nagu eespool arutasime, piisab sellest, et mitte määrata võtmete kasutamise algoritmi, mida pole olemas, ja krüpteerimismeetodit, mis on vaikimisi sama.
Nüüd kaaluge seda sulgu:
[ESS]
see Wi-Fi töörežiim või Wi-Fi võrgu topoloogia. Võite kohata režiimi BSS (Basic Service Set) – kui on üks pääsupunkt, mille kaudu ühendatud seadmed suhtlevad. Võib leida kohalikest võrkudest. Reeglina on erinevatest kohtvõrkudest pärit seadmete ühendamiseks vaja pääsupunkte, seega kuuluvad need laiendatud teenusekomplekti – ESS-i. IBSS-ide (Independent Basic Service Sets) tüüp näitab, et seade on võrdõigusvõrgu osa.
Võite näha ka WPS-i lippu:
[WPS]
WPS (Wi-Fi Protected Setup) on Wi-Fi võrgu poolautomaatse lähtestamise protokoll. Initsialiseerimiseks sisestab kasutaja kas 8-kohalise parooli või vajutab ruuteri nuppu. Kui teie pääsupunkt on esimest tüüpi ja see märkeruut kuvatakse teie pääsupunkti nime kõrval, on teil tungivalt soovitatav minna administraatoripaneelile ja keelata WPS-i juurdepääs. Fakt on see, et sageli saab 8-kohalise PIN-koodi teada MAC-aadressi järgi või saab selle ettenähtava aja jooksul korda teha, mida keegi ebaausalt ära võib kasutada.
6. Loo mudel ja sõelumisfunktsioon
Ülaltoodud andmete põhjal kirjeldame juhtunut andmeklasside abil:
/* схема аутентификации */
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.
}
Nüüd kirjutame funktsiooni, mis analüüsib võimaluste välja:
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. Vaata tulemust
Skaneerin võrku ja näitan teile, mida ma leidsin. Kuvatakse lihtsa väljundi tulemused läbi Log.d:
Capability of Home-Home [WPA2-PSK-CCMP][ESS][WPS]
...
capabilities=[Capability(authScheme=WPA2, keyManagementAlgorithm=PSK, cipherMethod=CCMP)], topologyMode=ESS, availableWps=true
Uurimata jäi rakenduskoodist võrku ühendamise küsimus. Ütlen vaid, et mobiilseadme OS-ist salvestatud paroolide lugemiseks on vaja juurõigusi ja valmisolekut failisüsteemis tuhnida, et lugeda wpa_supplicant.conf. Kui rakendusloogika nõuab parooli sisestamist väljastpoolt, saab ühenduse luua läbi klassi
Tänan
Kui arvad, et midagi vajab lisamist või parandamist, siis kirjuta kommentaaridesse :)
Allikas: www.habr.com