واي فاي والعديد من الاختصارات الأخرى. كيفية الحصول على البيانات على عقد Wi-Fi في تطبيق Android وليس الانتفاخ

بمجرد أن أحتاج إلى مسح تطبيقات شبكة Wi-Fi من Android والحصول على حساب تفصيلي للبيانات حول نقاط الوصول.

كان عليّ أن أواجه عدة صعوبات: في الوثائق غير الرسمية لنظام أندرويد ، تم إهمال العديد من الفئات الموصوفة (مستوى API> 26) ، وهو ما لم ينعكس فيه ؛ وصف بعض الأشياء في الوثائق هو الحد الأدنى (على سبيل المثال ، لم يتم وصف حقل القدرات لفئة ScanResult في وقت الكتابة بأي طريقة ، على الرغم من أنه يحتوي على الكثير من البيانات المهمة). قد تكون الصعوبة الثالثة هي أنه عند الاقتراب من Wi-Fi لأول مرة ، والذي يختلف عن قراءة النظرية وإعداد جهاز التوجيه لـ المضيف المحلي ، يجب عليك التعامل مع عدد من الاختصارات التي يبدو أنها مفهومة بشكل منفصل. لكن قد لا يكون من الواضح كيفية الارتباط بهيكله (الحكم شخصي ويعتمد على الخبرة السابقة).

تتناول هذه المقالة كيفية الحصول على بيانات شاملة عن بيئات Wi-Fi من كود Android بدون NDK ، الاختراقات ، ولكن فقط باستخدام Android API وفهم كيفية تفسيرها.

لن نسحب ونبدأ في كتابة الكود.

1. إنشاء مشروع


تم تصميم الملاحظة لأولئك الذين قاموا بإنشاء مشروع Android أكثر من مرة ، وبالتالي فإننا نحذف تفاصيل هذا العنصر. سيتم تقديم الكود أدناه بلغة Kotlin ، minSdkVersion = 23.

2. أذونات الوصول


للعمل مع Wi-Fi من التطبيق ، ستحتاج إلى الحصول على أذونات متعددة من المستخدم. وفقًا للوثائق ، من أجل مسح الشبكة على الأجهزة التي تعمل بإصدارات نظام التشغيل بعد 8.0 ، بالإضافة إلى الوصول لعرض حالة بيئة الشبكة ، تحتاج إما إلى الوصول لتغيير حالة وحدة Wi-Fi في الجهاز أو الوصول إلى الإحداثيات (تقريبية أو دقيقة). بدءًا من الإصدار 9.0 ، يجب أن تطلب من المستخدم كل من هذه وذاك ، وفي نفس الوقت يطلب من المستخدم صراحة تمكين خدمة الموقع. لا تنس أن تشرح للمستخدم بشجاعة أن هذا هو نزوة من جوجل ، وليس رغبتنا في التجسس عليه :)

الإجمالي ، في 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 الوارد في الوثائق على أنه غير موصوف من الإصدار 28 من واجهة برمجة التطبيقات ، ولكن تم إيقاف تشغيله. دليل يقترح استخدامه.

في المجموع ، تلقينا قائمة كائنات ScanResult .

4. نحن ننظر إلى ScanResult وفهم المصطلحات


دعونا نلقي نظرة على بعض الحقول من هذا الفصل ووصف ما تعنيه:

SSID - معرف مجموعة الخدمة هو اسم الشبكة.

BSSID - معرف مجموعة الخدمات الأساسية - عنوان MAC لمحول الشبكة (نقطة Wi-Fi)

المستوى - مؤشر قوة الإشارة المستقبلة [dBm (dBm الروسي) - ديسيبل ، القدرة المرجعية 1 mW.] - مؤشر مستوى الإشارة المستقبلة. يتطلب الأمر قيمة من 0 إلى -100 ، وكلما زادت المسافة من 0 ، زادت قوة الإشارة على طول الطريق من نقطة Wi-Fi إلى جهازك. يمكن العثور على مزيد من التفاصيل ، على سبيل المثال ، على ويكيبيديا . سوف أخبرك هنا أنه باستخدام WifiManager فئة Android ، يمكنك معايرة مستوى الإشارة على مقياس من ممتاز إلى فظيع مع الخطوة التي حددتها:

  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 جيجا هرتز. ولكي نكون أكثر دقة ، فإن النقطة تنقل المعلومات إلى هاتفك بتردد رقمي قريب من التردد المحدد. يتم توحيد عدد القنوات وقيم الترددات المقابلة. يتم ذلك بحيث تعمل النقاط القريبة بترددات مختلفة ، وبالتالي لا تتداخل مع بعضها البعض ولا تقلل بشكل متبادل من سرعة وجودة الإرسال. في الوقت نفسه ، لا تعمل النقاط على نفس التردد ، ولكن على نطاق التردد ( معلمة channelWidth) ، ويسمى عرض القناة. أي أن النقاط التي تعمل على القنوات المجاورة (وليس فقط على القنوات المجاورة ، ولكن حتى على 3 من نفسها) تخلق تداخلًا مع بعضها البعض. يمكن أن يكون هذا الرمز البسيط مفيدًا لك ، والذي يسمح لك بحساب رقم القناة حسب قيمة التردد للنقاط بتردد 2.4 و 5 غيغاهرتز:

 /*      */ 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. فهم الاختصارات وقدرات parsim


تجدر الإشارة إلى أن فئات الحزمة android.net.wifi. * تستخدم أداة wux_supplicant linux تحت الغطاء ، والإخراج في حقل القدرات هو نسخة من حقل الإشارات أثناء المسح.

سوف نتصرف بالتتابع. أولاً ، ضع في اعتبارك إخراج التنسيق الذي يتم فيه فصل العناصر الموجودة داخل الأقواس بعلامة "-":

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

القيمة الأولى تصف ما يسمى طريقة المصادقة بمعنى ، ما هي سلسلة الإجراءات التي يجب أن يقوم بها الجهاز ونقطة الوصول بحيث تسمح نقطة الوصول لنفسها باستخدام طريقة تشفير الحمولة الصافية. في وقت كتابة هذا المنشور ، كانت الخيارات الأكثر شيوعًا هي WPA و WPA2 ، حيث يكون كل جهاز متصل مباشرةً أو من خلال ما يسمى. يوفر خادم RADIUS (WPA-Enterprice) كلمة مرور عبر قناة مشفرة. على الأرجح ، في منزلك ، توفر نقطة الوصول اتصالًا وفقًا لهذا المخطط. الفرق بين الإصدار الثاني والأول في تشفير أكثر قوة: AES ضد TKIP غير الآمن. WPA3 ، وهو أكثر تعقيدًا وتقدماً ، يتم أيضًا إدخاله تدريجياً. من الناحية النظرية ، قد يكون هناك خيار في حل سعر CCKM (Cisco Centralized Key Managment) ، لكنني لم أقابله مطلقًا.

يمكن تكوين نقطة الوصول للمصادقة بواسطة عنوان MAC. أو ، إذا كانت نقطة الوصول توفر البيانات باستخدام خوارزمية WEP القديمة ، فليس هناك مصادقة تقريبًا (المفتاح السري هنا هو مفتاح التشفير). يتم تصنيف هذه الخيارات على أنها أخرى.
هناك أيضًا طريقة مفضلة في شبكة wi-fi العامة مع ميزة Captive Portal Detection المخفية - طلب المصادقة من خلال متصفح. تبدو نقاط الوصول هذه مفتوحة للماسحة الضوئية (وهي من وجهة نظر الاتصال الفعلي). لذلك ، نحن تصنيفها بأنها مفتوحة.

يمكن تعيين القيمة الثانية كخوارزمية إدارة المفاتيح . إنها معلمة لطريقة المصادقة الموضحة أعلاه. محادثات حول كيفية بالضبط تبادل مفاتيح التشفير يحدث. لننظر في الخيارات الممكنة. يستخدم EAP - المستخدم في WPA-Enterprice المذكور أعلاه ، قاعدة بيانات للتحقق من بيانات المصادقة المدخلة. SAE - يستخدم في WPA3 المتقدم ، أكثر مقاومة للخرق. PSK هو الخيار الأكثر شيوعًا ، فهو يتضمن إدخال كلمة المرور ونقلها في شكل مشفر. IEEE8021X - وفقًا للمعايير الدولية (بخلاف ما تدعمه عائلة WPA). OWE (التشفير اللاسلكي الانتهازي) هو امتداد لمعيار IEEE 802.11 ، للنقاط التي صنّفناها على أنها OPEN. يضمن OWE أمان البيانات المرسلة عبر شبكة غير آمنة من خلال تشفيرها. متغير ممكن أيضًا عند عدم وجود مفاتيح وصول ؛ دعنا نسمي هذا الخيار NONE.

المعلمة الثالثة هي ما يسمى طريقة التشفير (مخططات التشفير) - ما مدى دقة استخدام الشفرة لحماية البيانات المرسلة. نحن قائمة الخيارات. WEP - يستخدم تشفير دفق RC4 ، المفتاح السري هو مفتاح تشفير ، والذي يعتبر غير مقبول في عالم التشفير الحديث. TKIP - المستخدمة في WPA ، CKIP - في WPA2. يمكن تحديد TKIP + CKIP - عند نقاط قادرة على WPA و WPA2 للتوافق مع الإصدارات السابقة.

بدلاً من ثلاثة عناصر ، يمكنك العثور على علامة WEP وحيدة:

 [WEP] 

كما ناقشنا أعلاه ، هذا يكفي لعدم تحديد الخوارزمية لاستخدام المفاتيح ، والتي ليست موجودة ، وطريقة التشفير ، والتي هي طريقة واحدة بشكل افتراضي.

الآن النظر في هذه الفئة:

 [ESS] 

هذا هو وضع تشغيل Wi-Fi أو طوبولوجيا شبكات Wi-Fi . قد تواجه وضع BSS (مجموعة الخدمات الأساسية) - عند وجود نقطة وصول واحدة تتواصل من خلالها الأجهزة المتصلة. يمكن العثور عليها على الشبكات المحلية. عادةً ما تكون نقاط الوصول مطلوبة لتوصيل الأجهزة من شبكات محلية مختلفة ، لذا فهي جزء من Extended Service Sets - ESS. يشير نوع IBSS (مجموعات الخدمة الأساسية المستقلة) إلى أن الجهاز جزء من شبكة نظير إلى نظير.

قد تسقط علامة WPS أيضًا:

 [WPS] 

WPS (الإعداد المحمي بالدقة اللاسلكية) - بروتوكول للتهيئة شبه الآلية لشبكة Wi-Fi. للتهيئة ، يقوم المستخدم إما بإدخال كلمة مرور مكونة من 8 أحرف أو يشبك زرًا على جهاز التوجيه. إذا كانت نقطة الوصول من النوع الأول وتم تمييز هذه العلامة مقابل اسم نقطة الوصول الخاصة بك ، يوصى بشدة بالانتقال إلى لوحة المسؤول وتعطيل الوصول عبر WPS. والحقيقة هي أنه في كثير من الأحيان يمكن التعرف على رمز PIN المكون من 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 

ظلت مسألة الاتصال بالشبكة من رمز التطبيق غير مضاءة. لا يمكنني إلا أن أقول أنه من أجل قراءة كلمات مرور نظام التشغيل المحفوظة لجهاز محمول ، فإنك تحتاج إلى حقوق الجذر واستعداد للبحث في نظام الملفات لقراءة wpa_supplicant.conf. إذا كان منطق التطبيق يتضمن إدخال كلمة مرور من الخارج ، فيمكن إجراء الاتصال من خلال فئة android.net.wifi.WifiManager .

بفضل إيجور بونوماريف لإضافات قيمة.

إذا كنت تعتقد أنك بحاجة إلى إضافة أو إصلاح شيء ما ، فاكتب في التعليقات :)

Source: https://habr.com/ru/post/ar467765/


All Articles