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