
تقنية الثبات عبر COM في Windows
مستوحى من CVE-2026-21509
مثال تطبيقي لمعالج قائمة سياق Windows باستخدام C++ وCOM، يوضح تقنية ثبات خفية. من خلال تسجيل كائن COM مخصص، يتم تنفيذ الكود الخاص بك عندما ينقر المستخدم بزر الماوس الأيمن على أهداف محددة (ملفات، مجلدات، أو خلفيات) في مستكشف Windows.
تنويه: هذا المشروع لأغراض تعليمية وبحثية فقط. يمكن استخدام التقنيات الموضحة هنا لأغراض ضارة. المؤلف لا يوافق على استخدام هذا الكود لأي نشاط غير قانوني. كن مسؤولاً واستخدم هذه المعرفة بأخلاق.

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.cppيحتوي على الوظائف القياسية المطلوبة لكائن COM لتسجيل وإلغاء تسجيل DLL.
DllRegisterServer(): يكتب مسارات التسجيل المقابلة لامتدادات الملفات/الخلفيات المستهدفة. يتم تنفيذه عند تسجيل DLL.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(): ينظف السجل. يتم استدعاؤه عند إلغاء تسجيل DLL.MyClassFactoryمطلوب لإنشاء كائن COM. اقرأ المزيد عن مصانع الفئات.
Clsid_defined.hيحتوي على المعرف الفريد العمومي (GUID) الذي سيتم تسجيل التطبيق تحته في Explorer. يمكنك إنشاء GUID جديد باستخدام guidgen.exe في Visual Studio أو مولد 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.cppالفئة الأساسية التي تنفذ IShellExtInit و 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. 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)
يتم استدعاؤها عندما ينقر المستخدم على الخيار المخصص الخاص بك من قائمة السياق. هذا هو المكان الذي يتم فيه تنفيذ حمولة الثبات أو الإجراء المخصص الخاص بك.على الجهاز الافتراضي المستهدف، انسخ DLL المُجمّع وقم بتشغيل الأوامر التالية:
سجل DLL باستخدام ملفات Windows الثنائية القياسية.
regsvr32.exe RightHandPersistence.dll
أعد تشغيل عملية explorer.exe لضمان تحميل إضافة shell الجديدة في الذاكرة.
taskkill /f /im explorer.exe & start explorer.exe
لإزالة معالج قائمة السياق وتنظيف السجل، استخدم العلامة /u مع regsvr32.exe. هذا يستدعي وظيفة DllUnregisterServer الخاصة بك.
regsvr32.exe /u RightHandPersistence.dll
يقوم Windows بتصنيف 'المساحة الفارغة' بشكل مختلف عن الملفات. لاستهداف الخلفية، قم بتعيين مفاتيح التسجيل الخاصة بك إلى هذه المواقع المحددة.
يمكن العثور على مزيد من التفاصيل حول تعيين الامتدادات في وثائق قائمة سياق Windows Shell من Microsoft.
يمكنك تحديد نص مخصص للقائمة (مثل 'نسخ مخصص' أو 'تشغيل التشخيصات') من خلال تنفيذ طريقة 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 |