
# GhostLock (CVE-2026-43499) استغلال نواة لأجهزة أندرويد ذات مُحمّل إقلاع مقفل
استغلال نواة لأجهزة Android ذات أداة تحميل الإقلاع المقفلة. يحقق صلاحيات الجذر المؤقتة + تثبيت KernelSU دون فتح قفل أداة تحميل الإقلاع أو تعديل صورة الإقلاع. اكتشاف تلقائي لوقت التشغيل لإصدار النواة مع جدول إزاحات متعدد الأجهزة.
CVE-2026-43499 — Futex PI (ميراث الأولوية) Use-After-Free
تؤثر على نواة Linux من 5.7 إلى 7.1. تم إصلاحها في الإصدارات المستقرة 6.1.175 و6.6.140 و6.12.86. معظم أجهزة Android لا تزال غير مصححة حتى سبتمبر 2026.
استدعاء النظام pselect6 ينسخ بيانات fd_set على مكدس النواة. عند دمجه مع آلية انتظار futex PI، يمكن استعادة إطار مكدس محرر كبنية rt_mutex_waiter. ثم تقوم إعادة توازن شجرة rb-red أثناء اجتياز سلسلة PI بكتابة قيم محكومة إلى عناوين نواة عشوائية.
يتطلب تراكب مكدس pselect أن يقع rt_mutex_waiter المحرر داخل منطقة stack_fds التي يتحكم بها المستخدم (الكلمات 0–14). مكان وقوعه يحدده ملفا تعريف PGO/LTO للمترجم، وليس إصدار النواة. انظر تخطيط المكدس.
ملاحظة حول جدوى 6.1: نوى OPLUS 6.1 غير ممكنة باستمرار بسبب دمج PGO لـ
do_futex. ومع ذلك، تحتفظ بعض نوى 6.1 غير OPLUS (vivo) بسلسلة الاستدعاء القياسية وهي ممكنة (vivo T4، X Fold3 Pro). يجب التحقق من الجدوى لكل جهاز على حدة.
مساران للجذر، يتم اختيارهما تلقائيًا بناءً على قدرات الجهاز:
يتطلب off_ashmem_misc_fops != 0 (C ashmem مع miscdevice ثابت في BSS).
كتابة PI (mode=4) ← إعادة توجيه miscdevice fops إلى fops مزيفة
← قراءة/كتابة configfs ← pipe physrw (قراءة/كتابة نواة دقيقة ببايت واحد)
← SELinux enforcing = 0 (بايت واحد، بدون إتلاف policycap)
← UMH: حقن work_struct في system_unbound_wq
← سكربت الجذر ← ksud late-load ← تثبيت KSU
متاح على: OnePlus 13، OPPO Pad 4 Pro، أجهزة 5.10/6.1 C ashmem. غير متاح على Rust ashmem (6.12 GKI) — miscdevice مخصص على الكومة.
كتابة 1 (mode=1) ← SELinux enforcing = 0 (كتابة 8 بايت، تتلف البايتات المجاورة)
كتابة 2 (mode=2) ← task->cred = init_cred (uid=0، جميع الصلاحيات)
صدفة الجذر ← ksud late-load ← KSU ← إصلاح سياسة SELinux
بعد W1+W2، يقوم الاستغلال بتصحيح حقل config في ملف سياسة SELinux الثنائي (|= 0xC0000000 لـ ANDROID_NETLINK_ROUTE + GETNEIGH) ويعيد تحميله عبر /sys/fs/selinux/load لاستعادة اتصال الشبكة.
التطبيق (seccomp) ← كتابة 1 ← mini-adb TCP ← adb shell: استغلال كامل ← جذر
يتم توفير مشغل وقت الإقلاع بواسطة تطبيق GhostLock Anchor المنفصل.
مع NFDS=320، يخصص core_sys_select مخزن stack_fds بحجم 256 بايت على مكدس النواة:
stack_fds: 0 5 10 14 | 15 20 25 29
├─in─┤─out─┤─ex──┤ ├res_in┤res_out┤res_ex┤
◄── يتحكم به المستخدم ──►│◄── تصفره النواة ──►
يضع الاستغلال حقول waiter المزيفة (task، lock) في خرائط بتات إدخال fd_set. لـ 6.12 nested waiter (14 كلمة): أقصى waiter word ممكن = 3. لـ 5.10/6.1 compact waiter (10 كلمات): أقصى waiter word ممكن = 7.
يعتمد موضع waiter على عمق سلسلة الاستدعاء:
تستخدم جميع عمليات كتابة النواة اسمًا مستعارًا للخريطة الخطية. يختار أداة تحميل الإقلاع kernel_phys_load، والذي يختلف حسب SoC:
| SoC | kernel_phys_load |
|---|---|
| SM8845 (Ace 6T، 15T) | 0xa8000000 |
| SM8750 (OnePlus 13، OPPO Pad 4 Pro) | 0xa8000000 |
القيمة الخاطئة تفشل بصمت. اقرأها على جهاز مجذر:
su -c 'grep -i "Kernel code" /proc/iomem' # c7810000-... ← 0xc7800000
تجاوز وقت التشغيل: KPHYS=0xc7800000 /data/local/tmp/a/e
/data/local/tmp/a/e # الافتراضي (shift=0)
PSELECT_SHIFT=-2 /data/local/tmp/a/e # OnePlus 13 (6.6)
تستخدم نوى 5.10 0xffffffc008000000 (VA_BITS=39، مختلف عن الافتراضي 6.x 0xffffffc080000000). يتم التعامل مع هذا تلقائيًا عبر حقل kimage_text_base في إدخال إزاحة الجهاز.
make NDK_ROOT=/path/to/android-ndk
أو مباشرة:
NDK=/path/to/android-ndk
"$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android35-clang" \
-O2 -Wall -Isrc/core -Isrc/devices -DTARGET_CONFIG_H=\"target.h\" \
src/core/main.c src/core/util.c src/core/slide.c \
src/core/fops.c src/core/pipe_physrw.c src/core/root.c \
src/core/miniadb.c src/core/umh_root.c \
-o ./ghostlock -fPIE -pie -pthread
يوفر GhostLock صلاحيات الجذر المؤقتة. يتطلب تثبيت KernelSU ksud الذي يضم kernelsu.ko لكل إصدار KMI.
| الطريقة | الخطوات |
|---|---|
| APK ReSukiSU (موصى به) | ثبّت ReSukiSU أو هذا . يضم . |
adb shell mkdir -p /data/local/tmp/a
adb push ./ghostlock /data/local/tmp/a/e
adb shell chmod 755 /data/local/tmp/a/e
adb shell /data/local/tmp/a/e
شغّله بعد اكتمال الإقلاع وجاهزية ADB.
يلزم فقط boot.img — بدون جذر، بدون الحاجة للوصول إلى الجهاز.
انظر دليل أدوات kallsyms لسير العمل الكامل، أو:
python tools/extract_target.py --kallsyms kallsyms.txt
python tools/extract_btf.py kernel
تحقق مما إذا كان do_futex مدمجًا بواسطة PGO بالبحث في ثنائي النواة عن جميع تعليمات الفرع التي تستهدف futex_wait_requeue_pi. إذا كان __arm64_sys_futex يستدعيها مباشرة (متجاوزًا do_futex)، فمن المرجح أن الجهاز غير ممكن.
أضف src/devices/<name>/offsets.h مع الإزاحات المستخرجة وأدرجه في src/devices/offsets.h. استخدم ماكرو إزاحات البنية المناسب:
لأجهزة 5.10/6.1 compact waiter، اضبط أيضًا .kimage_text_base=0xffffffc008000000ULL.
لأغراض البحث الأمني المصرح به والتعليم فقط.
| الجهاز | SoC | النواة | فرع GKI | SHIFT |
|---|
| OnePlus Ace 6T (PLR110) | SM8845 | 6.12.38 | android16-5 | 0 |
| OnePlus 15 (CPH2745/2747/2749) | SM8850 | 6.12.23 | android16-5 | 0 |
| Xiaomi 17 (pudding) | SM8850 | 6.12.23 / 6.12.69 | android16-5 / android16-6 | 0 |
| OnePlus 13 (IN2060) | SM8750 | 6.6.89 | android15-8 | -2 |
| OPPO Pad 4 Pro | SM8750 | 6.6.89 | android15-8 | -2 |
| الجهاز | SoC | النواة | ملاحظات |
|---|
| OnePlus 15T (PLZ110) | SM8845 | 6.12.38 | نفس نواة Ace 6T |
| OPPO Reno10 Pro+ (CPH2521) | SM8475 | 5.10.236 | 5.10 compact waiter، waiter word=0 |
| Vivo X Fold3 Pro (PD2337) | SM8650 | 6.1.124 | 6.1 compact waiter، waiter word=3 |
| Vivo T4 | SM8650 | 6.1.145 | 6.1 compact waiter، waiter word=3 |
| الجهاز | SoC | النواة | السبب الجذري |
|---|
| OPPO Find X9 Ultra | SM8750 | 6.12.58 | PGO يزيل do_futex ← waiter word=14 |
| OnePlus 12 | SM8650 | 6.1.141 | PGO يدمج do_futex ← waiter word=13/19 |
| OnePlus 13R / Ace 5 | SM8650 | 6.1.x | OPLUS 6.1: waiter word=13 |
| realme RMX5070 | SM6650 | 6.1.141 | OPLUS 6.1: waiter word=13 |
| OPPO Pad 5 (OPD2502) | MT6878 | 6.1.134 | OPLUS 6.1: waiter word=13 |
| Motorola Edge 60 Fusion | MT6878 | 6.1.145 | غير OPLUS 6.1: نفس النتيجة |
| iQOO Neo 10 CN | SM8650 | 6.1.84 | إطار do_futex 0xD0 ← waiter word=-11 |
| OPPO PKW110 | — | 5.15.180 | إطار do_futex 0x140 ← waiter word=-29 |
| iQOO Z9 5G | — | 5.15.178 | إطار do_futex كبير جدًا |
| CPH2763 (OPPO) | — | 6.1.115 | OPLUS 6.1: PGO مدمج، waiter word=24 |
| النمط | سلسلة الاستدعاء | ممكن |
|---|
| android16-5 (6.12) | sys_futex ← do_futex ← fwrpi | ✅ waiter word=2 |
| android15-8 (6.6) | sys_futex ← do_futex ← fwrpi | ✅ waiter word=2 (SHIFT=-2) |
| vivo 6.1 | sys_futex ← do_futex ← fwrpi | ✅ waiter word=3 |
| OPLUS 6.1 | sys_futex ← fwrpi (PGO مدمج) | ❌ waiter word=13+ |
| android16-6 (X9 Ultra) | sys_futex ← fwrpi (PGO مدمج) | ❌ waiter word=14 |
| 5.10 OPLUS | sys_futex ← do_futex ← fwrpi | ✅ waiter word=0 |
| SM8650 (vivo T4، X Fold3 Pro) |
0xa8000000 |
| SM8850 (OnePlus 15، Xiaomi 17) | 0xc7800000 |
libksud.so| إصدار CI | حمّله من ReSukiSU CI |
| النواة | تخطيط Waiter | الماكرو |
|---|
| 6.12.x | Nested (14 كلمة) | STRUCT_OFFSETS_6_12 |
| 6.6.x | Nested (14 كلمة) | STRUCT_OFFSETS_6_6 |
| 6.1.x (vivo) | Compact (10 كلمات) | STRUCT_OFFSETS_6_1 |
| 5.10.x | Compact (10 كلمات) | STRUCT_OFFSETS_5_10 |
| الملف | الوصف |
|---|
src/core/main.c | نقطة دخول الاستغلال، W1/W2، مسار UMH، التمهيد، سكربت الجذر، إصلاح سياسة SELinux |
src/core/fops.c | مسار pselect، كتابة PI، مرحلة CFI، دعم compact waiter |
src/core/util.c | رش الكومة، KernelSnitch، تصريف slab، إعداد الحمولة |
src/core/pipe_physrw.c | قراءة/كتابة الذاكرة الفعلية عبر مخزن pipe |
src/core/umh_root.c | جذر UMH عبر حقن workqueue |
src/core/miniadb.c | عميل Mini ADB (TCP + مصادقة RSA) |
src/core/target.h | تخطيط الذاكرة، افتراضيات حقول البنية (6.12) |
src/core/runtime_struct_offsets.h | تجاوز حقول البنية لكل جهاز |
src/devices/offsets.h | جداول إزاحات الأجهزة + ماكرو STRUCT_OFFSETS_* |
tools/extract_target.py | استخراج الإزاحات من kallsyms |
tools/extract_btf.py | استخراج إزاحات البنية من BTF |
tools/kallsyms/ | سير عمل استرداد kallsyms الشامل |