
adb 기반 KernelSU 로더로, 순정 Google Pixel용: CVE-2026-43499(GhostLock)를 통해 임시 커널 R/W를 확보한 뒤, 실행 중인 KMI에 서명이 일치하는 kernelsu.ko를 지연 로드합니다. 매니저에 구애받지 않습니다.
adb 기반 도구로, 잠긴 부트로더가 있는 순정 Google Pixel을 부트로더 잠금 해제나 부트 이미지 수정 없이 KernelSU 루팅 기기로 전환합니다. 호스트에서 기기의 비특권 사용자 공간 커널 익스플로잇을 실행하여 임시 커널 읽기/쓰기 권한을 얻고, 해당 프리미티브를 사용하여 루트 자격 증명을 패치한 다음, 실행 중인 GKI 커널에 KernelSU 로드 가능 커널 모듈(kernelsu.ko)을 지연 로드하고 이미 설치된 KernelSU 매니저(KernelSU, KernelSU-Next, SukiSU 또는 다른 변형)에 제어권을 넘깁니다. Android 17 Pixel 기기의 GKI 6.1 및 6.6 커널을 대상으로 하며, 결정적 시퀀싱과 타임스탬프 로그를 위해 전체 흐름을 adb shell로 구동합니다.
기기 측 페이로드는 CVE-2026-43499("GhostLock")에 대한 벤더 제공 전체 체인 LPE로, kernel/locking/rtmutex.c의 futex/rtmutex 우선순위 상속 스택 use-after-free입니다. requeue-PI 롤백 경로에서 remove_waiter()는 실제 대기자가 아닌 requeuer(current)의 pi_blocked_on을 해제하여 해제된 커널 스택 슬롯에 있던 rt_mutex_waiter에 대한 댕글링 포인터를 남깁니다. 이 버그는 일반 비특권 프로세스에서도 도달 가능합니다:
owner, waiter, consumer)가 PI 체인을 구성합니다. 대기자는 FUTEX_WAIT_REQUEUE_PI에 대기하고, 메인 스레드는 FUTEX_CMP_REQUEUE_PI를 발생시키며, consumer의 sched_setattr이 롤백을 유도합니다.pselect()/select()(일부 6.1 대상에서는 TCP_ZEROCOPY_RECEIVE 경로)에 의해 재확보되며, 해당 fd_set 워드가 대기자 구조체 위에 놓여 위조된 평면 rt_mutex_waiter를 작성하여 댕글링 포인터가 공격자 제어의 rb-tree 및 lock 필드를 탐색하도록 합니다 — 단일 제어 포인터-쓰기 프리미티브입니다.mm_struct/sk_buff/pipe_buffer 객체를 보유한 슬랩 페이지를 찾습니다.그런 다음 파이프 프리미티브를 통해 루트 및 SELinux 상태가 패치됩니다: 루트 자식 태스크의 cred는 전체 기능 집합으로 uid/gid 0으로 제로화되고, SELinux osid/sid는 SECINITSID_KERNEL로 설정되며, seccomp는 해제되고, selinux_state.enforcing은 0으로 설정됩니다.
익스플로잇 체인, KASLR 오라클, KernelSnitch 부채널은 NebuSec의 IonStack Part II — GhostLock 연구(NebuSec/CyberMeowfia PoC, Apache-2.0)에서 비롯되었으며, Pixel/aarch64용으로 각색되었습니다. Attribution & License를 참조하세요.
체인에서 정확히 한 단계만 커널 패닉을 일으킬 수 있습니다: 재확보했다고 기대하는 페이지와 경쟁하는 KASLR 슬라이드 유도입니다. 다른 모든 단계는 재시도에 안전하며, 커널 텍스트 베이스는 단일 부팅 수명 동안 고정됩니다. 호스트 흐름은 이 속성에 따라 분할됩니다:
KASLR_BASE 없이 실행됩니다. 위조된 대기자 쓰기는 random_table sysctl ctl_table.data를 알려진 커널 텍스트 포인터로 재지정합니다. /proc/sys/kernel/random/boot_id를 읽으면 proc_do_uuid()를 통해 이를 유출하고, 이미지 오프셋을 빼면 _stext/KASLR 베이스가 산출됩니다. restore_slide_boot_id()는 손상된 ctl_table.data를 복구합니다. 경쟁 실패는 기기를 재부팅하므로 모든 시도 전에 부팅 대기가 선행되고, 활성 검사가 사라짐을 패닉으로 분류합니다. 성공 시 기기 로그는 slide-kaslr-ok pid=<pid> base=<hex>를 출력하고 베이스는 현재 부팅에 고정됩니다.KASLR_BASE=0x<base>를 내보낸 상태로 다시 실행됩니다. 이 경로는 패닉이 발생하지 않으며 임시 su를 통한 id가 uid=0을 보고할 때까지 반복됩니다.연결된 기기는 런타임에 data/targets.json에 대해 확인됩니다. 기기 하드코딩은 없습니다. 두 가지 독립적인 확인이 발생합니다:
uname -r)에서 가져오며, 일치하는 대상 항목에서 가져오거나 릴리스 문자열(예: android14-6.1)에서 파생됩니다.여러 기기에서 하나의 페이로드를 재사용하는 것은 GKI/KMI 구조에서 비롯됩니다. 동일한 GKI 빌드의 모든 기기는 바이트 단위로 동일한 vmlinux를 실행하며, 구조체 필드 오프셋(task_struct->cred, cred->uid, …)은 KMI 유형 계약과 MODVERSIONS CRC 강제에 의해 KMI 브랜치 수명 동안 고정됩니다. 반면 절대 커널 심볼 주소는 링커가 ab<NNN> 빌드별로 결정하므로 익스플로잇의 고정 오프셋은 특정 vmlinux 하나에 속합니다. 따라서 서로 다른 커널 이미지는 KMI가 일치하더라도 서로 다른 페이로드가 필요합니다. data/targets.json은 정확히 이를 인코딩합니다: 많은 기기가 커널 이미지를 키로 하는 하나의 페이로드로 중복 제거되는 반면, 다른 커널 이미지는 자체 페이로드를 갖습니다.
LKM 지연 로드는 로드 가능 모듈 지원이 있는 GKI 커널(5.10+)과 KMI 일치 .ko가 필요합니다. KernelSU 커널 모듈은 커널 내에서 매니저 APK의 v2 서명 블록을 검증하고 서명 인증서의 SHA-256을 .ko에 컴파일된 KSU_EXPECTED_SIZE/KSU_EXPECTED_HASH 쌍과 비교하여 매니저를 인증합니다. 따라서 매니저 릴리스에 포함된 kernelsu.ko와 해당 매니저의 APK는 하나의 서명 ID를 공유합니다. 불일치 ksud는 드라이버를 로드하지만 매니저 권한 부여 비트를 설정하지 않아 기기에 사용 가능한 루트가 없게 됩니다.
흐름은 이 바인딩을 존중합니다: 설치된 매니저의 APK 경로(pm path <manager package>)를 확인하고, APK를 가져오고, lib/arm64-v8a/libksud.so를 ksud 바이너리로 추출하며, 매니저가 설치되지 않은 경우 중단합니다. 임시 루트를 보유한 상태에서 해당 ksud는 루트 소유 실행 파일로 스테이징되고 ksud late-load --kmi <kmi> --package-name <manager package>로 호출됩니다. Late-load는 현재 KMI를 감지하고, 임베디드 자산에서 "{kmi}_kernelsu.ko"를 가져오고, 수동 심볼 재배치(/proc/kallsyms에 대해 각 SHN_UNDEF 심볼을 확인하고 항목을 SHN_ABS로 재작성)를 수행한 다음 패치된 버퍼에서 init_module(2)를 호출합니다. 그런 다음 init이 수행할 나머지 부팅 파이프라인(ksud 설치, restorecon, sepolicy.rule 및 루트 프로필 로드, post-fs-data/스테이지 스크립트 실행, 모듈 오버레이 마운트)을 실행합니다.
Late-load는 데몬화되고 분기된 자식에서 SELinux를 재강제하며, 이는 익스플로잇의 임시-su 데몬을 해체합니다. 따라서 검증은 su를 거치지 않아야 합니다. 대신 로드된 드라이버는 루트 없이 일반 셸에서 도달 가능한 syscall 표면을 통해 직접 쿼리됩니다: ksud debug version이 폴링되고 보고된 커널 버전이 파싱됩니다. 비어 있지 않은 0이 아닌 버전은 드라이버가 상주하고 응답 중임을 확인합니다. 드라이버 설치 경로는 reboot(2) 매직 → 설치 fd → KSU_IOCTL_GET_INFO 메커니즘입니다(reboot(0xDEADBEEF, 0xCAFEBABE, 0, &fd)는 익명 [ksu_driver] fd를 설치하고, GET_INFO는 {version, flags, features, uapi_version}을 반환). 레거시 prctl(0xDEADBEEF, …) 채널은 폴백으로 프로브됩니다. 시작 시 동일한 프로브는 모듈이 현재 부팅에 이미 상주하는 경우 전체 흐름을 단락시킵니다.
익스플로잇은 adbd의 마운트 네임스페이스 내에서 해당 apex bin 디렉토리 위에 마운트된 tmpfs에 임시 su를 /apex/com.android.virt/bin/su에 스테이징합니다. 이 디렉토리는 셸 PATH에서 /system/bin보다 앞서므로 흐름이 실행되는 동안 adb shell의 단순 su가 임시 su에 도달합니다. 그런 다음 late-load는 섀도를 제거하지 않고 임시-su 데몬을 해체합니다((e) 참조). 이는 루트가 작동 중임에도 su: connect daemon: Permission denied로 실패하는 고아 클라이언트를 실행하는 단순 adb shell su를 남기고, apex의 실제 바이너리(crosvm, virtmgr, vm, …)를 숨깁니다. 검증이 라이브 드라이버를 보고하면 흐름은 스테이징 tmpfs를 마운트 해제합니다 — 익스플로잇의 데몬이 이미 사라졌으므로 KernelSU 자체의 /system/bin/su를 통해 — 임시-su 클라이언트, 소켓 및 로그를 제거하고 일반 adb shell이 이제 해석하는 su를 보고합니다. 이는 최선 노력입니다: 실패 시 실행을 실패로 처리하는 대신 수동 umount 명령으로 경고하며, 재부팅은 마운트를 무조건 해제합니다.
adb가 있고 기기가 인증되어 있어야 합니다(USB 디버깅 활성화).kernelsu.ko의 소스입니다.artifacts/exploits/에 사전 빌드된 익스플로잇 페이로드(Building payloads 참조).# adb에 기기 하나, 매니저 설치, 페이로드 빌드 완료.
bin/pixel-ksu-root
드라이버는 data/targets.json에 대해 기기를 확인하고, 2단계 KASLR 흐름을 실행하고, 매니저 파생 ksud를 통해 모듈을 지연 로드하고, 드라이버 syscall을 통해 검증합니다. 기기에 대한 페이로드가 확인되지 않거나, 매니저가 설치되지 않았거나, 검증이 라이브 드라이버를 보고하지 않으면 0이 아닌 종료 코드로 종료됩니다.
KASLR_BASE=0x<hex> — Phase B 동안 기기 페이로드에 전달되어 고정된 이미 파생된 부팅별 베이스에 대해 재생합니다. Phase A 동안에는 설정되지 않아 페이로드가 베이스를 직접 파생합니다.ANDROID_NDK_HOME — Android NDK 경로, 페이로드 빌드 시에만 필요합니다.API — 페이로드 빌드 시 NDK 툴체인의 Android API 레벨(기본값 35).pixel-ksu-root/
├── bin/ 호스트 드라이버 진입점(adb 기반 흐름)
├── data/
│ └── targets.json 기기→페이로드 및 기기→KMI 확인 테이블
├── exploit/ 벤더 제공 CVE-2026-43499 페이로드 소스
│ ├── Makefile 대상별 aarch64 NDK 빌드
│ ├── src/ android15-6.6 기준 소스 세트
│ │ ├── main.c slide.c fops.c pipe.c root.c preload.c util.c
│ │ ├── su_daemon.c 체인에 의해 생성되는 임시-su 헬퍼
│ │ ├── kernelsnitch/ Futex 해시 점유 부채널 헤더
│ │ └── targets/ 기기+빌드별 target.h(커널 오프셋)
│ └── src/61/ android14-6.1 소스 세트(slide61.c, TCP 경로)
├── lib/ 호스트 측 공유 셸/헬퍼 함수
├── scripts/
│ └── build-payloads.sh 페이로드 세트 빌드 및 중복 제거
├── artifacts/
│ └── exploits/ 빌드된 중복 제거 페이로드 .so 파일
└── docs/ 설계 및 분석 노트
scripts/build-payloads.sh는 대상별 exploit/Makefile을 래핑하고 data/targets.json에 명명된 중복 제거 페이로드 세트를 artifacts/exploits/에 출력합니다. 기기별이 아닌 고유 오프셋 그룹당 하나의 .so를 빌드합니다(해당 그룹의 build_from 대상에서).
export ANDROID_NDK_HOME=/path/to/android-ndk # aarch64 NDK 툴체인 포함 필수
scripts/build-payloads.sh # data/targets.json의 모든 페이로드 빌드
Makefile은 ANDROID_NDK_HOME에서 aarch64 NDK Clang 툴체인을 선택하고 한 번에 단일 대상을 컴파일합니다. API(기본값 35)는 aarch64-linux-android<API>-clang 드라이버를 선택합니다. 소스 세트는 커널 계열에 따라 선택됩니다 — android15-6.6 대상은 src/ 기준을 컴파일하고, android14-6.1 대상은 src/61/을 컴파일합니다 — 각 대상의 절대 커널 오프셋은 src/targets/<codename>-<build>/target.h에서 가져옵니다. 단일 대상을 직접 빌드하려면:
make -C exploit TARGET=husky-CP2A.260705.006
data/targets.json은 18개 Pixel 모델을 포함하는 19개 기기/빌드 항목(bluejay는 두 펌웨어 빌드에 나타남)을 나열하며, 5개 커널 오프셋 페이로드로 그룹화됩니다. 선택은 커널 이미지 기준이므로 vmlinux를 공유하는 기기는 하나의 페이로드로 중복 제거되고, 다른 커널 이미지는 자체 페이로드를 갖습니다.
공유 android14-6.1-a 커널 이미지(6.1.157-android14-11-gbd23337e42e7-ab14791245)의 기기는 Pixel 6/6 Pro/6a, 7/7 Pro/7a, 8/8 Pro, 9/9 Pro/9 Pro XL/9 Pro Fold 제품군에 걸쳐 있습니다. android14-6.1-b와 android14-6.1-akita는 동일 KMI에서 커널 빌드 또는 오프셋이 다른 모델을 분리합니다. android15-6.6은 Pixel 10 제품군을 포함합니다.
NebuSec/CyberMeowfia 저장소에서 Apache-2.0으로 공개됨. 발견은 NebuSec의 VEGA 도구링에 기인하며 2026-07-07에 공개되었습니다.exploit/ 트리는 NebuSec 익스플로잇 위에 android14-6.1 및 android15-6.6 대상 오프셋과 KernelSU 지연 로드 데몬을 추가합니다. 별도 라이선스가 없으며 업스트림 Apache-2.0 조건을 상속합니다.ksud, 매니저 권한 부여 모델을 제공합니다.exploit/ 아래의 벤더 제공 소스는 업스트림 라이선스(NebuSec 파생 익스플로잇의 경우 Apache-2.0)를 유지합니다. 이 프로젝트는 매니저에 구애받지 않습니다: 설치된 KernelSU 변형 매니저를 지연 로드하며 특정 포크를 대상으로 하거나 번들하지 않습니다.
ksud late-load 경로init_module 로더 및 드라이버 감지apk_sign.rsashmem_miscs[0].fops를 위조된 file_operations로 덮어씁니다. 이 구조체의 모든 슬롯은 실제 프로토타입 호환 커널 함수(configfs_bin_write_iter, configfs_read_iter, copy_splice_read, ashmem_ioctl, noop_llseek, …)를 가리키므로 전방 에지 CFI를 충족하면서 ashmem fd의 read/write/splice가 제한된 커널 R/W를 제공합니다.pipe_buffer 구조체를 위조합니다(vmemmap↔직접 매핑 변환을 통해 page가 임의 대상을 가리키고, ops = anon_pipe_buf_ops, PIPE_BUF_FLAG_CAN_MERGE), 따라서 파이프의 일반 read()/write()가 임의 커널 주소와 바이트를 주고받습니다 — 안정적인 임의 커널 R/W입니다./proc/sys/kernel/random/boot_id| 페이로드 | KMI | 빌드 기준 | 기기 |
|---|
android14-6.1-a | android14-6.1 | bluejay-CP2A.260705.006 | oriole, raven, bluejay (CP2A), panther, cheetah, comet, shiba, husky, lynx, caiman |
android14-6.1-b | android14-6.1 | komodo-CP2A.260705.006 | komodo, tegu, tokay |
android14-6.1-akita | android14-6.1 | akita-CP2A.260805.005 | akita |
android14-6.1-cp1a | android14-6.1 | bluejay-CP1A.260405.005 | bluejay (CP1A) |
android15-6.6 | android15-6.6 | blazer-CP2A.260705.006 | frankel, blazer, mustang, rango |