إصلاح ، اختراق ، حفر. حل السعي عبر الإنترنت Droid Mission



في العام الماضي ، قمنا بإجراء بحث عبر الإنترنت لمطوري الأجهزة المحمولة - Droid Mission. خلال شهر واحد ، كان على المشاركين حل أكبر عدد ممكن من المشاكل في ثلاثة اتجاهات: إصلاحها! (البحث عن الأخطاء والبحث رمز) ، اختراقه! (الهندسة العكسية) وحفرها! (تعلم ميزات Android). في المجموع ، كان للمهمة 23 مهمة - وهي تشبه إلى حد كبير تلك التي يواجهها متخصصو Android في العمل الحقيقي. في المنشور سوف نعرض كل الشروط والحلول الصحيحة.


البحث عن الأخطاء ورمز البحث


اصلاحها! # 1

المؤلف: اناستازيا لاوشكينا

في ليلة الجمعة الهادئة ، يظل عميلان متأخرين ويقودان نزاعًا لا يذوب. تم توجيههم لتخزين كمية كبيرة من البيانات السرية في قاعدة بيانات Sqlite مع مفتاح عدد صحيح.

ينشئ العامل A جدولًا يحتوي على استعلام من النموذج: CREATE TABLE t (مفتاح INT PRIMARY KEY و secret_value_1 و secret_value_2) ، والعميل B مع استعلام النموذج CREATE TABLE t (مفتاح INTEGER PRIMARY KEY ASC ، secret_value_1 ، secret_value_2).

العميل أ متأكد تمامًا من عدم وجود خطأ في طلبه ، ومع ذلك ، لدى الوكيل ب حجة ضد هذا: فهو يدعي أنه يمكن انتهاك سلامة البيانات أثناء اقتراب العميل أ.

سرد باستخدام فاصلة: العمود أو الأعمدة المسؤولة عن تكامل Agent B ، ولكنها غير مسؤولة عن Agent A ؛ وكذلك بنية البيانات ، باللغة الروسية ، والتي بسببها سيكون طلب العميل B أسرع.

الملاحظات
تنسيق الإجابة: [اسم العمود 1] ، [اسم العمود N] ، [اسم الهيكل] (بدون أقواس ، بحرف صغير)

مثال الاستجابة: س ، ص ، صفيف

قرار

إنه حول rowId وعلاقته بالمفتاح الأساسي.

في حالة "CREATE TABLE t (المفتاح INTEGER PRIMARY KEY ASC ، secret_value_1 ، secret_value_2)" يعد المفتاح اسمًا مستعارًا لـ rowId. في حالة "CREATE TABLE t (مفتاح INT PRIMARY KEY ، secret_value_1 ، secret_value_2)" - لا. يمكن العثور على السبب في الوثائق .

لذلك ، في حالة عدم وجود علاقة رئيسية مع rowId ، سيتم تنفيذ طلب من النموذج "INSERT INTO t VALUES (" some "،" y "،" z ")" بنجاح ، مما قد ينتهك تكامل البيانات. في حالة وجود مثل هذا الاتصال ، سيحدث خطأ عدم تطابق نوع البيانات.

تم أخذ الإجابة كزوج من المفاتيح و rowId و key / rowId بشكل منفصل (لأنه إذا كان هناك اتصال ، فإنهم يشيرون إلى نفس العمود).

تتحقق السرعة من خلال التخزين في شكل شجرة بحث.

اصلاحها! # 2

المؤلف: اناستازيا لاوشكينا
ملف ثنائي

للكشف بسرعة عن الأعداء ، يطور Agent Kew تطبيقًا مع قائمة المجرمين المعروفين. لقد تمكن بسهولة من عرض هذه القائمة في التطبيق ، لكنه قرر في هذا الصدد أن هذه المعلومات المهمة يجب أن تكون على الشاشة الرئيسية.

للقيام بذلك ، وقال انه يحتاج إلى القطعة. مشكلة واحدة: لسبب ما ، لا يعرض التطبيق المصغر قائمة. تقول الغريزة للوكيل أن المشكلة تكمن فقط في سطر واحد.

يمكنك تسميته بفاصلة ، وكذلك الخط الذي تريد استبداله به ، من أجل الحصول على الحل الأمثل.

الملاحظات
تنسيق الإجابة: [السطر 1] ، [السطر 2] (بدون الأقواس)

مثال الاستجابة: FrameLayout ، ScrollView

قرار

1. نحن نبحث عن ملف التخطيط لعنصر واجهة المستخدم ، ونرى عنصر ConstraintLayout غير صالح فيه (انظر developer.android.com/guide/topics/appwidgets#CreatingLayout ).
2. تغييره إلى المقبول والأفضل - LinearLayout / FrameLayout.

على الرغم من حقيقة أن استخدام FrameLayout قد كسر تخطيط العناصر في عنصر واجهة المستخدم ، فإنه لا يزال مقبولاً كإجابة.

اصلاحها! # 3

المؤلف: أرتيوم فيتير
ملف ثنائي

لاحظ اختبار زيادة غير طبيعية في استهلاك ذاكرة الوصول العشوائي. هناك اشتباه بوجود تسرب في مكان ما.

يجب عليك التحقيق وتحديد المشكلة. في الاستجابة ، أشر إلى اسم طريقة فئة التطبيق ومكان مكالمته ، مما يؤدي إلى حدوث تسرب للذاكرة. إذا وجدت عدة مشاكل ، فقم بإدراجها جميعًا.

تنسيق الإجابة: [اسم الفئة التي تسمى فيها الطريقة]: [رقم السطر في هذا الملف]: [اسم الطريقة] (بدون أقواس)

أشر إلى عدة إجابات بترتيب معجم ، مفصولة ب #.

مثال:

إذا كنت تعتقد أن هناك تسرب للذاكرة في ملف ExampleFileName.java ،

class ExampleFileName {   public problemMethodName(Sting arg) {}   public test(Sting arg) {     problemMethodName(arg); //  8   ExampleFileName.java   } } 

مثال الاستجابة: ExampleFileName: 8: problemMethodName

قرار

الطريقة الأولى هي تحليل الشفرة.

  1. ندرس رمز التطبيق.
  2. التسرب الأول واضح. هذا تسجيل BroadCastReceiver في فئة SecondActivity. يمكن رؤية رسالة حول هذه المشكلة في logcat إذا قمت بتشغيل التطبيق.
  3. في حالة الانتباه إلى طريقة startTimer () ، ستلاحظ أن فئة CountDownTimer تضيف إغلاقًا إلى معالج مؤشر الترابط الرئيسي مع وجود رابط إلى textView. وقبل إتلاف النشاط ، لا تستدعي فئة المثيل (CountDownTimer) أسلوب الإلغاء (). هذا هو تسرب الذاكرة الثاني.

الطريقة الثانية هي الأدوات. يمكنك تنفيذ مكتبة leacanary في التطبيق ، والحصول على تفريغ الكومة عبر بنك التنمية الآسيوي أو android Profiler وتحليل التقارير الواردة. يمكن أن يساعد Eclipse Memory Analyzer (MAT) في التحليل. لفتح heapdump في MAT ، تحتاج إلى تحويله إلى تنسيق يمكن فهمه لـ MAT باستخدام الأداة المساعدة hprof-convd.

اصلاحها! # 4

بواسطة: فالي Ibragimov
ملف ثنائي

إيفان له يومه الأول في مسرح السينما على الإنترنت. نظرًا لكونه مطورًا رائعًا ، فقد طُلب منه على الفور إصلاح الأعطال عند مشاهدة فيلم. قرر في الوقت نفسه القيام بإعادة بناء المساكن. لقد أصبح الرمز أكثر إيجازًا ونظافة ، ولم يعد الخطأ مستنسخًا.

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

الاستجابة هي اسم الفصل الذي يجب استخدامه.

قرار

لإرسال موقع عرض كل خمس ثوانٍ والانتقال إلى الشبكة ، يتم استخدام ExecutorService. إنشاء إيفور مجدولثريدبوليكسيكوتور لمهمة دورية ، اعتقد إيفان - لماذا لا تستخدمه للذهاب إلى الشبكة؟ بعد كل شيء ، ScheduledThreadPoolExecutor هو سليل ThreadPoolExecutor. لم يكن إيفان حتى يشك في أن ScheduledThreadPoolExecutor يستخدم مؤشر ترابط واحد فقط ، وعند الانتقال إلى الشبكة ، ستحتاج إلى الانتظار حتى الانتهاء من المهمة الدورية.

 scheduleFuture = scheduledExecutorService.scheduleAtFixedRate(() -> {                    try {                        timingsApi.sendTiming(filmId, player.getContentPosition()).get();                    } catch (Exception e) {                        e.printStackTrace();                    }                },                0, PERIOD_SECONDS, TimeUnit.SECONDS); 

تم زيادة تعقيد حل المشكلة من خلال حقيقة أننا لم نتمكن من الوصول إلى ExoPlayer في مؤشر ترابط واجهة المستخدم - وفي الإصدار الجديد 2.9. * بدأت ExoPlayer في كتابة تحذيرات حول هذا في السجلات. لكن الآن هذا مجرد تحذير ، وليس خطأ ارتكبه إيفان.

اصلاحها! # 5

المؤلف: الكسندر تسيبن
ملف ثنائي

قامت إحدى الشركات بتطوير لعبة Farmer Simulator.

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

تم تكليف المطور Vasya بإدراك الأعداء. أثناء التنفيذ ، واجه Vasya مشكلة في الأداء. قرر إصلاحه بسبب تعدد العمليات. نظرًا لأن Vasya لم يكن معتادًا على تعدد مؤشرات الترابط ، فقد استفاد من حلول stackoverflow. لذلك تخلص من مشاكل الأداء.

ومع ذلك ، في مرحلة الاختبار ، وجد أن اللعبة تتجمد في بعض الأحيان. مساعدة فاسيا في العثور على السبب.

كاستجابة ، أدخل أرقام الأسطر الإشكالية للشفرة - مفصولة بفواصل ، بترتيب تصاعدي ودون مسافات. مثل هذا: 1،17،42

قرار

الأنواع البدائية للملاكمة (مثل int في Integer) هي عمليات مكلفة. لأغراض التحسين ، تقوم أجهزة Java أحيانًا بإعادة استخدام هذه الكائنات. الخطوط ليست استثناء.

يتم استخدام خطوط ENEMY_LOCK و DECISIONS_LOCK في رمز المزامنة. لذلك ، إذا كانت هناك أماكن في المشروع مع التزامن على نفس الخطوط ، فقد يحدث توقف تام.

بشكل عام ، لا يمكنك استخدام String / Integer ، إلخ ، للتزامن.

الجواب: 7.8

اصلاحها! # 6

الكاتب: إيفان بوخوف
ملف ثنائي

أصدر فريق معالجة الصور مكتبة أصلية جديدة ، تحتاج إلى تجربتها والإشارة إلى المشاكل ، إن وجدت.

قرار

هذه مهمة سهلة الاحماء. في الموارد تكمن المكتبة نفسها وملف الرأس لذلك. في الرأس ، تقوم الوظيفة الوحيدة بإرجاع مهمة.

لم يتبق شيء سوى إنشاء مشروع اختبار (عن طريق تثبيت NDK) وتسميته! استدعاء دالة على مؤشر الترابط الرئيسي سيتم استثناء استثناء طلب عدم الاتصال به بهذه الطريقة. ننقل التنفيذ إلى مؤشر ترابط آخر بأي طريقة - وكل ذلك يعمل.

الآن يستحق التحقق من الكائن المرتجع - هل هو في الحقيقة صورة نقطية؟ أسهل طريقة هي عرضه فورًا على ImageView. سنرى صورة مع سلسلة نصية ، والمهمة تتطلب إجابة أيضًا في شكل سلسلة. ربما هذا ليس مجرد صدفة. :)

اصلاحها! # 7

المؤلف: ديمتري زايتسيف
ملف ثنائي

هناك تطبيق مع رموز حيث يتم وضع التعليمات البرمجية المطلوبة. لسوء الحظ ، تم قطع التنسيق وتحتاج إلى استعادة للعثور على الرمز.

الملاحظات
بعد تصحيح الكود ، سوف يمر الإطار بـ 22 حرفًا تقريبًا التي يجب إدراجها في عكس اتجاه عقارب الساعة ، بدءًا من الركن الأيسر العلوي من الإطار.

مثال الاستجابة: ScQG1jxbazmjbcARefbRMo

قرار

أصبح الآن خنجر المعيار الفعلي في تطوير Android. عند تكوين DI بالفعل ، يكون من السهل جدًا كتابة Inject أمام المُنشئ وإعطاء بقية العمل إلى Dagger. من السهل جدًا أن تتوقف في وقت لاحق عن التفكير في كيفية توفير التبعيات. أيضًا في Android ، غالبًا ما يتعين عليك العمل مع فئة السياق وأحفاده: التطبيق والنشاط. يرتبط التطبيق بدورة حياة التطبيق ، ويتم ربط النشاط بدورة حياة الشاشة. لذلك ، في العمل مع هذه الفئات ، من المهم مراقبة العديد من الميزات. تستند المهمة على وجه التحديد إلى استخدام السياق الخاطئ ، ويتم إخفاء كل هذا باستخدام DI.

لحل هذه المشكلة ، يمكنك تنفيذ الخطوات التالية:

  1. فحص ملفات المشروع ولاحظ أنه يتم تطبيق ItemStyle على جميع TextViews.
  2. نرى أن النمط لا ينطبق حقا. يجب أن يؤدي هذا إلى فكرة أن المشكلة مرتبطة بالموضوع ، وبالتالي إلى سياق النشاط.
  3. فهم الرسم البياني للاعتماد وفهم أن سياق التطبيق مقدم في المحول.
  4. في ContestAdapter ، قم بتغيير نوع السياق إلى النشاط.

اصلاحها! # 8

بواسطة: فالي Ibragimov
ملف ثنائي

تم إعطاء إيفان مهمة إعادة تشكيل التطبيق للحصول على قائمة بالمهام من خلال ContentProvider باستخدام DI. قام بإعادة تشكيل التطبيق باستخدام Dagger ، وعندما بدأ تشغيله ، تعطل التطبيق.

ساعد إيفان على فهم السبب:

  1. حدد رقم السطر باسم الفئة الذي تريد نقله إلى فصل آخر.
  2. قم بتوفير رابط للوثائق مع رابط إلى مكان يساعدك على فهم سبب تعطل التطبيق.

الملاحظات
تنسيق الاستجابة: [اسم الفئة]: [رقم السطر] -> [اسم الفئة]: [رقم السطر] ، [رابط]

الإجابة على سبيل المثال:

FirstCLass: 12-> SecondClass: 45 ، https: //developer.android.com/reference/android/app/Activity#activity-lifecycle

قرار

المهمة تتألف من جزأين:

1. فهم وتقديم حل تعطل في ContentProvider عند الوصول إلى مكون DI. كان الحل الصحيح هو نقل تهيئة مكون DI إلى ContentProvider.



يتم استدعاء الأسلوب onCreate على ContentProvider أقدم من التطبيق. يسهل التحقق مما إذا كنت تفحص رمز بدء التطبيق في فئة ActivityThread وطريقة handleBindApplication.



2. قم بتوفير رابط يصف أن onCreate لـ ContentProvider يسمى سابقًا للتطبيق. لا تذكر Google ذلك في صفحة وثائق ContentProvider. ولكن هنا مقتطف من وصف طريقة onCreate Aplication:

يتم الاتصال به عند بدء تشغيل التطبيق ، قبل إنشاء أي نشاط أو خدمة أو كائنات الاستقبال (باستثناء موفري المحتوى).

اصلاحها! # 9

المؤلف: الكسندر تسيبن
ملف ثنائي

تم منح المطور مهمة تنفيذ طريقة العرض لبعض قوائم العناصر. في المعارف التقليدية ، كان هناك شرط مهم - لتمرير القائمة إلى العناصر الأولى والأخيرة حتى تظهر هذه العناصر في وسط الشاشة. قام المطور بتطبيق الوظيفة ، ولكن عند الاختبار اتضح أن التركيز في بعض الأحيان لا يعمل. ساعد المطور في العثور على الخطوط الإشكالية في الكود.

الملاحظات
تنسيق الإجابة:

<اسم الملف بدون امتداد>: <أرقام الأسطر مفصولة بفواصل>

<اسم الملف بدون امتداد>: <أرقام الأسطر مفصولة بفواصل>

يجب فرز الخطوط بترتيب معجمى. يجب فرز أرقام الأسطر بترتيب تصاعدي.

الإجابة على سبيل المثال:

بارفو: 1

فوبار: 12،13،14،99

قرار

هناك مشكلتان في التعليمات البرمجية:

1. وفقًا للرمز ، من المفترض أن الدعوة إلى onViewDetachedFromWindow ستحدث دائمًا بعد onBindViewHolder ، لكن هذا ليس كذلك. طريقة التوأم لـ onViewDetachedFromWindow هي onViewAttachedToWindow. نتيجة لذلك ، يُطلق على holder.view.reset () ويختفي توسيط إذا كان التمرير بطيئًا.

2. في نظام Android قبل الإصدار 7 ، لا يعمل addView (rootView ، params) تمامًا كما هو متوقع.

عند إضافة طريقة عرض ، يتم إنشاء LayoutParam ، والذي يبدو كما يلي:

الخطمي - github.com/aosp-mirror/platform_frameworks_base/blob/marshmallow-release/core/java/android/widget/FrameLayout.java#L403
Nougat - github.com/aosp-mirror/platform_frameworks_base/blob/nougat-release/core/java/android/widget/FrameLayout.java#L384

يحتوي FrameLayout.LayoutParams على مُنشئين ، أحدهما يقبل ViewGroup.MarginLayoutParams وينسخ الهوامش في نفسه: github.com/aosp-mirror/platform_frameworks_base/blob/nougat-release/core/java/android/view/ViewGroup.java#L14

يقبل المُنشئ الثاني ViewGroup.LayoutParams ويتجاهل الهوامش: github.com/aosp-mirror/platform_frameworks_base/blob/nougat-release/core/java/android/view/ViewGroup.java#L7328

ونتيجة لذلك ، لا يعمل توسيط نظام التشغيل Android حتى الإصدار 7.

الجواب هو:
ItemView: 35
النشاط الرئيسي: 53

الهندسة العكسية


اخترقها! # 1

المؤلف: فالنتين باريشيف
ملف ثنائي

سارع أحد المطورين ولم يختبر حتى النهاية .apk قبل التقديم إلى المسابقة.

اتضح أنه خلط بعض مجموعات المشاهدة في activity_main.xml. بالإضافة إلى ذلك ، وضع كل حرف من المفتاح في عرض نص منفصل. نتيجة لذلك ، تم فصل جميع المشاهدات على التخطيط وهناك غضب كامل على الشاشة.

حاول تحديد مجموعة العرض التي يجب أن تحل محل المجموعات الحالية.

الإجابة على المشكلة هي الكود الذي يظهر على الشاشة بعد استبدال مجموعة المشاهدة الصحيحة.

قرار

من الضروري إلغاء ترجمة .apk بأي طريقة متاحة (على سبيل المثال ، عن طريق decompilers عبر الإنترنت) وإعادة إنشاء المشروع بواسطة رمز.

إذا قمنا بتحليل main_layout ، فيمكننا إذن أن نخمن من السمات التي تشير إلى أن مجموعة عرض الجذر يجب أن تكون ConstraintLayout.

الجواب: tniartsnoc

اخترقها! # 2

المؤلف: الكسندر تسيبن
ملف ثنائي

تعطل مستخدم من ذوي الخبرة التطبيق. لم يفاجأ ، فتح السجلات ، ووجد الخط الذي تسبب في الخطأ: N72XbphDx5NnFl6CKMNl8w == وأرسله إلى الدعم الفني.

اتضح أنه كان يستخدم إصدارًا قديمًا من التطبيق ، والذي تم تطويره قبل استخدام مستودعات الشفرة ، وبالتالي فقد شفرة فك التشفير. ومع ذلك ، كان من الممكن العثور على .apk للإصدار القديم من التطبيق.

مساعدة فك تشفير الرسالة.

قرار

من الضروري إلغاء ترجمة .apk بأي طريقة متاحة (على سبيل المثال ، عن طريق decompilers عبر الإنترنت) وإعادة إنشاء المشروع بواسطة رمز.

يحتوي الكود نفسه على كل من وظيفة التشفير ووظيفة فك التشفير ، والتي يمكنك من خلالها إعطاء السلسلة المشفرة والحصول على إجابة.

الجواب هو:
TF: وظيفة جيدة!

اخترقها! # 3

المؤلف: فالنتين باريشيف
ملف ثنائي

إلى أي مدى تعرف دورة حياة تطبيق Android؟

هل تعلم أنه في بعض الحالات ، يمكن للنظام قتل عملية التقديم؟

محاكاة هذا الموقف على التطبيق.

سترى الجواب بعد استعادة التطبيق - في شكل رمز.

قرار

كان يكفي لتثبيت .apk على الهاتف ، والتشغيل والحصول على القضية عندما يقوم النظام بإلغاء تحميل التطبيق ، ولكن في نفس الوقت يبقى في الستار.

أحد الخيارات هو تثبيت التطبيق وتشغيله وتقليله (أو التبديل إلى تطبيق آخر). ثم نتواصل عبر adb بالكمبيوتر. في Android Studio ، حدد علامة التبويب Logcat ، وحدد عملية هذا التطبيق وانقر على أيقونة التوقف الأحمر. ثم افتح التطبيق المصغر مسبقًا من الستارة. ستعرض الشاشة الإجابة: sss2384gxcxxX.

اخترقها! # 4

الكاتب: إيفان بوخوف
ملف ثنائي

نشر زميل للجهة الأمامية عرضًا تجريبيًا للوحدة الجديدة ، ولكن نسيت إرسال المواصفات. الآن ينام في منطقة زمنية مختلفة ، ويجب أن يتم العرض التوضيحي في بضع دقائق. من محادثة مع أحد الزملاء ، تتذكر عبارة "نعم ، إنها سهلة ، تحتاج فقط إلى كتابة بذرة وستنجح".

قم بتنزيل الأرشيف وحاول التعامل بدون زميل.

قرار

هذه مهمة بسيطة ، ولكنها تتطلب بعض الفضول والمثابرة.

قم بتنزيل الأرشيف ، وحمل محتوياته إلى خادم الاختبار المحلي ، وقم بإنشاء مشروع باستخدام WebView وتشغيله. بعد انتهاء مهلة قصيرة ، نرى رسالة "معايرة الاتجاه". وهذا كل شيء. لكن الرسالة تشير إلى أنه ربما يجب عليك تحريف الهاتف بين يديك؟ بعد ذلك ، سيتم عرض رسالة مشبوهة حول استثناء الرمي - مع دعوة للتحقق من إخراج وحدة التحكم.

نفتح وحدة التحكم ونرى مكالمة لطريقة غير موجودة على كائن API. نضيف كائنًا إلى WebView لتطبيق JS API ونحاول مرة أخرى اختبار التطبيق.

على ما يبدو ، الأمر يستحق إضافة قيمة الإرجاع. نختار ، إضافة - يعمل. ولكن لا يوجد خط مع الإجابة في أي مكان. اقلب الهاتف مرة أخرى - تسمى طريقة جديدة. إضافته كذلك. بعد عدة تكرارات ، نحصل على مكالمة finalizeCalibrating ، ثم storeResult ، حيث سيصل خطنا.

عند تنزيل المصدر ، قد ترغب في حل أي شيء ، ولكن عليك فتحه وسحب الإجابة. تعمل هذه الطريقة ، ولكن بضع أشعل النار الصغيرة تنتظرك على طول الطريق.

اخترقها! # 5

الكاتب: إيفان بوخوف

تسربت النسخة التجميعية من الإصدار الجديد من android إلى الشبكة ، والتي تم تصحيحها على آلية توقيع التطبيق الجديد مباشرة على الجهاز. في هذا التجميع ، يتم حياكة المفتاح الخاص للتوقيع في الكود المصدر للنظام ، وترك المطورون أجزاء من واجهة المستخدم لاستلامها. العثور على المفتاح.


قرار

1. عند تشغيل المحاكي ، ستلاحظ تطبيق SecretActivity. إذا فتحته ، فستظهر نخب تقدم لك السجلات. نظرًا لأن هذا التجميع هو تصحيح أخطاء ، فهناك العديد من السجلات - يجب تصفيتها حسب اسم التطبيق.

 adb logcat | grep 'SecretActivity' 

1898 1898 E SecretActivity: Try broadcast ZggwxXsaQ9SapPKyHpnwnYmALHazVFWX

2. نحن نحاول رمي البث مع العمل من السجل:

 adb shell am broadcast -a ZggwxXsaQ9SapPKyHpnwnYmALHazVFWX 

3. سوف تظهر نخب على الشاشة مع اقتراح لرؤية السجلات التي كتبها علامة SecretReceiver.

 adb logcat | grep 'SecretReceiver' 

1898 1898 E SecretReceiver: ISecretService.aidl
1898 1898 E SecretReceiver: package android.app;
1898 1898 E SecretReceiver: interface ISecretService {
1898 1898 E SecretReceiver: String getSecret();
1898 1898 E SecretReceiver: }
1898 1898 E SecretReceiver: See global settings to bind SecretService


4. ننظر إلى الإعدادات العامة للعثور على إجراء للاتصال بـ SecretService.

 adb shell settings list global 

...
bind_secret_service_action=g8mNyGQZR8aHLTXNWcjdwJJYZ85Ewx83
...


5. نكتب عميلًا لخدمة ISecretService باستخدام واجهة aidl هذه.

 public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Intent intent = new Intent(); intent.setAction("g8mNyGQZR8aHLTXNWcjdwJJYZ85Ewx83"); PackageManager pm = getPackageManager(); List<ResolveInfo> resolveInfoList = pm.queryIntentServices(intent, 0); if (resolveInfoList == null || resolveInfoList.size() != 1) { return; } ResolveInfo serviceInfo = resolveInfoList.get(0); ComponentName component = new ComponentName(serviceInfo.serviceInfo.packageName, serviceInfo.serviceInfo.name); Intent explicitIntent = new Intent(intent); explicitIntent.setComponent(component); bindService(explicitIntent, new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { ISecretService secretService = ISecretService.Stub.asInterface(service); try { Log.d("MainActivity", secretService.getSecret()); } catch (Exception e) { Log.e("MainActivity", "RemoteException", e); } } @Override public void onServiceDisconnected(ComponentName name) { } }, Context.BIND_AUTO_CREATE); } } 

6. تشغيل ، في سجلات نحصل على الجواب:

 adb logcat | grep 'MainActivity' 

1898 1898 E MainActivity: VENHz=qWr7y!t3ZhP!8Skw!!kcTkt7V%

اخترقها! # 6

المؤلف: بافل فوروبكالوف
ملف ثنائي

كتب Mr. Tupper تطبيق Android يرسل الرسائل.

فك تشفير الرسالة والمضي قدما.

شكل الإجابة: السلسلة كرابط.

قرار

قم بتثبيت التطبيق وتشغيله على الجهاز. نرى زرين: إرسال رسالة وإرسال صيغة. عند النقر فوقها ، لن يحدث شيء مرئي. تحتاج إلى معرفة كيف وأين يرسل التطبيق شيئًا ما.



نفتح تطبيقات .apk باستخدام بعض الوسائل للهندسة العكسية وننظر إلى النشاط الرئيسي. هناك يمكنك أن ترى طريقتي onSendMessageClick و onSendFormulaClick. ينشئون هدفًا مع إجراء "com.yandex.tupper.action.NEW_MESSAGE" وإضافيين باستخدام المفتاح "com.yandex.tupper.message" ويرسلونه إلى التطبيقات من القائمة (باستخدام الطريقة العامة). يحصلون على القائمة عن طريق الاتصال بـ PackageManager.queryBroadcastReceivers.

يمكنك الاستمرار في استخدام أدوات الهندسة العكسية لدراسة الرسالة من خلال استخراجها من رمز التطبيق. ولكن هذا المسار معقد (وإن كان قليلاً) معقدًا بواسطة تشفير RSA الإضافي.

هناك طريقة أخرى تتوافق بشكل أفضل مع برمجة Android. تحتاج إلى كتابة تطبيق يعالج هذا البث. نقوم بإنشاء تطبيقنا في مستلم السجل الظاهر:

  <receiver android:name=".TupperMessageReceiver" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="com.yandex.tupper.action.NEW_MESSAGE" /> </intent-filter> </receiver> 

في المعالج ، نحصل على رسالة من خارج وندير نشاطنا الخاص ، والذي سنظهر نتيجة للمعالجة:

 public class TupperMessageReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String message = intent.getStringExtra(MainActivity.EXTRA_MESSAGE); if (message == null) { return; } Intent activityIntent = new Intent(context, MainActivity.class); activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); activityIntent.putExtra(MainActivity.EXTRA_MESSAGE, message); context.startActivity(activityIntent); } } 

الآن دعونا نتعامل مع فك تشفير الرسالة نفسها. إذا بحثت في Yandex عن "رسالة Tupper" ، يمكنك العثور على مقالة حول صيغة Wupper لصيغة Tupper. لديه مثال على صيغة مشفرة في شكل رقم:

48584 ...
4858450636189713423582095962494202044581400587983244549483093085061934704708809928450644769865524364849997247024915119110411605739177407856919754326571855442057210445735883681829823754139634338225199452191651284348332905131193199953502413758765239264874613394906870130562295813219481113685339535565290850023875092856892694555974281546386510730049106723058933586052544096664351265349363643957125565695936815184334857605266940161251266951421550539554519153785457525756590740540157929001765967965480064427829131488548259914721248506352686630476300

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

ننفذ خوارزمية فك التشفير في Java ، ومن أجل الجمال ، نقوم بتحويل الرقم الثنائي الناتج إلى صورة نقطية أحادية اللون:

  public class TupperCodec { static final int TUPPER_R = 17; private TupperCodec() {} public static BigInteger decodeFromDecString(String decString) throws NumberFormatException { BigInteger data = new BigInteger(decString, 10); return data.divide(BigInteger.valueOf(TUPPER_R)); } public static String getNumberAsBinImage(BigInteger number) { String binString = number.toString(2); StringBuffer result = new StringBuffer(binString.length()); int i; for (i = 0; i < binString.length(); i++) { if ((i % TUPPER_R) == 0 && i > 0) { result.append('\n'); } result.append(binString.charAt(binString.length() - 1 - i)); } int numberOfRows = (binString.length() + TUPPER_R - 1) / TUPPER_R; for (; i < numberOfRows * TUPPER_R; i++) { result.append(~_~quot&#0;quot~_~); } return result.toString(); } public static Bitmap getBinImageAsBitmap(String binImage) { String[] lines = binImage.split("\n"); int[] colors = new int[lines.length * TUPPER_R]; for (int i = 0; i < lines.length; i++) { String line = lines[i]; assert line.length() == TUPPER_R; for (int j = 0; j < line.length(); j++) { colors[i * TUPPER_R + j] = line.charAt(j) == '0' ? Color.WHITE : Color.BLACK; } } return Bitmap.createBitmap(colors, TUPPER_R, lines.length, Bitmap.Config.ARGB_8888); } } 

في النشاط ، اتصل بفك تشفير وعرض النتيجة كصورة نقطية في ImageView:

  public class MainActivity extends AppCompatActivity { static final String EXTRA_MESSAGE = "com.yandex.tupper.message"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent intent = getIntent(); if (intent != null && intent.hasExtra(MainActivity.EXTRA_MESSAGE)) { String message = intent.getStringExtra(MainActivity.EXTRA_MESSAGE); try { BigInteger data = TupperCodec.decodeFromDecString(message); String binImage = TupperCodec.getNumberAsBinImage(data); Bitmap bitmap = TupperCodec.getBinImageAsBitmap(binImage); ImageView imageView = findViewById(R.id.message_image); imageView.setImageBitmap(bitmap); CharSequence toastText = TextUtils.ellipsize(message, new TextPaint(), 400, TextUtils.TruncateAt.END); Toast.makeText(this, toastText, Toast.LENGTH_SHORT).show(); } catch (NumberFormatException ex) { Toast.makeText(this, getString(R.string.invalid_message), Toast.LENGTH_LONG).show(); } } } } 




clck.ru/FevR5 .

hack it! #7

:


.

. , , .

: - .



.apk zip- classes.dex — Java- . , , dex2jar Android Studio. dex2jar Java-, Android Studio class-. , .

, proguard ( android.support.* androidx.*, ), — com.yandex.contest.keygenme.MainActivity, Activity . , : MainActivity.a#doInBackground bbaab b , .



c d. N- π ( --), . , π hexed [c[i] + key[i]] = d[i], i = 0..11. , . 50 hex- π. : 537306089144. key_2056BE33E064.

, , — . doInBackground:



, , if (var12[0] == var8) {… }. var7 — i- . , var7 0 9 . . , .apk ( JVM) .

hack it! #8

:


N , . : Android 4.4, 1200 × 600, FM-. , , FM- . FM- , .

, FM-. .

, :

1. 106.00
2. (seek)
3. ,

, .

: . .

: , a(106.00) 106.00 , b(true) , c() , a(106.00);b(true);c()



: , FM- . .apk dex-. Java. , , — jadx.

.apk, . MainActivity. : fragment_holder RadioFullFragment . . RadioFullPresenter, ChangeRadioFrequencyUsecase, RadioRepo. .

«implements RadioRepo». : RadioRepoImpl. , b. ServiceConnection — . , b lambda$new$0$RadioRepoImpl. , $$Lambda$RadioRepoImpl$FYTR9gAgZEGvrLjkbkpAIup7OKw, serviceConnection IRadioService radioService. , RadioService.

: onServiceConnected «b radioManager = Stub.asInterface(service)». , . «bindService». bindService «com.some_company.help_service». , com.some_company.carradio.FmUtils. , , . , : j , : 8880 88.00 . 8800. a. , .

. : k z. RadioRepoImpl, enableRadio() disableRadio() k. z(boolean isForwardDirection), « (seek) ».

: a(10600);z(true);j().

hack it! #9

:


flatbuffers . GPX . . , .

FlatBuffers :

 namespace ru.yandex.android.task; struct GeoPoint { latitude:double; longitude:double; } table Points { items:[GeoPoint]; } root_type Points; 

: , sha256. .



, FlatBuffers.

1. fbs- .
2. Java-. JVM- , Gradle flatbuffers.
3. fbs-.
4. fbs-, - — . , FlatBuffers.
5. , . structs , struct table. .
6. Kotlin. FlatBuffers.

fbs , . FlatBufferBuilder input. input :

 val pointsList = Points.getRootAsPoints(buffer) val restoredPoints = (0 until pointsList.itemsLength()) .mapNotNull(pointsList::items) 

c , (lat, long). as-is GPX-.

GPX- ( ) . GPX XML. , XML- . XML- GPX-track-. XML- MAP- . «yandroid».

, . CLI-:

 echo "yandroid" | shasum -a 256 

.

Android


dig it! #1

:


QA- .

:

— ( 'Screen 1')
— GO NEXT ( 'Screen 2')
— GO BACK
— GO NEXT,
— 5–10

: 'Screen 2'.

: , « ».

.apk .



C stack trace, .

مثال

stack trace …

 at android.os.MessageQueue.nativePollOnce(Native method) at android.os.MessageQueue.next(MessageQueue.java:326) at android.os.Looper.loop(Looper.java:160) at com.android.server.SystemServer.run(SystemServer.java:454) at com.android.server.SystemServer.main(SystemServer.java:294) at java.lang.reflect.Method.invoke(Native method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:838) 

… , RuntimeInit.java, 493, :

 com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) 



, , « ».

/data/anr/traces.txt /data/anr/anr_* (https://developer.android.com/topic/performance/vitals/anr#pull_a_traces_file). adb-:

 adb root adb shell ls /data/anr adb pull /data/anr/<filename> 

( adb root , Google API.)

stack trace . — stack trace, :

 com.droid.mission.anrapk.MainActivity$2.onClick(MainActivity.java:43) 



dig it! #2

:

Android Studio, , MultiDex. -, apk- .dex- (65536). / apk Andorid Studio .dex-.

— dex- , dex- ( , ) . dex- .

: multidex , android gradle plugin 3.0.0 – 3.1.4

.

?



, dex-. Gradle — , , .apk.

Java- dex- ART/Dalvik: transformClassesWithDexBuilderForDebug. dex-, . Android Gradle plugin (AGP) Gradle . , — , Gradle . , . AGP, — DSL- Gradle build.gradle.

3.1.* minimal-main-dex. , .

dig it! #3

:
— - .

?

: — .



, . Android WindowManager. . , WindowManager.LayoutParams . , , TYPE_APPLICATION .

, , . , , - .

, Android SDK, , . , WindowManager AOSP. , , , .

, , TYPE_BOOT_PROGRESS . getWindowLayerFromTypeLw WindowManagerPolicy. Javadoc :

Returns the layer assignment for the window type. Allows you to control how different kinds of windows are ordered on-screen

, , . switch-case , layer — TYPE_POINTER, 2018. .

dig it! #4

:

, - , .

. , , , .

Android , ?



, , Android SDK, .

startActivity Context . Context Activity — , startActivity . startActivityForResult. , Activity mInstrumentation.execStartActivity .

? startActivity ActivityManagerService, ServiceManager.getService(Context.ACTIVITY_SERVICE).

ActivityManagerService . startActivityAsUser, startActivity, ActivityStarter execute. , .

C startActivity . , abort , true START_ABORTED Activity.

, , mService.mIntentFirewall.checkStartActivity. , . :

This is called from ActivityManager to check if a start activity intent should be allowed.

, IntentFirewall . RULES_DIR . : ifw.

dig it! #5

:

. , (, ) — 8800. , , (+8800). , 8800 +8800 , / , .

. . , +8800 8800 .

, (java/c/c++). , .

: source.android.com
— : androidxref.com



Dialer , , URI authorities = "content://com.android.contacts" .

ContentProvider. URI ContactsPoviider. : , SQL- . :

 sb.append("PHONE_NUMBERS_EQUAL(" + Tables.DATA + "." + Phone.NUMBER + ", "); 

PHONE_NUMBERS_EQUAL — SQL-. sqlite .

sqlite, , . ContactsProvider , config_use_strict_phone_number_comparation, . :

 <bool name="config_use_strict_phone_number_comparation">true</bool> 

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


All Articles