
إطار ربط وظائف نواة iOS للأجهزة المتوافقة مع checkra1n'able

مخرجات من سجل النواة بعد تجميع وتشغيل example/open1_hook.c
xnuspy هي وحدة pongoOS تقوم بتثبيت استدعاء نظام جديد، xnuspy_ctl، والذي يسمح لك بربط دوال النواة من مساحة المستخدم. وهي تدعم iOS 13.x و iOS 14.x و iOS 15.x على checkra1n 0.12.2 وما فوق. أجهزة 4K غير مدعومة.
هذه الوحدة تعطل تمامًا KTRR/KPP وتجعل من الممكن إنشاء ذاكرة RWX داخل EL1. لا تستخدم هذا على جهازك الأساسي.
يتطلب libusb: brew install libusb
قم بتشغيل make في الدليل الجذري. سيبني المحمل والوحدة.
أضف هذه قبل make.
XNUSPY_DEBUG=1
kprintf).XNUSPY_SERIAL=1
IOLog.XNUSPY_LEAKED_PAGE_LIMIT=n
64. يمكن العثور على مزيد من المعلومات تحت تصحيح أخطاء Kernel Panics.XNUSPY_TRAMP_PAGES=n
XNUSPY_DEBUG و XNUSPY_SERIAL لا يعتمدان على بعضهما البعض.
بعد أن قمت ببناء كل شيء، اجعل checkra1n يقوم بتشغيل جهازك إلى قشرة pongo: /Applications/checkra1n.app/Contents/MacOS/checkra1n -p
في نفس الدليل الذي بنيت فيه المحمل والوحدة، قم بتنفيذ loader/loader module/xnuspy. بعد القيام بذلك، سيقوم xnuspy بعمله وفي بضع ثوانٍ سيتم تشغيل جهازك. سينتظر loader بضع ثوانٍ إضافية بعد إصدار xnuspy-getkernelv في حال احتاج SEPROM إلى الاستغلال.
أحيانًا يتوقف بعض من هواتفي عند "Booting" بعد تشغيل KPF الخاص بـ checkra1n. لم أتمكن بعد من معرفة سبب ذلك، ولكن إذا حدث، حاول مرة أخرى. أيضًا، إذا توقف الجهاز بعد bootx، حاول مرة أخرى. أخيرًا، تعليم الكود المترجم لـ xnuspy_ctl كقابل للتنفيذ على iPhone X الخاص بي الذي يعمل بنظام iOS 13.3.1 هو أمر غير مستقر بعض الشيء، لكنه ينجح بنسبة 100% على هواتفي الأخرى. إذا حدث هلع (panic) مع خطأ إجهاض جلب التعليمات من النواة عند تنفيذ برنامج الربط الخاص بك، حاول مرة أخرى.
سيقوم xnuspy بتصحيح استدعاء نظام enosys للإشارة إلى xnuspy_ctl_tramp. هذا هو trampoline صغير يقوم بتعليم الكود المترجم لـ xnuspy_ctl كقابل للتنفيذ والتفرع إليه. يمكنك العثور على تنفيذ xnuspy_ctl في module/el1/xnuspy_ctl/xnuspy_ctl.c وأمثلة في دليل example.
داخل include/xnuspy/ يوجد xnuspy_ctl.h، ملف رأس يعرف ثوابت لـ xnuspy_ctl. من المفترض أن يتم تضمينه في جميع البرامج التي تقوم بربط دوال النواة.
يمكنك استخدام sysctlbyname لمعرفة أي استدعاء نظام تم تصحيحه:```
size_t oldlen = sizeof(long);
long SYS_xnuspy_ctl = 0;
sysctlbyname("kern.xnuspy_ctl_callnum", &SYS_xnuspy_ctl, &oldlen, NULL, 0);
هذه الاستدعاءات النظامية تأخذ أربع وسائط: `flavor`، `arg1`، `arg2`، و `arg3`.
يمكن أن يكون النكهة إما `XNUSPY_CHECK_IF_PATCHED`، `XNUSPY_INSTALL_HOOK`،
`XNUSPY_REGISTER_DEATH_CALLBACK`، `XNUSPY_CALL_HOOKME`، `XNUSPY_CACHE_READ`،
`XNUSPY_KREAD`، `XNUSPY_KWRITE`، أو `XNUSPY_GET_CURRENT_THREAD`.
يعتمد معنى الوسائط الثلاثة التالية على النكهة.
## `XNUSPY_CHECK_IF_PATCHED`
هذا موجود لتتمكن من التحقق من وجود `xnuspy_ctl`. استدعاؤه بهذه النكهة
سيؤدي إلى إرجاع `999`. يتم تجاهل قيم الوسائط الأخرى.
## `XNUSPY_INSTALL_HOOK`
صممت هذه النكهة لتتوافق مع واجهة برمجة تطبيقات [`MSHookFunction`](http://www.cydiasubstrate.com/api/c/MSHookFunction/).
`arg1` هو عنوان *غير مزاح (UNSLID)* لوظيفة النواة التي ترغب في ربطها. إذا
قدمت عنوانًا مزاحًا، فمن المرجح أن يحدث ذعر (panic). `arg2` هو مؤشر إلى
وظيفة الاستبدال المتوافقة مع ABI الخاصة بك. `arg3` هو مؤشر لـ `xnuspy_ctl` لـ
`copyout` عنوان النقلة (trampoline) الذي يمثل وظيفة النواة الأصلية.
يمكن أن يكون `NULL` إذا كنت لا تنوي استدعاء الوظيفة الأصلية.
## `XNUSPY_REGISTER_DEATH_CALLBACK`
تسمح لك هذه النكهة بتسجيل "استدعاء موت" اختياري (death callback)، وهي وظيفة سيقوم
xnuspy باستدعائها عند خروج برنامج الربط الخاص بك. يمنحك فرصة لتنظيف أي شيء
أنشأته من ربطات النواة الخاصة بك. إذا قمت بإنشاء أي خيوط نواة، فستطلب
منها الإنهاء في هذه الوظيفة.
لا يتم استدعاء الاستدعاء الخاص بك بشكل غير متزامن، لذا إذا قمت بحظر (block)، فأنت تمنع
خيط جمع القمامة (garbage collection thread) الخاص بـ xnuspy من التنفيذ.
`arg1` هو مؤشر إلى وظيفة الاستدعاء الخاصة بك. يتم تجاهل قيم الوسائط الأخرى.
## `XNUSPY_CALL_HOOKME`
`hookme` هو كعب صغير بلغة التجميع (assembly stub) يقوم xnuspy بتصديره من خلال ذاكرة التخزين المؤقت (cache) لـ xnuspy
لربطه. استدعاء `xnuspy_ctl` بهذه النكهة سيؤدي إلى استدعاء `hookme`،
مما يوفر لك طريقة لتحقيق تنفيذ كود النواة بسهولة دون الحاجة إلى ربط وظيفة نواة فعلية.
`arg1` هو وسيطة سيتم تمريرها إلى `hookme` عند استدعائها.
يمكن أن يكون `NULL`.
## `XNUSPY_CACHE_READ`
تمنحك هذه النكهة طريقة للقراءة من ذاكرة التخزين المؤقت لـ xnuspy. تحتوي على العديد من الأشياء
المفيدة مثل `kprintf`، `current_proc`، `kernel_thread_start`، بعض وظائف libc،
وإزاحة (slide) النواة حتى لا تضطر إلى العثور عليها بنفسك. للحصول على قائمة كاملة
بمعرّفات (IDs) ذاكرة التخزين المؤقت، اطّلع على `example/xnuspy_ctl.h`.
`arg1` هو أحد معرّفات ذاكرة التخزين المؤقت المحددة في `xnuspy_ctl.h` و `arg2` هو
مؤشر لـ `xnuspy_ctl` لـ `copyout` العنوان أو القيمة لما طلبته.
يتم تجاهل قيم الوسائط الأخرى.
## `XNUSPY_KREAD`
تمنحك هذه النكهة طريقة سهلة لقراءة ذاكرة النواة من مساحة المستخدم (userspace) دون
tfp0.
`arg1` هو عنوان افتراضي للنواة، `arg2` هو عنوان مخزن مؤقت (buffer) في مساحة المستخدم،
و `arg3` هو حجم ذلك المخزن المؤقت. سيتم كتابة `arg3` بايت
من `arg1` إلى `arg2`.
## `XNUSPY_KWRITE`
تمنحك هذه النكهة طريقة سهلة للكتابة إلى ذاكرة النواة من مساحة المستخدم دون
tfp0.
`arg1` هو عنوان افتراضي للنواة، `arg2` هو عنوان مخزن مؤقت في مساحة المستخدم،
و `arg3` هو حجم ذلك المخزن المؤقت. سيتم كتابة `arg3` بايت
من `arg2` إلى `arg1`.
## `XNUSPY_GET_CURRENT_THREAD`
توفر هذه النكهة لمساحة المستخدم عنوان النواة للخيط المتصل (calling thread).
`arg1` هو مؤشر لـ `xnuspy_ctl` لـ `copyout` القيمة المُرجَعة من
`current_thread`. يتم تجاهل قيم الوسائط الأخرى.
### الأخطاء (Errors)
بالنسبة لجميع النكهات باستثناء `XNUSPY_CHECK_IF_PATCHED`، يتم إرجاع `0` عند النجاح.
عند حدوث خطأ، يتم إرجاع `-1` ويتم تعيين `errno`. لا يعيد `XNUSPY_CHECK_IF_PATCHED`
أي أخطاء. يتم استخدام `mach_to_bsd_errno` في XNU لتحويل
`kern_return_t` إلى `errno المناسب`.
#### الأخطاء المتعلقة بـ `XNUSPY_INSTALL_HOOK`
يتم تعيين `errno` إلى...
- `EEXIST` إذا:
- يوجد ربط بالفعل لوظيفة النواة غير المزاحة المشار إليها بـ `arg1`.
- `ENOMEM` إذا:
- أعاد `unified_kalloc` القيمة `NULL`.
- `ENOSPC` إذا:
- لا توجد بنيات `xnuspy_tramp` حرة، وهي بنية بيانات داخلية
لـ xnuspy. لا ينبغي أن يحدث هذا إلا إذا كنت تقوم بربط مئات وظائف النواة
*في نفس الوقت*. إذا كنت بحاجة إلى المزيد من ربطات الوظائف، اطّلع على [الحدود (Limits)](#limits).
- `ENOTSUP` إذا:
- المتصل ليس من ملف تنفيذي (Mach-O) أو مكتبة ديناميكية.
- `ENOENT` إذا:
- لم يتمكن `mh_for_addr` من تحديد رأس (header) Mach-O المقابل لـ
`arg2` داخل مساحة عنوان المتصل.
- `EFAULT` إذا:
- رأس Mach-O المحدد ليس في الواقع رأس Mach-O. هذا على الأرجح
لن يحدث أبدًا.
- `EIO` إذا:
- لم يُرجع `mach_make_memory_entry_64` إدخال ذاكرة لكامل
قطاعي `__TEXT` و `__DATA` لرأس Mach-O المحدد.
يعتمد `errno` أيضًا على القيمة المُرجَعة من `vm_map_wire_external`،
`mach_vm_map_external`، `mach_make_memory_entry_64`، `copyin`، `copyout`، و
إذا كان ذلك مناسبًا، وظيفة التهيئة لمرة واحدة.
إذا أرجع هذه النكهة خطأً، فلن يتم ربط وظيفة النواة المستهدفة.
إذا مررت مؤشرًا غير `NULL` لـ `arg3`، فقد يكون أو لا يكون قد تم
تهيئته. من غير الآمن استخدامه إذا كان قد تم تهيئته.
#### الأخطاء المتعلقة بـ `XNUSPY_REGISTER_DEATH_CALLBACK`
يتم تعيين `errno` إلى...
- `ENOENT` إذا:
- عملية المتصل لم تقم بربط أي وظائف نواة.
إذا أرجع هذه النكهة خطأً، فلن يتم تسجيل استدعاء الموت الخاص بك.