डेवलपर्स: एंड्रॉइड के छिपे हुए एपीआई प्रतिबंधों को बायपास करना बहुत आसान है

click fraud protection

एंड्रॉइड 9 पाई और एंड्रॉइड 10 चेतावनियां देते हैं या छिपे हुए एपीआई तक सीधे पहुंच को रोकते हैं। यहां बताया गया है कि डेवलपर्स छुपे हुए एपीआई प्रतिबंधों से कैसे बच सकते हैं।

एक साल से भी अधिक समय पहले का फ्लैशबैक, और हम सभी यह देखने के लिए उत्साहित हैं कि Android P बीटा में क्या आने वाला है। उपयोगकर्ता नई सुविधाओं की प्रतीक्षा कर रहे हैं, और डेवलपर्स अपने ऐप्स को बेहतर बनाने के लिए कुछ नए टूल की प्रतीक्षा कर रहे हैं। दुर्भाग्य से उनमें से कुछ डेवलपर्स के लिए, पहला एंड्रॉइड पी बीटा थोड़ा अजीब आश्चर्य के साथ आया: छिपे हुए एपीआई प्रतिबंध। इससे पहले कि मैं वास्तव में इसका मतलब समझूं, मैं इसके संदर्भ के बारे में थोड़ा समझा दूं।

यहाँ सब किसके लिए है?

एंड्रॉइड ऐप डेवलपर्स को ऐप बनाते समय शुरुआत से शुरुआत करने की ज़रूरत नहीं होती है। Google ऐप विकास को आसान और कम दोहराव वाला बनाने के लिए टूल प्रदान करता है। इनमें से एक टूल Android SDK है। एसडीके अनिवार्य रूप से उन सभी कार्यों का संदर्भ है जिन्हें डेवलपर्स अपने ऐप्स में सुरक्षित रूप से उपयोग कर सकते हैं। ये फ़ंक्शन एंड्रॉइड के उन सभी वेरिएंट पर मानक आते हैं जिन्हें Google अनुमोदित करता है। हालाँकि, SDK संपूर्ण नहीं है। एंड्रॉइड के ढांचे के कुछ "छिपे हुए" हिस्से हैं जो एसडीके का हिस्सा नहीं हैं।

ये "छिपे हुए" भाग अधिक हैकी या निम्न-स्तरीय सामग्री के लिए अविश्वसनीय रूप से उपयोगी हो सकते हैं। उदाहरण के लिए, मेरी विजेट ड्रॉअर ऐप यह पता लगाने के लिए एक गैर-एसडीके फ़ंक्शन का उपयोग करता है कि कोई उपयोगकर्ता विजेट से ऐप कब लॉन्च करता है ताकि ड्रॉअर स्वचालित रूप से बंद हो सके। आप शायद सोच रहे होंगे: "क्यों न इन गैर-एसडीके कार्यों को एसडीके का हिस्सा बना दिया जाए?" खैर, समस्या यह है कि उनका संचालन पूरी तरह से पूर्वानुमानित नहीं है। Google यह सुनिश्चित नहीं कर सकता कि फ़्रेमवर्क का प्रत्येक भाग उसके द्वारा स्वीकृत प्रत्येक डिवाइस पर काम करता है, इसलिए सत्यापित करने के लिए अधिक महत्वपूर्ण तरीकों का चयन किया जाता है। Google इसकी गारंटी नहीं देता कि बाकी ढांचा सुसंगत रहेगा। निर्माता इन छिपे हुए कार्यों को बदल सकते हैं या पूरी तरह से हटा सकते हैं। यहां तक ​​कि एओएसपी के विभिन्न संस्करणों में भी, आप कभी नहीं जान पाते कि कोई छिपा हुआ फ़ंक्शन अभी भी मौजूद रहेगा या पहले की तरह काम करेगा।

यदि आप सोच रहे हैं कि मैं "छिपे हुए" शब्द का उपयोग क्यों कर रहा हूं, तो इसका कारण यह है कि ये फ़ंक्शन एसडीके का हिस्सा भी नहीं हैं। आम तौर पर, यदि आप किसी ऐप में किसी छिपी हुई विधि या क्लास का उपयोग करने का प्रयास करते हैं, तो यह संकलित होने में विफल हो जाएगा। इनका उपयोग करना आवश्यक है प्रतिबिंब या एक संशोधित SDK.

Android P के साथ, Google ने निर्णय लिया कि केवल उन्हें छिपाना ही पर्याप्त नहीं है। जब पहला बीटा जारी किया गया था, इसकी घोषणा की गई थी अधिकांश (सभी नहीं) छिपे हुए फ़ंक्शन अब ऐप डेवलपर्स के उपयोग के लिए उपलब्ध नहीं थे। जब आपका ऐप ब्लैकलिस्टेड फ़ंक्शन का उपयोग करेगा तो पहला बीटा आपको चेतावनी देगा। अगले बीटा ने बस आपके ऐप को क्रैश कर दिया। कम से कम मेरे लिए, यह काली सूची काफ़ी कष्टप्रद थी। न केवल यह काफी हद तक टूट गया नेविगेशन जेस्चर, लेकिन चूंकि छिपे हुए फ़ंक्शन डिफ़ॉल्ट रूप से ब्लैकलिस्ट किए जाते हैं (Google को प्रति-रिलीज़ में से कुछ को मैन्युअल रूप से श्वेतसूची में डालना पड़ता है), मुझे विजेट ड्रॉअर को काम पर लाने में बहुत परेशानी हुई।

अब, ब्लैकलिस्ट के आसपास काम करने के कुछ तरीके थे। पहला यह था कि अपने ऐप को केवल एपीआई 27 (एंड्रॉइड 8.1) को लक्षित करना था, क्योंकि ब्लैकलिस्ट केवल नवीनतम एपीआई को लक्षित करने वाले ऐप्स पर लागू होती थी। दुर्भाग्य से, Google के साथ न्यूनतम एपीआई आवश्यकताएँ प्ले स्टोर पर प्रकाशन के लिए, एपीआई 27 को इतने लंबे समय तक लक्षित करना ही संभव होगा। 1 नवंबर, 2019 तक, Play Store के सभी ऐप अपडेट को API 28 या उसके बाद का लक्ष्य होना चाहिए।

दूसरा समाधान वास्तव में कुछ ऐसा है जिसे Google ने Android में बनाया है। ब्लैकलिस्ट को पूरी तरह से अक्षम करने के लिए ADB कमांड चलाना संभव है। यह व्यक्तिगत उपयोग और परीक्षण के लिए बहुत अच्छा है, लेकिन मैं आपको पहले से बता सकता हूं कि एडीबी को स्थापित करने और चलाने के लिए अंतिम उपयोगकर्ताओं को प्राप्त करने का प्रयास करना एक बुरा सपना है।

तो वह हमें कहां छोड़ता है? यदि हम प्ले स्टोर पर अपलोड करना चाहते हैं तो हम एपीआई 27 को लक्षित नहीं कर सकते हैं, और एडीबी विधि व्यवहार्य नहीं है। हालाँकि, इसका मतलब यह नहीं है कि हमारे पास विकल्प खत्म हो गए हैं।

छिपी हुई एपीआई ब्लैकलिस्ट केवल गैर-श्वेतसूचीबद्ध उपयोगकर्ता अनुप्रयोगों पर लागू होती है। सिस्टम एप्लिकेशन, प्लेटफ़ॉर्म हस्ताक्षर के साथ हस्ताक्षरित एप्लिकेशन और कॉन्फ़िगरेशन फ़ाइल में निर्दिष्ट एप्लिकेशन सभी ब्लैकलिस्ट से मुक्त हैं। मज़ेदार बात यह है कि Google Play Services सुइट सभी उस कॉन्फ़िगरेशन फ़ाइल में निर्दिष्ट हैं। मुझे लगता है कि Google हममें से बाकियों से बेहतर है।

खैर, आइए ब्लैकलिस्ट के बारे में बात करते रहें। आज जिस बात में हमारी रुचि है वह यह है कि सिस्टम एप्लिकेशन को छूट दी गई है। उदाहरण के लिए, इसका मतलब है कि सिस्टम यूआई ऐप उन सभी छिपे हुए कार्यों का उपयोग कर सकता है जो वह चाहता है क्योंकि यह सिस्टम विभाजन पर है। जाहिर है, हम किसी ऐप को सिस्टम विभाजन पर नहीं धकेल सकते। इसके लिए रूट, एक अच्छा फ़ाइल प्रबंधक, अनुमतियों का ज्ञान चाहिए... ADB का उपयोग करना आसान होगा. हालाँकि, यह एकमात्र तरीका नहीं है जिससे हम एक सिस्टम ऐप बन सकते हैं, हालाँकि, कम से कम जहाँ तक छिपी हुई एपीआई ब्लैकलिस्ट का सवाल है।

अपने दिमाग को सात पैराग्राफ पहले पर केन्द्रित करें जब मैंने प्रतिबिंब का उल्लेख किया था। यदि आप नहीं जानते कि प्रतिबिंब क्या है, तो मैं पढ़ने की सलाह देता हूँ यह पृष्ठ, लेकिन यहां एक त्वरित सारांश है। जावा में, प्रतिबिंब सामान्य रूप से दुर्गम कक्षाओं, विधियों और क्षेत्रों तक पहुंचने का एक तरीका है। यह एक अविश्वसनीय रूप से शक्तिशाली उपकरण है. जैसा कि मैंने उस पैराग्राफ में कहा था, प्रतिबिंब गैर-एसडीके कार्यों तक पहुंचने का एक तरीका हुआ करता था। एपीआई ब्लैकलिस्ट प्रतिबिंब के उपयोग को अवरुद्ध करता है, लेकिन यह के उपयोग को अवरुद्ध नहीं करता है दोहरा-प्रतिबिंब।

अब, यहीं पर यह थोड़ा अजीब हो जाता है। आम तौर पर, यदि आप एक छिपी हुई विधि को कॉल करना चाहते हैं, तो आप कुछ इस तरह करेंगे (यह कोटलिन में है, लेकिन जावा समान है):

val someHiddenClass = Class.forName("android.some.hidden.Class")
val someHiddenMethod = someHiddenClass.getMethod("someHiddenMethod", String::class.java)

someHiddenMethod.invoke(null, "some important string")

हालाँकि, एपीआई ब्लैकलिस्ट के लिए धन्यवाद, आपको केवल एक ClassNotFoundException मिलेगा। हालाँकि, यदि आप दो बार प्रतिबिंबित करते हैं, तो यह ठीक काम करता है:

val forName = Class::class.java.getMethod("forName", String:: class.java)
val getMethod = Class::class.java.getMethod("getMethod", String:: class.java, arrayOf>()::class.java)
val someHiddenClass = forName.invoke(null, "android.some.hidden.Class") asClass
val someHiddenMethod = getMethod.invoke(someHiddenClass, "someHiddenMethod", String::class.java)

someHiddenMethod.invoke(null, "some important string")

अजीब है ना? अच्छा, हाँ, लेकिन नहीं भी। एपीआई ब्लैकलिस्ट ट्रैक करता है कि किसी फ़ंक्शन को कौन कॉल कर रहा है। यदि स्रोत मुक्त नहीं है, तो यह क्रैश हो जाता है। पहले उदाहरण में, स्रोत ऐप है। हालाँकि, दूसरे उदाहरण में, स्रोत सिस्टम ही है। हम जो चाहते हैं उसे सीधे प्राप्त करने के लिए प्रतिबिंब का उपयोग करने के बजाय, हम इसका उपयोग सिस्टम को यह बताने के लिए कर रहे हैं कि हम जो चाहते हैं उसे प्राप्त करें। चूंकि छिपे हुए फ़ंक्शन पर कॉल का स्रोत सिस्टम है, इसलिए ब्लैकलिस्ट अब हमें प्रभावित नहीं करती है।

तो हमारा काम हो गया. अब हमें एपीआई ब्लैकलिस्ट को बायपास करने का एक तरीका मिल गया है। यह थोड़ा अटपटा है, लेकिन हम एक रैपर फ़ंक्शन लिख सकते हैं ताकि हमें हर बार दोबारा विचार न करना पड़े। यह बहुत अच्छा नहीं है, लेकिन यह कुछ न होने से तो बेहतर है। लेकिन वास्तव में, हमारा काम पूरा नहीं हुआ है। ऐसा करने का एक बेहतर तरीका है जो हमें पुराने दिनों की तरह सामान्य प्रतिबिंब या संशोधित एसडीके का उपयोग करने देगा।

चूंकि ब्लैकलिस्ट के प्रवर्तन का मूल्यांकन प्रति-प्रक्रिया (जो कि ज्यादातर मामलों में प्रति-ऐप के समान है) किया जाता है, सिस्टम के लिए यह रिकॉर्ड करने का कोई तरीका हो सकता है कि प्रश्न में ऐप को छूट दी गई है या नहीं। सौभाग्य से, वहाँ है, और यह हमारे लिए सुलभ है। उस नए मिले डबल-रिफ्लेक्शन हैक का उपयोग करते हुए, हमें एक बार उपयोग होने वाला कोड ब्लॉक मिला है:

val forName = Class::class.java.getDeclaredMethod("forName", String:: class.java)
val getDeclaredMethod = Class::class.java.getDeclaredMethod("getDeclaredMethod", String:: class.java, arrayOf>()::class.java)

val vmRuntimeClass = forName.invoke(null, "dalvik.system.VMRuntime") asClass
val getRuntime = getDeclaredMethod.invoke(vmRuntimeClass, "getRuntime", null) as Method
val setHiddenApiExemptions = getDeclaredMethod.invoke(vmRuntimeClass, "setHiddenApiExemptions", arrayOf(arrayOf<String>()::class.java)) asMethod

val vmRuntime = getRuntime.invoke(null)

setHiddenApiExemptions.invoke(vmRuntime, arrayOf("L"))

ठीक है, इसलिए तकनीकी रूप से, यह सिस्टम को यह नहीं बता रहा है कि हमारा ऐप एपीआई ब्लैकलिस्ट से मुक्त है। वास्तव में एक और एडीबी कमांड है जिसे आप उन कार्यों को निर्दिष्ट करने के लिए चला सकते हैं जिन्हें ब्लैकलिस्ट नहीं किया जाना चाहिए। हम ऊपर इसी का लाभ उठा रहे हैं। कोड मूलतः उस चीज़ को ओवरराइड कर देता है जिसे सिस्टम हमारे ऐप के लिए छूट मानता है। अंत में "एल" पास करने का मतलब है कि सभी विधियाँ छूट गई हैं। यदि आप विशिष्ट तरीकों से छूट चाहते हैं, तो स्माली सिंटैक्स का उपयोग करें: Landroid/some/hidden/Class; Landroid/some/other/hidden/Class;.

अब वास्तव में हमारा काम पूरा हो गया है। एक कस्टम एप्लिकेशन क्लास बनाएं, उस कोड को उसमें डालें onCreate() विधि, और बेम, कोई और प्रतिबंध नहीं।


मूल रूप से इस पद्धति की खोज के लिए वर्चुअलएक्सपोज़्ड और ताइची के डेवलपर XDA सदस्य वेशू को धन्यवाद। हम इस समाधान के बारे में मुझे बताने के लिए XDA मान्यता प्राप्त डेवलपर टॉपजॉनवु को भी धन्यवाद देना चाहेंगे। यह कैसे काम करता है इसके बारे में यहां थोड़ा और बताया गया है, हालाँकि यह चीनी भाषा में है। मैं भी स्टैक ओवरफ़्लो पर इसके बारे में लिखा, जेएनआई में एक उदाहरण के साथ भी।