Isang araw kinailangan kong mag-scan mula sa Android Mga aplikasyon ng Wi-Fi network at kumuha ng detalyadong data tungkol sa mga access point.
Dito kailangan naming harapin ang ilang mga paghihirap: marami sa mga inilarawang klase ay hindi na ginagamit (API level > 26), na hindi makikita dito; ang paglalarawan ng ilang bagay sa dokumentasyon ay minimal (halimbawa, ang field ng mga kakayahan ng klase sa panahon ng pagsulat, halos walang inilarawan, bagaman naglalaman ito ng maraming mahahalagang data). Ang pangatlong kahirapan ay maaaring nakasalalay sa katotohanan na kapag una kang nakalapit sa Wi-Fi, maliban sa pagbabasa ng teorya at pag-set up ng router sa pamamagitan ng localhost, kailangan mong harapin ang isang bilang ng mga pagdadaglat na tila naiintindihan nang paisa-isa. Ngunit maaaring hindi halata kung paano iuugnay at binubuo ang mga ito (ang paghuhusga ay subjective at depende sa nakaraang karanasan).
Tinatalakay ng artikulong ito kung paano Android code para makakuha ng komprehensibong datos tungkol sa kapaligirang Wi-Fi nang walang NDK, mga hack, ngunit sa tulong lamang ng Android mga API at maunawaan kung paano bigyang-kahulugan ang mga ito.
Huwag tayong mag-antala at magsimulang magsulat ng code.
1. Gumawa ng proyekto
Ang talang ito ay para sa mga lumikha nang higit sa isang beses Android proyekto, kaya lalaktawan natin ang mga detalye ng seksyong ito. Ang code sa ibaba ay ipapakita sa Kotlin, minSdkVersion=23.
2. Mga pahintulot sa pag-access
Upang gumana sa Wi-Fi mula sa application, kakailanganin mong kumuha ng ilang mga pahintulot mula sa user. Alinsunod sa , para ma-scan ang network sa mga device na may mga bersyon ng OS pagkatapos ng 8.0, bilang karagdagan sa pag-access sa pagtingin sa estado ng network environment, kailangan mo ng access para baguhin ang estado ng Wi-Fi module ng device, o access sa mga coordinate (tinatayang o eksakto). Simula sa bersyon 9.0, dapat mong i-prompt ang user para sa pareho, at tahasan ding hilingin sa user na i-on ang mga serbisyo ng lokasyon. Huwag kalimutang buong galak na ipaliwanag sa user na ito ay kapritso ng Google, at hindi ang aming pagnanais na tiktikan siya :)
Sa kabuuan, sa AndroidIdagdag ang Manifest.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"/>
At sa code na naglalaman ng isang link sa kasalukuyang Aktibidad:
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. Gumawa ng BroadcastReceiver at mag-subscribe sa mga kaganapan sa pag-update ng data tungkol sa pag-scan sa kapaligiran ng Wi-Fi network
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
}
Ang paraan ng WiFiManager.startScan sa dokumentasyon ay minarkahan bilang depricated mula noong bersyon 28 ng API, ngunit naka-off. nagmumungkahi ng paggamit nito.
Sa kabuuan, nakatanggap kami ng isang listahan ng mga bagay .
4. Tingnan ang ScanResult at unawain ang mga tuntunin
Tingnan natin ang ilang larangan ng klase na ito at ilarawan kung ano ang ibig sabihin ng mga ito:
SSID — Ang Service Set Identifier ay ang pangalan ng network
BSSID – Basic Service Set Identifier – MAC address ng network adapter (Wi-Fi point)
antas — Received Signal Strength Indicator [dBm (Russian dBm) — Decibel, reference power 1 mW.] — Isang indicator ng natanggap na lakas ng signal. Tumatagal ng value mula 0 hanggang -100, mas malayo mula sa 0, mas maraming signal ang mawawala sa daan mula sa Wi-Fi point papunta sa iyong device. Higit pang mga detalye ay matatagpuan, halimbawa, sa Dito ko sasabihin sa iyo kung ano ang gagawin sa tulong ng Android klase maaari mong i-calibrate ang antas ng signal sa isang sukat mula sa mahusay hanggang sa kahila-hilakbot sa hakbang na iyong pinili:
val wifiManager = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
val numberOfLevels = 5
val level = WifiManager.calculateSignalLevel(level, numberOfLevels)
dalas — dalas ng pagpapatakbo ng Wi-Fi point [Hz]. Bilang karagdagan sa dalas mismo, maaari kang maging interesado sa tinatawag na channel. Ang bawat punto ay may sariling kadalisayan ng pagpapatakbo. Sa oras ng pagsulat, ang pinakasikat na hanay ng mga Wi-Fi point ay 2.4 GHz. Ngunit, upang maging mas tumpak, ang punto ay nagpapadala ng impormasyon sa iyong telepono sa isang bilang na dalas na malapit sa pinangalanan. Bilang ng mga channel at kaukulang frequency . Ginagawa ito upang ang mga kalapit na punto ay gumana sa iba't ibang mga frequency, sa gayon ay hindi nakakasagabal sa isa't isa at hindi nababawasan ang bilis at kalidad ng paghahatid. Sa kasong ito, ang mga punto ay gumagana hindi sa isang dalas, ngunit sa isang hanay ng mga frequency (parameter channelWidth), na tinatawag na lapad ng channel. Iyon ay, ang mga puntos na tumatakbo sa katabi (at hindi lamang katabi, ngunit kahit na 3 mula sa kanilang sarili) na mga channel ay nakakasagabal sa bawat isa. Maaari mong makitang kapaki-pakinabang ang simpleng code na ito, na nagbibigay-daan sa iyong kalkulahin ang numero ng channel mula sa halaga ng dalas para sa mga puntos na may dalas na 2.4 at 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
}
}
mga kakayahan - ang pinaka-kagiliw-giliw na patlang para sa pagsusuri, trabaho kung saan nangangailangan ng maraming oras. Dito nakasulat sa linya ang "mga kakayahan" ng punto. Sa kasong ito, hindi mo kailangang maghanap ng mga detalye ng interpretasyon ng string sa dokumentasyon. Narito ang ilang halimbawa ng maaaring nasa linyang ito:
[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. Pag-unawa sa mga abbreviation at mga kakayahan sa pag-parse
Ito ay nagkakahalaga ng pagbanggit na ang mga klase ng android.net.wifi.* package ay ginagamit sa ilalim ng hood ng isang Linux utility at ang resulta ng output sa field ng mga kakayahan ay isang kopya ng field ng mga flag kapag nag-scan.
Kami ay kikilos nang tuluy-tuloy. Isaalang-alang muna natin ang output ng isang format kung saan ang mga elemento sa loob ng mga panaklong ay pinaghihiwalay ng isang “-“ sign:
[WPA-PSK-TKIP+CCMP]
[WPA2-PSK-CCMP]
Ang unang kahulugan ay naglalarawan sa tinatawag na. Pamamaraan Authentication. Ibig sabihin, anong pagkakasunud-sunod ng mga aksyon ang dapat gawin ng device at ng access point para payagan ng access point ang sarili nitong magamit at kung paano i-encrypt ang payload. Sa oras ng pagsulat ng post na ito, ang pinakakaraniwang mga opsyon ay WPA at WPA2, kung saan ang bawat konektadong device nang direkta o sa pamamagitan ng tinatawag na. Ang RADIUS server (WPA-Enterprice) ay nagbibigay ng password sa isang naka-encrypt na channel. Malamang, ang access point sa iyong tahanan ay nagbibigay ng koneksyon ayon sa pamamaraang ito. Ang pagkakaiba sa pagitan ng pangalawang bersyon at ng una ay mayroon itong mas malakas na cipher: AES kumpara sa hindi secure na TKIP. Ang WPA3, na mas kumplikado at advanced, ay unti-unting ipinakilala. Sa teoryang, maaaring mayroong opsyon sa enterprice solution na CCKM (Cisco Centralized Key Management), ngunit hindi ko pa ito nakita.
Maaaring na-configure ang access point upang patotohanan sa pamamagitan ng MAC address. O, kung ang access point ay nagbibigay ng data gamit ang hindi napapanahong WEP algorithm, kung gayon ay talagang walang pagpapatunay (ang sikretong key dito ay ang encryption key). Inuri namin ang mga opsyon bilang OTHER.
Mayroon ding paraan na sikat sa pampublikong wi-fi na may nakatagong Captive Portal Detection - isang kahilingan sa pagpapatunay sa pamamagitan ng browser. Ang ganitong mga access point ay lilitaw sa scanner bilang bukas (na sila ay mula sa punto ng view ng pisikal na koneksyon). Samakatuwid, inuuri namin ang mga ito bilang OPEN.
Ang pangalawang halaga ay maaaring tukuyin bilang pangunahing algorithm ng pamamahala. Ito ay isang parameter ng paraan ng pagpapatunay na inilarawan sa itaas. Pinag-uusapan nang eksakto kung paano ipinagpapalit ang mga susi sa pag-encrypt. Isaalang-alang natin ang mga posibleng opsyon. EAP - ginagamit sa nabanggit na WPA-Enterprice, ay gumagamit ng database upang i-verify ang ipinasok na data ng pagpapatunay. SAE - ginagamit sa advanced na WPA3, mas lumalaban sa brute force. Ang PSK - ang pinakakaraniwang opsyon, ay nagsasangkot ng pagpasok ng password at pagpapadala nito sa naka-encrypt na form. IEEE8021X - ayon sa isang internasyonal na pamantayan (iba sa sinusuportahan ng pamilyang WPA). Ang OWE (Opportunistic Wireless Encryption) ay isang extension ng IEEE 802.11 standard para sa mga puntos na inuri namin bilang OPEN. Tinitiyak ng OWE ang seguridad ng data na ipinadala sa isang hindi secure na network sa pamamagitan ng pag-encrypt nito. Posible rin ang isang opsyon kapag walang access key, tawagan natin itong opsyong WALA.
Ang ikatlong parameter ay ang tinatawag na. mga scheme ng pag-encrypt — kung paano eksaktong ginagamit ang cipher upang protektahan ang ipinadalang data. Ilista natin ang mga opsyon. WEP - gumagamit ng RC4 stream cipher, ang sikretong key ay ang encryption key, na itinuturing na hindi katanggap-tanggap sa mundo ng modernong cryptography. TKIP - ginagamit sa WPA, CKIP - sa WPA2. TKIP+CKIP - maaaring tukuyin sa mga puntos na may kakayahang WPA at WPA2 para sa pabalik na pagkakatugma.
Sa halip na tatlong elemento, makakahanap ka ng malungkot na marka ng WEP:
[WEP]
Tulad ng aming tinalakay sa itaas, ito ay sapat na hindi upang tukuyin ang algorithm para sa paggamit ng mga susi, na hindi umiiral, at ang paraan ng pag-encrypt, na pareho sa default.
Ngayon isaalang-alang ang bracket na ito:
[ESS]
Ito Wi-Fi operating mode o Topology ng Wi-Fi network. Maaari kang makatagpo ng BSS (Basic Service Set) mode - kapag mayroong isang access point kung saan nakikipag-ugnayan ang mga konektadong device. Maaaring matagpuan sa mga lokal na network. Bilang isang tuntunin, kailangan ang mga access point para ikonekta ang mga device mula sa iba't ibang lokal na network, kaya bahagi sila ng Mga Extended Service Sets - ESS. Ang uri ng IBSSs (Independent Basic Service Sets) ay nagpapahiwatig na ang device ay bahagi ng isang Peer-to-Peer network.
Maaari mo ring makita ang watawat ng WPS:
[WPS]
Ang WPS (Wi-Fi Protected Setup) ay isang protocol para sa semi-awtomatikong pagsisimula ng isang Wi-Fi network. Upang makapagsimula, ang user ay maaaring magpasok ng isang 8-character na password o pinindot ang isang pindutan sa router. Kung ang iyong access point ay nasa unang uri at ang checkbox na ito ay lilitaw sa tabi ng pangalan ng iyong access point, lubos kang inirerekomenda na pumunta sa admin panel at huwag paganahin ang WPS access. Ang katotohanan ay madalas na ang 8-digit na PIN ay maaaring malaman ng MAC address, o maaari itong ayusin sa isang nakikinita na oras, na maaaring samantalahin ng isang tao nang hindi tapat.
6. Gumawa ng modelo at pag-parse function
Batay sa nalaman namin sa itaas, ilalarawan namin kung ano ang nangyari gamit ang mga klase ng 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.
}
Ngayon magsulat tayo ng isang function na mag-parse sa field ng mga kakayahan:
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. Tingnan ang resulta
I-scan ko ang network at ipapakita sa iyo kung ano ang nakita ko. Ipinapakita ang mga resulta ng simpleng output sa pamamagitan ng Log.d:
Capability of Home-Home [WPA2-PSK-CCMP][ESS][WPS]
...
capabilities=[Capability(authScheme=WPA2, keyManagementAlgorithm=PSK, cipherMethod=CCMP)], topologyMode=ESS, availableWps=true
Ang isyu ng pagkonekta sa network mula sa application code ay nanatiling hindi napag-aralan. Sasabihin ko lang na upang mabasa ang mga naka-save na password mula sa OS ng isang mobile device, kailangan mo ng mga karapatan sa ugat at isang pagpayag na halukayin ang file system upang mabasa ang wpa_supplicant.conf. Kung ang application logic ay nangangailangan ng pagpasok ng password mula sa labas, ang koneksyon ay maaaring gawin sa pamamagitan ng klase .
salamat para sa mahahalagang karagdagan.
Kung sa tingin mo ay may kailangang idagdag o itama, sumulat sa mga komento :)
Pinagmulan: www.habr.com
