본문 바로가기
카테고리 없음

[WebBook] 윈도우 구조 - 시스템 프로세스(Windows Startup Process) - 서브시스템 관리자 Csrss.exe

by 올엠 2022. 2. 28.
반응형

Client-Server Runtime Subsystem의 약자로, 앞서 Smss가 로드하는 3개의 서브시스템 중 하나로,  윈도우 서브시스템이라고도 불리우며, 윈도우상에서 실행되는 프로세스와 스레드들의 관리를 담당한다.
Csrss.exe(이하 Csrss)는 실행시 Basesrv.dll(Microsoft Windows NT Base API Server Library), Winsrv.dll(Windows Server Library), Csrsrv.dll(Client Server Runtime Process)을 로드하여 콘솔 윈도우(Console windows) 처리, 프로세스와 스레드 생성과 삭제, 16비트 가상 DOS 머신(VDM) 프로세스를 위한 기능 일부 및 SxS(Side-by-Side)를 지원하게 된다. 이와 관련하여 제공하는 API 리스트는 http://j00ru.vexillium.org/csrss_list/api_list.html에서 확인할 수 있다.
Csrss는 윈도우 시스템 프로세스로서 프로세스와 스레드의 설정을 담당하여, 현재 윈도우에서 실행되는 프로세스와 스레드 리스트를 관리하고 예외 처리 포트(13장 디스패칭에서 다룬다)를 생성하는 등, 사용자의 윈도우 환경을 관리하는 윈도우 서브시스템으로서 중요한 위치를 차지하는 프로세스라 할 수 있다. 그리고 Smss와 같이 네이티브 어플리케이션이다. 아래 그림의 프로세스 생성 과정을 통해 Csrss를 조금 더 쉽게 이해할 수 있을 것이다.

프로세스 생성 과정

Csrss에 대한 정보는 다음 레지스트리에서 설정값을 확인할 수 있다.

 

 HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\SubSystems\Windows

 

그리고 Csrss은 다른 서브시스템들과 빠른 통신을 위해 레지스트리 ServerDll에 등록된 Dll을 통해 LPC(Local Inter-Process Communication)로 처리를 하게 된다. LPC는 서브시스템 간 통신 사용 방식으로 바로 다음에 설명하겠다.

%SystemRoot%\system32\Csrss.exe

ObjectDirectory=\Windows
SharedSection=1024,3072,512
Windows=On
SubSystemType=Windows
ServerDll=basesrv,1
ServerDll=winsrv:UserServerDllInitialization,3 
ServerDll=winsrv:ConServerDllInitialization,2
ProfileControl=Off
MaxRequestThreads=16

추가로 사용자의 세션과 관련된 Desktop-Heap을 이해해야 Csrss를 온전히 이해하는 데 도움이 된다. 이는 추후 메모리 관리를 설명할 때 다시 다룰 예정으로 여기서는 이 정도만 설명하고, Csrss가 이용하는 LPC에 대해 확인해 보도록 하자.

 

LPC

LPC는 응용프로그램이 Csrss와 통신하거나, SRM(Security Reference Monitor’s) 및 Winlogon이 Lsass와 정보를 주고 받고자 할때, 그리고 고속으로 서로 다른 구조에서 데이터를 교환하고자 할때 사용된다(서로 다른 구조란 서로 다른 2개의 프로세스, 스레드를 뜻한다). 비스타부터는 강제로 동기화 방식으로 진행되던 LPC를 비동기화 방식으로 진행하는 방법도 새롭게 추가하였는데, 이를 ALPC(Asynchronous Local Inter-Process Communication)라고 한다.
이외에 RPC(Remote Procedure Call)라는 용어도 윈도우에서 종종 접할 수 있는데, 이는 LPC와 방식은 흡사하지만 서로 다른 기기에 위치(네트워크 적으로)하고 있을 때 사용되는 통신 방식을 RPC라 한다. 그럼 LPC 통신 흐름을 그림으로 살펴보자.

LPC 에 사용되는 API와 처리 흐름

위 그림에서 얘기하는 클라이언트는 요청자가 되고, 서버는 제공자라 할 수 있다. Lsass와 SRM을 비교한다면, Lsass가 요청자가 되고 SRM은 서버, 즉 제공자가 된다.
아래는 LPC에서 제공하는 Native API들로서, LPC에는 아래와 같은 API를 이용하여 서로 통신을 진행한다. 이 API들은 Ntdll.dll과 Ntoskrnl.exe를 통해 제공되며, 응용프로그램에서 직접 LPC를 사용할 수 없다.

API 설명
NtCreatePort 서버가 포트를 생성할 때 사용한다.
NtConnectPort 클라이언트가 포트 연결할 때 사용한다.
NtListenPort 서버에서 연결된 리스트를 요청이 왔을 때 사용한다.
NtAcceptConnectPort 서버에서 연결 허용 요청을 수락할 때 사용한다.
NtCompleteConnectPort 서버에서 연결 요청에 대한 연결이 완료되었을 때 사용한다.
NtRequestPort 메시지를 보내고 회신을 기다리지 않는다.
NtRequestWaitReplyPort 메시지를 보내고 회신을 기다린다.
NtReplyPort 회신 메시지를 보낸다.
NtReplyWaitReplyPort 회신 메시지를 보내고, 응답을 기다린다.
NtReplyWaitReceivePort 서버에서 회신 메시지를 보내고, 클라이언트의 응답을 기다린다.
NtImpersonateClientOfPort 서버 스레드에 의해 사용되며, 클라이언트 스레드의 보안 컨테스트를 임시로 획득한다.

Windbg에서 LPC 상태를 효과적으로 확인할 수 있는 확장 명령을 제공하는데, 바로 !lpc 명령에 파라미터를 추가하여 사용할 수 있다. 각 옵션들에 대해 아래와 같이 정리하였다.

파라미터 설명
message [id] 큐 안의 메시지 내용을 표시해 준다. 메시지ID를 주지 않으면 전체를 보여준다.
port [portaddress] 포트 상태 정보를 보여준다. 포트 어드레스 주소값를 주지 않으면 전체를 보여 준다.
scan portaddress 지정한 포트 어드레스 주소에서 오브젝트 타입이 “Port”거나 “WaitablePort”인 포트 정보를 보여준다.
thread [threadaddress] ETHREAD LpcReplyChain의 오브젝트가 “Port”거나 “WaitablePort”인 스레드는 회신을 기다리게 되는데, 전체 스레드에서 LpcReceivedMessageId, LpcReplyMessageId가 동일한Port 정보를 보여준다. 특정 스레드를 주지 않으면 전체를 보여준다.
poolsearch Kernel Pool에서 LPC tag (“LpcM”)로 되어 있는 내용을 “lpc message” 방식으로 검색하여 보여준다.

Windbg에서 위 옵션을 이용해 LPC 정보를 확인할 수 있다. 만약 LPC 통신을 이용하던 도중 장애가 발생하였다면, !lpc 명령을 이용하여 어디에서 대기(Wait) 상태가 지속되는지를 문제점을 확인할 수 있다. 아래는 Windbg를 통해 대기 상태인 스레드의 LPC 내용을 확인하는 과정이다.

// LPC를 사용중인 스레드를 확인해보자.
kd> !lpc thread
Searching message 0 in threads ...
    Server thread 81d17020 is working on message aea                         
Client thread 81da4020 waiting a reply from cff                          
    Server thread 81d08478 is working on message 1053                         
    Server thread 81ceb660 is working on message ac4                         
    Server thread 81af2920 is working on message cff                         
    Server thread 81aef020 is working on message b3b                         
    Server thread 81e08da8 is working on message 8a1                         
    Server thread 81cfada8 is working on message cf6                         
    Server thread 81bbb020 is working on message 1042                         
    Server thread 81bdbab8 is working on message 51d                         
    Server thread 81b45b30 is working on message 102f                         
    Server thread 81d1c560 is working on message 906                         
    Server thread 81d15da8 is working on message 1041                         
    Server thread 81d4dda8 is working on message 103d                         
    Server thread 81b45020 is working on message 1043                         
Done.                                              
.// 대기중인 스레드의 LPC ID는 스레드 정보를 통해서도 확인할 수 있다.                                              
kd> !thread 81da4020
THREAD 81da4020  Cid 0284.028c  Teb: 7ffde000 Win32Thread: e16f1848 WAIT: (WrLpcReply) UserMode Non-Alertable
    81da4214  Semaphore Limit 0x1
Waiting for reply to LPC MessageId 00000cff:
Current LPC port e1b92380
Not impersonating
DeviceMap                 e10087c0
Owning Process            0       Image:         <Unknown>
Attached Process          81ce8da0       Image:         Csrss.exe
Wait Start TickCount      1909           Ticks: 795 (0:00:00:07.961)
Context Switch Count      7                 LargeStack
UserTime                  00:00:00.000
KernelTime                00:00:00.000
Start Address 0x764c7d63
Stack Init f4f1a000 Current f4f19c50 Base f4f1a000 Limit f4f17000 Call 0
Priority 15 BasePriority 15 PriorityDecrement 0 DecrementCount 0
ChildEBP RetAddr  Args to Child              
f4f19c68 804de0f7 81da4090 81da4020 804de143 nt!KiSwapContext+0x2e (FPO: [Uses EBP] [0,0,4])
f4f19c74 804de143 81da4214 81da41e8 81da4020 nt!KiSwapThread+0x46 (FPO: [0,0,0])
f4f19c9c 80578fc6 00000001 00000011 81da4001 nt!KeWaitForSingleObject+0x1c2 (FPO: [Non-Fpo])
f4f19d50 804e07ec 00000084 0050ff00 0050ff00 nt!NtRequestWaitReplyPort+0x63d (FPO: [Non-Fpo])
f4f19d50 7c93e4f4 00000084 0050ff00 0050ff00 nt!KiFastCallEntry+0xf8 (FPO: [0,0] TrapFrame @ f4f19d64)
WARNING: Frame IP not in any known module. Following frames may be wrong.
0050fff4 00000000 00000000 00000000 00000000 0x7c93e4f4
// LPC의 message 옵션을 통해 세부적인 LPC 메시지 내용 및 상태 확인이 가능하다.
// 현재 사용중인 포트 정보와 연결 포트 값, 대기 큐 리스트등을 확인할 수 있다.
kd> !lpc message 00000cff
Searching message cff in threads ...
Client thread 81da4020 waiting a reply from cff                          
    Server thread 81af2920 is working on message cff                         
Searching thread 81da4020 in port rundown queues ...

Server communication port 0xe16ea378
    Handles: 1   References: 1
    The LpcDataInfoChainHead queue is empty  현재 대기 큐가 없음을 나타낸다.
        Connected port: 0xe1b92380      Server connection port: 0xe1721468  연결 포트와 서버 포트 정보

Client communication port 0xe1b92380  클라이언트 포트 정보
    Handles: 1   References: 2
    The LpcDataInfoChainHead queue is empty

Server connection port e1721468  Name: SmSsWinStationApiPort
    Handles: 1   References: 11
    Server process  : 81d402d8 (svchost.exe)
    Queue semaphore : 81b7f778
    Semaphore state 0 (0x0) 
    The message queue is empty
    The LpcDataInfoChainHead queue is empty
Done.

 

반응형