Нэг өдөр би Android програмуудаас Wi-Fi сүлжээг сканнердаж, хандалтын цэгүүдийн талаар дэлгэрэнгүй мэдээлэл авах шаардлагатай болсон.
Энд бид хэд хэдэн бэрхшээлтэй тулгарсан:
Энэ нийтлэлд NDK, хакердалгүйгээр, зөвхөн Android API ашиглан Wi-Fi орчны талаарх дэлгэрэнгүй мэдээллийг Android кодоос хэрхэн олж авах, хэрхэн тайлбарлах талаар ярилцах болно.
Хойшлуулахгүй, код бичиж эхэлцгээе.
1. Төсөл үүсгэх
Энэхүү тэмдэглэл нь Android төсөл нэгээс олон удаа үүсгэсэн хүмүүст зориулагдсан тул бид энэ зүйлийн дэлгэрэнгүй мэдээллийг орхигдуулсан болно. Доорх кодыг Kotlin, minSdkVersion=23 дээр үзүүлнэ.
2. Хандалтын зөвшөөрөл
Програмаас Wi-Fi-тай ажиллахын тулд та хэрэглэгчээс хэд хэдэн зөвшөөрөл авах шаардлагатай болно. -ын дагуу
Тиймээс, 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"/>
Мөн одоогийн үйл ажиллагааны холбоосыг агуулсан кодонд:
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. BroadcastReceiver үүсгэж, 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
}
Баримт бичигт WiFiManager.startScan аргыг API хувилбар 28-аас хойш хасагдсан гэж тэмдэглэсэн боловч унтраасан байна.
Нийтдээ бид объектуудын жагсаалтыг хүлээн авсан
4. ScanResult-г хараад нэр томъёог нь ойлгоорой
Энэ ангийн зарим талбаруудыг авч үзээд ямар утгатай болохыг тайлбарлая:
SSID — Үйлчилгээний багц танигч нь сүлжээний нэр юм
BSSID – Үндсэн үйлчилгээний багц танигч – сүлжээний адаптерийн MAC хаяг (Wi-Fi цэг)
түвшин — Хүлээн авсан дохионы хүч чадлын үзүүлэлт [дБм (Оросын дБм) — Децибел, жишиг хүч 1 мВт.] — Хүлээн авсан дохионы хүч чадлын үзүүлэлт. 0-ээс -100 хүртэлх утгыг авна, 0-ээс холдох тусам Wi-Fi цэгээс таны төхөөрөмж рүү хүрэх замд илүү их дохионы хүч алдагдана. Дэлгэрэнгүй мэдээллийг, жишээлбэл, эндээс олж болно
val wifiManager = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
val numberOfLevels = 5
val level = WifiManager.calculateSignalLevel(level, numberOfLevels)
давтамж — Wi-Fi цэгийн ажиллах давтамж [Гц]. Давтамжаас гадна та суваг гэж нэрлэгддэг сувгийг сонирхож магадгүй юм. Цэг бүр өөрийн гэсэн цэвэршилттэй байдаг. Үүнийг бичиж байх үед Wi-Fi цэгүүдийн хамгийн алдартай хүрээ нь 2.4 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
}
}
Боломжууд - маш их цаг хугацаа шаардсан дүн шинжилгээ хийх хамгийн сонирхолтой талбар. Энд цэгийн "чадвар" -ыг мөрөнд бичсэн болно. Энэ тохиолдолд та баримт бичигт мөрийн тайлбарын дэлгэрэнгүй мэдээллийг хайх шаардлагагүй. Энэ мөрөнд юу байж болох зарим жишээ энд байна:
[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. Товчлол, задлан шинжлэх чадварыг ойлгох
Android.net.wifi.* багцын ангиудыг Линукс хэрэглүүрийн дор ашигладаг гэдгийг дурдах нь зүйтэй.
Бид тууштай ажиллах болно. Эхлээд хаалт доторх элементүүдийг "-" тэмдгээр тусгаарласан форматын гаралтыг авч үзье.
[WPA-PSK-TKIP+CCMP]
[WPA2-PSK-CCMP]
Эхний утга нь гэж нэрлэгддэг зүйлийг тодорхойлдог. баталгаажуулах арга. Өөрөөр хэлбэл, хандалтын цэгийг өөрөө ашиглах, ачааллыг хэрхэн шифрлэхийг зөвшөөрөхийн тулд төхөөрөмж болон хандалтын цэг нь ямар дарааллаар ажиллах ёстой вэ. Энэ нийтлэлийг бичиж байх үед хамгийн түгээмэл сонголт бол WPA ба WPA2 бөгөөд тэдгээр нь төхөөрөмж бүрийг шууд эсвэл дамжуулан холбож өгдөг. RADIUS сервер (WPA-Enterprice) нь шифрлэгдсэн сувгаар нууц үг өгдөг. Магадгүй таны гэрт нэвтрэх цэг нь энэ схемийн дагуу холболтыг хангадаг. Хоёрдахь хувилбар болон эхний хувилбарын хоорондох ялгаа нь илүү хүчтэй шифртэй байдаг: AES нь найдвартай биш TKIP-тэй харьцуулахад. Илүү төвөгтэй, дэвшилтэт WPA3-ийг мөн аажмаар нэвтрүүлж байна. Онолын хувьд CCKM (Cisco Төвлөрсөн Түлхүүр Удирдлага) гэсэн аж ахуйн нэгжийн шийдэлтэй сонголт байж болох ч би үүнийг хэзээ ч харж байгаагүй.
Хандалтын цэгийг MAC хаягаар баталгаажуулахаар тохируулсан байж магадгүй. Эсвэл, хэрэв хандалтын цэг нь хуучирсан WEP алгоритмыг ашиглан өгөгдөл өгдөг бол үнэн хэрэгтээ баталгаажуулалт байхгүй болно (энд нууц түлхүүр нь шифрлэлтийн түлхүүр юм). Бид ийм сонголтыг БУСАД гэж ангилдаг.
Мөн олон нийтийн wi-fi-д түгээмэл хэрэглэгддэг, олзлогдсон портал илрүүлэх далд арга байдаг - хөтчөөр дамжуулан баталгаажуулах хүсэлт. Ийм хандалтын цэгүүд нь сканнерт нээлттэй мэт харагддаг (энэ нь физик холболтын үүднээс). Тиймээс бид тэдгээрийг НЭЭЛТТЭЙ гэж ангилдаг.
Хоёр дахь утгыг дараах байдлаар тэмдэглэж болно гол удирдлагын алгоритм. Энэ нь дээр дурдсан баталгаажуулалтын аргын параметр юм. Шифрлэлтийн түлхүүрүүдийг яг хэрхэн сольж байгаа талаар ярьдаг. Боломжит хувилбаруудыг авч үзье. EAP - дурдсан WPA-Enterprice-д ашигладаг бөгөөд оруулсан баталгаажуулалтын өгөгдлийг шалгахын тулд мэдээллийн санг ашигладаг. SAE - дэвшилтэт WPA3-д ашиглагддаг, харгис хэрцгий хүчинд илүү тэсвэртэй. PSK - хамгийн түгээмэл сонголт бол нууц үг оруулах, шифрлэгдсэн хэлбэрээр дамжуулах явдал юм. IEEE8021X - олон улсын стандартын дагуу (WPA гэр бүлийн дэмждэг стандартаас өөр). OWE (Opportunistic Wireless Encryption) нь бидний НЭЭЛТТЭЙ гэж ангилсан онооны IEEE 802.11 стандартын өргөтгөл юм. OWE нь хамгаалалтгүй сүлжээгээр дамжуулж буй мэдээллийн аюулгүй байдлыг шифрлэх замаар баталгаажуулдаг. Хандалтын түлхүүр байхгүй үед сонголт бас боломжтой, энэ сонголтыг NONE гэж нэрлэе.
Гурав дахь параметр нь гэж нэрлэгддэг параметр юм. шифрлэлтийн схемүүд - дамжуулагдсан өгөгдлийг хамгаалахын тулд шифрийг яг хэрхэн ашигладаг. Сонголтуудыг жагсаацгаая. WEP - RC4 урсгалын шифрийг ашигладаг бөгөөд нууц түлхүүр нь шифрлэлтийн түлхүүр бөгөөд орчин үеийн криптографийн ертөнцөд хүлээн зөвшөөрөгдөхгүй гэж үздэг. TKIP - WPA-д, CKIP - WPA2-д ашиглагддаг. TKIP+CKIP - хоцрогдсон нийцтэй байдлын үүднээс WPA болон WPA2 боломжтой цэгүүдэд зааж өгч болно.
Гурван элементийн оронд та ганцаардсан WEP тэмдгийг олж болно:
[WEP]
Дээр дурдсанчлан, энэ нь байхгүй түлхүүрүүдийг ашиглах алгоритм болон анхдагчаар ижил шифрлэлтийн аргыг зааж өгөхгүй байхад хангалттай юм.
Одоо энэ хаалтыг авч үзье:
[ESS]
энэ Wi-Fi үйлдлийн горим буюу Wi-Fi сүлжээний топологи. Холбогдсон төхөөрөмжүүд хоорондоо холбогддог нэг хандалтын цэг байгаа үед та BSS (Үндсэн үйлчилгээний багц) горимтой тулгарч магадгүй юм. Дотоод сүлжээнээс олж болно. Дүрмээр бол хандалтын цэгүүд нь өөр өөр дотоод сүлжээнээс төхөөрөмжүүдийг холбоход шаардлагатай байдаг тул тэдгээр нь Өргөтгөсөн үйлчилгээний багц - ESS-ийн нэг хэсэг юм. IBSSs (Independent Basic Service Sets) төрөл нь төхөөрөмж нь Peer-to-Peer сүлжээний нэг хэсэг гэдгийг харуулж байна.
Та мөн WPS тугийг харж болно:
[WPS]
WPS (Wi-Fi Protected Setup) нь Wi-Fi сүлжээг хагас автоматаар эхлүүлэх протокол юм. Эхлэхийн тулд хэрэглэгч 8 тэмдэгтээс бүрдэх нууц үг оруулах эсвэл чиглүүлэгч дээрх товчлуурыг дарна. Хэрэв таны хандалтын цэг эхний төрлийнх бөгөөд таны хандалтын цэгийн нэрний хажууд энэ нүд гарч байвал админ самбар руу орж WPS хандалтыг идэвхгүй болгохыг зөвлөж байна. Баримт нь ихэвчлэн 8 оронтой ПИН кодыг MAC хаягаар нь олж мэдэх, эсвэл хэн нэгэн шударга бусаар ашиглаж болох ойрын хугацаанд эрэмбэлэх боломжтой байдаг.
6. Загвар болон задлан шинжлэх функцийг үүсгэ
Дээр дурдсан зүйлс дээр үндэслэн бид өгөгдлийн ангиудыг ашиглан юу болсныг тайлбарлах болно.
/* схема аутентификации */
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.
}
Одоо боломжуудын талбарыг задлан шинжлэх функц бичье:
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. Үр дүнг харна уу
Би сүлжээгээ сканнердаж, юу олсоноо харуулах болно. Log.d-ээр дамжуулан энгийн гаралтын үр дүнг харуулав:
Capability of Home-Home [WPA2-PSK-CCMP][ESS][WPS]
...
capabilities=[Capability(authScheme=WPA2, keyManagementAlgorithm=PSK, cipherMethod=CCMP)], topologyMode=ESS, availableWps=true
Програмын кодоос сүлжээнд холбогдох асуудал шалгагдаагүй хэвээр байна. Хөдөлгөөнт төхөөрөмжийн үйлдлийн системээс хадгалсан нууц үгийг уншихын тулд танд root эрх, wpa_supplicant.conf-г уншихын тулд файлын системээр гүйлгэх хүсэл хэрэгтэй гэдгийг л хэлье. Хэрэглээний логик нь гаднаас нууц үг оруулах шаардлагатай бол классаар дамжуулан холболт хийж болно
Спасибо
Хэрэв та ямар нэг зүйл нэмэх эсвэл засах шаардлагатай гэж бодож байвал сэтгэгдэл дээр бичээрэй :)
Эх сурвалж: www.habr.com