Microsoft MVP성태의 닷넷 이야기
Windows: 274. Windows 7부터 도입한 conhost.exe [링크 복사], [링크+제목 복사],
조회: 5026
글쓴 사람
정성태 (seongtaejeong at gmail.com)
홈페이지
첨부 파일
 

(시리즈 글이 2개 있습니다.)
Windows: 274. Windows 7부터 도입한 conhost.exe
; https://www.sysnet.pe.kr/2/0/13832

Windows: 275. C# - CUI 애플리케이션과 Console 윈도우 (Windows 10 미만의 Classic Console 모드인 경우)
; https://www.sysnet.pe.kr/2/0/13834




Windows 7부터 도입한 conhost.exe

근래의 윈도우 운영체제 환경에서 콘솔 프로그램을 실행할 때 이와 함께 연달아 뜨는 conhost.exe라는 프로세스를 본 적이 있을 것입니다. 그러게요, conhost.exe 프로세스가 도대체 뭘까요? 이에 대해 검색해 보면, 아래의 글에서 아주 상세하게 설명해 주고 있습니다.

What Is conhost.exe and Why Is It Running?
; https://www.howtogeek.com/4996/what-is-conhost.exe-and-why-is-it-running/

Windows XP까지만 해도, "Command Prompt" Console은 csrss.exe 프로세스(CSRSS: ClientServer Runtime System Service)가 담당했다고 합니다. 이로 인해 몇 가지 문제가 있었다고 하는데요, 1) csrss.exe 프로세스에 문제가 생기면 Console 조차도 띄울 수 없는 상황이 발생했고, 2) csrss.exe 프로세스가 높은 권한을 가지고 있어서 일부 문제는 보안 취약점으로 이어질 수도 있고, 3) 시스템 프로세스에 속하는 csrss 내에 User Interface와 관련된 테마(Theme)를 다루는 코드를 넣을 수 없어 이후 윈도우 버전이 올라가면서 바뀌는 UI 테마를 Console에는 반영할 수 없었다고 합니다.

csrss 개발팀이 UI 테마 코드를 시스템 프로세스 내에 넣는 것을 원치 않았다고는 하지만, 만약 오직 문제가 UI 테마 하나였다면 아마도 ^^ 구겨 넣지 않았을까 싶습니다. 하지만, 여러 가지 문제가 있었기 때문에 Console 기능을 별도의 프로세스로 분리하기로 결정한 것이 아닌가 생각됩니다.

실제로 XP 당시의 이미지를 보면 메모장과는 달리 cmd.exe 창은 XP 테마가 없습니다.

[출처: What Is conhost.exe and Why Is It Running?]
con_host_0.png

이후, Vista의 Desktop Window Manager(DWM)에서는 다행히 중간 처리 단계에서 "Command Prompt" 창에 부분적으로 테마를 적용할 수 있게 되었지만 그래도 여전히 csrss에서 담당하는 UI는 테마 적용이 안 됐습니다.

[출처: What Is conhost.exe and Why Is It Running?]
(창의 프레임 영역은 테마가 적용, 스크롤바 영역은 미적용)
con_host_1.png

그리고 마침내, Windows 7에서 "Console Window Host Process"를 도입해 csrss.exe로부터 "윈도우 호스트" 부분을 독립시킴으로써 테마 문제를 (보안/안정성 문제까지 한꺼번에) 해결했습니다. 바로 그 프로세스가 conhost.exe로 cmd.exe와 csrss.exe 사이의 중간 계층으로 동작한다고 합니다. 일례로, Windows XP/Server 2003에서 cmd.exe나 콘솔 앱을 실행하면,

cmd.exe
ConsoleApp1.exe

위와 같이 그 프로세스만 뜨고, 해당 프로세스 공간에서 함께 뜨는 콘솔 윈도우는 내부적으로 csrss.exe 측에서 관리를 하게 됩니다. 반면 Windows Server 2008 R2에서 콘솔 앱을 실행하면,

csrss.exe
   |- conhost.exe (cmd.exe와 연결)
   ㄴ conhost.exe (ConsoleApp1.exe와 연결)

cmd.exe
ConsoleApp1.exe

콘솔 응용 프로그램 하나에 대해 그와 상응하는 conhost.exe가 csrss.exe의 자식 프로세스로 뜨는데요, 이후 Windows Server 2012 R2에서는 그마저도 개별 프로세스의 하위에 뜨는 것으로 바뀌었습니다.

cmd.exe
   ㄴ conhost.exe

ConsoleApp1.exe (탐색기 등을 이용해 실행)
   ㄴ conhost.exe

cmd.exe (cmd.exe 환경에서 ConsoleApp1.exe 실행한 경우 conhost.exe를 공유)
   |- conhost.exe
   ㄴ ConsoleApp1.exe

conhost.exe에 대한 마이크로소프트의 공식 문서도 "What Is conhost.exe and Why Is It Running?" 글의 내용과 유사합니다.

Console Host
; https://learn.microsoft.com/en-us/windows/console/definitions#console-host

The Windows Console Host, or conhost.exe, is both the server application for all of the Windows Console APIs as well as the classic Windows user interface for working with command-line applications. The complete contents of this binary, both the API server and the UI, historically belonged to Windows csrss.exe, a critical system process, and was diverged for security and isolation purposes.


그리고 위의 글을 훨씬 자세하게 풀어쓴,

Windows Command-Line: Inside the Windows Console
; https://devblogs.microsoft.com/commandline/windows-command-line-inside-the-windows-console/

블로그에 담긴 아래의 그림이 모든 것을 설명해 줍니다.

[출처: Windows Command-Line: Inside the Windows Console]
con_host_2.png

먼저, 저 그림의 하단에 있는 ConDrv(condrv.sys)는 Console과 "Headless" 명령행 응용 프로그램이 연동하는 것을 나타냅니다. 즉, CUI 응용 프로그램의 I/O를 conhost.exe의 API Server로 연결해 주는 역할을 하는 것입니다.

사실 condrv.sys는 Windows 7 당시에는 없었고, Windows 8/Windows Server 2012 R2부터 도입됐는데요, 따라서 그전에는 아마도 속도가 느린 IPC 수단을 이용해 통신을 한 듯합니다. (그러고 보면, 마이크로소프트는 어떻게든 성능을 높이기 위해 커널 레벨로 내리는 것을 선호하는 경향이 종종 있습니다. ^^)

그림의 상단 영역에 있는 ConHost.exe 박스를 볼까요?

비록 해당 그림에서 ConHost.exe의 박스 안에 "Console UI App Services"라고 그려져 있어 자칫 프로세스 내부에서 Console 윈도우를 생성한다고 생각할 수 있는데, 실제로 테스트해 보면 ConsoleWindowClass에 해당하는 윈도우는 명령행 응용 프로그램의 프로세스 공간에서 생성됩니다. 그 윈도우와 conhost.exe가 어떻게 통신하는지는 모르겠지만, 어쩄든 그 윈도우의 관리 코드 자체는 ConHost.exe에 있다고 봐야 할 것이고 그 구성 요소 이름을 "Console UI App Services"라고 명명한 듯합니다.

이후, "Console"에 사용자가 입력한 텍스트, 가령 Console.ReadLine 코드의 수행으로 입력한 텍스트는 "Input Buffer"로 들어가 Console API를 거쳐 "Output Buffer"로 나온다고 합니다. 이때 Output Buffer는 (간략하게 보자면) CHAR_INFO 구조체 배열로 보면 되고, 그 "Output Buffer"로부터 GDI Renderer를 통해 화면으로 그려지는 명령이 다시 ConsoleWindowClass로 전달돼 최종적으로 Console 화면에 그려지는 것입니다. 이와 함께 "Console"에 사용자가 입력한 텍스트는 "API Server"를 거쳐 ConDrv의 IOCTL로 중계로 응용 프로그램에 전달됩니다. 다시 말해 Console.ReadLine의 결과가 반환되는 것입니다.

그리고 또 하나의 입력 방식이 있는데요, 바로 응용 프로그램이 ConDrv를 통해 전달하는 출력입니다. 가령 Console.WriteLine을 하면, 이것은 다시 ConDrv를 거쳐 IOCTL로 변환돼 "API Server"로 전달되고 "Console API"를 통해 "Output Buffer"로 표현됩니다. 만약 이 과정에서 Console.WriteLine에 VT Sequence가 포함돼 있다면, 이것은 VT Parser를 한 번 더 거쳐 "Output Buffer"로 전달됩니다.

그러니까, 바로 저 "VT Parser"가 추가된 덕분에 윈도우에서 VT Sequence를 제대로 처리할 수 있게 된 것입니다. 하지만 이것도 버전에 따라 다른데요, 아래의 그림에서처럼,

[출처: Windows Command-Line: Inside the Windows Console]
con_host_3.png

As discussed above, Windows Console provides a rich API. Using the Console API, Command-Line apps and tools write text, change text colors, move the cursor, etc. And, because of the Console API, Windows Console had little need to support ANSI/VT sequences that provide very similar functionality on other platforms. In fact, until Windows 10, Windows Console only implemented the bare minimum support for ANSI/VT sequences: ...[생략]... The Console team added comprehensive support for ANSI/VT sequences to Windows 10's Console, ...[생략]...


Windows 7에서는 기본적인 VT Sequence만 지원했고 이후 Windows 10이 돼서야 제대로 지원을 하게 됐다고 합니다.




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]







[최초 등록일: ]
[최종 수정일: 11/29/2024]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... 61  62  63  64  65  66  67  68  69  70  71  72  [73]  74  75  ...
NoWriterDateCnt.TitleFile(s)
12111정성태1/12/202020540디버깅 기술: 155. C# - KernelMemoryIO 드라이버를 이용해 실행 프로그램을 숨기는 방법(DKOM: Direct Kernel Object Modification) [16]파일 다운로드1
12110정성태1/11/202019850디버깅 기술: 154. Patch Guard로 인해 블루 스크린(BSOD)가 발생하는 사례 [5]파일 다운로드1
12109정성태1/10/202016582오류 유형: 588. Driver 프로젝트 빌드 오류 - Inf2Cat error -2: "Inf2Cat, signability test failed."
12108정성태1/10/202017421오류 유형: 587. Kernel Driver 시작 시 127(The specified procedure could not be found.) 오류 메시지 발생
12107정성태1/10/202018602.NET Framework: 877. C# - 프로세스의 모든 핸들을 열람 - 두 번째 이야기
12106정성태1/8/202019636VC++: 136. C++ - OSR Driver Loader와 같은 Legacy 커널 드라이버 설치 프로그램 제작 [1]
12105정성태1/8/202018140디버깅 기술: 153. C# - PEB를 조작해 로드된 DLL을 숨기는 방법
12104정성태1/7/202019346DDK: 9. 커널 메모리를 읽고 쓰는 NT Legacy driver와 C# 클라이언트 프로그램 [4]
12103정성태1/7/202022465DDK: 8. Visual Studio 2019 + WDK Legacy Driver 제작- Hello World 예제 [1]파일 다운로드2
12102정성태1/6/202018803디버깅 기술: 152. User 권한(Ring 3)의 프로그램에서 _ETHREAD 주소(및 커널 메모리를 읽을 수 있다면 _EPROCESS 주소) 구하는 방법
12101정성태1/5/202019066.NET Framework: 876. C# - PEB(Process Environment Block)를 통해 로드된 모듈 목록 열람
12100정성태1/3/202016547.NET Framework: 875. .NET 3.5 이하에서 IntPtr.Add 사용
12099정성태1/3/202019418디버깅 기술: 151. Windows 10 - Process Explorer로 확인한 Handle 정보를 windbg에서 조회 [1]
12098정성태1/2/202019154.NET Framework: 874. C# - 커널 구조체의 Offset 값을 하드 코딩하지 않고 사용하는 방법 [3]
12097정성태1/2/202017217디버깅 기술: 150. windbg - Wow64, x86, x64에서의 커널 구조체(예: TEB) 구조체 확인
12096정성태12/30/201919880디버깅 기술: 149. C# - DbgEng.dll을 이용한 간단한 디버거 제작 [1]
12095정성태12/27/201921592VC++: 135. C++ - string_view의 동작 방식
12094정성태12/26/201919339.NET Framework: 873. C# - 코드를 통해 PDB 심벌 파일 다운로드 방법
12093정성태12/26/201918904.NET Framework: 872. C# - 로딩된 Native DLL의 export 함수 목록 출력파일 다운로드1
12092정성태12/25/201917666디버깅 기술: 148. cdb.exe를 이용해 (ntdll.dll 등에 정의된) 커널 구조체 출력하는 방법
12091정성태12/25/201919969디버깅 기술: 147. pdb 파일을 다운로드하기 위한 symchk.exe 실행에 필요한 최소 파일 [1]
12090정성태12/24/201920082.NET Framework: 871. .NET AnyCPU로 빌드된 PE 헤더의 로딩 전/후 차이점 [1]파일 다운로드1
12089정성태12/23/201919029디버깅 기술: 146. gflags와 _CrtIsMemoryBlock을 이용한 Heap 메모리 손상 여부 체크
12088정성태12/23/201917971Linux: 28. Linux - 윈도우의 "Run as different user" 기능을 shell에서 실행하는 방법
12087정성태12/21/201918439디버깅 기술: 145. windbg/sos - Dictionary의 entries 배열 내용을 모두 덤프하는 방법 (do_hashtable.py) [1]
12086정성태12/20/201920958디버깅 기술: 144. windbg - Marshal.FreeHGlobal에서 발생한 덤프 분석 사례
... 61  62  63  64  65  66  67  68  69  70  71  72  [73]  74  75  ...