
دليل خطوة بخطوة لبناء نوى Kali NetHunter مخصصة لنظام Android: جلب المصدر، اختيار سلسلة الأدوات، التجميع المتقاطع، والحرق.
أكبر عقبة أمام معظم الأشخاص الذين يرغبون في إعداد جهاز Nethunter هي متطلبات النواة. ما لم يكن جهازك يحتوي بالفعل على نواة مبنية مسبقًا (ومُصانة)، فسيُطلب منك بناء واحدة بنفسك. هناك الكثير من التوثيق حول هذه العملية بالفعل، لكن من تجربتي قد يكون من الصعب معرفة ما ينطبق على حالتك وما لا ينطبق.
تتفاقم هذه المشكلة بسبب الأوغاد الأشخاص الذين يكتبون أدلة بعناوين جاذبة للنقر مثل «ابنِ نواة Nethunter لأي جهاز Android!» أو بوعود كاذبة مثل «تعلّم كيفية ترجمة نواة Nethunter في عشر دقائق!» ومن المؤسف أيضًا أن واقع الإنترنت في 2025 هو أن كثيرًا من الأغبياء الأشخاص يعتقدون أن ChatGPT أو غيرها من نماذج اللغة الكبيرة لديها إجابات موثوقة على أسئلتهم، في حين أن كل ما تملكه تلك النماذج حقًا هو معلومات جمعتها من الأوغاد المذكورين أعلاه.
أكتب هذا الدليل بأكبر قدر ممكن من الشمول والصدق. ومع ذلك، ليس المقصود منه أن يكون الوثيقة الوحيدة التي ستحتاج إلى قراءتها لهذه العملية – بالتأكيد ستكون لديك أسئلة لا يمكن لهذا المستند الإجابة عنها. أود أن أشجعك على البحث عن إجابات لهذه الأسئلة في توثيق البرمجيات ذي الصلة، وليس على YouTube أو من ChatGPT.
قبل أن تبدأ أي جزء من هذه العملية، يجب أن تكون قد فعلت مسبقًا:
apt update && apt upgrade -y (اختياري: أضفت حزمًا وصفية (metapackages))لإكمال هذه العملية، ستحتاج إلى:
cd, rm, ls, mkdir, find, diff, grep, إلخ)vim للأشخاص الرائعين، وإلا فـ nano)build-devel على التوزيعات المبنية على Arch، build-essential على المبنية على Debian) – كما أنصحك بتثبيت Perl + Python3 لأن بعض ملفات Makefile الخاصة بالنواة تتطلب ذلكهل سيكون هذا ممكنًا لجهازي؟
نواة Linux مرخصة بموجب رخصة GNU العامة 2.0، وهي رخصة copyleft. هذا يعني أن الكود المصدري لنواة Linux موزع بحرية ويمكنك تعديل الكود المصدري كما تشاء (كما فعلت كل شركة مصنعة لأجهزة Android)، ومع ذلك، يجب أيضًا توزيع الكود المصدري الناتج بحرية.
على نحو لا يفاجئ أحدًا إطلاقًا، فإن العديد من الشركات العملاقة التي تستخدم كودًا مرخصًا بـ GPL تتجاهل شروط هذه الرخصة. فهي إما ترفض توزيع كودها المصدري أو تطلق جزءًا منه فقط (عادةً ما يكون معطوبًا، قديمًا، ويحتوي على كتل ثنائية مضمّنة). إذا لم يتوفر كود مصدري لنواة جهازك، فلا توجد طريقة لإنشاء نواة Nethunter له.
قدرتك على فتح قفل محمّل الإقلاع وتثبيت ROM مخصص تعتمد أيضًا بشكل كبير على مزاج الشركة المصنعة لجهازك. حتى لو سمحت بفتح قفل محمّل الإقلاع وتمكنت من عمل روت لهاتفك عبر Magisk، فإذا لم تنشر أشجار الأجهزة (device trees)، فمن المرجح ألا توجد ROMs مخصصة لجهازك. في هذه الحالة، من المشكوك فيه جدًا أن يكون الكود المصدري للنواة الذي نشرته (إن وُجد) قد حظي بأي صيانة منذ إصداره، أو أنه سيُبنى حتى دون تعديلات. إذا لم ترَ أي شخص آخر يصون أي شيء (نواة، ROMs، استردادات) لجهازك، فسيكون من الصعب، إن لم يكن مستحيلًا، تحويل هذا الجهاز إلى Nethunter كامل.
ملاحظة حول إصدارات النواة
لنتخيل أن هناك ROMs/نواة/استردادات مخصصة يتم تحديثها وصيانتها بانتظام لجهازك، لكن ببساطة لا توجد نواة Nethunter. في هذه الحالة، يجب أن تكون قادرًا على إكمال هذه العملية، لكنها ستختلف اعتمادًا على إصدار نواة Linux الذي يستخدمه جهازك.
المعلومات الواردة في هذا الدليل مبنية على تجربتي في تعديل نوى 4.14.x. هناك أدلة أقدم كُتبت تتحدث عن استخدام أدوات GCC (بدلاً من LLVM/clang، كما سنستخدم) وتنطبق على نوى 3.x. إذا كان جهازك يستخدم إصدار 5.x/6.x من نواة Linux، فلن تكون المعلومات الواردة في هذا الدليل كافية لإكمال هذه العملية. تتغير طريقة بناء Android باستمرار، ويجب أن تبحث عن دليل يغطي نوى GKI واستخدام Bazel/Kleaf.
من الطرق الجيدة للعثور على مستودعات تحتوي على الكود المصدري لنواة جهازك هي استخدام اسمه الرمزي (codename). يمتلك كل جهاز Android اسمًا رمزيًا، على الرغم من أن بعض الشركات المصنعة (مثل OnePlus) تتعامل مع هذا بمرح أكثر من غيرها (مثل Samsung). الاسم الرمزي لهاتفي Xiaomi Poco X3 NFC هو "surya"، بينما الاسم الرمزي لهاتفي Samsung A51 هو "SM-A515F". عادةً ما تتبع مستودعات الكود المصدري للنواة اصطلاح التسمية android_kernel_MANUFACTURER_CODENAME حيث تكون الشركة المصنعة هي الشركة الأم، أي android_kernel_xiaomi_surya وليس android_kernel_poco_surya. ومع ذلك، قد توجد أيضًا مستودعات مبنية حول SoC (نظام على رقاقة) لجهازك، وأحيانًا تكون "موحّدة" لتضمين ملفات مصدرية لأجهزة أخرى بنفس SoC. هذا هو الحال بالنسبة لجهاز Samsung الذي ذكرته، والذي يُسمى مستودع مصادره android_kernel_samsung_exynos9611. اطّلع على github/gitlab وشاهد ما يمكنك العثور عليه.
لأغراض هذا الدليل، سأستخدم أحدث إصدار من LineageOS 22.2 (مُبنى في 2025-08-04) على جهاز surya، لذلك سأرغب في استنساخ الكود المصدري للنواة من مستودع LineageOS. لكن قبل القيام بذلك، أريد نسخ ملفين من جهازي إلى الكمبيوتر الذي سأستخدمه لبناء النواة: /proc/config.gz و /proc/version. كان يمكنني نسخ الملف الأول، /proc/config.gz، إلى /sdcard، ثم سحبه من الجهاز عبر ADB، وفك ضغطه بـ gunzip، وإعادة تسميته. لكن ذلك يبدو كثيرًا من الخطوات، لذا ما فعلته بدلًا من ذلك هو:

ثم، على الجهاز نفسه، نفّذت (بصلاحيات الجذر)

ماذا يحدث هنا؟
على جهاز الكمبيوتر المحمول: nc (netcat) -l (الاستماع للاتصالات الواردة) -p (المنفذ) 4545 (في الحقيقة يمكن أن يكون أي رقم بين 1024-65535، لكنني عادةً ما أستخدم 4545) > (الكتابة إلى ملف) surya-defconfig-lineageos22.2-20250804 (اسم ملف وصفي) < (إدخال من ملف) /dev/null (جهاز فارغ – يضمن ذلك أنه إذا لمست لوحة المفاتيح فلن تُرسل ضغطة المفتاح إلى الملف الذي أستقبله، مما قد يفسده).
على الهاتف: zcat (مثل الأمر cat للدمج لكن لملفات gzipped) /proc/config.gz (إعدادات النواة التي بُنيت بها النواة قيد التشغيل حاليًا) | (إرسال مخرجات تلك العملية كمدخلات للعملية التالية) nc (netcat مجددًا) 192.168.1.42 (عنوان IP المحلي لجهاز الكمبيوتر المحمول) 4545 (المنفذ الذي حددته سابقًا)
في حين أن هذا ينبغي أن يعطيك ملف .config المستخدم لبناء النواة قيد التشغيل حاليًا، إلا أن هذا ليس هو الحال دائمًا. بعض الأجهزة الأكثر حداثة / إصدارات ROM الأحدث سترفض الإقلاع إذا كان الإعداد المحفوظ في /proc/config.gz لا يطابق ملف .config الذي استُخدم لبناء النواة الأصلية. لحسن الحظ، هذا هو الفحص الوحيد الذي يحدث (وليس شيئًا أصعب بكثير في التغلب عليه مثل مجموع اختباري SHA256 للنواة بأكملها)، لذا توصل بعض الأشخاص الأذكياء إلى طريقة لخداع الملف في /proc/config.gz ليطابق النواة الأصلية، على الرغم من تعديلاتهم. إذا كنت غير متأكد مما إذا كان الملف على جهازك حقيقيًا أم مخادعًا، يمكنك تنفيذ zcat /proc/config.gz | head ثم uname -r. إذا لم تتطابق أرقام الإصدارات، فالمخزّن في /proc كان مخادعًا. في هذه الحالة، بينما لا يزال بإمكانك المتابعة مع هذا الدليل، قد ترغب في تشغيل diff لمقارنة الإعداد المستخرج مع بعض الملفات التي تجدها في دليل arch/arm64/configs داخل كود مصدر نواتك.
أما بالنسبة إلى /proc/version، فقد لا يكون من الضروري إرسال هذا الملف، إذ أن كل ما نحتاجه فعلًا هو المعلومات حول إصدار clang/ld.lld الذي استُخدم لترجمته. لذا يمكننا ببساطة تشغيل cat /proc/version وإلقاء نظرة:

أوه! يبدو أن من بنى هذه النواة ارتكب “خطأً” بسيطًا، إذ سجّل ملف Makefile الخاص بهم جميع -CFLAGS التي شغّلوها مع clang، لكن ليس إصدار Clang. ومع ذلك، يمكننا أن نرى أنهم استخدموا سلسلة أدوات Android مبنية مسبقًا، وأنهم استخدموا إصدار ld.lld 19.0.1.
إليك صورة أكثر فائدة بعض الشيء. المخرجات الأولى من /proc/version قبل تعديل وبناء وتثبيت نواة جديدة على Samsung A51. المخرجات الثانية من /proc/version حاليًا.

هل لاحظت أي شيء؟ (لا، ليس اسم المستخدم واسم المضيف الغريبين لديّ).
أفضل حيلة لاختيار سلسلة الأدوات هي استخدام نفس سلسلة الأدوات تمامًا التي ترجمت النواة قيد التشغيل حاليًا.
في هذه الحالة، كانت Neutron clang 18.0.0git، وكان العثور عليها سهلاً للغاية:

وانظر إلى ذلك، فمجاميع md5 متطابقة وكل شيء.
لمجرد المتعة، دعنا نلقي نظرة سريعة على سلسلة /proc/version من جهاز أقدم بكثير، Samsung J7 (2016)، الاسم الرمزي j7xelte:

هذا جهاز قديم بما يكفي لدرجة أنه ما زال يستخدم سلاسل أدوات GCC لترجمة النواة.
ولكن عندما أبحث عن “gcc version 4.9.x 20150123 prerelease”، أجد مستودعين:

إذن أيّهما ينبغي أن أنزّل؟
الإجابة: كلاهما. يختلف GCC عن Clang في أنه عند بناء المترجمات/أدوات binutils/الروابط/إلخ للترجمة المتقاطعة، يتطلب بناء سلسلة أدوات منفصلة لكل “ثلاثية هدف” (target triple). تأخذ ثلاثية الهدف (على نحو مفترض) الصيغة
machine-vendor-operating_system
ولكن كما سنرى، لهذه “القاعدة” مليون استثناء. لكن لنبدأ بـ “machine” (الجهاز).
في قسم “ستحتاج” من هذا المستند، قلت إنك تحتاج إلى جهاز 64-بت بمعالج Intel أو AMD يعمل بنظام GNU/Linux. ذلك لأن سلاسل الأدوات التي سنستخدمها مترجمة لتعمل على x86_64-linux-gnu.
ومع ذلك، فإن هذه السلاسل هي مترجمات متقاطعة (cross-compilers)، مما يعني أن كود الآلة الذي تولّده من ملفات الكود المصدري C لن يعمل على ذلك الكمبيوتر، بل على كمبيوتر آخر بثلاثية هدف خاصة به.
Aarch64، المعروفة أيضًا باسم arm64، هي البنية التي يستخدمها تقريبًا كل جهاز Android. أما Arm، دون “64”، فتشير إلى تطبيقات 32-بت الخاصة برقائق ARM. تُترجم معظم نوى Android باستخدام ثلاثيتي aarch64 وarm معًا، لتوفير توافق عكسي مع البرامج ذات 32-بت.
الانتقال إلى الجزء التالي: “Linux”. واضح بذاته. إنها نواة Linux.
لكن الجزء الأخير من هذه “الثلاثيات” يستحق الشرح، ولو بإيجاز، لأنه فوضى معقدة ولكل مترجم يستخدم “الثلاثيات” (GCC, Rust, Go, LLVM) طريقته المختلفة بعض الشيء. “Android”، المثال الأول، منطقي، لكن ما هو “androideabi”؟ EABI تعني “واجهة التطبيقات الثنائية المدمجة” (embedded application binary interface)، لكنك في الحقيقة لست بحاجة للقلق كثيرًا بشأن ذلك – دعنا فقط نعتبر EABI هي القيمة الثالثة “الأساسية”. سترى أيضًا “gnueabi”، والتي تبدو أكثر منطقية الآن – تنفيذ GNU لـ EABI، أليس كذلك؟ (ما يشير إليه هذا فعليًا هو مكتبة GNU للغة C، أي glibc، ولهذا سترى أيضًا ثلاثيات مثل arm-linux-musleabi عند البناء مقابل مكتبة C بديلة مثل musl). قد ترى أيضًا “gnueabihf”. HF تعني “الفاصلة العائمة الصلبة” (hard float)، وإذا أردت معرفة كيف نفذت ARM حلًا داخل الرقاقة لعمليات الأعداد الصحيحة ذات الفاصلة العائمة، اقرأ مقالًا على ويكيبيديا.
إليك ما نحتاج إلى معرفته:
إذا كنت تستخدم سلسلة أدوات LLVM، فسنعلن عن نيتنا في الترجمة المتقاطعة بضبط CROSS_COMPILE=aarch64-linux-gnu- CROSS_COMPILE_32=arm-linux-gnueabi- (بهذه الطريقة، مع وجود - في النهاية) في سطر الأوامر.
إذا كنت تترجم لجهاز قديم جدًا وبالتالي تستخدم سلسلة أدوات GCC، فسنحتاج إلى مجموعتين من الملفات، مسبوقتين بثلاثيات مختلفة. قد تكون هذه هي نفس القيم في مثال LLVM، أو قد تكون مختلفة، مثل سلاسل الأدوات الخاصة بـ j7xelte.
لكن لماذا توجد طرق عديدة جدًا لكتابة الشيء نفسه؟ i386, i686, 386, i32, i64, x86, x64, x86_64, amd64 -- ما السبب المحتمل لهذا التنوع؟!
شريط فكاهي ذو صلة من xkcd:

بالعودة إلى المثال الذي سأترجمه اليوم (surya)، صادف أنني حفظت معلومات /proc/version من نواة أخرى، والتي كانت كالتالي:

هذا هو الشكل الذي ينبغي أن يبدو عليه الأمر إلى حد كبير، مع الرابط، والمجاميع الاختبارية، وإصدارات المترجم/الرابط، إلخ. وبما أن إصدارَي clang وLLD هنا كانا كلاهما 17.0.3، وأن /proc/version المشوّه الذي نملكه من LineageOS الحالية يُظهر LLD 19.0.3، أعتقد أنه من المنطقي أن نبحث عن سلسلة أدوات تحتوي على 19.0.3 لكليهما.
بعد حوالي ثلاث دقائق من البحث، وجدت مستودعًا يمكننا استنساخه كوحدة فرعية (لتسهيل الحصول على بناء قابل للتكرار) هنا: https://gitlab.com/kei-space/clang/r536225/ تبيّن أن سلسلة الأدوات تلك بها مشاكل خطيرة، لذا اخترت Neutron Clang 19. (سنعود إلى هذا).
إذن أصبح لدينا المصدر وسلسلة الأدوات جاهزين للاستنساخ، الأمر الذي يوصلنا إلى:
قررت إنشاء مستخدم جديد لهذا الشرح، خاصة حتى أتمكن من استخدام gh auth login وتنفيذ عمليات الالتزام (commits) دون أن تُنفَّذ عن طريق الخطأ إلى حساب github الرئيسي لديّ. لكن لفعل ذلك، كان عليّ إنشاء حساب (عبر المتصفح)، وإعداد مستخدم جديد، وتوليد مفاتيح SSH له...

انسخ .ssh/id_ed25519.pub إلى GitHub، ثم شغّل gh مجددًا في الطرفية

ومن ثم أكون جاهزًا

…تقريبًا. ما زلت بحاجة إلى إنشاء fork للمستودع في المتصفح،

ثم تهيئته/استنساخه في الطرفية.

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

الصيغة هي git submodule add URL directory/

تذكر، من أجل الحصول على سجل التزامات نظيف جدًا، نريد تشغيل git add . و git commit -a بعد كل تغيير.

لن أشغّل git push بعد، لكن عندما أفعل ذلك في النهاية، سيعمل على تحديث جميع الالتزامات.
هنا على الأرجح تتوقع أن يتحدث الدليل عن إجراء تعديلات على الكود المصدري للنواة لإضافة دعم Nethunter. ذلك آتٍ – قريبًا. أولًا، مع ذلك، دعنا نرَ كيف يُترجم الكود المصدري غير المعدّل باستخدام سلسلة الأدوات والإعدادات لدينا.

يجب نسخ ذلك الإعداد من النواة قيد التشغيل حاليًا إلى دليل الكود المصدري للنواة، لكن نظرًا لأننا سنستخدم out/ لملفاتنا الثنائية المترجمة، فأنا بحاجة إلى نسخه هناك أيضًا. كما أحتاج إلى إلحاق دليل bin/ الخاص بسلسلة الأدوات بمتغير PATH الخاص بي. كان يمكنني كتابة export PATH=/home/build_user/android_kernel_xiaomi_surya/toolchain/bin:$PATH لكن الطريقة الأسهل هي ببساطة cd إلى ذلك الدليل ثم تشغيل export PATH=$(pwd):$PATH. تعمل $() على توسيع ناتج الأمر الذي تحويه، وسيعرض pwd المسار الكامل لدليل العمل الحالي.
كما عرضت محتويات دليل bin/ الخاص بسلسلة الأدوات حتى ترى كيف أن أدوات LLVM binutils لها بادئة خاصة بها. من الناحية المثالية، يحتوي ملف Makefile على تعليمة تتيح لي عند التصريح بـ LLVM=1 أن تُضبط تلقائيًا AR=llvm-ar، AS=llvm-as، إلخ. لذا دعنا نرى ما بداخل ملف Makefile.

ممتاز! يمكنني ببساطة التصريح بـ LLVM=1 دون الحاجة إلى التصريح بالبقية بشكل فردي… في الغالب. أحتاج أيضًا إلى استخدام مُجمّع LLVM، لكن له تصريحه الخاص، LLVM_IAS:

إذن كل ما سأحتاج إلى التصريح به الآن هو ARCH=arm64 LLVM=1 LLVM_IAS=1 AS=llvm-as O=out CROSS_COMPILE=aarch64-linux-gnu- CROSS_COMPILE_32=arm-linux-gnueabi-. قد يبدو ذلك كثيرًا، لكنه أقل بكثير من التصريح بكل أداة binutil على حدة.
إذن دعنا نشغّل أمرنا لفتح الإعداد….
انتظر. يبدو أن سلسلة الأدوات هذه بها بعض المشاكل. لذلك قررت إلغاء تهيئة الوحدة الفرعية والحصول بدلًا من ذلك على Neutron Clang 19.0.0 من هنا، وسأنزّله باستخدام wget

ثم فك الضغط إلى دليل toolchain/ منشأ حديثًا (مع نسيان صيغة فك ضغط ملفات .tar.zst في البداية)

ومن ثم أضيف هذا الدليل إلى ملف .gitignore.
الآن عندما أشغّل هذا:

يعمل الأمر، ويفتح قائمة nconfig:

ستخبرك العديد من الدروس باستخدام menuconfig، لكنني أفضّل nconfig لأن 1) مظهره أجمل 2) ليس لديه نفس ميل menuconfig إلى عدم التحميل لأنه لا يمكنه العثور على مكتبات ncurses التي ثبّتها بالفعل. على أي حال، هذه مجرد نواة اختبار، لذا يمكننا تحميل .config وحفظه (مرة أخرى كـ .config) وننتهي الآن.
والآن نحاول بناء Image.gz، و…

خطأنا الأول! في النهاية!
وفقًا لـ هذا، يعود السبب إلى أن تحديث Arch كسر شيئًا ما.
على الرغم من أن Arch يأخذ، إلا أن Arch يعطي أيضًا، في هذه الحالة في شكل حزمة AUR libxml-legacy. لذا ثبّتُّ تلك الحزمة، وشغّلت make مجددًا، وهذه المرة:

كل التحية للقائمين على صيانة LineageOS، لأن النواة بأكملها بُنيت مع تحذير واحد فقط:

إذن الآن في out/arch/arm64/boot/ يمكننا العثور على Image.gz. لكن كيف يمكننا ومضه (Flashing) إلى جهازنا؟
نحتاج إلى إنشاء ملف AnyKernel3 بصيغة zip.
هناك طريقتان يمكنك من خلالهما القيام بذلك:
Image، أو Image.gz التي أنشأناها فقط، أو Image.gz-dtb (صورة مدمجة لشجرة الجهاز والنواة – هذه أقل شيوعًا هذه الأيام، ولكن إذا كان جهازك يتوقعها، فسيتعين عليك تفعيل "Build a concatenated Image.gz-dtb" في إعدادات النواة)، أو قد تكون Image.gz، و/أو dtbo.img، و/أو dtb.img.
لأغراض هذا الدليل، قمت بتنزيل واحدة من النوى العديدة التي يتم توزيعها على تيليجرام باسم أنمي غبي وبدون رابط للمصدر. لا تقم أبدًا بتثبيت أي من هذه النوى.
لكننا لن نفعل ذلك، لا تقلق، نحن فقط نستعير إعداد zip الخاص بـ AnyKernel الخاص بهم. لذا أُعيد تسمية الملف وأفك ضغطه

وقمت أيضًا بتحرير سكربت anykernel.sh لتغيير سلسلة اسم النواة. الآن دعنا نستبدل Image.gz من ذلك الـ zip بملفنا الجديد

استخدام zip -f (بمعنى "freshen") سيستبدل الملف الموجود بالداخل بالنسخة الجديدة ببساطة. الرقم 0 يعني بدون ضغط.
لنرَ ما إذا كان بإمكاني وميض هذه النواة وما إذا كانت ستعمل، لكن أولاً:

من الأسهل بكثير تتبع ملفات النواة المضغوطة عندما تضمّن سلاسل الوقت والتاريخ.

ومع ذلك، حرصًا على الدقة (وعلى الاعتماد بأقل قدر ممكن على نوى تيليجرام)، سأخبرك كيف تصنع ملفات dtb.img و/أو dtbo.img الخاصة بك، لأن التوثيق المتعلق بهذا الأمر غير كافٍ بشكل مؤلم.
يوجد برنامجان من AOSP لهذا الغرض. أحدهما، mkdtboimg، مكتوب بلغة Python، مما يسهّل ببساطة تنزيل وتشغيل mkdtboimg.py من موقع AOSP الرسمي. ومع ذلك، قد تحتاج أيضًا إلى الآخر، mkdtimg، المكتوب بلغة C ويُشحن بدون Makefile. وفقًا للتوثيق، فإن ملفات Android.bp كافية -- كل ما عليك هو سحب كود AOSP بالكامل لتشغيل الأوامر المذكورة هناك. أجد هذا الأمر جنونيًا تمامًا، لذا أخذت ملف Makefile الذي صنعه شخص آخر منذ زمن طويل لبناء هذه الأداة بشكل مستقل، وحدّثت الملفات المصدرية إلى أحدث إصدار، ثم بنيتها بنمط static-PIE ضد Musl. يمكنك تنزيل هذا الثنائي (والذي سيعمل على أي حاسوب Linux بمعمارية x86_64، مثل الذي تستخدمه لبناء النواة) من هنا، أو بناؤه بنفسك من الكود المصدري.
الآن هنا الجزء الصعب: ملفات .dtbo التي تُنتج أثناء بناء النواة لن تكون قابلة للتحويل إلى ملفات dtb.img/dtbo.img دون جهد إضافي بسيط. يحتاج Android إلى أن يتضمن استدعاء dtc العلم -a 64. وبما أننا نستدعي بالفعل DTC_EXT=/usr/bin/dtc لإجبار Makefile على استخدام DTC المحدّث الجميل من مدير الحزم لدينا بدلاً من المعطوب الموجود في العديد من النوى، فليس من الصعب أن نضع هذا الأمر داخل علامات اقتباس مفردة ونضيف العلم. يمكنك ببساطة تمرير DTC_EXT='/usr/bin/dtc -a 64'. أما في حالتي، فأحب إنشاء (واختبار) سكربتات build.sh لكل النوى التي أحافظ عليها، بحيث يمكن لأي شخص، حتى لو كان مبتدئًا جدًا، بناء نواته من المصدر دون قراءة هذا الدليل. وبينما كنت أعاني مع طبقات متعددة من منطق bash بعلامات الاقتباس المفردة والمزدوجة، وجدت حلاً بسيطًا، وإن لم يكن أنيقًا، يضمن استدعاء DTC بالعلم الصحيح: سكربت غلاف (wrapper).
لقد أنشأت ملفًا قابلًا للتنفيذ باسم dtc في الدليل الأعلى للنواة، يحتوي على الأسطر التالية:
#!/bin/sh
exec /usr/bin/dtc -a 64 $@
ثم وجّهت DTC_EXT= إلى ذلك الملف، وهذا حلّ المشكلة.
قد تتساءل: «ما ملفات .dtbo هذه؟ إن عمليات بناء النواة لديّ لا تُنتجها أبدًا!» في هذه الحالة يجب أن تتحقق من تفعيل رمز النواة هذا:

إذًا، كيف نستخدم هذه الأدوات؟ أول شيء فعلته هو تحليل ملفات dtb.img وdtbo.img التي وجدتها في ملفات نوى مضغوطة أخرى لمعرفة نوع هذه الملفات. (أعلم، أعلم، لا نريد الاعتماد على نوى مشهد الـ ROM المخصص الغريبة لنواتنا الخاصة، لكن هذا يستحق التحقق). أمر file dtb.img أرجع:
dtb.img: Device Tree Blob version 17, size=345849, boot CPU=0, string block size=31481, DT structure block size=314312
وهي (تقريبًا) نفس النتيجة تمامًا التي أحصل عليها عند تشغيل file ../arch/arm64/boot/dts/qcom/sdmmagpie.dtb:
../arch/arm64/boot/dts/qcom/sdmmagpie.dtb: Device Tree Blob version 17, size=345856, boot CPU=0, string block size=31481, DT structure block size=314312
كان ذلك الاختلاف الطفيف يقلقني، حتى شغّلت diff <(strings dtb.img) <(strings ../arch/arm64/boot/dts/qcom/sdmmagpie.dtb) ووجدت أنها تحتوي على نفس الأشياء تمامًا. لذلك يمكنني الآن أن أفترض بأمان أن إنشاء dtb.img خاص بي هو مجرد نسخ sdmmagpie.dtb وتغيير الاسم.
أما بالنسبة لـ dtbo.img، فلا نحصل على مساعدة كبيرة من file:
dtbo.img: data
ولكن هنا يمكننا استخدام إما mkdtimg أو mkdtboimg.py لتحليله. عندما أشغّل mkdtimg dump dtbo.img، أحصل على:

لذا أعرف أنه عند إنشاء ملفي الخاص، يجب أن أمرّر إما
mkdtimg create dtbo.img --page_size=4096 ../arch/arm64/boot/dts/qcom/sdmmagpie-idp-overlay.dtbo
أو
mkdtboimg create --page_size=4096 dtbo.img ../arch/arm64/boot/dts/qcom/sdmmagpie-idp-overlay.dtbo
كلا الأمرين ينتجان ملفات متطابقة. يمكنك أيضًا تشغيل mkdtimg dump dtbo.img لاحقًا ومقارنة القيم مع الملف الآخر. إذا كنت بحاجة إلى تضمين أكثر من ملف .dtbo في صورتك، فما عليك سوى إلحاق مساره في نهاية أي من الأمرين.
نعود الآن إلى نواة الاختبار التي أنشأناها. الخبر الجيد أنها اشتغلت بدون أي مشاكل، والخبر السيئ هو أنني سأضطر إلى إصلاح ملف Makefile الذي يُنتج /proc/version بهذا الشكل القبيح.
لكن هذا يمكن أن ينتظر. الآن، أخيرًا، وصلنا إلى:
حان الوقت لإضافة بعض الوحدات الفرعية (submodules). أولًا، هذه الوحدة التي تأتي مع تعليمات سهلة المتابعة جدًا. (ملاحظة: أصبحت تحتوي الآن أيضًا على رموز نواة نظام CAN، حيث تم دمج طلب السحب الخاص بي الذي أضافها، لكنك لن ترى ذلك في لقطات الشاشة أدناه).

والآن عندما أعيد make nconfig (نفس الأمر السابق)

لدينا هذا الخيار الجديد الجميل

هذا سيفعّل كل هذه الأشياء. اختر ذلك، واحفظه كـ .config – ولكن كن حذرًا، فهو سيُحفظ في out/.config وسنحذف هذا الدليل بأكمله قبل أن نبني مرة أخرى. لذا بمجرد خروجك من nconfig، انسخ هذا الملف إلى دليل مصدر النواة.
الآن حان الوقت لتعديل بعض الملفات المصدرية، لذا دعنا نضيف مستودع سكربتات بناء Nethunter كوحدة فرعية:

ننتقل بـ cd إلى الدليل الجديد ونشغّل ./build.sh، ثم نختار الخيار 4: Apply Nethunter kernel patches.

إذا تلقيت أي رسائل تقول «اكتمل التشغيل التجريبي مع أخطاء»، فلا تقم بتطبيق التصحيح (patch). وإلا، فانطلق. في حالتي، طبقت التصحيحات 4 و5 و8.
الآن وبعد أن أجرينا التغييرات، لنعد إلى الدليل الأعلى لمصدر النواة ونلتزم بها (commit).

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

سنحتاج إلى تعديل Kconfig وMakefile في drivers/net/wireless/realtek كي تلتقط الإعدادات هذه التعريفات المضافة حديثًا، ولكن أيضًا:

تأكد من تبديل المنصة في rtl8812au/Makefile إلى ANDROID_ARM64 (وكذلك بالنسبة إلى rtl8188eus).
من الجدير أيضًا إعادة التحقق من Kconfig في التعريفات المضافة حديثًا لمعرفة اسم خيار الإعداد:

الآن أعرف أنني بحاجة إلى الإشارة إليه باسم 88XXAU في ملف Makefile الذي يعلوه بمستوى واحد.

لحسن الحظ، يتم تضمين Kconfig فقط بهذه الطريقة:

سأضطر إلى تحرير هذه الملفات مرة أخرى بعد إضافة rtl88x2bu وفرع ARM لـ rtl8188fu أيضًا. (وكما اتضح، خيار إعداد rtl88x2bu يُسمى RTL8822BU، ولهذا يستحق الأمر دائمًا التحقق).
الآن بالنسبة لتعريفات MediaTek المنقولة (backported). باستخدام هذا الـ commit كدليل، نجحت في نقل هذه التعريفات إلى جهازين مختلفين يستخدمان نوى 4.14.x. (أترون لماذا تاريخ الـ commits مهم؟) لكن نحتاج أولاً إلى دليل mt76 بجميع ملفاته.
بدلًا من الاضطرار إلى git clone لنواة 4.19 ونسخ الملفات منها، ثم إجراء التعديلات اللازمة على تلك الملفات في نسختك الجديدة، يمكنك ببساطة إضافة https://github.com/akabul0us/mt76.git كوحدة فرعية. ثم حرّر Makefile وKconfig في دليل drivers/net/wireless/mediatek:

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

لكن يتبيّن أن مصدر النواة لدينا يحتوي بالفعل على هذا الهيكل (struct):

لذا ننتقل إلى الملف التالي الذي سنعدّله، include/linux/overflow.h. يحتوي هذا الملف على بعض التعديلات، لكن بما أنها واضحة تمامًا في الـ commit الأصلي، سأعفيك من المزيد من لقطات الشاشة. include/linux/skbuff.h وinclude/linux/scatterplot.h لديهما تغييرات أيضًا، لكن لا شيء منها ضروري لـ include/net/cfg80211.h. التغييرات الضرورية على include/net/mac80211.h طفيفة – فقط إدراج RX_ENC_HE كسطر أخير داخل enum mac80211_rx_encoding { } وإضافة u8 vht_flag; إلى struct ieee80211_rx_status { }. الملف net/wireless/of.c موجود بالفعل وهو مطابق للملف الموجود في الـ commit الذي ننتقي منه (cherry-pick)، إذن انتهينا من ذلك. (يالها من راحة!)
أما بالنسبة لدعم Docker، فبفضل (مرة أخرى) cyberknight777 على هذا، يمكننا فقط النسخ واللصق

والآن نحن مستعدون لتشغيل nconfig مرة أخرى! ...تقريبًا. أولًا، قم بعمل commit وادفع التغييرات، ثم rm -rf out/ (تأكد من حفظ .config خارج ذلك الدليل)، ثم mkdir -p out، وبعدها فقط يمكننا العودة إلى الإعدادات.

ملاحظة حول تعريفات Realtek USB خارج الشجرة (out-of-tree) التي أضفناها إلى النواة: إنها سيئة نوعًا ما. إذا حاولت بناء أكثر من واحد منها inline، فستحصل على أخطاء في زمن الربط. الحل المعروف منذ زمن طويل هو بناء واحد فقط (1) inline والباقي كوحدات. أما تعريفات Mediatek، فيمكن بناؤها inline دون أي مشاكل.
لقد انتهى بي الأمر بتفعيل مجموعة كبيرة من الأشياء الأخرى، إذا كنت تريد رؤية الفرق الكامل فقد وضعته هنا: هنا لكن على أي حال، لنبنِ!

بداية موفقة - من الجيد دائمًا أن ترى لمحة عن ملفات الكائن (object files) الجديدة التي أضفتها للتو وهي تُبنى دون أخطاء أو تحذيرات.

هذا؟ أقل جمالًا، لكنه سهل الإصلاح. كل ما علينا فعله هو إزالة -Wno-stringop-overread من أي ملف Makefile يحتوي على هذا العلم التحذيري. وبما أننا في هذا السياق، فإن -Werror صارم بعض الشيء، ألا تظن ذلك؟ (يعني هذا العلم «معاملة جميع التحذيرات كأخطاء»، مما يوقف البناء عند أي عثرة، بما في ذلك علم -W غير معروف).

على الأقل هذا سهل الإصلاح.

علامة # سريعة في بداية ذلك السطر وسنكون جاهزين لتشغيل make مرة أخرى – وهذه المرة، أكملت العملية حتى النهاية!
لكن بما أنني قمت بإعداد بعض التعريفات كوحدات، فلم ننتهِ تمامًا. نحتاج إلى تشغيل make modules، أو بشكل أكثر تحديدًا، make -j $(nproc --all) ARCH=arm64 O=out CROSS_COMPILE=aarch64-linux-gnu- CROSS_COMPILE_32=arm-linux-gnueabi- LLVM=1 LLVM_IAS=1 AS=llvm-as modules. وأوه يا رجل، الكود البرمجي لتعريفات Realtek لـ rtl8188fu هو فوضى عارمة:

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

لقد بُنيت بنجاح، على الأقل. سنعود إليها بعد قليل. أولًا دعنا نحدّث ملف النواة المضغوط:

(كدت أنسى - هذه لم تعد نواة «اختبار» بعد الآن، بل نواة Nethunter حقيقية).
أما بالنسبة للوحدات، فإن ملفات .tar هي الطريقة المثلى حقًا لأنها تحافظ على كل شيء يخص الملفات التي تحتويها – ومع ذلك، فإنها تحافظ أيضًا على المسارات. ما لم نفعل شيئًا حيال ذلك، فعند فك ضغط ملف الوحدات (tarball) سننشئ مجموعة من الدلائل، مثل drivers/net/wireless/realtek/rtl8188fu/rtl8188fu.ko على سبيل المثال، لذا دعنا ننشئ دليلًا (ونضيفه إلى .gitignore)، وننسخها إليه، ثم ننشئ الأرشيف.

هل يمكنك وميض هذه كما تفعل مع النواة؟

يجب فك ضغط هذه الوحدات في مكان ما على جهازك. أقول «مكان ما» لأنه لا يهم المكان حقًا، طالما أن الوحدة تُحمَّل عندما تشغّل insmod /whatever/path/to/whatever.ko. يمكنك فعل ذلك في /sdcard، سيكون ذلك جيدًا، لكن تذكر، أنا إضافي (extra)، لذا سأقوم بفك ضغطها في المكان «المناسب» لهذا الجهاز، /vendor/lib/modules. بالطبع، /vendor مُثبَّت للقراءة فقط، لذا سأحتاج أولاً إلى تشغيل شل الجذر (وليس في طرفية Nethunter – فهذه chroot – على الرغم من أنه يمكنك استخدام تطبيق طرفية Nethunter إذا اخترت «New Session → Root Shell») وتشغيل mount -o rw,remount /vendor قبل أن أتمكن من فعل أي شيء على ذلك القسم. ثم cd /vendor/lib/modules; tar xzvf /sdcard/or/wherever/you/saved/the/tarball.tgz; mount -o ro,remount /vendor وتنتهي من الوحدات.
إذا حصلت على خطأ يفيد بعدم وجود مساحة كافية على ذلك القسم، يمكنك أيضًا ببساطة استخدام رابط رمزي (symbolic link) – ضع الملف في، على سبيل المثال، /sdcard/modules، ثم أنشئ رابطًا باستخدام المسار المطلق. لذا إذا فعلنا ذلك مع 88x2bu.ko، سنشغّل ln -s /storage/emulated/0/modules/88x2bu.ko /vendor/lib/modules/88x2bu.ko.

قم بدفعة أخيرة لمستودعك، وإذا أردت، احفظ .config الذي استخدمته كملف defconfig جديد لـ nethunter. (هذا يساعد حقًا الأشخاص الذين يبنون من المصدر).
هل تعمل؟ إنها تُومض بنجاح، بالتأكيد، لكن هل تعمل حقًا؟
حسنًا، الوقت متأخر جدًا هنا لذا لن أختبر كل ميزة على الإطلاق الآن، لكن دعنا ننتقل إلى الميزة الحاسمة: وضع المراقبة (monitor mode)/حقن الحزم (packet injection) على التعريفات التي أضفتها إلى النواة. لنبدأ مع rtl88x2bu:

ليس سيئًا أبدًا، بالنسبة لتعريف Realtek.
والآن الحدث الرئيسي: mt76x2u:

هذا جهاز اختبار اختراق حقيقي!
الخطوة الأخيرة هي رفع ملفات .zip و.tar.gz إلى GitHub كإصدار (release). ثم انشر عنها على xdaforums أو تيليجرام أو تويتر أو أي مكان تظن أن مستخدمي نفس الجهاز/الـ ROM سيجدونها ويستفيدون منها.
وعندما يرد عليك بعض الأغبياء الجاحدين بحقك بعبارة «NOW U MAKE KARNEL FOR DEVICE BUTTPHONE 34AC PRO EDITION?!!؟»، أعطهم رابط هذا الدليل وقل لهم أن يحسّنوا أنفسهم (git gud).
تصبحون على خير، جميعًا.
--Akabul0us