تُوزَّع تطبيقات أندرويد في شكل ملفات APK — حزمة تطبيقات أندرويد — وفهم بنيتها الداخلية أمرٌ لا غنى عنه لكل ممارس في مجال أمان الهاتف المحمول. سواء كنت مختبر اختراق يُقيّم تطبيقاً طرفياً، أو مطوراً يسعى إلى تعزيز منتجه الخاص، أو باحثاً أمنياً يتعقب الثغرات، فإن إتقان الهندسة العكسية للـ APK يمنحك ميزة حاسمة. يستعرض هذا الدليل العملية بأكملها: من فهم محتويات الـ APK، إلى سلسلة الأدوات المستخدمة لفكه وإعادة ترجمته، مروراً بالثغرات التي يجري اكتشافها بانتظام، وصولاً إلى الدفاعات التي تعترضها.
١. تشريح ملف APK
الـ APK ليس سوى أرشيف ZIP. إعادة تسميته بامتداد .zip وفك ضغطه تكشف البنية التالية:
- classes.dex — الكود الثانوي Dalvik المُجمَّع الذي يعمل على بيئة تشغيل ART في أندرويد. قد تحتوي التطبيقات الكبيرة على
classes2.dexوclasses3.dexوما إلى ذلك (multidex). - AndroidManifest.xml — ملف XML مُشفَّر ثنائياً يُعلن عن كل مكوّن تعرضه التطبيق: الأنشطة (Activities) والخدمات (Services) ومستقبلات البث (BroadcastReceivers) ومزودي المحتوى (ContentProviders). كما يُعلن عن الأذونات المطلوبة والحد الأدنى لإصدار SDK.
- resources.arsc — جدول موارد مُجمَّع يربط معرّفات الموارد (أعداد صحيحة) بقيمها: السلاسل النصية والتخطيطات والصور.
- lib/ — مكتبات مشتركة أصلية (ملفات ELF بامتداد
.so) مُجمَّعة لأهداف ABI مثلarmeabi-v7aوarm64-v8aوx86_64. - assets/ — ملفات خام مضمّنة مع التطبيق: HTML وJavaScript لـ WebViews وملفات إعدادات وأحياناً قواعد بيانات مدمجة.
- META-INF/ — شهادة التوقيع (
CERT.RSA) وملخّص المانيفست (MANIFEST.MF) وملف التوقيع (CERT.SF). هكذا يتحقق أندرويد من أصالة الحزمة.
فهم هذه البنية يُشير بدقة إلى أماكن البحث: تميل بيانات الاعتماد إلى الاختباء في assets/ أو مُضمَّنة في classes.dex؛ وأسرار الكود الأصلي تقع في ملفات .so؛ بينما يُعلَن عن تعرّض المكوّنات في AndroidManifest.xml.
٢. سلسلة أدوات الهندسة العكسية
تعتمد الهندسة العكسية الحديثة لأندرويد على عدد قليل من الأدوات المجرّبة التي تتكامل فيما بينها:
apktool
يفكّ apktool الـ APK إلى كود smali (لغة تجميع Dalvik) ويستعيد ملف AndroidManifest.xml المقروء وملفات الموارد. إنها الخطوة الأولى في تقريباً كل تحليل.
apktool d app.apk -o output/
يحتوي الدليل الناتج output/smali/ على تمثيلات على مستوى التجميع لكل فئة. وهي مقروءة لكنها مطوّلة — jadx أكثر عملية لتحليل المنطق.
jadx
يُعيد jadx ترجمة الكود الثانوي .dex مباشرةً إلى شيفرة مصدرية Java، مما يجعل منطق العمل مقروءاً للوهلة الأولى.
jadx -d jadx_out/ app.apk
يوفر jadx أيضاً واجهة رسومية (jadx-gui) تتيح البحث والمراجع المتقاطعة والتنقل — لا غنى عنها في قواعد الكود الكبيرة.
dex2jar + JD-GUI
بديل أقدم لا يزال مستخدماً: يحوّل dex2jar ملف .dex إلى ملف .jar، وبعدها يعرضه JD-GUI كـ Java. يتعامل مع بعض أنواع التشويش بشكل مختلف عن jadx ويمكن أن يكون مرجعاً للتحقق المتبادل.
d2j-dex2jar app.apk -o app.jar
jd-gui app.jar
strings على المكتبات الأصلية
غالباً ما تتضمن الثنائيات الأصلية .so أسراراً مُشفَّرة في الكود لا تصل إليها تشويشات طبقة Java. تشغيل strings عليها يكشف في أغلب الأحيان عن نقاط نهاية API وبيانات اعتماد ومفاتيح تشفير.
strings lib/arm64-v8a/libcore.so | grep -iE "key|secret|token|pass|api"
adb logcat
يلتقط تحليل سجلات وقت التشغيل ما تفعله التطبيق فعلياً أثناء التنفيذ. يترك كثير من المطورين معلومات حساسة في سجلات التصحيح التي لا تُحذف أبداً في بنيات الإنتاج.
adb logcat -s "MyApp" | grep -iE "token|auth|password"
٣. ما يبحث عنه مختبرو الاختراق
الأسرار المُضمَّنة في الكود
بعد إعادة الترجمة، يُجرى بحث بنمط في دليل الإخراج للكشف عن بيانات اعتماد مدمجة. الاكتشافات في العالم الحقيقي شائعة بشكل مفاجئ:
// مثال على ما يجده مختبرو الاختراق أثناء إعادة الترجمة
private static final String API_KEY = "sk-prod-1234567890abcdef";
private static final String DB_PASSWORD = "P@ssw0rd123!";
private static final String FIREBASE_SECRET = "AIzaSy...";
تنجو هذه السلاسل من إعادة الترجمة سليمةً لأن ثوابت السلاسل في Java تُجمَّع حرفياً في مجموعة ثوابت .dex. يُعيد التشويش تسمية الفئات والأساليب لكنه نادراً ما يُشفّر السلاسل النصية الحرفية بشكل افتراضي.
المكوّنات المُصدَّرة
يمكن لأي مكوّن مُعلَن بـ android:exported="true" في المانيفست ويفتقر إلى إذن مخصص أن يُستدعى من أي تطبيق مثبَّت أو أمر adb — دون أي تدخل من المستخدم. يُعدّد المختبرون هذه المكوّنات فوراً:
apktool d app.apk -o out/ && grep -n 'exported="true"' out/AndroidManifest.xml
نشاط مُصدَّر يتعامل مع روابط عمق حساسة دون التحقق منها هو مسار مباشر لتجاوز المصادقة أو سرقة البيانات.
تخزين البيانات غير الآمن
لدى أندرويد SharedPreferences وقواعد بيانات SQLite والتخزين الداخلي/الخارجي. تشمل الأخطاء الشائعة تخزين كلمات المرور أو الرموز المميزة في SharedPreferences (مقروءة عالمياً على الأجهزة المزروتة)، واستخدام قواعد SQLite دون تشفير، وكتابة البيانات الحساسة في التخزين الخارجي حيث يمكن للتطبيقات الأخرى قراءتها.
// غير آمن: تخزين رمز جلسة في SharedPreferences غير مشفرة
SharedPreferences prefs = getSharedPreferences("auth", MODE_WORLD_READABLE);
prefs.edit().putString("token", sessionToken).apply();
التشفير الضعيف
كثيراً ما تكشف إعادة الترجمة عن أنماط مضادة للتشفير: DES أو 3DES حيث يكون AES-256 مناسباً؛ MD5 أو SHA-1 لتجزئة كلمات المرور بدلاً من bcrypt أو Argon2؛ AES في وضع ECB الذي يُسرّب أنماط النص الصريح؛ متجهات تهيئة ثابتة أو يمكن التنبؤ بها.
التسجيل غير الآمن
فئة Log في أندرويد مقروءة عالمياً من أي تطبيق يمتلك READ_LOGS على إصدارات API الأقدم. العبارات التالية تشكّل تسرّباً للبيانات:
Log.d("AuthManager", "User token: " + token);
Log.v("Payment", "Card number: " + cardNumber);
٤. تجاوز تثبيت SSL
يمنع تثبيت شهادة SSL/TLS الاعتراض برفض الاتصالات عندما لا تتطابق شهادة الخادم مع مفتاح عام مضمَّن أو تجزئة شهادة. تجاوزه شرط أساسي لفحص حركة المرور المشفرة بوكيل مثل Burp Suite.
تجاوز قائم على Frida
Frida هو مجموعة أدوات للقياس الديناميكي تحقن JavaScript في عملية قيد التشغيل، لتعليق أي دالة Java أو أصلية في وقت التشغيل. الاستدعاء القياسي لجلسة تحليل نشطة:
frida -U -f com.target.app --no-pause -l bypass-ssl.js
سكريبت Frida المعروف لتجاوز تثبيت OkHttp3 يُعلّق الأسلوب CertificatePinner.check() ويجعله بلا أثر:
Java.perform(function() {
var CertificatePinner = Java.use('okhttp3.CertificatePinner');
CertificatePinner.check.overload('java.lang.String', 'java.util.List')
.implementation = function(hostname, peerCertificates) {
console.log('[*] تم تجاوز تثبيت SSL لـ: ' + hostname);
// العودة دون استثناء — فحص التثبيت معطّل
};
});
Objection
يُغلّف Objection أداة Frida في مستكشف سطر أوامر ويؤتمت المهام الشائعة كتجاوز تثبيت SSL وتجاوز كشف الروت واستكشاف نظام الملفات:
objection -g com.target.app explore
# ثم داخل موجه objection:
android sslpinning disable
٥. التحليل الديناميكي مع Frida
يتيح Frida، ما وراء تثبيت SSL، التلاعب الكامل بمنطق التطبيق في وقت التشغيل. يستخدمه المختبرون لتعليق فحوصات المصادقة، واستخراج مفاتيح التشفير من الذاكرة في لحظة استخدامها، وتتبع تدفقات البيانات الحساسة.
مثال عملي: تعليق أسلوب تسجيل دخول لتسجيل بيانات الاعتماد وإجبار نجاح المصادقة بصرف النظر عن استجابة الخادم:
Java.perform(function() {
var LoginActivity = Java.use('com.example.app.LoginActivity');
LoginActivity.checkPassword.implementation = function(pass) {
console.log('[*] استُدعي checkPassword بالقيمة: ' + pass);
// تجاوز الفحص — إرجاع true دائماً
return true;
};
LoginActivity.validateOtp.implementation = function(otp) {
console.log('[*] تم اعتراض OTP: ' + otp);
return true;
};
});
يكشف هذا النمط بيانات الاعتماد بنص صريح ويُثبت أن منطق المصادقة يجب ألا يُعتمد عليه أبداً على جانب العميل.
٦. الثغرات الرئيسية في تطبيقات APK الفعلية
سوء إعداد Firebase
تُضمّن كثير من التطبيقات إعداد Firebase في google-services.json — ملف مدرج في الـ APK وسهل الاستخراج. إذا كانت قواعد أمان Firestore أو Realtime Database لمشروع Firebase تسمح بالقراءة دون مصادقة، فإن أي مهاجم يسترد هذا الملف يحصل على وصول إلى بيانات المستخدمين. يعثر المختبرون باستمرار على قواعد بيانات بقواعد مكافئة لـ: "read": true, "write": true.
اختطاف روابط العمق عبر الأنشطة المُصدَّرة
إذا كان نشاط مُصدَّر يتعامل مع مخططات intent-filter (روابط عمق مخصصة مثل myapp://reset-password?token=XYZ) دون فرض التحقق من الحزمة، يمكن لتطبيق خبيث تسجيل المخطط ذاته واعتراض رابط العمق، مما يُمكّنه من سرقة رموز إعادة تعيين كلمات المرور أو رموز OAuth.
Tapjacking وهجمات التراكب
في إصدارات أندرويد الأقدم، يمكن لتراكب خبيث (نافذة شفافة جزئياً مرسومة فوق تطبيق مستهدف) أن يخدع المستخدمين ليضغطوا على عناصر واجهة لا يرونها — منح أذونات أو إرسال نماذج أو تأكيد مدفوعات. الدفاع هو السمة XML filterTouchesWhenObscured أو استدعاء setFilterTouchesWhenObscured(true) في الكود.
٧. الدفاعات
تشويش ProGuard / R8
فعّل R8 في بناء الإصدار الخاص بك. يُقلّص الكود ويُحسّنه ويُشوّشه، إعادة تسمية الفئات والأساليب بأسماء مكوّنة من حرف واحد وإزالة الكود الميت. على الرغم من أنه ليس منيعاً، إلا أنه يرفع بشكل ملحوظ تكلفة التحليل ويمنع الاستخراج العرضي لبيانات الاعتماد.
تثبيت الشهادة
نفّذ التثبيت باستخدام CertificatePinner من OkHttp أو مكتبة TrustKit-Android. ثبّت على تجزئات المفتاح العام لـ CA الوسيطة (وليس شهادات الأوراق) للبقاء بعد تدوير الشهادات، وقم دائماً بتضمين تثبيت احتياطي:
CertificatePinner pinner = new CertificatePinner.Builder()
.add("api.yourapp.com", "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")
.add("api.yourapp.com", "sha256/BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=") // احتياطي
.build();
Android Keystore للمفاتيح التشفيرية
لا تُشفّر المفاتيح التشفيرية أبداً في الكود المصدري. يخزن نظام Android Keystore المفاتيح في تخزين آمن مدعوم بأجهزة ولا يكشف أبداً عن مادة المفتاح الخام لعملية التطبيق. يمكن ربط المفاتيح بضرورة مصادقة المستخدم (بيولوجية أو رمز PIN) قبل الاستخدام.
حذف سجلات التصحيح في بنيات الإصدار
استخدم قواعد ProGuard لإزالة جميع استدعاءات Log.* في بنيات الإصدار، أو اعتمد مكتبة تسجيل (مثل Timber) تحذف السجلات دون مستوى مُهيَّأ في متغيرات غير التصحيح.
تقييد تصدير المكوّنات
يجب أن يُعلن كل مكوّن في AndroidManifest.xml صراحةً عن android:exported="false" ما لم يكن هناك سبب مقصود لتعريضه. للمكوّنات التي يجب تصديرها (معالجات روابط العمق وأهداف المشاركة)، اشترط إذن مستوى التوقيع المخصص حتى تتمكن تطبيقاتك الخاصة فقط من استدعائها دون تدخل صريح من المستخدم.
تشفير التخزين المحلي
استخدم مكتبة Jetpack Security (EncryptedSharedPreferences وEncryptedFile) لتشفير البيانات الحساسة في حالة السكون بشكل شفاف. للقواعد بيانات، يوفر SQLCipher تشفير AES-256 مع حد أدنى من التغييرات في الـ API.
الخاتمة
الهندسة العكسية لـ APK أندرويد تخصص ناضج بسلسلة أدوات راسخة ومجموعة متوقعة من فئات الثغرات. تظهر المشكلات ذاتها — الأسرار المُضمَّنة والمكوّنات المُصدَّرة والتخزين غير الآمن والتشفير الضعيف وغياب التثبيت — مراراً وتكراراً في التطبيقات من جميع الأحجام والفئات. معرفة كيفية تعامل المهاجمين مع الـ APK هو المسار الأكثر مباشرة لبناء تطبيقات تتحمل هذا التحليل.
في كايفورا، يُجري فريق أمان الهاتف المحمول لدينا تقييمات شاملة للـ APK تشمل التحليل الثابت والقياس الديناميكي وفحص حركة مرور الشبكة واختبار API الخلفية. إذا كان تطبيقك الأندرويد يتعامل مع بيانات مستخدمين حساسة أو معاملات مالية، فإن التدقيق المهني قبل الإطلاق ليس اختيارياً — إنه تكلفة التشغيل المسؤول.