[시스템 아키텍처] 핵심 시스템 컴포넌트 - 2
[시스템 아키텍처] 핵심 시스템 컴포넌트 - 2
커널
- 커널은 기본 메커니즘을 제공하는
ntoskrnl.exe
내의 함수 집합으로 구성된다.- 이들 함수에는 익스큐티브 컴포넌트에 의해 사용되는 스레드 스케줄링과 동기화 서비스 및 각 프로세서 아키텍처별로 다른 인터럽트와 예외 디스패칭 같은 저수준 하드웨어 아키텍처 종속적인 지원이 해당된다.
- 커널 코드는 주로 C로 작성됐으며, C에서 쉽게 접근할 수 없는 특화된 프로세서 명령어와 레지스터에 대한 액세스가 요구되는 작업에는 어셈블리 코드가 사용됐다.
커널 객체
- 커널은 익스큐티브의 상위 레벨 컴포넌트가 필요로 하는 것을 수행할 수 있게 잘 정의된 예측 가능한 OS 기반 요소(Primitive)와 메커니즘의 기반을 제공한다.
- 커널은 OS 메커니즘을 구현하고, 정책을 만드는 것을 배제함으로써 익스큐티브의 나머지 부분으로부터 커널 자체를 분리한다.
- 커널이 구현한 스레드 스케줄링과 디스패칭을 제외한 거의 모든 정책 결정은 익스큐티브에 있다.
- 커널 외부의 익스큐티브는 스레드와 여타 공유 가능한 리소스를 객체로 표현한다.
- 객체는 자신들의 조작에 필요한 객체 핸들과 자신들을 보호하기 위한 보안 점검, 그리고 생성될 때 공제하기 위한 리소스 쿼터 같은 정책 오버헤드가 요구된다.
- 커널 내에서는 커널 통제 중앙 처리를 돕고 익스큐티브 객체 생성을 지원하기 위한 커널 객체라고 하는 단순 객체 집합을 구현해 오버헤드를 제거했다.
- 대부분의 익스큐티브 레벨 객체는 커널에서 정의한 속성과 결합시킨 하나 이상의 커널 객체로 캡슐화되어 있다.
- 컨트롤 객체로 불리는 커널 객체의 한 집합은 다양한 OS 함수 제어에 대한 의미론을 확립한다. 이 집합은 APC 객체와 지연된 프로시저 호출(DPC) 객체, I/O 관리자에서 사용하는 인터럽트 객체 같은 여러 객체를 포함한다.
- 디스패처 객체로 알려진 또 다른 객체 집합은 스레드 스케줄링을 변경하거나 스레드 스케줄링에 영향을 주는 동기화 기능을 통합한다.
- 디스패처 객체는 커널 스레드와 뮤텍스, 이벤트, 커널 이벤트 페어, 세마포어, 타이머, 대기 가능 타이머를 포함한다.
- 익스큐티브는 커널 객체의 인스턴스를 생성하고 조작하고 유저 모드에 제공하기 위해 좀 더 복잡한 객체를 구축하고자 커널 함수를 사용한다.
커널 프로세서 컨트롤 영역과 컨트롤 블록
- 커널은 프로세서 컨트롤 영역(KPCR; Kernel Processor Control Region)이라고 하는 데이터 구조체를 사용하고 프로세서 한정적 데이터를 저장한다.
- KPCR은 프로세서의 인터럽트 테이블과 태스크 상태 세그먼트, 글로벌 디스크립터 테이블 같은 기본 정보를 담고 있다. 또한 ACPI 드라이버와 HAL 같은 모듈과 공유하는 인터럽트 컨트롤 상태를 담고 있다.
- KPCR에 쉽게 접근할 수 있도록 커널은 이를 가리키는 포인터를 32비트 윈도우에서
FS
레지스터에 저장하고, 64비트 윈도우 시스템에서GS
레지스터에 저장한다.
- KPCR은 또한 커널 프로세서 컨트롤 블록(KPRCB; Kernel PRocessor Control Block)라고 하는 내장된 데이터 구조체를 담고 있다.
- 서드파티 드라이버와 다른 내부 윈도우 커널 컴포넌트를 위해 문서화되어 있는 KPCR과 다르게 KPRCB는
ntoskrnl.exe
의 커널 코드에 의해서만 사용되는 비공개 구조체이다. - 스케줄링 정보, 디스패처 데이터베이스, DPC 큐, CPU 벤더/식별자 정보, CPU와 NUMA 토폴로지, 캐시 크기, 시간 계정 정보 등의 정보를 가진다. 또한 I/O, 캐시 관리자, DPC, 메모리 관리자 등의 통계 정보를 담고 있다.
- KPRCB는 종종 메모리 접근을 최적화하기 위해 캐시 정렬된 프로세서별 구조체를 저장하기 위해 사용된다.
- 서드파티 드라이버와 다른 내부 윈도우 커널 컴포넌트를 위해 문서화되어 있는 KPCR과 다르게 KPRCB는
KPCR과 KPRCB 살펴보기
!pcr
과!prcb
커널 디버거 명령을 사용해 KPCR과 KPRCB의 내용을 볼 수 있다. 기본적으로는 CPU 0의 정보를 보여주며, 명령 뒤에 숫자를 추가해 CPU를 지정할 수 있다.!pcr
명령은 원격 디버깅 세션에서 변경할 수 있는 현재 프로세서의 정보를 보여주며, 로컬 디버깅을 하고 있다면 CPU 번호를 지정한!pcr
익스텐션을 사용해 KPCR의 주소를 구할 수 있으며, 이 주소로@$pcr
을 대체한다.dt nt!_KPCR @$pcr
과!prcb
의 결과
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 0: kd> dt nt!_KPCR @$pcr +0x000 NtTib : _NT_TIB +0x000 GdtBase : 0xfffff800`18a2ffb0 _KGDTENTRY64 +0x008 TssBase : 0xfffff800`18a2e000 _KTSS64 +0x010 UserRsp : 0x00000034`409ffa48 +0x018 Self : 0xfffff800`15b02000 _KPCR +0x020 CurrentPrcb : 0xfffff800`15b02180 _KPRCB +0x028 LockArray : 0xfffff800`15b02870 _KSPIN_LOCK_QUEUE +0x030 Used_Self : 0x00000034`3f51a000 Void +0x038 IdtBase : 0xfffff800`18a2d000 _KIDTENTRY64 +0x040 Unused : [2] 0 +0x050 Irql : 0 '' +0x051 SecondLevelCacheAssociativity : 0xc '' +0x052 ObsoleteNumber : 0 '' +0x053 Fill0 : 0 '' +0x054 Unused0 : [3] 0 +0x060 MajorVersion : 1 +0x062 MinorVersion : 1 +0x064 StallScaleFactor : 0xbb3 +0x068 Unused1 : [3] (null) +0x080 KernelReserved : [15] 0 +0x0bc SecondLevelCacheSize : 0x1800000 +0x0c0 HalReserved : [16] 0xb2872000 +0x100 Unused2 : 0 +0x108 KdVersionBlock : (null) +0x110 Unused3 : (null) +0x118 PcrAlign1 : [24] 0 +0x180 Prcb : _KPRCB
1 2 3 4 5 6 7 8 0: kd> !prcb PRCB for Processor 0 at fffff80015b02180: Current IRQL -- 2 Threads-- Current fffff80016c7da40 Next 0000000000000000 Idle fffff80016c7da40 Processor Index 0 Number (0, 0) GroupSetMember 1 Interrupt Count -- 00018034 Times -- Dpc 0000000b Interrupt 00000008 Kernel 0000070b User 00000073dt
명령을 사용해_KPRCB
데이터 구조체를 직접 덤프할 수 있다. 예를 들어 부트 시점에 탐지되는 프로세서의 속도를 알고 싶다면 다음 명령으로MHz
필드를 살펴보면 된다.
1 2 3 4 0: kd> dt nt!_KPRCB fffff80015b02180 MHz +0x044 MHz : 0xbb3 0: kd> ? bb3 Evaluate expression: 2995 = 00000000`00000bb3
하드웨어 지원
- 커널의 다른 주요 임무는 윈도우에 의해 지원되는 하드웨어 아키텍처 간의 차이점으로부터 익스큐티브와 디바이스 드라이버를 추상화하거나 격리시키는 것이다.
- 커널은 이식 가능하고 모든 아키텍처에서 의미상 동일한 인터페이스 집합을 제공하며, 이들 이식 가능한 인터페이스를 구현한 대부분의 코드는 모든 아키텍처에서 동일하다.
- 인터페이스 중 일부는 아키텍처별로 다르게 구현되어 있으며, 일부 인터페이스는 부분적으로 아키텍처 한정적인 코드가 구현되어 있다.
- 커널은 오래된 16비트 MS-DOS 프로그램을 지원할 필요로 인해 x86 한정적인 인터페이스 코드를 일부 가진다.
- 아키텍처 한정적인 코드의 또 다른 예는 변환 버퍼와 CPU 캐시 지원을 제공하기 위한 인터페이스이다. 이는 캐시가 구현된 방법 때문에 아키텍처별로 다른 코드를 필요로 한다.
- 다른 예는 컨텍스트 전환이다. 고수준에서는 스레드 선택과 컨텍스트 전환을 위해 같은 알고리즘이 사용됐지만, 프로세서별 구현에는 아키텍처적인 차이가 있다. 컨텍스트가 프로세서 상태에 의해 기술되기 때문에 아키텍처별로 무엇이 저장되고 로드될지 달라진다.
하드웨어 추상화 계층(HAL)
- 하드웨어 추상화 계층은 이식성을 가능하게 하는 핵심 부분으로, 윈도우가 실행 중인 하드웨어 플랫폼에 대한 저수준 인터페이스를 제공하는 로드 가능한 커널 모듈(
hal.dll
)이다.- I/O 인터페이스와 인터럽트 컨트롤러, 멀티프로세서 통신 메커니즘 같은 하드웨어 의존적인 세부 사항을 감춘다.
- 모든 함수는 아키텍처 한정적이고 머신에 의존적이다.
- 윈도우 내부 컴포넌트는 플랫폼 의존적인 정보가 필요할 때 하드웨어를 직접 액세스하는 것보다 사용자가 작성한 드라이버와 마찬가지로 HAL 루틴을 호출함으로써 이식성을 유지한다.
- x86 윈도우에는 다음과 같은 HAL이 포함되어 있다.
halacpi.dll
: 고급 구성 및 전원 인터페이스. APIC 지원이 없는 단일 프로세서 머신halmacpi.dll
: ACPI가 있는 고급 프로그램 가능 인터럽트 컨트롤러
- x64와 ARM 머신에서는
hal.dll
이라는 하나의 HAL 이미지만 존재한다. x64 머신 프로세서가 ACPI와 APIC 지원을 필요로 하여 모든 x64 머신이 같은 마더보드 구성을 가지게 되었기 때문이다.
디바이스 드라이버
- 디바이스 드라이버는 로드 가능한 커널 모드 모듈(
.sys
)로 I/O 관리자와 관련 하드웨어 사이를 인터페이스로 연결한다. 다음과 같은 세 가지 컨텍스트 중 하나로 커널 모드에서 동작한다.- I/O 함수를 호출한 유저 스레드 컨텍스트
- 커널 모드 시스템 스레드 컨텍스트(PnP 관리자로부터의 요청 등)
- 인터럽트의 결과로서 어떤 특정한 스레드의 컨텍스트가 아닌 인터럽트가 발생할 때 그 시점의 스레드 컨텍스트
- 윈도우의 디바이스 드라이버는 하드웨어를 직접 조작하지 않는다. 대신 하드웨어와 통신하기 위해 HAL 내의 함수를 호출한다.
- 드라이버는 보통 C(때로 C++)로 작성되어 있다. 그러므로 HAL 루틴을 적절히 사용해 윈도우가 지원하는 CPU 아키텍처 사이에서 소스코드 이식성을 가질 수 있고, 아키텍처 계열에서 바이너리 이식성을 가질 수 있다.
디바이스 드라이버의 유형
- 하드웨어 디바이스 드라이버
- 물리적 디바이스나 네트워크로부터 입력을 읽어 들이거나 출력을 쓰기 위해 하드웨어를 조작하는 데 HAL을 사용한다.
- 버스 드라이버와 휴먼 인터페이스 드라이버, 대용량 스토리지 드라이버 등과 같이 많은 유형의 하드웨어 디바이스 드라이버가 있다.
- 파일 시스템 드라이버
- 파일 지향적인 I/O 요청을 받아들이고 특정 장치로 I/O 요청을 보내는 윈도우 드라이버이다.
- 프로토콜 드라이버
- TCP/IP, NetBEUI, IPX/SPX 같은 네트워크 프로토콜을 구현한다.
- 커널 스트리밍 필터 드라이버
- 오디오와 비디오 레코딩, 디스플레이 같은 데이터 스트림 상에서의 시그널 처리를 수행하기 위해 함께 연결되어 있다.
- 소프트웨어 드라이버
- 일부 유저 모드 프로세스를 대신해 커널 모드에서만 이뤄질 수 있는 동작을 수행하는 커널 모듈이다.
- Sysinternals 등의 많은 유틸리티가 정보를 수집하거나 유저 모드 API로는 수행이 불가능한 작업을 하기 위해 드라이버를 사용한다.
- 파일 시스템 필터 드라이버, 네트워크 리디렉터와 서버 등
윈도우 드라이버 모델
- WDM(Windows Driver Model)의 관점으로 볼때 세 가지 종류의 드라이버가 있다.
- 버스 드라이버: 버스 컨트롤러나 어댑터, 브리지, 자식 디바이스를 가진 디바이스에 서비스를 제공
- 펑션 드라이버: 메인 디바이스 드라이버로서 디바이스에 대한 동작 인터페이스를 제공
- 필터 드라이버: 디바이스나 기존 드라이버에 기능을 추가하거나 다른 드라이버로부터의 I/O 요청이나 응답을 수정하기 위해 사용
- WDM 드라이버 환경에서는 단일 드라이버가 디바이스의 모든 면을 제어하지 않는다. 펑션 드라이버가 디바이스를 조작하고, 버스 디바이스는 버스상의 디바이스를 PnP 관리자에 복로하는 작업에 관여한다.
- 대부분의 경우 저수준 필터 드라이버는 디바이스 하드웨어의 행위를 수정한다. 실제로 16개의 I/O 포트를 필요로 하는 디바이스가 버스 드라이버에게 4개의 I/O 포트가 필요하다고 보고하면 하위 레벨의 디바이스 펑션 필터 드라이버는 버스 드라이버로부터 PnP 관리자에게 보고되는 하드웨어 리소스 목록을 가로채 I/O 포트의 개수를 갱신할 수 있다.
- 상위 레벨 필터 드라이버는 보통 디바이스에 가치를 더하는 기능을 제공한다. 어떤 디스크를 위한 상위 레벨 디바이스 필터 드라이버는 부가적인 보안 점검을 강제할 수 있다.
윈도우 드라이버 파운데이션
- WDF(Windows Driver Foundation)은 커널 모드 드라이버 프레임워크(KMDF)와 유저 모드 드라이버 프레임워크(UMDF)라는 두 가지 프레임워크를 제공해 윈도우 드라이버 개발을 단순하게 한다.
- KMDF는 WDM에 대한 단순한 인터페이스를 제공하며, 하위 버스/펑션/필터 모델을 수정하지 않고도 드라이버 작성자로부터 KMDF의 복잡성을 감춘다.
- KMDF 라이브러리는 이벤트에 응답하고 자신들이 관리하는 하드웨어 한정적이지 않은 작업을 수행하기 위해 KMDF 라이브러리를 호출할 수 있다.
- UMDF는 비디오 카메라와 MP3 플레이어, 핸드폰, 프린터 같은 어떤 클래스의 드라이버가 유저 모드 드라이버로 구현되는 것을 가능하게 한다.
- 본질적으로 유저 모드 서비스에서 각 유저 모드 드라이버를 실행한다.
- 하드웨어에 대한 실제 접근을 제공하는 커널 모드 래퍼 드라이버와 통신하기 위해 ALPC를 ㅅ하용한다.
- UMDF 드라이버가 크래시되면 프로세스가 종료되고 다시 시작되므로, 시스템이 불안정해지지 않는다.
범용 윈도우 드라이버
- 범용 윈도우 드라이버(Universal Windows Drivers)라는 용어는 윈도우 10 공통 코어에 의해 제공되는 API와 디바이스 드라이버 인터페이스를 공유하는 디바이스 드라이버를 작성하기 위한 능력을 가리킨다.
- 이들 드라이버는 특정 CPU 아키텍처에 대해 바이너리 호환 가능하며, IoT 장치에서부터 폰과 홀로렌즈, Xbox One, 노트북 및 데스크톱에 이르기까지 다양한 폼 팩터로 사용될 수 있다.
설치된 디바이스 드라이버 살펴보기
문서화되지 않은 인터페이스 자세히 보기
- 핵심 시스템 이미지(
ntoskrnl.exe
,hal.dll
,ntdll.dll
등)에서 익스포트됐거나 글로벌 심볼에 있는 이름을 살펴보면 현재 문서화됐고 지원되고 있는 것보다 윈도우가 할 수 있는 일이 뭔가 더 있을 것이라는 생각이 든다.ntdll.dll
의 함수 목록을 살펴보면 각 서브시스템이 노출하는 부분집합에 대비해 윈도우가 유저 모드 서브시스템 DLL에 제공하는 전체 시스템 서비스 목록을 알 수 있다.- 윈도우 서브시스템 DLL의 임포트 루틴을 살펴보고 이들이
ntdll.dll
내의 어떤 함수를 호출하는지 조사해보는 것도 좋다.- 커널 모드 디바이스 루틴이 사용하는 익스포트된 루틴의 상당수가 문서화되어 있지만, 일부는 그렇지 않다.
- 윈도우 시스템 루틴의 명명 규칙은 다음과 같다.
<접두어><오퍼레이션><객체>
ExAllocatePoolWithTag
는 Paged Pool이나 Non-Paged Pool에 할당하는 익스큐티브 지원 루틴이다.KeInitializeThread
는 커널 스레드 객체를 할당하고 설정하는 루틴이다.
시스템 프로세스
- 다음의 시스템 프로세스는 모두 윈도우 10 시스템에 존재한다.
- 유휴 프로세스
- 시스템 프로세스와 안전한 시스템 프로세스, 메모리 압축 프로세스: 유저 모드 실행 파일을 실행하지 않는다는 점에서 완전한 프로세스가 아니며, 최소 프로세스로 불린다.
- 세션 관리자(
smss.exe
), 윈도우 서브시스템(csrss.exe
), 세션 0 초기화(wininit.exe
), 로그온 프로세스(winlogon.exe
) - 서비스 컨트롤 관리자(
services.exe
, 생성한 자식 서비스 프로세스(svchost.exe
등)) - 로컬 보안 인증 서비스(
lsass.exe
,lsaiso.exe
)
- 이들 프로세스의 연관 관계를 이해하기 위해 프로세스 간의 부모/자식 관계를 나타내는 프로세스 트리를 ProcMon으로 볼 수 있다.
시스템 유휴 프로세스
- 유휴 프로세스는 실제 유저 모드 이미지를 실행하지 않으며, 유휴 시간을 처리한다.
시스템 프로세스와 시스템 스레드
- 시스템 프로세스(PID 4)는 커널 모드에서만 동작하는 특별한 스레드의 집과 같은 곳이다.
- 시스템 스레드는 일반 유저 모드 스레드의 모든 속성과 컨텍스트를 가진다. 그러나
ntoskrnl.exe
나 다른 어떤 로드된 디바이스 드라이버든 시스템 공간에 로드된 커널 모드 실행 코드만을 동작시킨다는 것이 차이다. - 시스템 스레드는 유저 프로세스 주소 공간을 갖지 않으므로, Paged Pool이나 Non-Paged Pool과 같은 OS 메모리 힙으로부터 동적 스토리지를 할당해야만 한다.
- 시스템 스레드는
PsCreateSystemThread
와IoCreateSystemThread
함수에 의해 생성된다. 이들 함수는 커널 모드에서만 호출할 수 있다. - 윈도우는 다양한 디바이스 드라이버와 마찬가지로 시스템을 초기화하는 동안 I/O를 수행하거나, 객체를 대기하거나, 디바이스 폴링 같은 스레드 컨텍스트가 요구되는 동작을 수행하기 위해 시스템 스레드를 생성한다.
- 커널의 균형 세트 관리자: 스케줄링, 메모리 관리와 관련된 이벤트 구동
- 캐시 관리자: 선행 읽기나 후위 쓰기 I/O 구현
- 파일 서버 디바이스 드라이버: 네트워크로 공유된 디스크 파티션상의 파일 데이터에 대한 네트워크 I/O 요청 응답
- 플로피 드라이버: 플로피 디바이스 폴링
- 시스템 스레드는 시스템 프로세스에 의해 소유된다. 그러나 디바이스 드라이버는 어떤 프로세스에든 시스템 스레드를 생성할 수 있다.
안전한 시스템 프로세스
- 안전한 시스템 프로세스는 기술적으로 VTL 1 수준의 안전한 커널 주소 공간과 핸들, 시스템 스레드의 집에 해당한다.
- VTL 0 커널이 스케줄링과 객체 관리, 메모리 관리를 소유하고 실제로 이들은 안전한 시스템 프로세스와는 관계되지 않는다.
- 이 프로세스의 유일한 사용처는 사용자에게 VBS가 현재 동작중이라는 사실에 대한 시각적 표시를 제공하기 위함이다.
메모리 압축 프로세스
- 메모리 압축 프로세스는 특정 프로세스의 워킹셋으로부터 축출된 스탠바이 메모리에 해당하는 압축된 페이지를 저장하기 위해 자신의 유저 모드 주소공간을 이용한다.
- 안전한 시스템 프로세스와 달리 메모리 압축 프로세스는 일반적으로 흔히 볼 수 있는
SmKmStoreHelperWorker
와SmStReadThread
같은 다수의 시스템 스레드를 호스팅한다. 이들 두 스레드는 메모리 압축을 관리하는 저장소 관리자에 속한다. - 이 프로세스는 실제로 자신의 메모리를 유저 모드 주소 공간에 저장한다.
세션 관리자
- 세션 관리자(
smss.exe
)는 시스템에서 생성되는 첫 번째 유저 모드 프로세스이다. 익스큐티브와 커널 초기화의 마지막 시기를 수행하는 커널 모드 시스템 스레드는 이 프로세스를 생성한다. smss.exe
는 시작 시 자신이 첫 번째 인스턴스이거나 마스터smss.exe
가 세션을 생성하기 위해 시작시킨 인스턴스인지 검사한다. 커맨드라인이 존재하면 후자에 해당한다.smss.exe
는 부팅 동안 터미널 서비스 세션 생성 중 여러 인스턴스를 생성함으로써 동시에 다수의 세션을 생성할 수 있다.- 하나의 세션이 초기화를 마치면
smss.exe
의 복사본이 종료되며, 최초의smss.exe
만이 활성 상태로 남는다.
마스터 smss.exe
의 초기화 단계
- 프로세스와 최초 스레드를 임계 상태(Critical Process/Thread)로 표시한다. 임계 상태로 표시된 프로세스나 스레드가 종료되면 윈도우는 크래시된다.
- 프로세스로 하여금 유효하지 않은 핸들 사용과 힙 손상 등의 특정 오류를 임계 상황으로 처리하게 하고, 동적 코드 실행 비활성화 미티게이션을 활성화한다.
- 프로세스의 기본 우선순위를 11로 향상시킨다.
- 시스템이 핫 프로세서 추가를 지원한다면 자동 프로세서 친화성 갱신을 활성화한다. 이 경우 새로운 세션은 추가된 프로세서를 사용할 수 있다.
- ALPC 명령과 기타 워크 아이템을 처리할 스레드 풀을 초기화한다.
- 명령을 받을
\SmApiPort
ALPC 포트를 생성한다. - 시스템의 NUMA 토폴로지에 대한 로컬 복사본을 초기화한다.
- 파일 재명명 동작을 동기화하기 위한
PendingRenameMutex
뮤텍스를 생성한다. - 초기 프로세스 환경 블록을 생성하고 필요하다면 Safe Mode 변수를 갱신한다.
HKLM\SYSTEM\CurrentControlSet\Control\Session Manager
키의ProtectionMode
값에 기반을 두고 다양한 시스템 자원에 대해 사용될 보안 디스크립터를 생성한다.HKLM\SYSTEM\CurrentControlSet\Control\Session Manager
키의ObjectDirectories
값에 기반을 두고\RPC Control
과\Windows
라는 객체 관리자 디렉터리를 생성한다.BootExecute
와BootExecuteNoPnpSync
,SetupExecute
아래에 나열된 프로그램을 저장한다.HKLM\SYSTEM\CurrentControlSet\Control\Session Manager
키의S0InitialCommand
값에 나열된 프로그램 경로를 저장한다.HKLM\SYSTEM\CurrentControlSet\Control\Session Manager
키에서NumberOfInitialSessions
값을 읽는다.HKLM\SYSTEM\CurrentControlSet\Control\Session Manager
키의PendingFileRenameOperations
와PendingFileRenameOperations2
아래에 나열된 파일 재명명 동작을 읽는다.HKLM\SYSTEM\CurrentControlSet\Control\Session Manager
키의AllowProtectedRenames
와ClearTempFiles
,TempFileDirectory
,DisableWpbtExecution
값을 읽는다.HKLM\SYSTEM\CurrentControlSet\Control\Session Manager
키의ExcludeFromKnownDllList
값에서 DLLs 목록을 읽는다.HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management
키의PagingFiles
와ExistingPageFiles
목록 값,PagefileOnOsVolume
과WaitForPagingFiles
구성 값 같은 페이징 파일 정보를 읽는다.HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\DOS Devices
키에 저장된 값을 읽고 저장한다.HKLM\SYSTEM\CurrentControlSet\Control\Session Manager
키에 저장된KnownDlls
값 목록을 읽고 저장한다.HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment
에 정의된 시스템 전역 환경 변수를 생성한다.\KnownDlls
디렉터리를 생성하며,WoW64
를 가진 64비트 시스템에서는\KnownDlls32
디렉터리를 생성한다.- 객체 관리자 네임스페이스 내의
\Global??
아래HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Dos Devices
내에 정의된 장치에 대한 심볼릭 링크를 생성한다. - 객체 관리자 네임스페이스 내에
루트\Sessions
디렉터리를 생성한다. - 악의적 유저 모드 애플리케이션이 서비스의 시작 전에 실행될 경우에 발생할 수 있는 스푸핑 공격으로부터 서비스 애플리케이션을 보호하기 위한 보호 메일슬롯과 네임드 파이프 프리픽스를 생성한다.
- 이전에 파싱된
BootExecute
와BootExecuteNoPnpSync
목록의 프로그램 부분을 실행시킨다. (기본 프로그램은autochk.exe
) - 레지스트리의 나머지 부분을 초기화한다. (HKLM 소프트웨어와 SAM, 보안 하이브)
- 레지스트리에 의해 비활성화가 되지 않는다면 해당 ACPI 테이블에 등록된 윈도우 플랫폼 바이너리 테이블 바이너리를 실행한다.
- 윈도우 복구 환경의 부트가 아니라면 앞서 살펴본 레지스트리 키에 명시된 펜딩 파일 재명명 작업을 처리한다.
HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management
와HKLM\SYSTEM\CurrentControlSet\Control\CrashControl
키에 기반을 두고 페이징 파일과 전용 덤프 파일 정보를 초기화한다.- NUMA 시스템에서 사용되는 메모리 냉각 기술에 대한 시스템 호환성을 검사한다.
- 오래된 페이징 파일을 저장하고 크래시 전용 덤프 파일을 생성하며, 이전의 크래시 정보에 기반을 두고 필요한 새로운 페이징 파일을 생성한다.
PROCESSOR_ARCHITECTURE
와PROCESSOR_LEVEL
,PROCESSOR_IDENTIFIER
,PROCESSOR_REVISION
과 같은 추가적인 동적 환경 변수를 생성한다.HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\SetupExecute
에 있는 프로그램을 실행시킨다.smss.exe
와 교환되는 정보를 위해 자식 프로세스(예를 들면csrss.exe
)와 공유하는 언네임드 세션 객체를 생성한다. 이 섹션에 대한 핸들은 상속을 통해 자식 프로세스로 전달된다.- 이전의 레지스트리 검사에서 예외로 등록된 것들은 제외하고 알려진 DLL을 열고 영구 섹션으로 매핑한다.
- 세션 생성 요청에 대응하기 위한 스레드를 생성한다.
- 세션 0(비대화식 세션)을 초기화하기 위한
smss.exe
인스턴스를 생성한다. - 세션 1(대화식 세션)을 초기화하기 위한
smss.exe
인스턴스를 생성한다. 레지스트리에 구성이 되어 있다면 잠재적인 미래의 사용자 로그온에 미리 대비하기 위해 추가적인 대화식 세션 용도의smss.exe
인스턴스를 생성한다.smss.exe
가 이들 인스턴스를 생성할 때NtCreateUserProcess
에서 매번PROCESS_CREATE_NEW_SESSION
플래그를 사용해 새로운 세션 ID의 명시적 생성을 요청한다. 이는 내부 메모리 관리자 함수MiSessionCreate
를 호출하는 효과를 가진다. 이 함수는 필요한 커널 모드 세션 데이터 구조체(SessionObject
등)를 생성하고 윈도우 서브시스템(win32k.sys
)의 커널 모드 부분이 사용하느 ㄴ세션 공간 주소와 기타 세션 공간 디바이스 드라이버를 설정한다.- 이런 단계가 완료되면
smss.exe
는csrss.exe
의 세션 0 인스턴스에 대한 핸들을 무기한 대기한다.csrss.exe
는 임계 프로세스이므로 이 대기는 결코 완료되지 않는다.
- 이런 단계가 완료되면
smss.exe
의 세션 시작 인스턴스
- 세션을 위한 서브시스템 프로세스들을 생성한다. (
csrss.exe
) winlogon
(대화식 세션)이나 세션 0 이니셜 커맨드를 생성한다.- 이를 마지막으로 임시적인
smss.exe
프로세스는 종료한다. 서브시스템 프로세스와winlogon
,wininit
은 부모가 없는 프로세스인 채로 유지된다.
윈도우 초기화 프로세스
wininit.exe
프로세스는 다음과 같은 시스템 초기화 기능을 수행한다.- 자신과 메인 스레드를 임계 상태로 표시한다.
- 프로세스로 하여금 유효하지 않은 핸들 사용과 힙 손상 등의 특정 오류를 임계 상황으로 처리하게 한다.
- SKU가 상태 분리를 지원한다면 이에 대한 지원을 초기화한다.
- 어떤 WinLogon이 먼저 시작해야 하는지를 탐지하기 위해 WinLogon 프로세스가 사용할
Global\FirstLogonCheck
라는 이벤트를 생성한다. - WinLogon 인스턴스가 사용할
BasedNamedObjects
객체 관리자 디렉터리 내에WinlogonLogoff
이벤트를 생성한다. 이 이벤트는 로그오프 동작이 시작될 때에 시그널된다. - 자신의 프로세스 기본 우선순위를 13으로 상승시키고 자신의 메인 스레드 우선순위는 15로 상승시킨다.
HKLM\Software\Microsoft\Windows NT\CurrentVersion\Winlogon
키에NoDebugThread
레지스트리 값으로 정기적 타이머 큐를 생성한다. 이 타이머는 커널 디버거에 의해 명시된 유저 모드 프로세스로 디버깅이 이뤄지게 한다.- 환경 변수
COMPUTERNAME
에 머신 이름을 설정하고 도메인 이름과 호스트 이름 같은 TCP/IP 관련 정보를 갱신하고 구성한다. - 기본 프로파일 환경변수인
USERPROFILE
과ALLUSERSPROFILE
,PUBLIC
,ProgramData
를 설정한다. %SystemRoot%\Temp
를 확장해 임시 디렉터리를 생성한다.- 세션 0이 대화식 세션이라면 폰트 로딩과 DWM을 설정한다. (이는 SKU에 따라 다름)
- 세션 0에서 실행하는 프로세스를 위한 윈도우 스테이션(Winsta0)과 두 개의 데스크톱(Winlogon, Default)으로 구성된 최초의 터미널을 생성한다.
- 로컬에 저장됐는지 또는 대화식으로 입력을 받아야 하는지에 따라 LSA 머신 암호화 키를 초기화한다.
- 서비스 컨트롤 관리자(SCM 또는
service.exe
)를 생성한다. - 로컬 보안 인증 서브시스템 서비스(
lsass.exe
)를 시작한다. Credential Guard가 활성화되어 있다면 격리된 LSA 트러스트릿(lsaiso.exe
)을 시작한다. 이 또한 UEFI로부터 VBS 권한 설정 키를 질의해야 한다. - 셋업이 현재 펜딩 상태라면 셋업 프로그램을 시작한다. (최초 설치되는 동안에 처음 시작되는 부트이거나 주요 OS 빌드 업데이트라면)
- 시스템 종료 요청이나 앞서 언급한 시스템 프로세스 중 하나가 종료하기를 무기한 대기한다.
서비스 컨트롤 관리자
- 서비스는 대화식 로그온 없이 시스템 부트 타임에 자동으로 실행되도록 구성 가능하다는 점에서 리눅스의 데몬 프로세스 같은 것이다. 이는 수동으로 시작할 수 있다.
- 일반적으로 서비스는 특수한 조건하에서 로그인된 사용자와 상호작용할 수 있지만, 이들과 상호작용하지 않는다.
- 대부분의 서비스는 특수한 서비스 계정(SYSTEM이나 LOCAL_SERVICE 등)에서 실행하더라도 여타 서비스는 사용자 계정으로 로그인한 것과 동일한 보안 컨텍스트로 실행할 수 있다.
- 서비스 컨트롤 관리자(SCM)는 서비스 프로세스에 대한 시작과 중지, 상호작용에 대한 책임이 있는
%SystemRoot%\System32\Services.exe
이미지를 실행하는 특별한 시스템 프로세스이며, 보호 프로세스이다.- 서비스 프로그램은 실제로 서비스의 성공적인 시작이나 상태 요청에 대한 응답, 일시 중지, 서비스 종료 같은 동작을 수행하기 위해 SCM과 상호작용하는 특별한 윈도우 함수를 호출하는 윈도우 이미지이다.
- 서비스는
HKLM\SYSTEM\CurrentControlSet\Services
레지스트리 아래에 정의되어 있다.
- 다수의 윈도우 컴포넌트는 프린터 스풀러와 이벤트 로그, 작업 스케줄러, 다양한 네트워크 컴포넌트 같은 서비스로 구현되어 있다.
- 설치된 서비스를 나열하려면 제어판에서 관리 툴을 선택하고 서비스를 선택하거나, 시작에서
services.msc
를 실행한다. - 서비스는 다른 서비스와 프로세스를 공유할 수도 있다. 항상 1대1로 대응되지 않는다.
Winlogon과 LogonUI, Userinit
- 윈도우 로그온 프로세스(
winlogon.exe
)는 대화식 유저 로그온과 로그오프를 처리한다.- 사용자가 보안 주의 시퀀스(SAS; Secure Attention Sequence) 키 입력 조합을 입력할 때 유저 로그온 요청을 통지받는다. 윈도우의 기본 SAS는 Ctrl + Alt + Delete이다.
- SAS가 존재하는 이유는 이 키 입력이 유저 모드 프로그램에 의해 가로채질 수 없기 때문에 로그온 프로세스를 흉내내는 패스워드 가로채기 프로그램으로부터 사용자를 보호하기 위함이다.
- 로그온 프로세스의 식별과 인증과 인증 부분은 자격증명 제공자(Credential Providers)로 불리는 DLL을 통해 구현된다.
- 표준 윈도우 자격증명 제공자는 기본 윈도우 인증 인터페이스인 패스워드와 스마트카드를 구현한다.
- 윈도우 10은 생체 인식 자격증명 제공자(Windows Hello)를 제공한다. 그렇지만 개발자는 표준 윈도우 사용자 이름/비밀번호 방법을 대체하는 다른 식별이나 인증 메커니즘을 구현하기 위해 고유한 자격증명 제공자를 제공할 수 있다.
winlogon.exe
는 시스템이 의존하고 있는 민감한 시스템 프로세스이므로 자격증명 제공자와 로그온 대화상자를 나타내기 위한 UI는logonUI.exe
라고 하는winlogon.exe
의 자식 프로세스 내부에서 실행된다.- 사용자가 자신들의 자격증명을 입력하거나 로그온 인터페이스를 해제할 때
logonUI.exe
프로세스는 종료된다.
- 사용자가 자신들의 자격증명을 입력하거나 로그온 인터페이스를 해제할 때
winlogon.exe
는 2차 인증을 수행하기 위해 필요한 부가적인 네트워크 공급자 DLL을 로드할 수 있다. 이 기능을 통해 다중 네트워크 공급자는 로그온 동안 한 번에 모든 식별과 인증 정보를 모을 수 있다.- 사용자 이름과 비밀번호가 캡처되고 나면 인증을 받기 위해 로컬 보안 인증 서비스 프로세스(
lsass.exe
)로 보내진다.lsass.exe
는 액티브 디렉토리나 SAM에 저장되어 있는 것과 비밀번호가 일치하는지와 같은 실제 검증을 수행하기 위해 DLL로 구 현된 적절한 인증 패키지를 호출한다. - 인증이 성공하면
lsass.exe
는 사용자의 보안 프로파일을 담고 있는 접근 토큰 객체를 생성하기 위해 보안 참조 모니터(SRM)의 함수(예를 들면NtCreateToken
)를 호출한다. - UAC가 사용되고 있고 로그온한 사용자가 관리자 그룹이나 관리자 특권을 가지고 있다면
lsass.exe
는 두 번째 토큰의 제한된 버전을 생성한다. 이후 이 접근 토큰은 사용자의 세션에 초기 프로세스를 생성하기 위해 WinLogon에 의해 사용된다.- 초기 프로세스는
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon
레지스트리 키 아래에 있는 값Userinit
에 저장되어 있다. - 기본 값은
userinit.exe
이며, 하나 이상의 이미지가 리스트에 있을 수 있다.
- 초기 프로세스는
userinit.exe
는 사용자 환경 초기화(로그인 스크립트 실행, 네트워크 연결 재설정 등)를 수행하고, 레지스트리의Shell
값을 살핀 후 시스템에 정의된 셸을 실행하기 위한 프로세스(기본값은explorer.exe
)를 생성한다. 이후userinit.exe
는 종료된다. 이것이 바로 탐색기의 부모가 나타나지 않는 이유다.winlogon.exe
는 사용자의 로그온과 로그오프 과정뿐만 아니라 키보드로부터 SAS를 가로챌 때마다 활성화된다. 로그온돼 있을 때 Ctrl + Alt + Delete를 누르면 옵션으로 로그오프와 작업 관리자 실행, 워크스테이션 잠금, 시스템 종료 등을 제공하는 윈도우 보안 대화상자가 나타난다.
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.