Skip to content

Latest commit

 

History

History
286 lines (215 loc) · 30.4 KB

File metadata and controls

286 lines (215 loc) · 30.4 KB

اللغات: English | 简体中文 | 繁體中文 | 日本語 | 한국어 | Français | Deutsch | Español | Italiano | Русский | العربية

استعادة شيفرة Java من Android

← فهرس التوثيق

يستعيد neverd mobile شيفرة Java مقروءة من APK وDEX وsmali باستخدام محرك NeverD المدمج فقط. تشترك أدوات القراءة المطوّرة بصورة مستقلة في نموذج Dalvik ذي أنواع محددة ومولّد Java محدود العمل. هذه ميزة CLI تجريبية؛ ولا تعد باستعادة أي APK بالكامل. لا تتوفر حاويات APK ومخرجات Java عبر SDK الأصلي للغة C أو SDK إضافات Python أو محمّل الواجهة الرسومية أو neverd decompile --language.

شيفرة Java المستعادة هي إعادة بناء للبايت كود. لا تتوفر التعليقات الأصلية والتنسيق واختيارات لغة المصدر والمعرّفات المحذوفة؛ كما ينتج عن بايت كود Kotlin شيفرة Java. لا يثبت نجاح التشغيل التكافؤ الدلالي، ولا يضمن إمكان إعادة ترجمة كل دالة. لا يشغّل مسار العمل هذا أي تطبيق يخضع للتحليل.

البداية السريعة

بعد بناء NeverD، اختر مجلد إخراج جديدًا:

neverd mobile app.apk -o recovered-app
neverd mobile classes.dex -o recovered-dex
neverd mobile MainActivity.smali -o recovered-class
neverd mobile decoded/smali -o recovered-java

افتح recovered-app/sources/ لقراءة ملفات Java، وrecovered-app/report.json لفحص قائمة المدخلات والقيود. يُفضّل استخدام مجلد كمدخل عندما تشير أصناف smali إلى بعضها.

إعداد بيئات التشغيل

المكوّن المتطلب طريقة الاختيار
NeverD ابنِ الهدف neverd باستخدام أدوات تدعم C++20. مسار العمل المحمول مدمج في واجهة CLI الأصلية ولا يستدعي مفسّر Python. وزّع الملف التنفيذي مع المكتبات الأصلية التي يتطلبها بناؤك. build/bin/neverd / PATH

تستخدم استعادة Android محرك NeverD المدمج بلغة C++20 فقط، ولا تحتاج إلى Python أو Java وقت التشغيل. يقبل التصريحات والعمليات المعتادة القابلة للتمثيل من DEX 035 و037–040 وsmali. يفشل صراحةً مع DEX 041 والاستدعاءات الديناميكية مثل invoke-custom وبعض مسارات التهيئة والتعليقات التوضيحية الدلالية أو العمليات المجهولة والمعرّفات التي لا يمكن تمثيلها بلغة Java. قبول تنسيق ملف لا يعني دعم جميع تعليماته وتصريحاته.

يميز ربط أسماء Java بين ترويسة الصنف وجسمه، ويمكنه معالجة حالات حجب الأسماء المعروفة داخل الحزمة نفسها؛ لكنه يرفض صراحةً الحالات التي يمنع فيها غياب تصريحات الأصناف الأب أو الواجهات الخارجية التحقق من ربط أسماء الأنواع أو مراجع شيفرة Java المساعدة المولدة، ولا يفترض غياب أنواع متداخلة قابلة للوراثة دون تصريح متاح إلا في java.lang.Object. تُقرّب القيم العائمة الحرفية في smali مباشرةً إلى الدقة الأحادية أو المزدوجة المستهدفة، مع الحفاظ على أنماط البتات الناتجة.

يحفظ محرك C++ المدمج بيانات Signature الوصفية المدعومة للأصناف والحقول والدوال ويتحقق منها، بما يشمل متغيرات الأنواع والمصفوفات والأنواع البديلة وحدود الأنواع وحجب الأسماء على مستوى الدالة. يجب أن تتطابق نتيجة محو الأنواع مع هوية تصريح DEX الأصلي. تُحفظ Throws، ويُرفض تسلسل وراثة الاستثناءات إن تعذر إثباته. تظل الوراثة ذات المعاملات النوعية أو استبدال أنواع الأعضاء، وإعادة توليد الدوال الجسرية، واستدعاءات الدوال ذات المعاملات النوعية، والأنواع الداخلية ذات المعاملات، ومطابقة معاملات المنشئ المخفية غير مدعومة صراحةً عند غياب الإثبات المطلوب.

تُحفظ علامة Java 8 الفارغة والمرئية وقت التشغيل @java.lang.Deprecated على الأصناف والحقول والدوال والمنشئات. تُرفض التعليقات التوضيحية على المعاملات، والمهيئات الساكنة المعلَّمة، ومستويات الرؤية الأخرى، وقيم العناصر مثل since أو forRemoval. تقارن CI بصورة منفصلة سمة Deprecated في ملف الصنف والتعليقات التوضيحية وقت التشغيل بعد إعادة الترجمة، بما يشمل التصريحات المرجعية غير المعلَّمة والدوال المساعدة المولَّدة؛ ولا تُحتسب الدوال المساعدة ضمن عدد الدوال الأصلية.

يحفظ DEX وsmali أيضًا تعليق المنصة التوضيحي @android.annotation.SuppressLint على الأصناف والحقول والدوال والمنشئات. يتطلب رؤية build ومصفوفة نصوص واحدة باسم value، مع حفظ المصفوفات والنصوص الفارغة والقيم المكررة وترتيبها وقيم المحارف المهروبة. تبقى التعليقات على المعاملات والمهيئات الساكنة غير مدعومة. تستخدم CI حزمة Android SDK للتحقق من التعليقات المحفوظة بسياسة CLASS بعد إعادة الترجمة ومقارنة سلوك البرنامج.

يحفظ المحرك المدمج أيضًا @Retention و@Target و@Documented و@Inherited المرئية وقت التشغيل على تصريحات التعليقات التوضيحية المدعومة، ويُنتج تصريح @interface حقيقيًا. لا تسمح هذه المجموعة الفرعية بحقول أو دوال أو معاملات نوعية أو تصريحات متداخلة. تُدعم التعليقات التوضيحية على المستوى الأعلى أو كأعضاء ساكنة عندما يمكن إثبات الأسماء وإمكانية الوصول والانتماء إلى النوع المحيط؛ وتُرفض النطاقات المحلية أو المجهولة.

يتطلب تطبيق علامة فارغة على تصريح صنف أو واجهة أو تعليق توضيحي وجود تعريف مطابق يمكن الوصول إليه ضمن مجموعة الأصناف التي يجري تحليلها معًا. ويجب أن تسمح Retention وTarget بالتطبيق الفعلي. يمكن إعادة بناء تصريح SOURCE، لكن يُرفض تطبيقه إذا ظل محفوظًا في المدخلات؛ وتتطلب CLASS أو Retention غير المحددة رؤية DEX من نوع build (0)، بينما تتطلب RUNTIME رؤية runtime (1). يبقى غياب Retention مختلفًا عن CLASS الصريحة، وغياب Target مختلفًا عن المصفوفة الفارغة، ويُحفظ ترتيب مصفوفة Target. تقتصر قيم Target على Java 8؛ وتُرفض القيم الأحدث مثل MODULE وRECORD_COMPONENT. تُحفظ @Inherited دون نسخ التطبيقات الموروثة كتعليقات توضيحية مباشرة على الأصناف الفرعية.

تظل تصريحات عناصر التعليقات التوضيحية وقيمها الافتراضية، والتطبيقات المخصصة غير الفارغة، والعلامات المخصصة على الحقول أو الدوال أو المعاملات، والتعريفات الخارجية للتعليقات التوضيحية، وحاويات التعليقات التوضيحية القابلة للتكرار، وkotlin.Metadata غير مدعومة. يُخرَج تعريف العلامة كتصريح صنف بلا دوال عناصر أو دوال مساعدة، ولا يزيد عدد الدوال المستعادة.

تعالج CI أمثلة Java 8 الخاصة بالمشروع باستخدام D8 وNeverD، ثم تعيد ترجمة كل شيفرة Java المولدة وتقارن بيانات Signature الوصفية كاملةً ونتائج الانعكاس والسلوك. لا تثبت هذه الفحوص استعادة التطبيقات الحقيقية بالكامل.

Linux وmacOS

cmake --build build --target neverd

./build/bin/neverd mobile app.apk -o recovered-app

ضع المسارات التي تحتوي على مسافات بين علامتي اقتباس.

Windows PowerShell

& .\build\bin\neverd.exe mobile .\app.apk -o .\recovered-app

قد تضع عمليات البناء متعددة الإعدادات الملف التنفيذي في build/bin/Release/. اتبع متطلبات توزيع المكتبات الأصلية المعتادة لذلك البناء.

المدخلات المدعومة والقيود

يصف جدول المدخلات التالي الاستعادة. أما أوضاع الاستعلام الموضحة لاحقًا فتستخدم نطاقات تحقق أضيق.

المدخل السلوك القيد الأساسي
.apk يتحقق من ملف ZIP كاملًا، ثم يحلّل معًا ملفات classes.dex وclasses2.dex والملفات DEX المرقّمة اللاحقة في الجذر الشيفرة فقط؛ لا يفك الموارد أو ملف البيان
.dex التحقق من DEX 035 أو 037–040 وتحليله بأداة القراءة المدمجة يفشل DEX 041 والتصريحات أو العمليات غير المدعومة؛ إعادة تسمية الملف أو اقتطاعه لا تنتج شيفرة بايت صالحة
.smali يحلّل الصنف المقدّم لا يحمّل تلقائيًا الأصناف المجاورة المشار إليها
مجلد smali يجمع ملفات .smali تكراريًا ويحلّلها معًا ضمّن الأصناف المتداخلة وجذور smali التابعة لها داخل مجلد الإدخال

لتحليل شجرة APK مفكوكة تحتوي على smali/ وsmali_classes2/، مرّر المجلد المشترك الذي يحتويهما. لا تصل إلى الأداة إلا ملفات .smali، لكن تُفحص الشجرة المقدّمة كاملةً وتُنسخ أولًا؛ لذلك تُحتسب الأصول الكبيرة غير المرتبطة بالشيفرة ضمن حدود الإدخال أيضًا. يقلّ العمل باستخدام مجلد صغير يحتوي فقط على جذور smali المطلوبة.

تُعامل حزم APK المجزأة كمدخلات منفصلة. يمكن معالجة كل APK يحتوي على DEX على حدة، لكن هذا الأمر لا يدمج مجموعة APK؛ وتفشل الأجزاء التي تحتوي على موارد فقط لعدم وجود DEX في الجذر. لا تُقبل .aab و.apks و.xapk و.odex و.oat و.vdex كمدخلات لهذا الأمر.

لا تُستعاد موارد APK أو AndroidManifest.xml أو الأصول أو مكتبات JNI/المكتبات الأصلية أو الشيفرة المنزّلة أثناء التشغيل على هيئة Java. استخرج مكتبة .so أصلية بشكل منفصل، واستخدم neverd decompile library.so -o library.c. يجب أن تكون الحمولة المشفّرة أو المحزّمة متاحة مسبقًا بصيغة DEX/smali عادية كي يعمل هذا المسار الساكن؛ فهو لا يفك حزم الحماية، ولا يتصل بالأجهزة، ولا يتجاوز وسائل الحماية.

جرد سريع للفئات

neverd mobile app.apk --list-classes
neverd mobile classes.dex --list-classes --class-prefix com.example
neverd mobile app.apk --list-classes --class-prefix Lcom/example/ --json
neverd mobile app.apk --list-classes -o classes.txt

يقرأ هذا الاستعلام هويات الفئات دون فك ترميز أجسام الأساليب أو توليد Java. ولا يحتاج إلى مجلد تجهيز أو بيئة تشغيل خارجية. يحتوي الإخراج النصي على واصف DEX دقيق واحد في كل سطر، بترتيب دليل ZIP ثم ترتيب التعريفات في DEX. يقبل --class-prefix بادئة واصف أو بادئة حزمة مفصولة بالنقاط؛ ويطابق البادئة حرفيًا دون اشتراط توافقها مع حدود الحزمة. تفشل تعريفات الفئات المكررة صراحةً، بما في ذلك التكرار بين ملفات DEX. وتفشل أيضًا هويات الفئات التي لا يمكن تمثيلها بصيغة UTF-8 دون فقدان.

دون -o، يكتب الاستعلام إلى stdout. في وضع الاستعلام، يشير -o إلى ملف جديد وليس مجلد استعادة. تبقى الملفات الموجودة دون تغيير. تُجمع النتائج حتى تنجح جميع ملفات DEX المحددة، لذا يمنع ملف DEX غير سليم يظهر لاحقًا نشر جرد جزئي. يتضمن --json عدد الفئات المطابقة وعدد الفئات الكلي وعدد ملفات DEX، إضافةً إلى validation_scope: "dex-envelope-and-class-identities".

تُفحص جميع أسماء ZIP ورؤوسه ونطاقاته وحدود الموارد المعلنة. لا يُفك الضغط ولا يُفحص CRC إلا لمحتويات classes.dex وملفات classesN.dex المرقمة الموجودة في الجذر؛ وتبقى سلامة محتويات الموارد غير المعنية دون تحقق. يحتفظ كل DEX بفحوص الرأس وSHA-1 وAdler-32 وحدود الخريطة وبيانات الفئات الوصفية المشار إليها. لا تُفحص أجسام الأساليب ولا البيانات الوصفية غير المشار إليها. هذا استعلام جرد، وليس فحص سلامة للأرشيف كله أو دليلًا على استعادة Java. يظل DEX 041 وقسما method-handle وcustom-call-site غير مدعومة. ويظل مسار الاستعادة الكاملة المعتاد يفحص محتويات كل مدخل في الأرشيف.

تُطبق --timeout و--max-files و--max-bytes. يحتسب حد الفئات جميع التعريفات عبر ملفات DEX قبل التصفية؛ كما تحتسب مدخلات ZIP غير المحددة ضمن حدود الأرشيف. لا تقبل عملية الجرد خيارات iOS أو مدخلات smali.

استعلامات المراجع في الشفرة

ابحث عن معاملات التعليمات المباشرة دون توليد Java:

neverd mobile app.apk --find-refs string --query 'login failed' --json
neverd mobile classes.dex --find-refs type --query 'Lcom/example/Service;' --exact
neverd mobile app.apk --find-refs method --query '->connect(' --owner 'Lcom/example/Client;'
neverd mobile app.apk --find-refs field --query 'Lcom/example/State;->ready:Z' --exact -o refs.jsonl

المطابقة هي بحث حرفي عن سلسلة جزئية، مع التمييز بين حالة الأحرف. يطابق --exact الهدف كاملًا: محتوى السلسلة، أو واصف النوع، أو هوية أسلوب مثل Lpkg/Type;->name(I)V، أو هوية حقل مثل Lpkg/Type;->name:I. يقصر --owner مالك هدف مراجع الأساليب أو الحقول على واصف مطابق تمامًا. ولا يصفي الأسلوب الذي يحتوي المرجع. لا تُدعم الاستعلامات الفارغة أو مدخلات smali أو الجمع بين خيارات الاستعلام والاستعادة؛ وتُعامل المحارف الخاصة بالتعابير النمطية كمحارف حرفية عادية.

الإخراج الافتراضي كائن JSON مضغوط واحد لكل موضع ظهور (JSON Lines). يعيد --json تقريرًا بالعدادات ومصفوفة references. يسجل كل صف dex_entry، وهوية الأسلوب الحاوي كاملةً في method، وpc_code_units (وحدات من 16 بت بدءًا من أول تعليمة في الأسلوب)، وopcode، وkind، وtarget_index (محلي داخل DEX)، وtarget. تُحفظ جميع مواضع الظهور، بما فيها الشفرة المشتركة المنسوبة إلى عدة تعريفات للأساليب. تتضمن صفوف السلاسل أيضًا وحدات target_utf16 الدقيقة؛ وتكون target مساويةً لـ null حين يمنع بديل UTF-16 منفرد النشر بصيغة UTF-8 دون فقدان. يجب أن تكون الهويات الأخرى قابلةً للتمثيل بصيغة UTF-8.

يستخدم الماسح حدود التعليمات وفحوص المعاملات ومعالجة بيانات payload وفحوص تدفق التحكم الخاصة بقارئ الاستعادة. لا يمكن أن تصبح القيم الفورية أو بيانات payload للتبديل/المصفوفات مراجع. ويفحص كل جسم شفرة معرّف، حتى عند عدم تطابق أي هدف، قبل تعيين code_scan_complete: true. يشمل defined_method_count التصريحات الأصلية والمجردة؛ ويحتسب scanned_method_count التعريفات ذات الأجسام، فيما يحتسب scanned_code_item_count الأجسام الفعلية المختلفة لكل DEX. يحتسب matching_pool_entries الأهداف المطابقة، بما فيها الأهداف غير المشار إليها.

يغطي validation_scope: "dex-code-references" غلاف DEX وجداول المعرّفات وانتماء الفئات والأعضاء، وبيانات الشفرة والاستثناءات والتنقيح المستهلكة. تقع التعليقات التوضيحية والقيم الثابتة المرمّزة والاستخدامات في التصريحات وحدها والبيانات الوصفية غير المشار إليها خارج هذا الاستعلام. هذا ليس استعادةً لـ Java ولا متحقق ART. تفشل الشفرة غير المدعومة والبيانات المستهلكة غير السليمة صراحةً. وللتحقق من APK حدود المحتويات المحددة نفسها الخاصة بجرد الفئات؛ وتبقى سلامة محتويات الموارد غير المحددة دون تحقق.

تُجمع النتائج عبر جميع ملفات DEX المحددة قبل النشر، بما يشمل فحص تكرار الفئات بين ملفات DEX. يشير -o الاختياري إلى ملف جديد. يحد --max-files مجاميع تعريفات الفئات وتعريفات الأساليب ومواضع الظهور في النتائج كلًا على حدة، وكذلك مدخلات ZIP. يحد --max-bytes المدخلات وبيانات الاستعلام المحتفظ بها وذاكرة العمل لكل جسم والإخراج (مع هوامش محافظة لتمدد JSON). هذه ميزانيات للعملية؛ أما RSS للعملية فيشمل أيضًا مخازن الإدخال والتكاليف الإضافية للمخصّص وبيئة التشغيل. وتُطبق كذلك ميزانيات الوقت والعمل المعتادة.

الخيارات وترتيب الأولوية

neverd mobile app.apk -o recovered-app --platform=android \
  --timeout=600 --max-files=30000 --max-bytes=4294967296 --json
الخيار القيمة الافتراضية المعنى
-o PATH مطلوب للاستعادة مجلد استعادة جديد؛ وفي كلا وضعي الاستعلام، ملف إخراج جديد اختياري
--list-classes معطّل استعلام عن هويات فئات APK/DEX دون استعادة Java
--class-prefix PREFIX جميع الفئات بادئة حرفية لواصف أو اسم مفصول بالنقاط؛ يتطلب --list-classes
--find-refs KIND معطّل استعلام عن مراجع التعليمات المباشرة إلى السلاسل أو الأنواع أو الأساليب أو الحقول
--query TEXT مطلوب للمراجع سلسلة جزئية حرفية من هوية الهدف
--exact معطّل مطابقة هوية هدف المرجع كاملةً
--owner DESCRIPTOR أي مالك المالك الدقيق للهدف في استعلامات الأساليب/الحقول
--platform=auto|android auto اختيار Android صراحةً أو استنتاج المنصة من المدخل
--timeout N 300 ميزانية زمن التحليل بالثواني، بقيمة موجبة
--max-files N 20000 حد موجب لعدد العناصر، بما فيها المجلدات التي تُنشأ
--max-bytes N 2147483648 حد موجب بالبايت للمدخل والبيانات المستخرجة والمخرجات النهائية
--json معطّل طباعة تقرير بصيغة JSON؛ وإلا تُخرج استعلامات المراجع JSON Lines

اختيار --arch غير الافتراضي و--artifact و--metadata-only وقيمة --max-func غير الصفرية تخص iOS وتُرفض مع Android؛ ويُقبل --arch=auto الصريح.

تظل ميزانيات الملفات والبايتات مطبّقة على المدخلات والبيانات المستخرجة والمخرجات النهائية. تتحقق أدوات القراءة والمولّد المدمجان أيضًا من حدود العمل والزمن المنقضي. رفع أحد الحدود لا يعطّل الحدود الأخرى.

بنية المخرجات وتقرير JSON

recovered-app/
  sources/                       حزم Java وأصنافها المستعادة
  metadata/android-methods.json  تغطية أساليب المحرك المدمج
  report.json                    قائمة ذات إصدار وحدود الاستعادة

تُحذف المدخلات المؤقتة. قد تشترك الأصناف المتداخلة في ملف الصنف الخارجي، لذلك لا يساوي عدد ملفات Java عدد أصناف DEX. قد تستخدم الأساليب الناتجة حلقة توزيع في Java؛ ولا تنفّذ DEX الأصلي ولا تستدعيه عبر جسر وقت التشغيل.

يتضمن التقرير المدمج android_method_recovery، وتُكتب البيانات نفسها في metadata/android-methods.json مع الاحتفاظ بكل أسلوب أصلي. يجب تحقق method_count = recovered_method_count + projected_method_count + declaration_only_method_count + unrecovered_method_count؛ تعني قيمة projected_method_count الغائبة صفرًا، وتظل unrecovered_method_count صفرًا قبل النشر. تحمل أساليب native وabstract الأصلية الحالة declaration-only ولا تُحتسب ضمن الأجسام المستعادة.

يمكن إخراج مجموعة محدودة من الأصناف المحلية المسماة التي لا تلتقط متغيرات خارجية داخل الأسلوب الثابت الحاوي المحدد بدقة. يتطلب ذلك أسلوبًا عاديًا بأنواع عددية أولية، وصنفًا بلا حقول يرث مباشرة من Object، وبانيًا حقيقيًا بلا معاملات، وأساليب كائن بأنواع أولية، واستخدامات للكائنات ثبت أنها لا تخرج عن النطاق المدعوم. تظل الأصناف المجهولة والتقاط المتغيرات والمعدّلات غير المدعومة والاستخدامات غير المثبتة أسبابًا لإخفاق صريح.

تحمل الأساليب المحلية والأسلوب الحاوي الحالة source-projected مع projection_kind: "named-method-local"، وتبقى التغطية partial حتى عندما تكون حالة التقرير العام success. تظل الأسماء الثنائية وأعلام الوصول بعد إعادة الترجمة غير متحقق منها. قد يختار مترجم Java اسمًا ثنائيًا مختلفًا، لذا يحتفظ class_source_bindings بالصنف الأصلي والأسلوب الحاوي الدقيق ومسار المصدر والاسم المحلي مع binary_name_status: "unverified".

يسرد generated_source_helpers الأساليب الإضافية بالأنواع الدقيقة throw-helper وconstant-helper وdefault-constructor وfield-initializer. يشير النوع الأخير إلى <clinit> إضافي مولّد لم يكن موجودًا في قائمة الأساليب الأصلية. لا تُحتسب هذه الإضافات ضمن العدد الأصلي للأساليب. لا يثبت نجاح الترجمة أو تطابق الأسماء في مرة واحدة استعادة كاملة. لا يتضمن المثال المختصر التالي أساليب مسقطة إلى المصدر:

{
  "schema_version": 1,
  "status": "success",
  "platform": "android",
  "source": "app.apk",
  "input_kind": "apk",
  "backend": {
    "name": "neverd",
    "version": "1",
    "execution": "builtin"
  },
  "input_code_files": [
    "classes.dex",
    "classes2.dex"
  ],
  "dex_count": 2,
  "smali_count": 0,
  "java_source_count": 2,
  "java_sources": [
    "sources/example/Main.java",
    "sources/example/Peer.java"
  ],
  "logs": [],
  "android_method_recovery": {
    "schema_version": 1,
    "status": "recovered",
    "class_count": 2,
    "method_count": 6,
    "recovered_method_count": 5,
    "declaration_only_method_count": 1,
    "unrecovered_method_count": 0
  }
}

تكون قيمة input_kind إحدى القيم apk أو dex أو smali أو smali-directory. يسرد input_code_files أسماء ملفات البايت كود الداخلة أو مسارات smali، بينما تكون مسارات java_sources وlogs نسبية إلى جذر الإخراج. يمثّل source الاسم الأساسي للمدخل. تتضمن التقارير الفعلية قيودًا إضافية لإعادة البناء؛ احتفظ بها عند عرض النتائج على أدوات أخرى.

عند الأتمتة، افحص رمز خروج العملية قبل الاعتماد على status، واحفظ التقرير خارج مجلد الإخراج الجديد عند إعادة توجيه stdout:

neverd mobile app.apk -o recovered-app --json > recovery-result.json

تعيد واجهة CLI الأصلية صفرًا عند النجاح ورمزًا غير صفري عند فشل الاستعادة. مع --json تتضمن الأخطاء المعالجة schema_version وstatus: "error" وerror. قد تُبلّغ أخطاء تحليل المعاملات أو بدء الملف التنفيذي والمكتبات الأصلية والمقاطعات عبر stderr فقط. افحص حالة الخروج أولًا.

معالجة الإخفاقات واستكشاف المشكلات

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

العَرَض الإجراء
DEX أو تعليمة أو تصريح أو تهيئة غير مدعومة قراءة التشخيص ومراجعة النطاق المدعوم
مدخل غير صالح أو صنف مكرر تصحيح شيفرة البايت أو مجموعة الأصناف؛ لا تُحذف الأجسام غير المدعومة بصمت
تجاوز الوقت أو الميزانية تقليل المدخلات أو ضبط --timeout و--max-files و--max-bytes وفق الموارد المتاحة
المخرجات موجودة اختيار دليل إخراج جديد

التحقق وعمق الدعم

يُستخدم Python فقط في نصوص اختبارات التطوير أدناه؛ وتعمل الاستعادة المحمولة المدمجة في واجهة CLI الأصلية المكتوبة بلغة C++20.

cmake --build build --target check-neverd-mobile
ctest --test-dir build -L NeverDMobileTests --output-on-failure
python3 scripts/test_mobile_android_internal.py --d8 PATH --neverd build/bin/neverd

تتحقق اختبارات المكونات وCLI من التحليل وعقود المخرجات والتنظيف بعد الفشل. يستخدم مشغّل المقارنة الداخلي JDK، بما فيه java وjavac، وD8 لإنشاء أمثلة DEX/APK مستقلة ثم ترجمة Java المستعادة وتشغيلها. هذه اعتماديات اختبار وليست متطلبات تشغيل للاستعادة المدمجة. شغّله على البناء الحالي وافحص نتائجه قبل اعتبار حالة ما متحققة. نجاح الأمثلة لا يثبت الاستعادة الكاملة لتطبيقات عشوائية.

راجع نظرة عامة على الأجهزة المحمولة لمسار iOS ذي الصلة.