
루팅은 루팅이라는 단어 그대로 Root + ing 안드로이드 시스템에서 사용하는 최고 관리자인 Root 권한을 취득하는 과정을 의미한다.
루트는 uid=0 으로 안드로이드 시스템을 제어하며, 해당 권한을 얻는 방법에 있어 권한이 어디에서 만들어지느냐에 따라 일반적으로 알고 있는 Magisk 루팅과 커널 루팅으로 나뉜다.
안드로이드 내 부트 이미지 - boot.img 는 크게 3개로 구성된다.
- 커널 (Image): 하드웨어와 시스템 호출을 수행하는 리눅스
- ramdisk: init 과 초기 유저환경 (userspace)
- DT: SoC 및 보드 정보 (구형 디바이스의 경우 해당 값이 민감함)
커널 루팅은 ramdisk (부팅 프로세스 시작 / 필수 드라이버 로드 / 스토리지 마운트 등을 담당. AOS 9버전 이전에는 커널 이미지인 boot.img 내부 커널과 램디스크가 함께 묶여 있었으나 10 이후부터 구글의 동적 파티션 도입으로 램디스크 역할이 system.img 로 흡수되었음. 최신 기기들의 경우 복구 모드인 recovery.img 나 특수 파티션 내 램디스크를 포함.) 의 init을 패치하는 대신에 커널 내부 su 에 해당하는 경로를 만드는 방식이다. 특정 앱이 su 권한, 그러니까 관리자 권한을 요청하면 커널이 자격을 바꿔주고 허용되지 않은 프로세스 (흔히 알고 있는 Magisk Hide 나 Access List 등이 여기에 해당된다.)에는 su 자체가 보이지 않도록 적용할 수 있다.
커널 루팅의 구현체는 크게 두 가지로 나눌 수 있다.
- KernelSU 계열; 커널 소스 내 드라이버를 넣거나 GKI 기기에서는 LKM으로 로드
- APatch / KernelPatch: 별도 소스 없이 기존 이미지에 kpimg 를 바이너리로 삽입
두 개의 공통 전제는 부트로더 언락이 선행되어야 한다는 점이다. 이는 OS 코어가 되는 커널을 바꾸거나 boot 를 다시 작성해야하기 문이다. 즉,
커널 루팅은 Magisk 처럼 유저환경 (userspace) 데몬이 관리자인 root 를 흉내 내는 것이 아닌, 애초에 커널 권한 평면에서 관리자 권한 su 를 제공하는 것이다.
▼ What is SU
su 는 프로그램인가, 훅인가. 헷갈릴 수 있는 개념이라 별도로 작성한다.
su 라는 이름은 프로그램/훅 둘다 포함되는 이름인데, userspace 실행 파일이다. 다만 권한을 진짜로 바꾸는 위치가 Magisk 와 커널 루팅에서 다른데, 권한을 실제로 바꾸는 대상은 Linux 내 credential (cred) 이다. Magisk와 커널 루팅은 cred 를 누가, 어느 특권 레벨에서 바꾸느냐에서 다른 것이다.
기본적으로 AOS 에서 사용하는 su 는 /system/xbin/su 같은 프로그램이다. 실행되면 setuid(0) 계열로 자신의 uid 를 0으로 바꾸고, 해당 호출로 커널의 commit_creds / cred 변경으로 끝낸다.
*credential 은 리눅스에서 프로세스 하나에 메모리/파일 디스크립터와 별도로 자격 증명 묶음이 붙어있다. 이 구조체가 struct cred 라고 불리는 것.
- uid / gid: 실제 사용자 및 그룹
- euid / egid: 현재 권한 검사에 사용하는 실효 ID
- suid / fsuid: 저장된 ID 및 파일 접근용 ID
- groups: 보조 그룹
- capabilities:CAP_SYS_ADMIN, CAP_NET_RAW 처럼 root 를 잘게 나눈 비트
- 키링, dumpable 여부
- AOS의 경우, SELinux 컨텍스트가 같이 따라 붙는 경우 존재
권한 검사 실체는 "해당 프로그램이 root 인가?" 가 아닌, 커널이 해당 프로세스의 cred 값을 보고 파일이나 소켓, ptrace, 마운트를 허용하는가 이다.(여기에서 uid=0은 cred.uid 또는 euid 값이 0이라는 뜻이다.)
CPU가 Ring 0 혹은 EL1 의 의미를 가지는 것은 아니며, 앱은 uid 값이 0이더라도 여전히 EL0에서 실행된다.
권한을 올리는 커널 API는 대략 다음과 같다.
- prepare_creds(): 새 cred 복사본
- commit_creds(): 해당 프로세스에서 새 cred 를 확정
- override_creds() / revert_creds(): 잠깐 덮었다가 되돌리는 값
기존 su는 해당 경로를 타고 euid를 0으로 만드는데, setuid 비트가 있는 바이너리에도 실행 시점에 커널이 cred를 바꿔준다.
Magisk
Magisk 는 AOS 부팅 시, ramdisk / init 을 패치하여 magiskd 데몬을 uid=0 인 EL0 프로세스로 띄운다. 앱이 su를 실행하면 소켓으로 데몬에게 '이 uid 를 root 권한을 줄까?' 라고 질의하고, 데몬은 정책 허용 앱 목록을 확인하고 대상 프로세스 cred를 uid=0과 필요 capability 값을 바꿔 해당 프로세스의 credential 을 올리게된다.
결국 권한 협상 자체는 userspace 데몬이 수행하기 때문에 커널 입장에서는 이미 root인 프로세스 (magiskd)가 다른 프로세스 cred를 조작하는 것에 가깝다. 하여 Magisk Hide 및 DenyList 는 EL0에 남는 흔적 (소켓/데몬/앱 패키지/마운트)을 가리는 쪽에 가깝다.
KernelSU / APatch
/system/bin/su 나 /system/bin/kp 도 작은 userspace 바이너리 프로그램으로 볼 수 있다. 다만 해당 파일이 하는 일은 "데몬에게 요청" 하는 것이 아니라 커널에 직접 약속된 시스템 콜 (System Call 등)을 주입하는 것 이다. 커널 내 KSU 및 kpimg 가 호출자를 보고 cred 를 바꾸게 되는 것이다.
- 해당 바이너리가 커널에 약속된 시스템 콜 (KSU prctl / APatch SuperCall)을 주입한다.
- 커널 내 드라이버 및 kpimg 가 호출자/SuperKey/App Profile 을 확인한다.
- EL1에서 prepare_creds + commit_creds 로 해당 프로세스의 cred 값을 바꾼다.
여기에서 데몬에게 부탁하는 단계가 핵심이 아니라, 중요한 것은 커널 단에 있다. APatch 를 이용하여 루팅을 성공하게 되면, 당장 su 명령은 안되고 /system/bin/kp 로 관리자 root 권한으로 변경되는데, 이유는 다음과 같다.
- EL1 실행 벡터인 kpimg 는 이미 실행 가능한 상태임.
- 보통 사용되는 /system/bin/su 경로 및 /data/adb 는 유저공간으로, 안드로이드 패치로 추가 확장으로 생성됨.
결국 두 루팅의 차이점은 다음과 같다.
Magisk: EL0 root 데몬이 정책 이후 다른 프로세스의 cred 값을 올림.
Kernel Rooting: EL0의 su/kp 값이 EL1에 요청하고, 커널이 프로세스 cred 값을 바꿈.
결과로 보이는 uid=0 은 지만, 결국 commit_creds 를 누가 호출하느냐가 차이점.
| 레벨 | 해당 구간 |
| EL0 | 앱, magiskd, su/kp 파일 (uid=0 일지라도 해당 구간에 해당) |
| EL1 | 리눅스 커널, kpimg, KSU (cred를 커널이 바꾸는 구간) |
| EL2 | 하이퍼바이저 |
| EL3 | 시큐어 모니터 (Knox 일부) |
※ uid=0 은 리눅스의 신원이지 CPU 커널 모드가 아님을 유의해야한다.
Kernel Rooting vs Magisk Rooting
| Magisk | Kernel Rooting (Kernel SU / APatch) |
|
| 루팅 얻는 구간 | ramdisk / init | 커널 Image |
| su | 유저 영역 (userspace) 데몬 | 커널 + 약간의 유저영역 (userspace) |
| 커널 버전 | Android 6+ 에서 대체로 무난 | 커널 ABI 에 대한 강한 종속성 |
| 실패 형태 | 모듈 충돌 | 부팅 초반 로고 루프 등 벽돌현상 |
| 모듈 | Magisk module, Zygisk | KSU module / APM, KPM |
| 숨김 | DenyList 등 | App profile, 커널에서 su 은닉 |
| OTA | 절차가 정형화됨 | boot 가 바뀌는 경우, 재패치 필요 |
| 구형 기기 (3.18) | 성공 사례가 많음. | 가능한 구현 버전을 찾아야함. |
ABI는 바이너리가 서로를 호출할 때의 계약 (인자, 구조체 레이아웃 심볼)이다. kpimg 는 소스 없이 파일 내 몇 번째 바이트에 있다로만 확인하여 해당 주소로 점프하는데, 버전 3.18과 버전 6.1에서 기술적으로 가리키는 곳이 달라 이 죽는다.때문에 kpimg 버전도 맞아야 정상 부팅이 가능하다. (점프 목적지가 버전마다 다르기에 맞춰줘야한다는 뜻) Magisk 가 커널 버전을 안타는 이유는 해당 레이아웃을 따로 짚지 않기 때문.
Magisk 로 루팅하는 경우는 시스템리스 유저영역에 대한 루팅에 가까운데, 커널은 그대로 두되 부팅 이후 단계에서 권한을 취득한다. 그래서 커버가 되는 기기 영역이 넓다. 하지만 커널 루팅의 경우 커널이 먼저 권한을 열게되어 탐지 면에서 유리한 지점이지만 kpimg 이나 KSU 드라이버가 해당 커널에서 실행되지 않으면 시스템이 시작도 하기 전에 시스템이 다운된다.
따라서 커널루팅을 하기 위해 수행한 boot.img 패치가 성공하였다 하더라도 패치된 boot.img 를 이용한 부팅으로 uid=0 가 유지되는 것 다른 말이된다.
추가로 루팅 탐지 솔루션이나 은행 앱 등에서 Magisk 는 거의 대부분이라고 해도 좋을 정도로 탐지가 되어, "커널 루팅이라면 괜찮을거야!" 라고 생각하기 쉬운데, 커널 루팅이라고 해서 무조건 우회되는 것은 또 아니다.
은행 앱의 경우, su 경로 이외 Play Integrity (BASIC/DEVICE/STRONG) 와 부트로더 언락을 같이 확인하는데, 커널 루팅은 ELO 흔적을 줄여줄 뿐, 증명 키를 새로 만드는 것은 아니다.
▼ iOS Rootless Jailbreak VS Magisk
Magisk 설명을 보다 보면 iOS 루트리스 탈옥과 동일하게 OS 파티션을 직접쓰지 않는 점 때문에 "어라 그럼 Magisk 와 iOS Rootless 가 비슷하거나 동일한건가" 라고 착각할 수 있으나, 권한 모델은 달라 동일하게 권한을 얻는 구조는 아니다.
Magisk Systemless
Magisk 의 경우/system 영역을 영구적으로 수정하지 않는다. AOS 부팅 이후, 마운트 네임스페이스에서 파일을 덮어 보여준다. 그래서 루팅을 풀게되면 원본 파티션에 가깝게 돌아가지만, uid=0 를 사용하므로 시스템 내 리눅스 uid=0 프로세스(EL0)는 생성된다. (EL은 Exception Level)
iOS Rootless jailbreak
iOS 15 이후에 시스템 스냅샷 (OS가 설치된 공간을 ReadOnly로 완전 설정한다는 의미) 이 잠긴다. 탈옥을 시도해도 /Applications 과 같은 시스템 영역을 이전 iOS 버전들처럼 쓰기도 되지 못하여 /var/jb 와 같은 별도 프리픽스에 도구를 설치하고 이용한다. (때문에 checkra1n과 같은 탈옥으로 툴을 설치 및 사용하는 경우, 재부팅 이후에 접근 권한이 막혀 탈옥 툴을 사용하지 못하는 이유다.) 커널 익스플로잇을 이용하여 사용자 권한을 올려도 SIP (System Integrity Protection. 시스템 무결성 보호 기술로 시스템 핵심 파일 건드릴 수 없게함.) 이나 서명, 그리고 APFS 스냅샷 (기존 시스템 백업본) 이 잔존한다.
결국 Rootless 는 루트가 없는 것이 아닌 루트여도 시스템 볼륨이 쓰기 잠금됨에 가깝다고 볼 수 있다.
| Magisk | iOS Rootless | |
| 목표 | /system 파티션을 고치지 않고 root 권한 획득 | 시스템 스냅샷 무결성을 깨지 않고 탈옥 도구 유지 |
| 권한 | Linux uid=0 (EL0) | 커널 익스플로잇 + 제한된 파일 트리 유지 |
| 커널 | 보통 그대로 유지 | 익스플로잇으로 일시적 커널 권한 획득 |
| 대응 | DenyList / Zygisk 등 | 앱 경로 및 인젝션, 서명 위조 |
Magisk 는 "파티션을 유지하여 AOS 루트 권한 획득" 이고, iOS 루트리스는 "시스템 볼륨 자체를 안뜯는 탈옥" 이다.
본 글에서 작성한 커널 루트 (KSU/APatch)는 오히려 커널 (EL1) 코드를 남긴다는 점에서 Magisk/iOS 루트리스와 반대 개념이라고 볼 수 있다.
커널 루팅 방법 종류
KernelSU
커널 루팅으로 가장 널리 잘 알려져있다. 공식적으로 지원되는 버전은 Android 12 이상, 커널 5.10 이상의 기기다. GKI 2.0, 리눅스 5.10 이상.
동작모드로 2가지를 지원해준다.
- LKM: 제조사 커널은 유지하되, 모듈만 로드. 디바이스에 대해 우선적으로 권장되지만 삼성 Knox 등에서 실패할 가능성이 존재함.
- GKI: 커널 자체를 KernelSU GKI 이미지로 교체. Knox 가 적용된 삼성 디바이스나 특수 기기용으로 주로 사용된다.
▼ GKI / LKM
GKI (Generic Kernel Image)
구글이 정한 공통 커널 이미지. 안드로이드 12부터 출고되는 기기는 제조사 드라이버와 구글 공통 커널을 나누도록하여 공통 쪽이 GKI 2.0 이다. 커널 버전이 5.10-android12-9 처럼 KMI (Kernel Module Interface)로 맞춰지면 동일한 KMI끼리 이론상 커널이미지를 바꿔 꽂을 수 있다.
KernelSU 문서에서 "GKI 모드" 는 디바이스 내 들어있는 제조사 커널을 KernelSU가 빌드한 GKI 커널로 교체한다는 뜻이다.
LKM (Loadable Kernel Module)
커널을 통으로 바꾸지 않고, 이미 돌아가는 커널에 모듈을 로드하는 방식이다. KernelSU LKM은 boot/init_boot 의 ramdisk 쪽에 Loader 을 심어서 부팅 중 커널로 KSU 모듈을 삽입한다. 제조사 커널과 튜닝은 남는다.
삼성은 Knox 와 RKP 때문에 LKM이 거절되는 경우가 존재하여, 이러한 경우 GKI 교체로 전환한다.
- GKI는 커널 자체를 공통 이미지로 교체하는 것을, LKM 는 있는 커널 위에 모듈을 얹는 것을 말한다.
매니저 앱 기준, 두 가지로 나눌 수 있다.
- Not installed: 공식 지원되는 디바이스가 그러하며 LKM 이나 GKI 를 설치한다.
- Unsupported: 공식 boot 나 LKM이 없어 커널 소스에 직접 통합시키거나 비공식 커널 사용이 필요하다.
비 GKI (4.x, 3.18 등)의 경우 KernelSU 의 v1.0 이후 공식 대상이 아니다. 소스에 드라이버를 넣고 직접 빌드하면 가능한 기기도 존재하나, 해당 소스에 대한 유지보수는 업로드를 수행한 커뮤니티나 사용자의 몫이다. KernelSU 에 대한 포크 버전인 KernelSU-Next와 SukiSU-Ultra 의 경우는 옛 커널을 더 넓게 보나, 3.18 은 여전히 지원이 끊긴 상태다.
KernelSU 사이트에는 지원하는 공식 모델 목록이 아닌 커널 정책으로 안내하고 있다. 최초 디바이스가 AOS 12상이며 커널이 그때 5.10 이상의 GKI 이며, KernelSU 앱 실행 시, Not installed 라고 출력되면 공식 방법대로 커널 루팅을 수행하면 된다.
S7의 경우, 지원하지 않는 디바이스로 분류되며 ROM이 23.2 라도 커널 버전이 3.18 버전인 경우, 공식 경로가 아니라서 지원되지 않는다.
APatch (KernelPatch)
기존 boot.img 의 커널에 kpimg 를 삽입하는데, 문서상 커널버전 3.18-6.12, ARM64, CONFIG_KALLSYMS=y (가능하면 ALL=y). 인 경우 사용한다.
사용 파일은 다음과 같다.
- kpimg: 커널 내 삽입되는 코드
- kptools: kallsyms 를 읽고 나서 kpimg 를 붙이는 툴
- APatch 앱: 안드로이드 내부에서 패치 UI와 유저공간 모듈 및 su 에 대한 안드로이드 패치를 수행해준다.
주의할 점은 위 세 가지 파일이 같은 버전의 KernelPatch 태그로 묶여 있어야한다는 점이다.
ex) 앱 빌드번호 10763과 kpimg 버전 0.10.7 은 다른 버전이다.
| APatch 앱 | 내장 KernelPatch |
| 10569-10570 | 0.10.4 - |
| 10657 | 0.10.5 |
| 10763 | 0.10.7 |
| 11039 | 0.11.2 |
| 11107 | 0.12.0 |
해당 세대가 맞더라도 첨부된 kpimg 가 해당 디바이스 커널에서 부팅되는지와는 또 별개다.
절차요약:
- 디바이스 원본 boot.img 백업
- 커널 추출 → kptools 로 kpimg 삽입 → DT/ramdisk 유지 재포장
- boot 플래싱
- 재부팅이후 앱에서 안드로이드 패치 설치 (사용자 단 su 등 설치)
APatch on Galaxy S7 (herolte)
본인의 경우, 본래 KernelSU 를 이용하여 커널 루팅을 수행하려고 하였으나 AOS 버전이 낮아 APatch 를 이용하여 루팅을 수행하게 되었다.
- 기기: SM-G930K (Galaxy S7)
- ROM: 원본 AOS 버전이 낮아 비공식 LineageOS 23.2 버전 사용 (lineage-23.2-20260714-UNOFFICIAL-herolte)
- 커널: 3.18.140-gb027cb67e9a7 (2026.07.14 버전: 비공식 LineageOS 내 존재하는 boot.img 파일)
- 설정: CONFIG_KALLSYMS=y, CONFIG_KALLSYMS_ALL=y
- 설정 값은 밑에 작성할 명령어로 확인 가능하다
커널 정보 확인:
| heroltektt:/ $ uname -a Linux localhost 3.18.140-gb027cb67e9a7 #2 SMP PREEMPT Tue Jul 14 08:18:48 CEST 2026 aarch64 Toybox |
설정 값 확인:
| heroltektt:/ $ zcat /proc/config.gz | grep -E 'CONFIG_KALLSYMS' CONFIG_KALLSYMS=y CONFIG_KALLSYMS_ALL=y |
KALLSYMS 는 스트립된 커널 내 심볼 표로, ALL=y 는 데이터 심볼까지 넣는다는 뜻이다.
kptools 가 해당 주소를 찾기 위해선 이 심볼 표가 필요하며, 둘다 y 일지라도 최신버전의 kpimg 가 3.18 ABI (구 버전ABI) 에서 실행되다가 프로세스가 죽으면서 벽돌상태에 빠질 수 있다. 견디지 못한다는 표현은 파일에 삽입은 가능하나, 부팅직후 EL1 에서 해당 코드가 죽어 실행이 불가하다는 뜻
처음에 본인은 APatch.apk 파일이 존재해서 그저 apk 파일만 디바이스 내 설치 이후, boot.img 파일을 이용하여 임의 패치 수행 후, 패치된 boot.img 파일을 플래싱하면 끝나는 줄 알았다.

하지만 최신 버전의 APatch로 수행한 경우, 구버전 AOS 커널을 사용하는 디바이스에서 최신버전 kpimg 런타임을 견디지 못해 디바이스가 벽돌이 되어버리는 현상이 생긴다.
따라서 정상적인 APatch 를 위해선 APatch 를 커널 버전에 맞는 구버전을 찾아서 수행하던가, 아니면 kptools, kpimg-android 로 패칭을 수행해야한다. 앱 기준으로 커널은 0.10.4 버전이 필요하여 magiskboot repack 을 이용하여 새로운 boot.img 생성 후, TWRP 로 플래시하여 성공하게 되었다.
이때 해당 커널에서 일반 su 는 존재하지 않으며 /system/bin/kp 가 커널 su 가 된다. su 등에 대한 설치는 APatch 앱 내 '안드로이드패치' 기능으로 설정이 가능하며, APatch 0.10.5 에서 커널패치를 수행하여 0.10.4 (아마 커널 버전에 맞춰 설치가 수행된 것 같다.) 로 패치, 이후 재부팅을 성공하였고 uid=0 값까지 확인하였다.
*수행 명령어
// 본인의 경우, wsl 로 수행하였는데 Powershell 로 수행해도 된다.
// 1. 필요파일 목록
// 1.1. 기존 boot.img
// 1.2. kptools-linux
// 1.3. kpimg-android
// 1.4. 부트 이미지 패치를 위한 Magisk-v30.7.apk (버전은 상관 없다.)
// 2. kptools-linux 권한 부여
chmod +x kptools-linux
// 3. magisk 부팅 이용을 위한 압축 해제
unzip -o magisk.apk 'lib/x86_64/libmagiskboot.so'
unzip -o magisk.apk 'lib/x86_64/libmagiskboot.so'
mv lib/x86_64/libmagiskboot.so magiskboot
// 4. magisk 권한부여
chmod +x magiskboot
// 5. boot.img 확인
file boot.img
// 6. magisk를 이용한 boot.img 언팩
./magiskboot unpack boot.img
// 6.1. 언팩 파일 목록 확인
ls -al
// 7. 생성된 커널, 작업을 위한 이름 변경
mv kernel kernel-b
// 8. kptools-linux 를 이용한 root 키 (qwer1234) 적용과 패치 바이너리 설정
./kptools-linux -p --image kernel-b --skey 'qwer1234' --kpimg kpimg-android --out kernel
// 9. boot.img 패치
./magiskboot repack boot.img
// 10. 패치된 boot.img 파일 확인
ls -l new-boot.img
file new-boot.img
// 11. 패치된 boot.img 파일 복사 (디바이스 내)
cp new-boot.img /mnt/p/0/sdcard/new-boot.img
이때 벽돌 상태 (부팅 애니메이션이 끊기며 무한 재부팅으로 간다거나, 로고 이미지만 나오고 있으면 실패라 기존 boot.img 로 원복이 필요함) 가 아니라면 다음 명령을 통해 확인하면 된다.
/system/bin/kp -c id
# 안드로이드 패치 이후
su -c id
uname -a
![]() |
![]() |
S7 모델처럼 DT가 분리된 boot 이미지의 경우, 앱으로 수행하기보다 magiskboot 를 이용하는 것이 안전하며, KALLSYMS_ALL 이 활성화 상태더라도 kpimg 세대가 맞지 않으면 성공하지 않는다. KernelSU는 이 커널에서 공식 대상이 아니라서 같은 목표를 소스 빌드로 가려면 8890 트리에 KSU/SukiSU를 넣고 gcc 4.9로 Image를 다시 만드는 작업이 된다.
부트로더의 언락과 커스텀 롬, 임의 boot 패치는 보증 무효나 벽돌 가능성이 크다. 벽돌을 풀면 된다고 하지만 잘못 하다간 영구 벽돌이 될 수 있음을 항상 염두해야한다.
커널 루팅이라고 해서 은행이나 Play Integrity 통과를 보장할 수 없으며, 책임은 본인하게 있음을 잊지 말자.
▼ 참고문헌
FAQ | KernelSU
kernelsu.org
GitHub - bmax121/APatch: The patching of Android kernel and Android system
The patching of Android kernel and Android system. Contribute to bmax121/APatch development by creating an account on GitHub.
github.com
GitHub - bmax121/KernelPatch: Patching and hooking the Linux kernel with only a stripped Linux kernel image.
Patching and hooking the Linux kernel with only a stripped Linux kernel image. - bmax121/KernelPatch
github.com
Releases · flo2theO/Samsung-Galaxy-S7-Lineageos
Lineageos 23. Contribute to flo2theO/Samsung-Galaxy-S7-Lineageos development by creating an account on GitHub.
github.com

