Skip to content
KitploitKITPLOIT
도구익스플로잇블로그
Log in
제출
도구익스플로잇블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
xnuspy — checkra1n 호환 기기를 위한 iOS 커널 함수 후킹 프레임워크 | Kitploit
도구/GitHubGitHub/jsherman212/xnuspy
iOS SecurityExploitationDebuggersBinary Analysis
GitHubjsherman212/xnuspy

xnuspy

checkra1n 호환 기기를 위한 iOS 커널 함수 후킹 프레임워크

저장소 보기
595112754년 전Kitploit 검토 완료

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

xnuspy

alt text

example/open1_hook.c를 컴파일하고 실행한 후 커널 로그의 출력

xnuspy는 새로운 시스템 콜 xnuspy_ctl을 설치하는 pongoOS 모듈로, 사용자 공간에서 커널 함수를 후킹할 수 있게 해줍니다. checkra1n 0.12.2 이상의 iOS 13.x, iOS 14.x, iOS 15.x를 지원합니다. 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는 xnuspy-getkernelv를 실행한 후 SEPROM을 익스플로잇해야 할 경우를 대비하여 몇 초 더 기다립니다.

알려진 문제

가끔 제 휴대폰 중 일부가 checkra1n의 KPF 실행 후 "Booting"에서 멈추는 경우가 있습니다. 아직 원인을 파악하지 못했지만, 이런 경우 다시 시도하십시오. 또한, bootx 후 장치가 멈추면 다시 시도하십시오. 마지막으로, iOS 13.3.1을 실행하는 iPhone X에서 컴파일된 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);

이 시스템 콜은 `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`
이 flavor는 `xnuspy_ctl`이 존재하는지 확인하기 위해 존재합니다. 이 flavor로 호출하면 `999`를 반환합니다. 다른 인자의 값은 무시됩니다.

## `XNUSPY_INSTALL_HOOK`
이 flavor는 [`MSHookFunction`](http://www.cydiasubstrate.com/api/c/MSHookFunction/)의 API와 일치하도록 설계했습니다.
`arg1`은 후크하려는 커널 함수의 *UNSLID* 주소입니다. 슬라이드된 주소를 제공하면 대부분 패닉이 발생합니다. `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 함수, 커널 슬라이드 등 여러 유용한 항목이 포함되어 있어 직접 찾을 필요가 없습니다. 캐시 ID의 전체 목록은 `example/xnuspy_ctl.h`를 확인하세요.

`arg1`은 `xnuspy_ctl.h`에 정의된 캐시 ID 중 하나이며, `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`를 제외한 모든 flavor에서 성공 시 `0`이 반환됩니다. 오류 시 `-1`이 반환되고 `errno`가 설정됩니다. `XNUSPY_CHECK_IF_PATCHED`는 오류를 반환하지 않습니다. XNU의 `mach_to_bsd_errno`를 사용하여 `kern_return_t`를 적절한 `errno`로 변환합니다.

#### `XNUSPY_INSTALL_HOOK` 관련 오류
`errno`는 다음과 같이 설정됩니다...
- `EEXIST` (이미 존재):
  - `arg1`로 지정된 unslid 커널 함수에 대한 후크가 이미 존재하는 경우.
- `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가 이미 커널 캐시 내부의 사용되지 않은 코드로 대체해야 했던 경우에만 발생할 수 있습니다. 이 경우 `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` 세그먼트 외부에 있는 사용자 공간 코드는 절대 실행할 수 없습니다.* 예를 들어, 실수로 `kprintf` 대신 `printf`를 호출하면 패닉이 발생합니다. `XNUSPY_CACHE_READ`를 통해 이미 사용할 수 없는 경우, 호출하려는 libc 함수를 다시 구현해야 합니다. 그러나 다른 커널 함수에 대한 함수 포인터를 만들고 호출하는 것은 가능합니다.
- *사용자 공간 코드에서 일반적으로 사용되는 많은 매크로가 커널에서는 안전하지 않습니다.* 예를 들어, `PAGE_SIZE`는 상수가 아니라 `vm_page_size`로 확장됩니다. 이 변수를 읽기 전에 PAN(10세대 이상, 권장하지 않음)을 비활성화해야 합니다. 그렇지 않으면 패닉이 발생합니다.
- *코드를 `-fno-stack-protector` 및 `-D_FORTIFY_SOURCE=0`으로 컴파일해야 합니다.* 어떤 경우에는 장치가 다른 사용자 공간 포인터를 역참조하여 `___stack_chk_guard`를 읽어야 하며, 10세대 이상에서 패닉이 발생합니다.
- *안전을 위해 후크 프로그램을 컴파일러 최적화 없이 컴파일하세요.*

https://developer.apple.com/library/archive/documentation/Darwin/Conceptual/KernelProgramming/style/style.html 을 훑어보는 것도 권장합니다.
도구 다운로드