Skip to content
KitploitKITPLOIT
उपकरणब्लॉग
जमा करें
उपकरणब्लॉग
जमा करें

हैकिंग, पेनटेस्ट और साइबर सुरक्षा उपकरण आपके सुरक्षा शस्त्रागार के लिए!

Kitploit हैकिंग, साइबर सुरक्षा और पेंटेस्टिंग टूल्स की एक निर्देशिका है। कमजोरियों को खोजने, सिस्टम का विश्लेषण करने, परीक्षण को स्वचालित करने और अपनी सुरक्षा को मजबूत करने के लिए नवीनतम प्रोजेक्ट अपडेट खोजें।

··फ़ीड·संपर्क·गोपनीयता·© 2026 Kitploit

टूल निर्देशिका

श्रेणियाँ

सभी श्रेणियाँ देखें
Loading categories
xnuspy — आईओएस कर्नेल फंक्शन हुकिंग फ्रेमवर्क checkra1n'able उपकरणों के लिए | Kitploit
उपकरण/GitHubGitHub/jsherman212/xnuspy
आईओएस सुरक्षाशोषणडीबगर्सबाइनरी विश्लेषण
GitHubjsherman212/xnuspy

xnuspy

आईओएस कर्नेल फंक्शन हुकिंग फ्रेमवर्क checkra1n'able उपकरणों के लिए

रिपॉजिटरी देखें
595112544 साल पहलेKitploit द्वारा समीक्षित

सबसे लोकप्रिय

सभी देखें →

हमारे समुदाय द्वारा सबसे अधिक उपयोग किए जाने वाले उपकरण खोजें।

सभी उपकरण खोजें

हमारे उपकरणों का संग्रह ब्राउज़ करें

सभी उपकरण देखें →
साझा करें

xnuspy

alt text

कर्नेल लॉग से आउटपुट example/open1_hook.c को संकलित और चलाने के बाद

xnuspy एक pongoOS मॉड्यूल है जो एक नया सिस्टम कॉल xnuspy_ctl स्थापित करता है, जो आपको यूज़रस्पेस से कर्नेल फ़ंक्शन को हुक करने की अनुमति देता है। यह iOS 13.x, iOS 14.x, और iOS 15.x को checkra1n 0.12.2 और उससे ऊपर पर सपोर्ट करता है। 4K डिवाइस समर्थित नहीं हैं।

यह मॉड्यूल KTRR/KPP को पूरी तरह से बेअसर कर देता है और EL1 के अंदर RWX मेमोरी बनाना संभव बनाता है। इसे अपने प्राथमिक डिवाइस पर उपयोग न करें।

आवश्यकता है libusb: brew install libusb

बिल्डिंग

शीर्ष स्तर की निर्देशिका में make चलाएँ। यह लोडर और मॉड्यूल बनाएगा।

बिल्ड विकल्प

इन्हें make से पहले जोड़ें।

  • XNUSPY_DEBUG=1
    • xnuspy से डीबग आउटपुट को कर्नेल लॉग (kprintf) पर भेजें।
  • XNUSPY_SERIAL=1
    • xnuspy से डीबग आउटपुट को IOLog पर भेजें।
  • XNUSPY_LEAKED_PAGE_LIMIT=n
    • उन पृष्ठों की संख्या निर्धारित करें जिन्हें xnuspy अपने कचरा संग्रहण थ्रेड द्वारा डीलोकेट करने से पहले लीक करने की अनुमति है। डिफ़ॉल्ट 64 है। अधिक जानकारी डीबगिंग कर्नेल पैनिक्स के अंतर्गत पाई जा सकती है।
  • XNUSPY_TRAMP_PAGES=n
    • उन पृष्ठों की संख्या निर्धारित करें जिन्हें xnuspy अपने ट्रम्पोलिन संरचनाओं के लिए आरक्षित करेगा। डिफ़ॉल्ट 1 है। अधिक जानकारी सीमाएँ के अंतर्गत पाई जा सकती है।

XNUSPY_DEBUG और XNUSPY_SERIAL एक-दूसरे पर निर्भर नहीं हैं।

उपयोग

सब कुछ बनाने के बाद, checkra1n को अपने डिवाइस को pongo शेल में बूट करने के लिए कहें: /Applications/checkra1n.app/Contents/MacOS/checkra1n -p

उसी निर्देशिका में जहाँ आपने लोडर और मॉड्यूल बनाए हैं, loader/loader module/xnuspy चलाएँ। ऐसा करने के बाद, xnuspy अपना काम करेगा और कुछ सेकंड में आपका डिवाइस बूट हो जाएगा। loader SEPROM के शोषण की आवश्यकता होने पर xnuspy-getkernelv जारी करने के बाद कुछ और सेकंड प्रतीक्षा करेगा।

ज्ञात समस्याएँ

कभी-कभी मेरे कुछ फ़ोन checkra1n के KPF चलने के बाद "Booting" पर अटक जाते हैं। मुझे अभी तक पता नहीं चला है कि इसका कारण क्या है, लेकिन यदि ऐसा होता है, तो पुनः प्रयास करें। साथ ही, यदि डिवाइस bootx के बाद हैंग हो जाता है, तो पुनः प्रयास करें। अंत में, मेरे iPhone X पर iOS 13.3.1 चलाने पर संकलित xnuspy_ctl कोड को निष्पादन योग्य के रूप में चिह्नित करना थोड़ा अनियमित है, लेकिन मेरे अन्य फ़ोनों पर 100% सफल होता है। यदि आप अपना हुक प्रोग्राम निष्पादित करते समय कर्नेल निर्देश लाने में विफलता के साथ पैनिक करते हैं, तो पुनः प्रयास करें।

xnuspy_ctl

xnuspy एक enosys सिस्टम कॉल को पैच करके xnuspy_ctl_tramp की ओर इंगित करेगा। यह एक छोटा ट्राम्पोलिन है जो संकलित 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);

root@kitploit:~
यह सिस्टम कॉल चार तर्क लेता है: `flavor`, `arg1`, `arg2`, और `arg3`।
flavor या तो `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` हो सकता है।
अगले तीन तर्कों का अर्थ flavor पर निर्भर करता है।

## `XNUSPY_CHECK_IF_PATCHED`
यह इसलिए मौजूद है ताकि आप जाँच सकें कि `xnuspy_ctl` मौजूद है या नहीं। इस flavor के साथ इसे कॉल करने पर यह `999` लौटाएगा। अन्य तर्कों के मानों को अनदेखा किया जाता है।

## `XNUSPY_INSTALL_HOOK`
मैंने इस flavor को [`MSHookFunction`](http://www.cydiasubstrate.com/api/c/MSHookFunction/) के API से मेल खाने के लिए डिज़ाइन किया है।
`arg1` उस कर्नेल फ़ंक्शन का *अनस्लाइड* पता है जिसे आप हुक करना चाहते हैं। यदि आप स्लाइड किया हुआ पता देते हैं, तो संभवतः पैनिक होगा। `arg2` आपके ABI-संगत प्रतिस्थापन फ़ंक्शन का सूचक है। `arg3` एक सूचक है जिसमें `xnuspy_ctl` मूल कर्नेल फ़ंक्शन का प्रतिनिधित्व करने वाले ट्रैम्पोलिन के पते को `copyout` करेगा। यदि आप मूल को कॉल करने का इरादा नहीं रखते हैं तो यह `NULL` हो सकता है।

## `XNUSPY_REGISTER_DEATH_CALLBACK`
यह flavor आपको एक वैकल्पिक "डेथ कॉलबैक" पंजीकृत करने की अनुमति देता है, एक फ़ंक्शन जिसे xnuspy आपके हुक प्रोग्राम के बाहर निकलने पर कॉल करेगा। यह आपको अपने कर्नेल हुक से बनाई गई किसी भी चीज़ को साफ करने का मौका देता है। यदि आपने कोई कर्नेल थ्रेड बनाया है, तो आप इस फ़ंक्शन में उन्हें समाप्त करने का निर्देश देंगे।

आपका कॉलबैक अतुल्यकालिक रूप से लागू नहीं होता है, इसलिए यदि आप ब्लॉक करते हैं, तो आप xnuspy के कचरा संग्रह थ्रेड को निष्पादित होने से रोक रहे हैं।

`arg1` आपके कॉलबैक फ़ंक्शन का सूचक है। अन्य तर्कों के मानों को अनदेखा किया जाता है।

## `XNUSPY_CALL_HOOKME`
`hookme` एक छोटा असेंबली स्टब है जिसे xnuspy xnuspy कैश के माध्यम से आपके लिए हुक करने के लिए निर्यात करता है। इस flavor के साथ `xnuspy_ctl` को लागू करने से `hookme` कॉल हो जाएगा, जो आपको वास्तविक कर्नेल फ़ंक्शन को हुक किए बिना आसानी से कर्नेल कोड निष्पादन प्राप्त करने का एक तरीका प्रदान करता है।

`arg1` एक तर्क है जो `hookme` के लागू होने पर उसे दिया जाएगा। यह `NULL` हो सकता है।

## `XNUSPY_CACHE_READ`
यह flavor आपको xnuspy कैश से पढ़ने का एक तरीका देता है। इसमें कई उपयोगी चीज़ें हैं जैसे `kprintf`, `current_proc`, `kernel_thread_start`, कुछ libc फ़ंक्शन, और कर्नेल स्लाइड, ताकि आपको उन्हें स्वयं खोजने की आवश्यकता न पड़े। कैश आईडी की पूरी सूची के लिए `example/xnuspy_ctl.h` देखें।

`arg1` `xnuspy_ctl.h` में परिभाषित कैश आईडी में से एक है और `arg2` एक सूचक है जिसमें `xnuspy_ctl` आपके द्वारा अनुरोधित पते या मान को `copyout` करेगा। अन्य तर्कों के मानों को अनदेखा किया जाता है।

## `XNUSPY_KREAD`
यह flavor आपको tfp0 के बिना यूज़रस्पेस से कर्नेल मेमोरी पढ़ने का एक आसान तरीका देता है।

`arg1` एक कर्नेल वर्चुअल पता है, `arg2` एक यूज़रस्पेस बफ़र का पता है, और `arg3` उस यूज़रस्पेस बफ़र का आकार है। `arg3` बाइट `arg1` से `arg2` पर लिखे जाएंगे।

## `XNUSPY_KWRITE`
यह flavor आपको tfp0 के बिना यूज़रस्पेस से कर्नेल मेमोरी में लिखने का एक आसान तरीका देता है।

`arg1` एक कर्नेल वर्चुअल पता है, `arg2` एक यूज़रस्पेस बफ़र का पता है, और `arg3` उस यूज़रस्पेस बफ़र का आकार है। `arg3` बाइट `arg2` से `arg1` पर लिखे जाएंगे।

## `XNUSPY_GET_CURRENT_THREAD`
यह flavor यूज़रस्पेस को कॉल करने वाले थ्रेड का कर्नेल पता प्रदान करता है।

`arg1` एक सूचक है जिसमें `xnuspy_ctl` `current_thread` के रिटर्न मान को `copyout` करेगा। अन्य तर्कों के मानों को अनदेखा किया जाता है।

### त्रुटियाँ
`XNUSPY_CHECK_IF_PATCHED` को छोड़कर सभी flavors के लिए, सफलता पर `0` लौटाया जाता है।
त्रुटि पर, `-1` लौटाया जाता है और `errno` सेट किया जाता है। `XNUSPY_CHECK_IF_PATCHED` कोई त्रुटि नहीं लौटाता है। `kern_return_t` को उपयुक्त `errno` में बदलने के लिए XNU के `mach_to_bsd_errno` का उपयोग किया जाता है।

#### `XNUSPY_INSTALL_HOOK` से संबंधित त्रुटियाँ
`errno` को इस पर सेट किया जाता है...
- `EEXIST` अगर:
  - `arg1` द्वारा निरूपित अनस्लाइड कर्नेल फ़ंक्शन के लिए पहले से ही एक हुक मौजूद है।
- `ENOMEM` अगर:
  - `unified_kalloc` ने `NULL` लौटाया।
- `ENOSPC` अगर:
  - कोई मुफ्त `xnuspy_tramp` स्ट्रक्ट नहीं है, जो xnuspy के अंदरूनी डेटा स्ट्रक्चर है। यह तब तक नहीं होना चाहिए जब तक आप एक साथ सैकड़ों कर्नेल फ़ंक्शन हुक नहीं कर रहे हों। यदि आपको अधिक फ़ंक्शन हुक की आवश्यकता है, तो [सीमाएँ](#limits) देखें।
- `ENOTSUP` अगर:
  - कॉल करने वाला Mach-O निष्पादन योग्य या डायनामिक लाइब्रेरी से नहीं है।
- `ENOENT` अगर:
  - `mh_for_addr` कॉल करने वाले के पता स्थान के अंदर `arg2` के अनुरूप Mach-O हेडर निर्धारित करने में असमर्थ था।
- `EFAULT` अगर:
  - निर्धारित Mach-O हेडर वास्तव में Mach-O हेडर नहीं है। यह शायद कभी नहीं होगा।
- `EIO` अगर:
  - `mach_make_memory_entry_64` ने निर्धारित Mach-O हेडर के `__TEXT` और `__DATA` सेगमेंट के पूरे हिस्से के लिए एक मेमोरी एंट्री नहीं लौटाई।

`errno` `vm_map_wire_external`, `mach_vm_map_external`, `mach_make_memory_entry_64`, `copyin`, `copyout`, और यदि लागू हो, तो एक-बार आरंभीकरण फ़ंक्शन के रिटर्न मान पर भी निर्भर करता है।

यदि यह flavor कोई त्रुटि लौटाता है, तो लक्ष्य कर्नेल फ़ंक्शन हुक नहीं किया गया था।
यदि आपने `arg3` के लिए एक गैर-`NULL` सूचक पास किया है, तो यह आरंभ हो भी सकता है और नहीं भी। यदि ऐसा हुआ तो इसका उपयोग करना असुरक्षित है।

#### `XNUSPY_REGISTER_DEATH_CALLBACK` से संबंधित त्रुटियाँ
`errno` को इस पर सेट किया जाता है...
- `ENOENT` अगर:
  - कॉल करने वाली प्रक्रिया ने कोई कर्नेल फ़ंक्शन हुक नहीं किया है।

यदि यह flavor कोई त्रुटि लौटाता है, तो आपका डेथ कॉलबैक पंजीकृत नहीं हुआ था।

#### `XNUSPY_CALL_HOOKME` से संबंधित त्रुटियाँ
`errno` को इस पर सेट किया जाता है...
- `ENOTSUP` अगर:
  - `hookme` `xnuspy_tramp` संरचनाओं वाली मेमोरी से बहुत दूर है। यह pongoOS के अंदर निर्धारित किया जाता है, और केवल तभी हो सकता है जब xnuspy को kernelcache के अंदर पहले से मौजूद अप्रयुक्त कोड पर वापस जाना पड़े। इस मामले में, `hookme` को कॉल करना लगभग निश्चित रूप से कर्नेल पैनिक का कारण बनेगा, और आपको हुक करने के लिए एक और कर्नेल फ़ंक्शन खोजना होगा।

यदि यह flavor कोई त्रुटि लौटाता है, तो `hookme` कॉल नहीं किया गया था।

#### `XNUSPY_CACHE_READ` से संबंधित त्रुटियाँ
`errno` को इस पर सेट किया जाता है...
- `EINVAL` अगर:
  - `arg1` द्वारा निरूपित स्थिरांक कैश में किसी चीज़ का प्रतिनिधित्व नहीं करता है।
  - `arg1` `IO_LOCK` था, लेकिन कर्नेल iOS 14.4.2 या उससे नीचे या iOS 15.x है।
  - `arg1` `IPC_OBJECT_LOCK` था, लेकिन कर्नेल iOS 15.x है।
  - `arg1` `IPC_PORT_RELEASE_SEND` था, लेकिन कर्नेल iOS 14.5 या उससे ऊपर है।
  - `arg1` `IPC_PORT_RELEASE_SEND_AND_UNLOCK` था, लेकिन कर्नेल iOS 14.4.2 या उससे नीचे है।
  - `arg1` `KALLOC_CANBLOCK` था, लेकिन कर्नेल iOS 14.x या उससे ऊपर है।
  - `arg1` `KALLOC_EXTERNAL` था, लेकिन कर्नेल iOS 13.x है।
  - `arg1` `KFREE_ADDR` था, लेकिन कर्नेल iOS 14.x या उससे ऊपर है।
  - `arg1` `KFREE_EXT` था, लेकिन कर्नेल iOS 13.x है।
  - `arg1` `PROC_REF` था, लेकिन कर्नेल iOS 14.8 या उससे नीचे है।
  - `arg1` `PROC_REF_LOCKED` था, लेकिन कर्नेल iOS 15.x है।
  - `arg1` `PROC_RELE` था, लेकिन कर्नेल iOS 14.8 या उससे नीचे है।
  - `arg1` `PROC_RELE_LOCKED` था, लेकिन कर्नेल iOS 15.x है।
  - `arg1` `VM_MAP_UNWIRE` था, लेकिन कर्नेल iOS 15.x है।
  - `arg1` `VM_MAP_UNWIRE_NESTED` था, लेकिन कर्नेल iOS 14.8 या उससे नीचे है।

`errno` `copyout` के रिटर्न मान और यदि लागू हो, तो एक-बार आरंभीकरण फ़ंक्शन के रिटर्न मान पर भी निर्भर करता है।

यदि यह flavor कोई त्रुटि लौटाता है, तो आपके द्वारा `arg2` के लिए पास किया गया सूचक आरंभ नहीं किया गया था।

#### `XNUSPY_KREAD` और `XNUSPY_KWRITE` से संबंधित त्रुटियाँ
`errno` को इस पर सेट किया जाता है...
- `EFAULT` अगर:
  - `arg1` या `arg2` के लिए पता अनुवाद विफल रहा। यदि आपने `XNUSPY_DEBUG=1` के साथ संकलित किया है, तो इसके बारे में एक संदेश कर्नेल लॉग में मुद्रित होता है।

यदि यह flavor कोई त्रुटि लौटाता है, तो कर्नेल मेमोरी पढ़ी/लिखी नहीं गई थी।

#### `XNUSPY_GET_CURRENT_THREAD` से संबंधित त्रुटियाँ
यदि `copyout` विफल होता है, तो `errno` को उसके रिटर्न मान पर सेट किया जाता है।

# महत्वपूर्ण जानकारी

### सामान्य नुकसान
प्रतिस्थापन फ़ंक्शन लिखते समय, यह भूलना आसान था कि मैं कर्नेल कोड लिख रहा था। हुक लिखते समय ध्यान रखने योग्य कुछ बातें यहाँ दी गई हैं:

- *आप अपने प्रोग्राम के `__TEXT` सेगमेंट के बाहर रहने वाला कोई भी यूज़रस्पेस कोड निष्पादित नहीं कर सकते*। यदि आप गलती से `printf` को `kprintf` के बजाय कॉल करते हैं, तो आप पैनिक करेंगे। यदि वह फ़ंक्शन `XNUSPY_CACHE_READ` के माध्यम से पहले से उपलब्ध नहीं है, तो आपको जिस भी libc फ़ंक्शन को कॉल करना है उसे पुनः लागू करना होगा। हालाँकि, आप अन्य कर्नेल फ़ंक्शनों के लिए फ़ंक्शन पॉइंटर बना सकते हैं और उन्हें कॉल कर सकते हैं।
- *यूज़रस्पेस कोड में आमतौर पर उपयोग किए जाने वाले कई मैक्रोज़ कर्नेल के लिए असुरक्षित हैं।* उदाहरण के लिए, `PAGE_SIZE` एक स्थिरांक नहीं, बल्कि `vm_page_size` में विस्तारित होता है। इस वेरिएबल को पढ़ने से पहले आपको PAN (A10+ पर, जिसे मैं करने की अनुशंसा भी नहीं करता) को अक्षम करना होगा अन्यथा आप पैनिक करेंगे।
- *अपने कोड को `-fno-stack-protector` और `-D_FORTIFY_SOURCE=0` के साथ संकलित करना सुनिश्चित करें* कुछ मामलों में, डिवाइस को `___stack_chk_guard` को एक अन्य यूज़रस्पेस पॉइंटर को डीरेफरेंस करके पढ़ना होगा, जो A10+ पर पैनिक करेगा।
- *सुरक्षा के लिए, अपने हुक प्रोग्राम को कंपाइलर ऑप्टिमाइज़ेशन के साथ संकलित न करें।*

https://developer.apple.com/library/archive/documentation/Darwin/Conceptual/KernelProgramming/style/style.html को स्किम करने की भी अनुशंसा की जाती है।

### कर्नेल पैनिक को डीबग करना
कोड लिखते समय बग अपरिहार्य हैं, इसलिए अंततः आप कर्नेल पैनिक का कारण बनेंगे। पैनिक का मतलब जरूरी नहीं कि xnuspy में बग है, इसलिए कोई समस्या खोलने से पहले, कृपया सुनिश्चित करें कि जब आप मूल फ़ंक्शन को कॉल करने और उसका मान लौटाने (यदि आवश्यक हो) के अलावा कुछ नहीं करते हैं, तब भी आप पैनिक करते हैं। यदि आप अभी भी पैनिक करते हैं, तो यह संभवतः xnuspy बग है (और कृपया एक समस्या खोलें), लेकिन यदि नहीं, तो आपके प्रतिस्थापन में कुछ गड़बड़ है।

चूँकि xnuspy वास्तव में EL0 पृष्ठों पर निष्पादन को पुनर्निर्देशित नहीं करता है, पैनिक को डीबग करना उतना सीधा नहीं है। `module/el1/xnuspy_ctl/xnuspy_ctl.c` खोलें, और `xnuspy_install_hook` में `kwrite_instr` के एकमात्र कॉल से ठीक पहले, कुछ सेकंड के लिए `IOSleep` कॉल जोड़ें। ऐसा यह सुनिश्चित करने के लिए किया जाता है कि डिवाइस के पैनिक होने से पहले लॉग के प्रसार के लिए पर्याप्त समय हो। `XNUSPY_DEBUG=1 make -B` के साथ xnuspy को पुनः संकलित करें और मॉड्यूल को फिर से लोड करें। मॉड्यूल लोड करने के बाद, यदि आपने पहले से नहीं किया है, तो `klog/` से `klog` संकलित करें। इसे अपने डिवाइस पर अपलोड करें और `stdbuf -o0 ./klog | grep shared_mapping_kva` चलाएँ। अपना हुक प्रोग्राम फिर से चलाएँ और `klog` से एक लाइन की तलाश करें जो इस तरह दिखती है:

`shared_mapping_kva: dist 0x7af4 uaddr 0x104797af4 umh 0x104790000 kmh 0xfffffff00c90c000`

यदि आप एक से अधिक हुक स्थापित कर रहे हैं, तो एक से अधिक घटनाएँ होंगी। उस स्थिति में, `dist` और `uaddr` अलग-अलग होंगे, लेकिन `umh` और `kmh` नहीं होंगे। `kmh` आपके प्रोग्राम के `__TEXT` सेगमेंट के कर्नेल मैपिंग की शुरुआत को इंगित करता है। अपने हुक प्रोग्राम को अपने पसंदीदा डिस्सेम्बलर में डालें और इसे रीबेस करें ताकि इसका Mach-O हेडर `kmh` के पते पर हो। IDA Pro के लिए, वह है `Edit -> Segments -> Rebase program...` जिसमें `Image base` चयनित है। आपके डिवाइस के पैनिक होने और फिर से रीबूट होने के बाद, यदि पैनिक लॉग में ऐसे पते हैं जो कर्नेल के आपके प्रतिस्थापन के मैपिंग के अनुरूप हैं, तो वे डिस्सेम्बली से मेल खाएँगे। यदि कोई नहीं हैं, तो संभवतः आपके प्रतिस्थापन के अंदर किसी प्रकार का सूक्ष्म मेमोरी भ्रष्टाचार है।

xnuspy के पास यह जानने का भी कोई तरीका नहीं है कि आपके हुक अनइंस्टॉल होने के बाद कोई कर्नेल थ्रेड अभी भी आपके प्रोग्राम के `__TEXT` सेगमेंट के कर्नेल मैपिंग पर निष्पादित हो रहा है (या होगा)। इससे निपटने के लिए xnuspy जो चीज़ें करता है उनमें से एक है आपके हुक प्रोग्राम के मरने के तुरंत बाद इस मैपिंग को डीलोकेट नहीं करना। इसके बजाय, इसे एक क्यू के अंत में जोड़ा जाता है। जब xnuspy का कचरा संग्रह थ्रेड नोटिस करता है कि उस क्यू में रखी गई मैपिंग के पृष्ठों की संख्या के संबंध में एक निर्धारित सीमा पार हो गई है, तो यह क्यू के सामने से डीलोकेट करना शुरू कर देगा और तब तक जारी रहेगा जब तक वह सीमा पार नहीं हो जाती। डिफ़ॉल्ट रूप से, यह सीमा 1 MB या 64 पृष्ठ है।

हालाँकि यह बहुत मदद करता है, आपके हुक प्रोग्राम के `__TEXT` और `__DATA` सेगमेंट जितने बड़े होंगे, xnuspy के इस दौड़ को जीतने की संभावना उतनी ही कम होगी। यदि आप नियमित रूप से पैनिक कर रहे हैं और आपका हुक प्रोग्राम कुछ बड़ा है, तो `make` से पहले `XNUSPY_LEAKED_PAGE_LIMIT=n` जोड़कर इस सीमा को बढ़ाने का प्रयास करें। यह इस सीमा को 64 के बजाय `n` पृष्ठों पर सेट करेगा।

### सीमाएँ
xnuspy अपने `xnuspy_tramp` स्ट्रक्ट्स के लिए XNU बूट होने से पहले स्टैटिक कर्नेल मेमोरी का एक पृष्ठ आरक्षित करता है, जिससे आप एक साथ लगभग 225 कर्नेल फ़ंक्शन हुक कर सकते हैं। यदि आप और चाहते हैं, तो `make` से पहले `XNUSPY_TRAMP_PAGES=n` जोड़ सकते हैं। यह xnuspy को `xnuspy_tramp` संरचनाओं के लिए `n` पृष्ठ स्टैटिक मेमोरी आरक्षित करने का निर्देश देगा। हालाँकि, यदि xnuspy को kernelcache के अंदर पहले से मौजूद अप्रयुक्त कोड पर वापस जाना पड़ता है, तो इसे अनदेखा किया जाता है। ऐसा कब होता है, यह [यह कैसे काम करता है](#how-it-works) में विस्तृत है।

### लॉगिंग
किसी कारण से, `os_log_with_args` से लॉग कमांड लाइन टूल `oslog` से आउटपुट स्ट्रीम में दिखाई नहीं देते हैं। `kprintf` से लॉग भी वहाँ नहीं पहुँचते हैं, लेकिन उन्हें `dmesg` के साथ देखा जा सकता है। हालाँकि, `dmesg` एक लाइव फ़ीड नहीं है, इसलिए मैंने `klog` लिखा, एक उपकरण जो `kprintf` लॉग को रियल टाइम में दिखाता है। इसे `klog/` में खोजें। मैं आपके `kprintf` संदेशों के लिए `dmesg` को स्पैम करने के बजाय इसका उपयोग करने की दृढ़ता से अनुशंसा करता हूँ।

यदि आपको `klog` चलाने के बाद `open: Resource busy` मिलता है, तो यह कमांड चलाएँ `launchctl unload /System/Library/LaunchDaemons/com.apple.syslogd.plist` और पुनः प्रयास करें।

दुर्भाग्य से, यदि XNU के bootargs में `atm_diagnostic_config=0x20000000` सेट है, तो आप कोई `NSLog` नहीं देख पाएँगे। `klog` इस बूट आर्गुमेंट की उपस्थिति पर निर्भर करता है। यदि आप `NSLog` वापस चाहते हैं, तो `loader.c` के अंदर `pongo_send_command` से उस बूट आर्गुमेंट को हटा दें।

### हुक अनइंस्टॉलेशन
xnuspy आपके लिए इसका प्रबंधन करेगा। एक बार जब कोई प्रक्रिया बाहर निकलती है, तो उस प्रक्रिया द्वारा स्थापित सभी कर्नेल हुक एक सेकंड या उससे कम समय में अनइंस्टॉल हो जाते हैं।

### हुक करने योग्य कर्नेल फ़ंक्शन
अधिकांश फ़ंक्शन हुकिंग फ्रेमवर्क की कुछ न्यूनतम लंबाई होती है जो किसी दिए गए फ़ंक्शन को हुक करने योग्य बनाती है। xnuspy की यह सीमा *केवल* तब होती है जब आप मूल फ़ंक्शन को कॉल करने की योजना बनाते हैं *और* हुक किए गए फ़ंक्शन का पहला निर्देश `B` नहीं है। इस मामले में, न्यूनतम लंबाई आठ बाइट है। अन्यथा, कोई न्यूनतम लंबाई नहीं है।

xnuspy अपने ट्रैम्पोलिन के लिए `X16` और `X17` का उपयोग करता है, इसलिए कर्नेल फ़ंक्शन जो उम्मीद करते हैं कि ये फ़ंक्शन कॉल के दौरान बने रहेंगे, उन्हें हुक नहीं किया जा सकता (ऐसे बहुत कम हैं जो इसकी उम्मीद करते हैं)। यदि आप जिस फ़ंक्शन को हुक करना चाहते हैं वह `BL` से शुरू होता है, और आप मूल को कॉल करने का इरादा रखते हैं, तो आप ऐसा केवल तभी कर सकते हैं जब मूल फ़ंक्शन के निष्पादन से `X17` संशोधित न हो।

### थ्रेड-सुरक्षा
`xnuspy_ctl` पहली बार फ्रेश बूट के बाद कॉल किए जाने पर एक बार का आरंभीकरण करेगा। यह xnuspy का एकमात्र हिस्सा है जो रेस करने योग्य है क्योंकि मैं जिस रीड/राइट लॉक का उपयोग करता हूँ उसे स्थिर रूप से आरंभ नहीं कर सकता। पहली कॉल के लौटने के बाद, कोई भी भविष्य की कॉल थ्रेड-सुरक्षित होने की गारंटी है।

# यह कैसे काम करता है
यह सरलीकृत है, लेकिन मुख्य विचार को अच्छी तरह से पकड़ता है। xnuspy में एक फ़ंक्शन हुक एक संरचना है जो लिखने योग्य, निष्पादन योग्य कर्नेल मेमोरी पर रहती है। अधिकांश मामलों में, यह pongoOS के अंदर `alloc_static` द्वारा लौटाई गई मेमोरी है। इसे इस प्रकार संक्षेपित किया जा सकता है:```
struct {
	uint64_t replacement;
	uint32_t tramp[2];
	uint32_t orig[10];
};

जहाँ replacement प्रतिस्थापन फ़ंक्शन का कर्नेल वर्चुअल एड्रेस (बाद में विस्तार से बताया गया) है, tramp एक छोटा ट्रैम्पोलिन है जो निष्पादन को replacement पर पुनर्निर्देशित करता है, और orig एक बड़ा, अधिक जटिल ट्रैम्पोलिन है जो मूल फ़ंक्शन का प्रतिनिधित्व करता है।

xnuspy सबसे पहले यह निर्धारित करता है कि EL0 प्रतिस्थापन कॉलिंग प्रक्रिया के एड्रेस स्पेस के अंदर कहाँ स्थित है। ऐसा इसलिए किया जाता है ताकि डायनामिक लाइब्रेरीज़ से कर्नेल फ़ंक्शन को हुक किया जा सके। Mach-O हेडर जो उस प्रतिस्थापन के एड्रेस से मेल खाता है, सहेज लिया जाता है।

इसके बाद, उस हेडर के __TEXT और __DATA सेगमेंट (साथ ही उनके बीच का कोई भी सेगमेंट, यदि कोई हो) का एक साझा यूज़र-कर्नेल मैपिंग बनाया जाता है। __TEXT साझा किया जाता है ताकि आप अपने हुक से अन्य फ़ंक्शन को कॉल कर सकें। __DATA साझा किया जाता है ताकि ग्लोबल वेरिएबल में परिवर्तन EL1 और EL0 दोनों द्वारा देखे जा सकें।

चूँकि यह मैपिंग __TEXT और __DATA की एक-से-एक प्रतिलिपि है, इसलिए उस पर उपयोगकर्ता के प्रतिस्थापन फ़ंक्शन का एड्रेस निकालना आसान है। कॉलिंग प्रक्रिया के Mach-O हेडर का एड्रेस u, साझा मैपिंग की शुरुआत का एड्रेस k, और उपयोगकर्ता के प्रतिस्थापन फ़ंक्शन का एड्रेस r दिए जाने पर, हम निम्नलिखित सूत्र लागू करते हैं: replacement = k + (r - u)

उसके बाद, replacement साझा मैपिंग पर उपयोगकर्ता के प्रतिस्थापन फ़ंक्शन का कर्नेल वर्चुअल एड्रेस है और इसे फ़ंक्शन हुक संरचना में लिखा जाता है। xnuspy निष्पादन को प्रतिस्थापन फ़ंक्शन के EL0 एड्रेस पर पुनर्निर्देशित नहीं करता क्योंकि यह अत्यंत असुरक्षित है: यह न केवल हमें शेड्यूलर की दया पर छोड़ देता है, बल्कि यह हमें उस परिदृश्य पर कोई नियंत्रण नहीं देता जहाँ कर्नेल हुक वाली प्रक्रिया मर जाती है जबकि कर्नेल थ्रेड अभी भी प्रतिस्थापन पर निष्पादित हो रहा है।

अंत में, साझा मैपिंग को निष्पादन योग्य के रूप में चिह्नित किया जाता है और एक बिना शर्त तत्काल शाखा (B) को असेंबल किया जाता है। यह निष्पादन को tramp की शुरुआत की ओर निर्देशित करता है, और यह वही है जो अब हुक किए गए कर्नेल फ़ंक्शन के पहले निर्देश को बदलता है। दुर्भाग्य से, यह हमें किसी दिए गए कर्नेल फ़ंक्शन से 128 MB से अधिक दूर हुक संरचनाओं पर शाखा लगाने से सीमित करता है। xnuspy बूट करने से पहले इस परिदृश्य की जाँच करता है और यदि यह पाता है कि ऐसा हो सकता है, तो हुक संरचनाओं के लिए अप्रयुक्त कोड पर भरोसा करने के बजाय कर्नेल कैश में पहले से मौजूद अप्रयुक्त कोड पर वापस आ जाता है।

अन्य नोट्स

मैं पैचफ़ाइंडर को काम करने के लिए अपनी पूरी कोशिश करता हूँ, इसलिए यदि कुछ काम नहीं कर रहा है, तो कृपया एक Issue खोलें।

टूल डाउनलोड करें