본문 바로가기
Programming/7. Device Driver

Windows 아키텍처 기초 - 3화 커널 모드 vs 유저 모드

by S.W 2026. 5. 20.
Windows 커널 & 드라이버 시리즈 — 3화

커널 모드 vs 유저 모드 — CPU 특권 레벨과 Ring의 의미

📅 2026 ⏱ 읽기 약 12분 🏷 아키텍처 / CPU 보안
"커널 모드와 유저 모드가 뭐가 다른 건가요?" — 이건 드라이버 개발을 시작할 때 가장 먼저 부딪히는 질문이에요. 이번 화에서는 CPU 레벨에서 이 두 모드가 어떻게 구분되는지, 그리고 유저 앱이 커널 기능을 쓰려면 어떤 경로를 거치는지 알아보겠습니다.

CPU에는 특권 레벨이 있다

컴퓨터 보안의 핵심 아이디어 중 하나는 "모든 코드가 동등하게 신뢰받아서는 안 된다"는 거예요. 사용자가 설치한 앱이 OS 핵심 데이터를 마음대로 바꿀 수 있다면 큰일 나겠죠.

그래서 x86/x64 CPU는 하드웨어 레벨에서 특권 레벨(Privilege Level)을 구현했어요. 이걸 Ring이라고 부릅니다.

Ring 0
← 커널 모드 (최고 권한)
Ring 1
← Windows에서는 미사용
Ring 2
← Windows에서는 미사용
Ring 3
← 유저 모드 (제한된 권한)

CPU는 현재 실행 중인 코드가 어느 Ring에 있는지 추적하고, Ring에 따라 허용되는 명령어와 메모리 접근 범위를 하드웨어 레벨에서 제한합니다.

📌 Windows는 Ring 0과 Ring 3만 쓴다 x86 CPU에는 Ring 0~3이 있지만, Windows는 Ring 0(커널 모드)과 Ring 3(유저 모드) 두 가지만 사용해요. Linux도 마찬가지예요. Ring 1, 2는 있지만 현대 OS에서는 거의 쓰지 않습니다.

Ring 0 (커널 모드) — 모든 권한

Ring 0에서 실행되는 코드는 CPU가 할 수 있는 모든 것을 할 수 있어요.

  • 물리 메모리 전체에 직접 접근 가능
  • in, out 같은 특권 명령어(I/O 포트 직접 접근) 실행 가능
  • CPU 레지스터(CR0, CR3 등) 직접 읽기/쓰기 가능
  • 인터럽트 제어 가능
  • 페이지 테이블 수정 가능

드라이버 코드는 Ring 0에서 실행됩니다. 그래서 드라이버에 버그가 있으면 시스템 전체가 죽어버려요 — BSOD가 바로 그겁니다.

Ring 3 (유저 모드) — 제한된 권한

Ring 3에서 실행되는 코드는 CPU가 강제로 제약을 걸어둡니다.

  • 자신의 프로세스 주소 공간에만 접근 가능 (다른 프로세스 메모리 직접 접근 불가)
  • 특권 명령어 실행 시도 → 즉시 예외(Exception) 발생
  • 하드웨어에 직접 접근 불가 — 커널에 요청해야 함
  • 앱이 크래시해도 OS와 다른 프로세스는 영향 없음

이 제약 덕분에 어떤 앱이 오작동해도 OS 자체는 살아있을 수 있어요. Ring 3 코드가 Ring 0 영역에 손을 뻗으면 CPU가 즉시 차단하고 OS에 알립니다.

그렇다면 앱은 어떻게 파일을 읽을까? — 시스템 콜

Ring 3에서 실행되는 앱이 파일을 읽으려면, 직접 디스크에 접근할 수 없으니까 커널(Ring 0)에 "파일 좀 읽어줘"라고 요청해야 해요. 이 요청 메커니즘을 시스템 콜(System Call)이라고 합니다.

예를 들어 우리가 이런 코드를 쓴다고 해볼게요:

// C 코드 (유저 모드) HANDLE hFile = CreateFile( L"C:\\test.txt", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );

이 한 줄의 API 호출이 실제로 커널까지 도달하는 과정을 따라가 보면:

1
CreateFile() — kernel32.dll의 Win32 API
2
NtCreateFile() — ntdll.dll의 네이티브 API
3
syscall 명령어 — CPU가 Ring 3 → Ring 0으로 전환
4
KiSystemCall64() — 커널 진입점 (ntoskrnl.exe)
5
I/O Manager → NTFS 드라이버 — 실제 파일 접근
6
결과 반환 — Ring 0 → Ring 3로 복귀

3단계의 syscall 명령어가 핵심이에요. x64에서는 syscall, 32bit에서는 int 0x2E 또는 sysenter가 쓰였어요. 이 명령어가 실행되는 순간, CPU는 특권 레벨을 Ring 3에서 Ring 0으로 바꾸고 미리 정해진 커널 진입점으로 점프합니다.

syscall 명령어가 하는 일

CPU 내부적으로 syscall이 실행되면 다음 일이 일어나요:

  1. 현재 스택 포인터, 명령어 포인터, 플래그를 저장
  2. CS 세그먼트 셀렉터를 Ring 0 코드 세그먼트로 변경
  3. LSTAR MSR 레지스터에 저장된 주소(커널 진입점)로 점프
  4. 커널이 요청을 처리하고 sysret 명령으로 복귀
💡 시스템 콜 번호(Syscall Number)란? NtCreateFile, NtReadFile 같은 각 시스템 콜은 고유한 번호를 가지고 있어요. ntdll.dll이 레지스터(EAX)에 이 번호를 넣고 syscall을 호출하면, 커널이 번호를 보고 어떤 함수를 호출할지 결정합니다. 이 번호는 Windows 버전마다 다를 수 있어요.

컨텍스트 스위치(Context Switch) 비용

유저 모드 → 커널 모드 전환은 공짜가 아니에요. 매번 전환할 때마다 CPU 레지스터 저장/복원, TLB 플러시 등의 오버헤드가 발생합니다. 그래서 고성능 I/O 시스템(io_uring, Windows I/O Completion Ports 등)은 커널 진입 횟수를 줄이는 방향으로 설계되어 있어요.

구분 커널 모드 (Ring 0) 유저 모드 (Ring 3)
실행 주체 드라이버, ntoskrnl.exe 일반 앱, 프레임워크
메모리 접근 전체 물리/가상 메모리 자신의 주소 공간만
하드웨어 접근 직접 가능 시스템 콜을 통해서만
크래시 영향 BSOD — 시스템 전체 종료 해당 프로세스만 종료
보안 권한 최고 권한 프로세스 토큰 권한 이하

실제로 시스템 콜을 들여다보기

WinDbg나 x64dbg로 ntdll!NtCreateFile의 어셈블리를 보면 이런 코드가 나와요:

; ntdll!NtCreateFile (x64) mov r10, rcx ; 첫 번째 인자를 r10에 백업 (syscall 규약) mov eax, 55h ; 시스템 콜 번호 (0x55 = NtCreateFile, 버전마다 다름) syscall ; Ring 3 → Ring 0 전환! ret ; 커널이 결과 반환 후 여기로 복귀

딱 네 줄이에요. 이게 전부입니다. 단순하지만 이 네 줄 안에 OS 보안 모델의 핵심이 담겨 있어요.

⚠️ 주의: 시스템 콜 번호를 하드코딩하지 마세요 Windows 버전마다 시스템 콜 번호가 바뀔 수 있어요. 정상적인 드라이버라면 ntdll.dll을 통해 간접적으로 커널에 접근하거나, WDK에서 제공하는 정식 API를 사용해야 합니다. 번호를 직접 하드코딩하는 건 루트킷 같은 악성 소프트웨어에서나 쓰는 기법이에요.

✅ 3화 요약
  • x86/x64 CPU는 Ring 0~3의 특권 레벨을 지원하며, Windows는 Ring 0(커널)Ring 3(유저)만 사용합니다.
  • Ring 0는 모든 권한, Ring 3는 자신의 주소 공간만 접근 가능합니다.
  • 유저 앱이 커널 기능을 쓰려면 시스템 콜(syscall)을 통해 요청해야 해요.
  • 시스템 콜 시 CPU가 하드웨어 레벨에서 특권 레벨을 전환합니다.
  • 드라이버는 Ring 0에서 실행되므로, 버그는 BSOD로 이어집니다.
다음 화
4화 — 가상 메모리와 주소 공간: 프로그램이 보는 메모리와 실제 메모리의 차이 →

#커널모드 #유저모드 #Ring0 #시스템콜 #특권레벨