Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
(연관된 글이 7개 있습니다.)
(시리즈 글이 2개 있습니다.)
VC++: 143. ionescu007/lxss github repo에 공개된 lxssmanager.dll의 CLSID_LxssUserSession/IID_ILxssSession 사용법
; https://www.sysnet.pe.kr/2/0/12676

VC++: 144. 역공학을 통한 lxssmanager.dll의 ILxssSession 사용법 분석
; https://www.sysnet.pe.kr/2/0/12677




ionescu007/lxss github repo에 공개된 lxssmanager.dll의 CLSID_LxssUserSession/IID_ILxssSession 사용법

아래의 글을 쓸 때까지만 해도,

Wslhub.Sdk 사용으로 알아보는 CoInitializeSecurity 사용 제약
; https://www.sysnet.pe.kr/2/0/12665

lxssmanager.dll에서 제공하는 CLSID_LxssUserSession/IID_ILxssSession COM 개체가 공개된 건 줄 알았습니다. ^^; 하지만, 비공개였고 그나마 찾은 자료는 github의 개인 repo였습니다. (WSL이 오픈소스로 공개되긴 했지만 ILxssSession 관련 부분은 아직 비공개입니다.)

ionescu007/lxss
; https://github.com/ionescu007/lxss

lxss/inc/lxssmanager.h
; https://github.com/ionescu007/lxss/blob/master/inc/lxssmanager.h

lxss/lxlaunch/lxlaunch.cpp
; https://github.com/ionescu007/lxss/blob/master/lxlaunch/lxlaunch.cpp

wslbridge2/src/LxssUserSession.hpp
; https://github.com/Biswa96/wslbridge2/blob/master/src/LxssUserSession.hpp

저 repo의 저작자는 나름의 역공학을 통해 그 결과를 공유해 주고 있는데요, 해당 자료를 COM 방식으로 정리하면 다음과 같이 요약될 수 있습니다.

#pragma once

#include <initguid.h>

DEFINE_GUID(CLSID_LxssManager, 0x4F476546, 0xB412, 0x4579, 0xB6, 0x4C, 0x12, 0x3D, 0xF3, 0x31, 0xE3, 0xD6);

typedef struct _LXSS_STD_HANDLE
{
    ULONG Handle;
    BOOLEAN Pipe;
} LXSS_STD_HANDLE, * PLXSS_STD_HANDLE;

typedef struct _LXSS_CONSOLE_DATA_V2
{
    ULONG ConsoleHandle;
} LXSS_CONSOLE_DATA_V2, * PLXSS_CONSOLE_DATA_V2;

typedef struct _LXSS_CONSOLE_DATA
{
    ULONG InputHandle;
    ULONG OutputHandle;
    ULONG ControlHandle;
    USHORT Width;
    USHORT Height;
} LXSS_CONSOLE_DATA, * PLXSS_CONSOLE_DATA;

typedef struct _LXSS_STD_HANDLES
{
    LXSS_STD_HANDLE StdIn;
    LXSS_STD_HANDLE StdOut;
    LXSS_STD_HANDLE StdErr;
} LXSS_STD_HANDLES, * PLXSS_STD_HANDLES;

interface ILxInstance;

MIDL_INTERFACE("536A6BCF-FE04-41D9-B978-DCACA9A9B5B9") ILxssSession : IUnknown
{
    STDMETHOD(GetCurrentInstance)(ILxInstance** pInstanceOut);
    STDMETHOD(StartDefaultInstance)(_In_ const IID& InstanceIid, _Out_ PVOID* InstanceOut);
    STDMETHOD(SetState)(/* unknown */);
    STDMETHOD(QueryState)(/* unknown */);
    STDMETHOD(InitializeFileSystem)(/* unknown */);
    STDMETHOD(Destroy)(/* unknown */);
};

MIDL_INTERFACE("8f9e8123-58d4-484a-ac25-7ef7d5f7448f") ILxInstance : IUnknown
{
    STDMETHOD(GetConfiguration)(/* unknown */);
    STDMETHOD(GetId)(/* unknown */);
    STDMETHOD(QueryState)(/* unknown */);
    STDMETHOD(SetState)(/* unknown */);
    STDMETHOD(CreateLxProcess)(_In_ PCCH CommandLine,
        _In_ ULONG ArgumentCount,
        _In_ PCCH* Arguments,
        _In_ ULONG EnvironmentCount,
        _In_ PCCH* Environment,
        _In_ PCCH CurrentDirectory,
        _In_ ULONG Flags,
        _In_ PLXSS_STD_HANDLES StdHandles,
        _In_ PLXSS_CONSOLE_DATA ConsoleData,
        _In_ ULONG Uid,
        _Out_ PULONG ProcessHandle);
    STDMETHOD(RegisterAdssBusServer)(_In_ PCCH ServerName, _Out_ PULONG ServerHandle);
    STDMETHOD(ConnectAdssBusServer)(/* unknown */);
    STDMETHOD(Destroy)(/* unknown */);
    STDMETHOD(GetState)(/* unknown */);
    STDMETHOD(StartSelf)(/* unknown */);
    STDMETHOD(StopSelf)(/* unknown */);
    STDMETHOD(GetSuspendState)(/* unknown */);
};

보는 바와 같이 저작자도 ILxssSession의 GetCurrentInstance, StartDefaultInstance 2개 함수와 ILxInstance의 CreateLxProcess, RegisterAdssBusServer 2개 함수에 대해서만 그 signature를 파악해낸 정도입니다.

어쨌든 이 정도만을 바탕으로 다음과 같이 테스트를 해볼 수 있는데,

#include <Windows.h>
#include <stdio.h>
#include "lxssmanager.h"

HRESULT OleMain();

int main()
{
    HRESULT hr = CoInitializeEx(nullptr, 0);
    if (hr != S_OK)
    {
        return 1;
    }

    hr = OleMain();

    CoUninitialize();

    return hr;
}

HRESULT OleMain()
{
    HRESULT hr = S_FALSE;

    hr = CoInitializeSecurity(nullptr,
        -1,
        nullptr,
        nullptr,
        RPC_C_AUTHN_LEVEL_DEFAULT,
        RPC_C_IMP_LEVEL_IMPERSONATE,
        nullptr,
        EOAC_STATIC_CLOAKING,
        nullptr);

    if (hr != S_OK)
    {
        return hr;
    }

    ILxssSession* pSession = nullptr;
    ILxInsanace* pInstance = nullptr;

    do
    {
        hr = CoCreateInstance(CLSID_LxssManager, nullptr, CLSCTX_LOCAL_SERVER, 
            __uuidof(ILxssSession), (PVOID*)&pSession);
        if (hr != S_OK)
        {
            break;
        }

        printf("pSession == %p\n", pSession);

        hr = pSession->GetCurrentInstance(&pInstance);
        printf("GetCurrentInstance hr == %d(0x%x)\n", hr, hr);

        // -2147024891 == 0x80070005 E_ACCESSDENIED (Access is denied.)
        // -2147024894 == 0x80070002 (The system cannot find the file specified.)
        // -2147024809 == 0x80070057 (The parameter is incorrect.)
        // -2147220734 == 0x80040302

        hr = pSession->StartDefaultInstance(__uuidof(ILxInstance), (PVOID *)&pInstance);
        printf("StartDefaultInstance hr == %d(0x%x)\n", hr, hr);

        if (hr != S_OK)
        {
            break;
        }

    } while (false);

    if (pSession != nullptr)
    {
        pSession->Release();
    }

    if (pInstance != nullptr)
    {
        pInstance->Release();
    }

    return hr;
}

그런데 실제로 실행을 해보면 GetCurrentInstance는 0x80070057(E_INVALIDARG)을 반환하고, StartDefaultInstance 호출은 Get으로 받아온 인스턴스가 유효하지 않은 탓도 있겠지만 아예 crash가 발생합니다.

Faulting application name: ConsoleApplication1.exe, version: 0.0.0.0, time stamp: 0x60c9fe1d
Faulting module name: ntdll.dll, version: 10.0.19041.1023, time stamp: 0x7977b9de
Exception code: 0xc0000005
Fault offset: 0x00000000000a3ef0
Faulting process id: 0x4300
Faulting application start time: 0x01d762b478547e8a
Faulting application path: C:\temp\ConsoleApplication1\x64\Debug\ConsoleApplication1.exe
Faulting module path: C:\WINDOWS\SYSTEM32\ntdll.dll
Report Id: 7e85962d-3fa7-4bea-bd46-992aeee231e9
Faulting package full name: 
Faulting package-relative application ID: 

아마도 그때 당시에는 잘 동작했을지 모르겠지만 지금의 Windows 10에서는 오류가 발생하고 있습니다. 아쉽군요. ^^

(2023-10-20 업데이트) 해당 github의 저자가 작성한 코드도 참고해 보세요.

lxss/lxlaunch/lxlaunch.cpp
; https://github.com/ionescu007/lxss/blob/master/lxlaunch/lxlaunch.cpp


(첨부 파일은 이 글의 예제 코드를 포함합니다.)




이걸 테스트하면서 알게 된 사실이 하나 있는데요, 전에 CoInitializeSecurity가 다른 DLL을 로드하면서 자동 호출이 된다고 했었는데요,

별도 DLL에 포함된 타입을 STAThread Main 메서드에서 사용하는 경우 CoInitializeSecurity 자동 호출
; https://www.sysnet.pe.kr/2/0/12666

이와 유사하게 C++ 프로그램에서도 CoInitializeSecurity가 자동 호출되는 경우가 있었습니다. 재현은 다음과 같이 할 수 있는데요,

HRESULT hr = CoInitializeEx(nullptr, 0);

PVOID* pVoid;
hr = CoCreateInstance(CLSID_ShellDesktop, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown,
    (void**)&pVoid);

if (hr != S_OK)
{
    return;
}

hr = CoInitializeSecurity(nullptr,
    -1,
    nullptr,
    nullptr,
    RPC_C_AUTHN_LEVEL_DEFAULT,
    RPC_C_IMP_LEVEL_IMPERSONATE,
    nullptr,
    EOAC_STATIC_CLOAKING,
    nullptr);

// hr == 0x80010119 : Security must be initialized before any interfaces are marshalled or unmarshalled. It cannot be changed once initialized.
//       RPC_E_TOO_LATE (-2147417831) 

확실하게 파고들지는 않았지만, 아마도 CoCreateInstance 내부에서 호출이 되는 것 같습니다. 즉, CoInitializeEx를 호출했다고 하면 COM을 사용하겠다는 의도이고 그럼 당연히 개체 생성을 했을 것이므로 CoCreateInstance를 호출했을 것입니다.

결국 COM Apartment 초기화가 된 스레드를 사용한 응용 프로그램이 있다면 높은 확률로 CoInitializeSecurity API가 호출되었을 것입니다.




C# - CoCreateInstance 관련 Inteop 오류 정리
; https://www.sysnet.pe.kr/2/0/12678

Wslhub.Sdk 사용으로 알아보는 CoInitializeSecurity 사용 제약
; https://www.sysnet.pe.kr/2/0/12665

별도 DLL에 포함된 타입을 STAThread Main 메서드에서 사용하는 경우 CoInitializeSecurity 자동 호출
; https://www.sysnet.pe.kr/2/0/12666

COM+ 서버 응용 프로그램을 이용해 CoInitializeSecurity 제약 해결
; https://www.sysnet.pe.kr/2/0/12667

ionescu007/lxss github repo에 공개된 lxssmanager.dll의 CLSID_LxssUserSession/IID_ILxssSession 사용법
; https://www.sysnet.pe.kr/2/0/12676

역공학을 통한 lxssmanager.dll의 ILxssSession 사용법 분석
; https://www.sysnet.pe.kr/2/0/12677

C# - DLL Surrogate를 이용한 Out-of-process COM 개체 제작
; https://www.sysnet.pe.kr/2/0/12668

DLL Surrogate를 이용한 Out-of-process COM 개체에서의 CoInitializeSecurity 문제
; https://www.sysnet.pe.kr/2/0/12670

CoInitializeSecurity의 전역 설정을 재정의하는 CoSetProxyBlanket 함수 사용법
; https://www.sysnet.pe.kr/2/0/12679




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

[연관 글]






[최초 등록일: ]
[최종 수정일: 5/20/2025]

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

비밀번호

댓글 작성자
 




1  2  3  4  5  6  7  8  [9]  10  11  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
13754정성태10/4/20246772닷넷: 2304. C# 13 - (8) 부분 메서드 정의를 속성 및 인덱서에도 확대파일 다운로드1
13753정성태10/4/20246432Linux: 81. Linux - PATH 환경변수의 적용 규칙
13752정성태10/2/20247638닷넷: 2303. C# 13 - (7) ref struct의 interface 상속 및 제네릭 제약으로 사용 가능 [6]파일 다운로드1
13751정성태10/2/20246203C/C++: 176. C/C++ - ARM64로 포팅할 때 유의할 점
13750정성태10/1/20246056C/C++: 175. C++ - WinMain/wWinMain 호출 전의 CRT 초기화 단계
13749정성태9/30/20246216닷넷: 2302. C# - ssh-keygen으로 생성한 Private Key와 Public Key 연동파일 다운로드1
13748정성태9/29/20246662닷넷: 2301. C# - BigInteger 타입이 byte 배열로 직렬화하는 방식
13747정성태9/28/20247326닷넷: 2300. C# - OpenSSH의 공개키 파일에 대한 "BEGIN OPENSSH PUBLIC KEY" / "END OPENSSH PUBLIC KEY" PEM 포맷파일 다운로드1
13746정성태9/28/20246504오류 유형: 924. Python - LocalProtocolError("Illegal header value ...")
13745정성태9/28/20246369Linux: 80. 리눅스 - 실행 중인 프로세스 내부의 환경변수 설정을 구하는 방법 (lldb)
13744정성태9/27/20246878닷넷: 2299. C# - Windows Hello 사용자 인증 다이얼로그 표시하기파일 다운로드1
13743정성태9/26/20247558닷넷: 2298. C# - Console 프로젝트에서의 await 대상으로 Main 스레드 활용하는 방법 [1]
13742정성태9/26/20247592닷넷: 2297. C# - ssh-keygen으로 생성한 ecdsa 유형의 Public Key 파일 해석 [1]파일 다운로드1
13741정성태9/25/20246928디버깅 기술: 202. windbg - ASP.NET MVC Web Application (.NET Framework) 응용 프로그램의 덤프 분석 시 요령
13740정성태9/24/20246551기타: 86. RSA 공개키 등의 modulus 값에 0x00 선행 바이트가 있는 이유(ASN.1 인코딩)
13739정성태9/24/20246834닷넷: 2297. C# - ssh-keygen으로 생성한 Public Key 파일 해석과 fingerprint 값(md5, sha256) 생성 [1]파일 다운로드1
13738정성태9/22/20246524C/C++: 174. C/C++ - 윈도우 운영체제에서의 file descriptor, FILE*파일 다운로드1
13737정성태9/21/20247033개발 환경 구성: 727. Visual C++ - 리눅스 프로젝트를 위한 빌드 서버의 msbuild 구성
13736정성태9/20/20247056오류 유형: 923. Visual Studio Code - Could not establish connection to "...": Port forwarding is disabled.
13735정성태9/20/20246798개발 환경 구성: 726. ARM 플랫폼용 Visual C++ 리눅스 프로젝트 빌드
13734정성태9/19/20246466개발 환경 구성: 725. ssh를 이용한 원격 docker 서비스 사용
13733정성태9/19/20246971VS.NET IDE: 194. Visual Studio - Cross Platform / "Authentication Type: Private Key"로 접속하는 방법
13732정성태9/17/20247123개발 환경 구성: 724. ARM + docker 환경에서 .NET 8 설치
13731정성태9/15/20247639개발 환경 구성: 723. C# / Visual C++ - Control Flow Guard (CFG) 활성화 [1]파일 다운로드2
13730정성태9/10/20248012오류 유형: 922. docker - RULE_APPEND failed (No such file or directory): rule in chain DOCKER
13729정성태9/9/20248874C/C++: 173. Windows / C++ - AllocConsole로 할당한 콘솔과 CRT 함수 연동 [1]파일 다운로드1
1  2  3  4  5  6  7  8  [9]  10  11  12  13  14  15  ...