
เอาต์พุตจากบันทึกเคอร์เนลหลังจากรวบรวมและเรียกใช้ example/open1_hook.c
Xnuspy เป็นโมดูล pongoos ที่ติดตั้งการโทรระบบใหม่ xnuspy_ctl ซึ่งช่วยให้คุณสามารถเชื่อมต่อฟังก์ชั่นเคอร์เนลจาก Userspace รองรับ iOS 13.x, iOS 14.x และ iOS 15.x บน checkra1n 0.12.2 ขึ้นไป ไม่รองรับอุปกรณ์ 4K
โมดูลนี้มี neuters Ktrr/KPP อย่างสมบูรณ์และทำให้สามารถสร้างหน่วยความจำ RWX ภายใน EL1 ได้ อย่าใช้สิ่งนี้กับไดรเวอร์ประจำวันของคุณ
ต้องใช้ libusb : brew install libusb
เรียก make ในไดเรกทอรีระดับบนสุด มันจะสร้างตัวโหลดและโมดูล
เพิ่มสิ่งเหล่านี้ก่อน make
XNUSPY_DEBUG=1kprintf )XNUSPY_SERIAL=1IOLogXNUSPY_LEAKED_PAGE_LIMIT=n64 ข้อมูลเพิ่มเติมสามารถพบได้ภายใต้ความตื่นตระหนกของเคอร์เนลXNUSPY_TRAMP_PAGES=n XNUSPY_DEBUG และ XNUSPY_SERIAL ไม่ได้ขึ้นอยู่กับกันและกัน
หลังจากที่คุณสร้างทุกอย่างให้ทำการตรวจสอบอุปกรณ์ของคุณไปยังเชลล์ pongo: /Applications/checkra1n.app/Contents/MacOS/checkra1n -p
ในไดเรกทอรีเดียวกันคุณสร้างตัวโหลดและโมดูลให้ทำ loader/loader module/xnuspy หลังจากทำเช่นนั้น Xnuspy จะทำสิ่งนั้นและในไม่กี่วินาทีอุปกรณ์ของคุณจะบูต loader จะรออีกสองสามวินาทีหลังจากออก xnuspy-getkernelv ในกรณีที่ Seprom จะต้องใช้ประโยชน์
บางครั้งโทรศัพท์สองสามโทรศัพท์ของฉันจะติดอยู่ที่ "บูท" หลังจากการทำงานของ KPF ของ CheckRA1N ฉันยังไม่ทราบว่าอะไรเป็นสาเหตุนี้ แต่ถ้ามันเกิดขึ้นลองอีกครั้ง นอกจากนี้หากอุปกรณ์แขวนหลังจาก bootx ลองอีกครั้ง ในที่สุดการทำเครื่องหมายรหัส xnuspy_ctl ที่คอมไพล์เป็นแบบปฏิบัติการบน iPhone X ของฉันที่ใช้ iOS 13.3.1 เป็นจุดเริ่มต้น แต่ก็ประสบความสำเร็จ 100% ของเวลาบนโทรศัพท์เครื่องอื่นของฉัน หากคุณตื่นตระหนกกับคำสั่งเคอร์เนลที่ได้รับการยกเลิกเมื่อคุณดำเนินการโปรแกรม Hook ของคุณลองอีกครั้ง
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);
การเรียกระบบนี้ใช้สี่ข้อโต้แย้ง flavor arg1 , arg2 และ arg3 รสชาติ XNUSPY_GET_CURRENT_THREAD เป็น XNUSPY_CHECK_IF_PATCHED , XNUSPY_INSTALL_HOOK , XNUSPY_REGISTER_DEATH_CALLBACK , XNUSPY_CALL_HOOKME , XNUSPY_CACHE_READ , XNUSPY_KREAD , XNUSPY_KWRITE ความหมายของข้อโต้แย้งสามข้อถัดไปขึ้นอยู่กับรสชาติ
XNUSPY_CHECK_IF_PATCHED มีอยู่เพื่อให้คุณสามารถตรวจสอบได้ว่ามี xnuspy_ctl หรือไม่ การเรียกใช้กับรสชาตินี้จะทำให้มันกลับมา 999 ค่าของอาร์กิวเมนต์อื่น ๆ จะถูกละเว้น
XNUSPY_INSTALL_HOOK ฉันออกแบบรสชาตินี้ให้ตรงกับ API ของ MSHookFunction arg1 เป็นที่อยู่ ที่ไม่ชัดเจน ของฟังก์ชันเคอร์เนลที่คุณต้องการขอ หากคุณจัดหาที่อยู่ SLID คุณอาจจะตื่นตระหนก arg2 เป็นตัวชี้ไปยังฟังก์ชั่นการแทนที่ ABI ที่เข้ากันได้ของคุณ arg3 เป็นตัวชี้สำหรับ xnuspy_ctl เพื่อ copyout ที่อยู่ของแทรมโพลีนที่แสดงถึงฟังก์ชันเคอร์เนลดั้งเดิม นี่อาจเป็น NULL หากคุณไม่ได้ตั้งใจจะเรียกต้นฉบับ
XNUSPY_REGISTER_DEATH_CALLBACKรสชาตินี้ช่วยให้คุณสามารถลงทะเบียน "การโทรกลับตาย" เสริมฟังก์ชั่น xnuspy จะโทรหาเมื่อโปรแกรม Hook ของคุณออก มันให้โอกาสคุณในการทำความสะอาดทุกสิ่งที่คุณสร้างขึ้นจากตะขอเคอร์เนลของคุณ หากคุณสร้างเธรดเคอร์เนลใด ๆ คุณจะบอกให้พวกเขายุติในฟังก์ชั่นนี้
การโทรกลับของคุณจะไม่ถูกเรียกใช้แบบอะซิงโครนัสดังนั้นหากคุณบล็อกคุณกำลังป้องกันการรวบรวมชุดรวบรวมขยะของ Xnuspy จากการดำเนินการ
arg1 เป็นตัวชี้ไปยังฟังก์ชั่นการโทรกลับของคุณ ค่าของอาร์กิวเมนต์อื่น ๆ จะถูกละเว้น
XNUSPY_CALL_HOOKME hookme เป็นต้นขั้วขนาดเล็กที่มีการส่งออก xnuspy ผ่านแคช xnuspy เพื่อให้คุณขอ การเรียกใช้ xnuspy_ctl ด้วยรสชาตินี้จะทำให้ hookme ได้รับการเรียกโดยให้วิธีการให้คุณได้รับการดำเนินการรหัสเคอร์เนลได้อย่างง่ายดายโดยไม่ต้องขอฟังก์ชั่นเคอร์เนลจริง
arg1 เป็นอาร์กิวเมนต์ที่จะส่งผ่านไปยัง hookme เมื่อมีการเรียกใช้ นี่อาจเป็น NULL
XNUSPY_CACHE_READ รสชาตินี้ช่วยให้คุณอ่านจากแคช xnuspy มันมีสิ่งที่มีประโยชน์มากมายเช่น kprintf , current_proc , kernel_thread_start , ฟังก์ชั่น libc บางอย่างและสไลด์เคอร์เนลดังนั้นคุณไม่ต้องหาตัวเอง สำหรับรายการ Cache ID ที่สมบูรณ์ลองดู example/xnuspy_ctl.h
arg1 เป็นหนึ่งในรหัสแคชที่กำหนดไว้ใน xnuspy_ctl.h และ arg2 เป็นตัวชี้สำหรับ xnuspy_ctl เพื่อ copyout ที่อยู่หรือค่าของสิ่งที่คุณร้องขอ ค่าของอาร์กิวเมนต์อื่น ๆ จะถูกละเว้น
XNUSPY_KREADรสชาตินี้ช่วยให้คุณอ่านหน่วยความจำเคอร์เนลจาก Userspace ได้อย่างง่ายดายโดยไม่มี TFP0
arg1 เป็นที่อยู่เสมือนเคอร์เนล arg2 เป็นที่อยู่ของบัฟเฟอร์ผู้ใช้พื้นที่และ arg3 เป็นขนาดของบัฟเฟอร์ผู้ใช้พื้นที่นั้น arg3 ไบต์จะถูกเขียนจาก arg1 ถึง arg2
XNUSPY_KWRITEรสชาตินี้ให้วิธีง่ายๆในการเขียนหน่วยความจำเคอร์เนลจากผู้ใช้พื้นที่โดยไม่ต้องใช้ TFP0
arg1 เป็นที่อยู่เสมือนเคอร์เนล arg2 เป็นที่อยู่ของบัฟเฟอร์ผู้ใช้พื้นที่และ arg3 เป็นขนาดของบัฟเฟอร์ผู้ใช้พื้นที่นั้น arg3 ไบต์จะถูกเขียนจาก arg2 ถึง arg1
XNUSPY_GET_CURRENT_THREADรสชาตินี้ช่วยให้ผู้ใช้พื้นที่เคอร์เนลของเธรดการโทร
arg1 เป็นตัวชี้สำหรับ xnuspy_ctl เพื่อ copyout ค่าส่งคืนของ current_thread ค่าของอาร์กิวเมนต์อื่น ๆ จะถูกละเว้น
สำหรับรสชาติทั้งหมดยกเว้น 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 ถ้า:arg1ENOMEM ถ้า:unified_kalloc ส่งคืน NULLENOSPC ถ้า:xnuspy_tramp ฟรีโครงสร้างข้อมูลภายในถึง xnuspy สิ่งนี้ไม่ควรเกิดขึ้นเว้นแต่ว่าคุณจะได้ฟังก์ชั่นเคอร์เนลหลายร้อยฟังก์ ชั่นในเวลาเดียวกัน หากคุณต้องการตะขอฟังก์ชั่นเพิ่มเติมลองดูข้อ จำกัดENOTSUP ถ้า:ENOENT ถ้า:mh_for_addr ไม่สามารถระบุส่วนหัว Mach-O ที่สอดคล้องกับ arg2 ภายในพื้นที่ที่อยู่ของผู้โทรEFAULT ถ้า: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 และหากมีฟังก์ชั่นการเริ่มต้นครั้งเดียว
หากรสชาตินี้ส่งคืนข้อผิดพลาดฟังก์ชั่นเคอร์เนลเป้าหมายจะไม่ติดยาเสพติด หากคุณผ่านตัวชี้ที่ไม่ใช่ NULL สำหรับ arg3 อาจมีการเริ่มต้นหรือไม่ได้เริ่มต้น มันไม่ปลอดภัยที่จะใช้ถ้าเป็น
XNUSPY_REGISTER_DEATH_CALLBACK errno ถูกตั้งค่าเป็น ...
ENOENT ถ้า:หากรสชาตินี้ส่งคืนข้อผิดพลาดการโทรกลับของคุณจะไม่ได้ลงทะเบียน
XNUSPY_CALL_HOOKME errno ถูกตั้งค่าเป็น ...
ENOTSUP ถ้า:hookme อยู่ห่างจากหน่วยความจำที่มีโครงสร้าง xnuspy_tramp มากเกินไป สิ่งนี้จะถูกกำหนดภายใน Pongoos และสามารถเกิดขึ้นได้ก็ต่อเมื่อ Xnuspy ต้องย้อนกลับไปยังรหัสที่ไม่ได้ใช้ในเคอร์เนล ในกรณีนี้การโทรหา hookme เกือบจะทำให้เคอร์เนลตื่นตระหนกและคุณจะต้องคิดฟังก์ชั่นเคอร์เนลอื่นเพื่อขอ หากรสชาตินี้ส่งคืนข้อผิดพลาด hookme จะไม่ถูกเรียก
XNUSPY_CACHE_READ errno ถูกตั้งค่าเป็น ...
EINVAL ถ้า:arg1 ไม่ได้แสดงถึงสิ่งใดในแคชarg1 คือ IO_LOCK แต่เคอร์เนลคือ iOS 14.4.2 หรือต่ำกว่าหรือ iOS 15.xarg1 คือ IPC_OBJECT_LOCK แต่เคอร์เนลคือ ios 15.xarg1 คือ 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.xarg1 คือ KFREE_ADDR แต่เคอร์เนลคือ iOS 14.x หรือสูงกว่าarg1 คือ KFREE_EXT แต่เคอร์เนลคือ ios 13.xarg1 เป็น PROC_REF แต่เคอร์เนลคือ iOS 14.8 หรือต่ำกว่าarg1 คือ PROC_REF_LOCKED แต่เคอร์เนลคือ ios 15.xarg1 เป็น PROC_RELE แต่เคอร์เนลคือ iOS 14.8 หรือต่ำกว่าarg1 คือ PROC_RELE_LOCKED แต่เคอร์เนลคือ ios 15.xarg1 คือ VM_MAP_UNWIRE แต่เคอร์เนลคือ ios 15.xarg1 คือ VM_MAP_UNWIRE_NESTED แต่เคอร์เนลคือ iOS 14.8 หรือต่ำกว่า errno ยังขึ้นอยู่กับค่าส่งคืนของ copyout และถ้ามีค่าส่งคืนของฟังก์ชันการเริ่มต้นครั้งเดียว
หากรสชาตินี้ส่งคืนข้อผิดพลาดตัวชี้ที่คุณผ่านไปสำหรับ arg2 จะไม่เริ่มต้น
XNUSPY_KREAD และ XNUSPY_KWRITE errno ถูกตั้งค่าเป็น ...
EFAULT ถ้า:arg1 หรือ arg2 หากคุณรวบรวมด้วย XNUSPY_DEBUG=1 ข้อความเกี่ยวกับมันจะถูกพิมพ์ลงในบันทึกเคอร์เนลหากรสชาตินี้ส่งคืนข้อผิดพลาดหน่วยความจำเคอร์เนลจะไม่อ่าน/เขียน
XNUSPY_GET_CURRENT_THREAD หาก copyout ล้มเหลว errno จะถูกตั้งค่าเป็นค่าส่งคืน
ในขณะที่เขียนฟังก์ชั่นทดแทนมันเป็นเรื่องง่ายที่จะลืมว่าฉันกำลังเขียนรหัสเคอร์เนล นี่คือสองสามสิ่งที่ควรทราบเมื่อคุณเขียนตะขอ:
__TEXT ของโปรแกรมของคุณ คุณจะตื่นตระหนกหากคุณตั้งใจเรียก printf แทน kprintf โดยไม่ตั้งใจ คุณต้องใช้ฟังก์ชั่น LIBC ใด ๆ ที่คุณต้องการเรียกใช้อีกครั้งหากฟังก์ชั่นนั้นไม่สามารถใช้งานได้ผ่าน XNUSPY_CACHE_READ คุณสามารถสร้างพอยน์เตอร์ฟังก์ชั่นไปยังฟังก์ชั่นเคอร์เนลอื่น ๆ และโทรหาสิ่งเหล่านั้นได้PAGE_SIZE ขยายไปยัง vm_page_size ไม่ใช่ค่าคงที่ คุณต้องปิดการใช้งาน PAN (บน A10+ซึ่งฉันไม่แนะนำให้ทำ) ก่อนที่จะอ่านตัวแปรนี้หรือคุณจะตื่นตระหนก-fno-stack-protector และ -D_FORTIFY_SOURCE=0 ในบางกรณีอุปกรณ์จะต้องอ่าน ___stack_chk_guard โดยการยกเลิกการเจรจาต่อรองตัวชี้ USERSPACE อื่นซึ่งจะตื่นตระหนกบน A10+skimming https://developer.apple.com/library/archive/documentation/darwin/conceptual/kernelprogramming/style/style.html
ข้อบกพร่องนั้นหลีกเลี่ยงไม่ได้เมื่อเขียนโค้ดดังนั้นในที่สุดคุณก็จะทำให้เคอร์เนลตื่นตระหนก ความตื่นตระหนกไม่ได้หมายความว่ามีข้อผิดพลาดที่มี xnuspy ดังนั้นก่อนที่จะเปิดปัญหาโปรดตรวจสอบให้แน่ใจว่าคุณยังคงตื่นตระหนกเมื่อคุณไม่ทำอะไรเลยนอกจากเรียกฟังก์ชั่นดั้งเดิมและส่งคืนค่า (ถ้าจำเป็น) หากคุณยังคงตื่นตระหนกอยู่ก็อาจเป็นข้อผิดพลาด xnuspy (และโปรดเปิดปัญหา) แต่ถ้าไม่มีบางอย่างผิดปกติกับการแทนที่ของคุณ
เนื่องจาก Xnuspy ไม่ได้เปลี่ยนเส้นทางการดำเนินการไปยังหน้า EL0 จริง ๆ แล้วการดีบักความตื่นตระหนกจึงไม่ตรงไปตรงมา เปิด module/el1/xnuspy_ctl/xnuspy_ctl.c และก่อนที่จะโทรไปที่ kwrite_instr เพียงครั้งเดียวใน xnuspy_install_hook ให้เพิ่มการโทรไปยัง IOSleep เป็นเวลาสองวินาที สิ่งนี้ทำเพื่อให้แน่ใจว่ามีเวลาเพียงพอก่อนที่อุปกรณ์จะตื่นตระหนกสำหรับบันทึกเพื่อเผยแพร่ xnuspy สามรอบด้วย XNUSPY_DEBUG=1 make -B และโหลดโมดูลอีกครั้ง หลังจากโหลดโมดูลถ้าคุณยังไม่ได้รวบรวม klog จาก klog/ อัปโหลดไปยังอุปกรณ์ของคุณและทำ stdbuf -o0 ./klog | grep shared_mapping_kva เรียกใช้โปรแกรม Hook ของคุณอีกครั้งและดูบรรทัดจาก klog ที่มีลักษณะเช่นนี้:
shared_mapping_kva: dist 0x7af4 uaddr 0x104797af4 umh 0x104790000 kmh 0xfffffff00c90c000
หากคุณติดตั้งตะขอมากกว่าหนึ่งคันจะมีมากกว่าหนึ่งครั้ง ในกรณีนี้ dist และ uaddr จะแตกต่างกันไป แต่ umh และ kmh จะไม่ kmh ชี้ไปที่จุดเริ่มต้นของการทำแผนที่เคอร์เนลของเซ็กเมนต์ __TEXT ของโปรแกรมของคุณ โยนโปรแกรม hook ของคุณลงใน disassembler ที่คุณชื่นชอบและ rebase ดังนั้นส่วนหัวของ Mach-o อยู่ที่ที่อยู่ของ kmh สำหรับ IDA Pro นั่นคือ Edit -> Segments -> Rebase program... พร้อม Image base Base หลังจากอุปกรณ์ของคุณตื่นตระหนกและรีบูตอีกครั้งหากมีที่อยู่ที่สอดคล้องกับการทำแผนที่ของเคอร์เนลในการแทนที่ในบันทึกความตื่นตระหนกพวกเขาจะจับคู่กับการถอดชิ้นส่วน หากไม่มีคุณอาจมีการทุจริตหน่วยความจำที่ละเอียดอ่อนภายในการแทนที่ของคุณ
Xnuspy ยังไม่มีทางรู้ว่าเธรดเคอร์เนลยังคงดำเนินการ (หรือจะดำเนินการ) ในการทำแผนที่เคอร์เนลของเซ็กเมนต์ __TEXT ของโปรแกรมของคุณหลังจากถอนการติดตั้งตะขอของคุณ หนึ่งในสิ่งที่ Xnuspy ทำเพื่อจัดการกับสิ่งนี้คือการไม่จัดการการทำแผนที่นี้ทันทีหลังจากโปรแกรม Hook ของคุณตาย แต่จะถูกเพิ่มลงในตอนท้ายของคิว เมื่อมีการแจ้งชุดคอลเลกชันขยะของ Xnuspy แล้วขีด จำกัด ที่กำหนดไว้นั้นเกินกว่าจำนวนหน้าของการแมปที่มีมูลค่ากี่หน้าจะถูกจัดขึ้นในคิวนั้นมันจะเริ่มที่จะจัดการจากด้านหน้าของคิวและจะดำเนินการต่อไปจนกว่าขีด จำกัด นั้นจะไม่เกิน โดยค่าเริ่มต้นขีด จำกัด นี้คือ 1 MB หรือ 64 หน้า
แม้ว่าสิ่งนี้จะช่วยได้อย่างมาก แต่กลุ่ม __TEXT และ __DATA ของโปรแกรม Hook ของคุณก็ยิ่งชนะ Xnuspy ได้น้อยกว่าการแข่งขันครั้งนี้ หากคุณตื่นตระหนกเป็นประจำและมีโปรแกรมเบ็ดที่ค่อนข้างใหญ่ลองเพิ่มขีด จำกัด นี้โดยการเพิ่ม XNUSPY_LEAKED_PAGE_LIMIT=n ก่อน make สิ่งนี้จะกำหนดขีด จำกัด นี้เป็น n หน้ามากกว่า 64
Xnuspy ขอสงวนหน้าหนึ่งของหน่วยความจำเคอร์เนลแบบคงที่ก่อนที่รองเท้า XNU สำหรับโครงสร้าง xnuspy_tramp ของมันช่วยให้คุณเชื่อมต่อกับฟังก์ชั่นเคอร์เนล 225 รายการพร้อมกัน หากคุณต้องการมากขึ้นคุณสามารถเพิ่ม XNUSPY_TRAMP_PAGES=n ก่อน make สิ่งนี้จะบอก xnuspy เพื่อสำรองหน้า n ของหน่วยความจำคงที่สำหรับโครงสร้าง xnuspy_tramp อย่างไรก็ตามหาก Xnuspy ต้องถอยกลับไปที่รหัสที่ไม่ได้ใช้แล้วภายในเคอร์เนลคาเช่ก็จะถูกละเว้น เมื่อสิ่งนี้เกิดขึ้นมีรายละเอียดเกี่ยวกับวิธีการทำงาน
ด้วยเหตุผลบางอย่างบันทึกจาก os_log_with_args ไม่ปรากฏในสตรีมที่ส่งออกจากเครื่องมือบรรทัดคำสั่ง oslog บันทึกจาก kprintf ไม่ได้ทำเช่นกัน แต่ สามารถ มองเห็นได้ด้วย dmesg อย่างไรก็ตาม dmesg ไม่ใช่ฟีดสดดังนั้นฉันจึงเขียน klog เครื่องมือที่แสดงบันทึก kprintf แบบเรียลไทม์ ค้นหาใน klog/ ฉันขอแนะนำอย่างยิ่งให้ใช้สิ่งนั้นแทนการสแปม dmesg สำหรับข้อความ kprintf ของคุณ
หากคุณ open: Resource busy หลังจากเรียกใช้ klog ให้เรียกใช้คำสั่งนี้ launchctl unload /System/Library/LaunchDaemons/com.apple.syslogd.plist แล้วลองอีกครั้ง
น่าเสียดายที่คุณจะไม่สามารถเห็น NSLog ใด ๆ ถ้า atm_diagnostic_config=0x20000000 ถูกตั้งค่าใน BOOTARGS ของ XNU klog ขึ้นอยู่กับอาร์กิวเมนต์บูตนี้ที่มีอยู่ หากคุณต้องการให้ NSLog กลับมาให้ลบอาร์กิวเมนต์บูตออกจาก pongo_send_command ภายใน loader.c
Xnuspy จะจัดการสิ่งนี้ให้คุณ เมื่อกระบวนการออกเคอร์เนลตะขอทั้งหมดที่ติดตั้งโดยกระบวนการนั้นจะถูกถอนการติดตั้งภายในหนึ่งวินาทีหรือมากกว่านั้น
เฟรมเวิร์กการเชื่อมต่อฟังก์ชั่นส่วนใหญ่มีความยาวขั้นต่ำที่ทำให้ฟังก์ชั่นที่กำหนดสามารถเชื่อมต่อได้ Xnuspy มีขีด จำกัด นี้ เฉพาะ ในกรณีที่คุณวางแผนที่จะเรียกฟังก์ชั่นดั้งเดิม และ คำสั่งแรกของฟังก์ชั่น hooked ไม่ใช่ B ในกรณีนี้ความยาวต่ำสุดคือแปดไบต์ มิฉะนั้นจะไม่มีความยาวขั้นต่ำ
Xnuspy ใช้ X16 และ X17 สำหรับ trampolines ดังนั้นฟังก์ชั่นเคอร์เนลที่คาดว่าจะมีอยู่ในการเรียกใช้ฟังก์ชั่นไม่สามารถเชื่อมต่อได้ (มีไม่มากที่คาดหวังสิ่งนี้) หากฟังก์ชั่นที่คุณต้องการเบ็ดเริ่มต้นด้วย BL และคุณตั้งใจจะเรียกต้นฉบับคุณสามารถทำได้หากการดำเนินการฟังก์ชั่นดั้งเดิมไม่ได้แก้ไข X17
xnuspy_ctl จะทำการเริ่มต้นครั้งเดียวในครั้งแรกที่เรียกว่าหลังจากบูตสด นี่เป็นเพียงส่วนเดียวของ xnuspy ซึ่งเป็นเชื้อชาติได้เนื่องจากฉันไม่สามารถเริ่มต้นการอ่าน/เขียนล็อคที่ฉันใช้อย่างคงที่ หลังจากการโทรกลับครั้งแรกการโทรในอนาคตใด ๆ ก็จะรับประกันได้ว่าจะปลอดภัย
สิ่งนี้ง่าย แต่มันจับความคิดหลักได้ดี ฟังก์ชั่นเบ็ดใน xnuspy เป็นโครงสร้างที่อยู่ในหน่วยความจำเคอร์เนลที่เขียนได้และสามารถเรียกใช้งานได้ ในกรณีส่วนใหญ่นี่คือหน่วยความจำที่ส่งคืนโดย alloc_static ภายใน pongoos มันสามารถต้มลงไปได้:
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 ตรวจสอบสถานการณ์นี้ก่อนที่จะบูทและกลับไปที่รหัสที่ไม่ได้ใช้แล้วในเคอร์เนลคาเช่เพื่อให้โครงสร้างตะขออยู่แทนหากพบว่าสิ่งนี้อาจเกิดขึ้นได้
ฉันพยายามอย่างเต็มที่เพื่อให้แน่ใจว่า PatchFinders ทำงานได้ดังนั้นหากมีอะไรบางอย่างไม่ทำงานโปรดเปิดปัญหา