# Playing around COM objects - PART 1

## Introduction

COM is a platform-independent, distributed, object-oriented system **for creating binary software components that can interact.** COM is the foundation technology for Microsoft's OLE (Object Linking and Embedding)(compound documents) and ActiveX (Internet-enabled components) technologies.

In other word, COM was originally created to enable Microsoft Office applications to communicate and exchange data between documents such embedding an Excel chart inside a Word document or PowerPoint presentation <---This ability called OLE.

![OLE ability this figure was taken from the talk of James Forshaw "COM in 60 seconds"](https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FFAWPIsIL9mzvlPUX7QvZ%2Ffigure.png?alt=media\&token=a472bf91-1712-4d8c-a9b4-8f0b0f46726e)

As well as COM designed <mark style="color:green;">**to promote software interoperability**</mark>; that is, to allow two or more applications or “components” to easily interact with one another, even if they were written by different vendors at different times, in different programming languages, or if they are running on different machines and different operating systems.

![](https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FjZfttiwVF78WIzWRJ66n%2Fjames.png?alt=media\&token=1b9bb1b8-158f-4358-9f9d-cb6b85aa4d03)

### COM objects and Interfaces

First of all, what is an <mark style="color:green;">**object**</mark>? An object is an <mark style="color:green;">**instantiation**</mark> of some *<mark style="color:green;">**class**</mark>*. At a generic level, a “class” is the definition of a set of related attributes and methods grouped together for a specified  purpose. The purpose is generally to provide some service to “things” outside the object, namely clients that want to make use of those services.

<mark style="color:red;">**A client never has direct access to the COM object in its entirety**</mark>. Instead, clients always access the object through clearly <mark style="color:green;">**defined contracts**</mark>: the interfaces that the object supports.&#x20;

A COM object exposes its features through an *<mark style="color:green;">**interface**</mark>*, which is a collection of member functions.

An **interface** is basically **an abstract class**, containing only <mark style="color:green;">**pure virtual functions**</mark> and has no data members.

Therefore, **an abstract class is a class that contain only  pure virtual declaration of functions** (the " = 0 " indicates the purity)) and has no data members:

```cpp
class IClassA
{
public:
   virtual void func1() = 0;
};
```

An abstract class is a class that <mark style="color:red;">**cannot be used to create objects**</mark>; however, it can be subclassed.

So, the following line of code is not valid and it will throw an error as an object cannot be created for the abstract class:

```cpp
IClassA* pNewInstance = new IClassA;
```

<mark style="color:green;">**The interface class can only be approached by using**</mark><mark style="color:green;">**&#x20;**</mark>*<mark style="color:green;">**a pointer to the virtual table that exposes the methods in the interface**</mark>***.** Interface does not come by itself, it usually comes with an inherited class that implements the exposed method in the interface. Such a class that implements the interface exposed methods is often called a co-class(derived class). Here is an example of a co-class:

```cpp
class ClassB: public IClassA
{
public:
   virtual void func1() { // implementation here }
};
```

**Code Explanation:** Here,  **IClassA** is the base class, and as it has a pure virtual function (**func1**), it has become an abstract class. **ClassB** is derived from the parent class **IClassA**. The func1 is defined in the derived class.

We can use a global method to create an instance of the co-class or we can use a static method as well. **The technique of using a method that creates an instance of a co-class and returning a pointer to its interface is often called&#x20;**<mark style="color:green;">**Class Factoring**</mark>. Here is the global create instance method:

```cpp
IClassA* CreateInstance()
{
    return new ClassB;
}
```

In the main function, we try to create a pointer of base class type, it will be created successfully, and we can point it to the derived class. This pointer can be used to call the derived class function.

```cpp
int main() {
//IClassA b;   ---------- > this line will throw an error
IClassA* b = CreateInstance(); //---------- > pointer can be created, so this line is correct
b -> func1();
}
```

**A COM class** is identified by using a unique <mark style="color:green;">**128-bit**</mark> Class ID (<mark style="color:green;">**CLSID**</mark>) that associates a class with a particular deployment in the file system, which for Windows is a DLL or EXE. A CLSID is a <mark style="color:green;">**GUID**</mark>, which means that no other class has the same CLSID.(*Strongly-typed*)

Also we can use a programmatic identifier (<mark style="color:green;">**ProgID**</mark>) ***which is a registry entry that can be associated with a CLSID***. Like the CLSID, the ProgID identifies a class but with less precision because it is not guaranteed to be globally unique.(*it's human readable and are locally scoped*)

**Interfaces** are strongly typed. Every interface has its own unique interface identifier, named an <mark style="color:green;">**IID**</mark>, which eliminates collisions that could occur with human-readable names. The IID is a globally unique identifier (<mark style="color:green;">**GUID**</mark>). *The name of an interface is always prefixed with an ''**I**" by convention.*

{% hint style="info" %}
**COM Clients only interact with pointers to interfaces as we described before:** When a client has access to an object, it has nothing more than a pointer through which it can access the functions in the interface. The pointer is opaque, meaning that it hides all aspects of internal implementation. In COM, the client can only call functions of the interface to which it has a **pointer**.&#x20;
{% endhint %}

### Object Presentation

It is convenient to use a simple presentation to show the relation between a COM object and its interfaces :

![Typical picture of a COM object that supports 3 interfaces A,B, and C](https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FzzUJZmeutCvqVtkBiHFQ%2Finterfaces.png?alt=media\&token=fa87bab4-1626-4cb9-94c3-52dd0d312052)

Now, when a client want to interact with this COM object he must use a pointer to the targeted interface:

![Interface B extend towards the client connected to it](https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2F4CAj80ppunEH9WsoUpwq%2Fcient.png?alt=media\&token=c08d6986-c857-492f-a339-9ad6012e0ee5)

In order to enumerate COM objects through a number of different views (e.g. by CLSID, by ProgID, by server executable), enumerate interfaces on the object and then create an instance and invoke methods we will use the famous tool [OleViewDotNet](https://github.com/tyranid/oleviewdotnet) made by [James Forshaw](https://twitter.com/tiraniddo) and the tool [COMView](https://www.japheth.de/COMView.html).

Let's try to analyze this CLSID that have the following GUID :&#x20;

&#x20;                                                    <mark style="color:red;">**13709620-C279-11CE-A49E-444553540000,**</mark>

![13709620-C279-11CE-A49E-444553540000](https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FiegDibwVge9wAZQtgCgY%2Fshellin.png?alt=media\&token=e71dfad4-907c-4e10-90bc-0acd8b78fad7)

In COM, an object can support multiple interfaces as depicted on the above picture: IDispatch, IObjectSafety, IObjectSafety, IShellDispatch{1,2,3,4,5} and there are 2 interfaces that should demands a little special attention : <mark style="color:green;">**IUnknown & IClassFactory**</mark>.

As we said previously an interface is strongly-typed which mean it has an only unique identifier called <mark style="color:green;">**IID**</mark>:

![Supported interfaces on the CoClass CLSID 13709620-C279-11CE-A49E-444553540000 ](https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2F2D715UPIXtdaeOwQywI2%2FIID.png?alt=media\&token=77b11ea4-f6ee-46e0-aee7-fea36e5bc1d2)

### 1) IUnknown interface

IUnkown is a fundamental interface in COM that contains basic operations of not only all objects, but all interfaces as well.  An object is not considered a COM object unless it implements this interface.

All interfaces in COM are <mark style="color:green;">**polymorphic**</mark> with IUknown:

![The definition of IUnkown using the IDL notation.](https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FlqoI4dTWe4yD6N0BkvLv%2Funknown.png?alt=media\&token=39f599f4-3d4b-48a8-a7c7-356a46816299)

So if you look at the first 3 functions in any interfaces you will see **QueryInterface**, **AddRef***,* and **Release:**

![The re-usage of the 3 functions of IUnknown interface in IShellDispatch5 interface due to polymorphic concept.](https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FZPVUaQXNZ6nTLxfecjdn%2Frela.png?alt=media\&token=a75d18bb-6bcc-4e17-8bb9-0967e249fc7f)

***In other words, IUnknown is the base interface from which all other interfaces inherit.***

Before continuing, I would like to highlight something we've discussed it before which is this expression "**COM Client only interact with a&#x20;***<mark style="color:green;">**pointer**</mark>***&#x20;to interfaces**'', this pointer is a pointer to an array of pointers to the objects's implementations of the interface member functions:

![A client has a pointer to an interface which is a pointer to a pointer to an array (table) of pointers to the object’s implementation.](https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FuT2DS8od2uzO5hRf3x6J%2Fpvtl.png?alt=media\&token=54c83f72-76a1-48e1-90a0-db4a4b97cc1d)

By convention the pointer to the interface function table is called the <mark style="color:green;">**pVtbl**</mark> pointer. The table itself is generally referred to with the name <mark style="color:green;">**vtbl**</mark> for “<mark style="color:green;">**virtual function table**</mark>.” :&#x20;

![Convention places object data following the pointer to the interface function table.](https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FHexsTpq1qKLkBhi70InH%2Fvtl.png?alt=media\&token=edd52348-0e2e-42d1-99fe-b3478b1abf81)

### 2) IClassFactory interface

As you know, we create instances of a COM object using:

* The interface specifications.
* The CLSID declaration in the COM class.

<mark style="color:red;">**We do not directly use the COM class to create an instance of a type of COM object**</mark>.

Instead, <mark style="color:green;">**an intermediate object called a**</mark><mark style="color:green;">**&#x20;**</mark>*<mark style="color:green;">**class object**</mark>*<mark style="color:green;">**&#x20;**</mark><mark style="color:green;">**is used to create instances of a COM object.**</mark>

#### **Class Object**

A class object is a specialized type of COM object that knows how to create a specific type of COM object. There is a one-to-one relationship between a ***class object*** and a ***COM object***.

Every type of class object knows how to create only one type of COM object. For example, if two COM objects, called **O1** and **02**, are implemented within a COM server, two class objects must also be implemented, one that knows how to create **01** and one that knows how to create **02.**

A class object can be considered of as a "***creator***" object. Its only goal is to <mark style="color:green;">**create instances of a COM object.**</mark>

Clients obtain a pointer to a class object's interface by asking the COM subsystem for a specific class object that can create the COM object they want. Using this interface pointer, clients have the class object create one or more instances of their associated COM object.

The COM specification defines a COM object creation interface called <mark style="color:green;">**IClassFactory:**</mark>

![IClassfactory implementation](https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FPBcc5PBmtM5xfAnDsY4a%2Ffactory.png?alt=media\&token=13ddf518-0740-4d19-bef1-22d3e9d47757)

> Class objects that implement `IClassFactory` as their object creation interface are called class factorie&#x73;**.**

Given a CLSID the client must now create an object of that class in order to make use of its services. It does so using two steps:

1\.      Obtain the “class factory” for the CLSID.

2\.      Ask the class factory to instantiate an object of the class

3\.      Returning an interface pointer to the client.

![A client asks a class factory in the server to create an object.](https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FO6hKznScSW0H2kWEwC67%2F2021-12-12_150543.png?alt=media\&token=a77ea6ab-77e6-49ab-837f-bb7ad5e97e41)

{% hint style="info" %}
The IClassFactory interface is implemented by COM servers on a “class factory” object for the purpose of creating new objects of a particular class.
{% endhint %}

### Ol32.dll!CoGetClassObject

Now that we grasp what a class factory we can examine how a client obtains the class factory.

This COM library function do whatever is necessary to obtain a class factory object for the given CLSID and return one of that class factory's interface pointers to the client.After that the client may calls IClassFactory::CreateInstance to instantiate objects of the class.

```cpp
HRESULT CoGetClassObject(
  [in]           REFCLSID rclsid,
  [in]           DWORD    dwClsContext,
  [in, optional] LPVOID   pvReserved,
  [in]           REFIID   riid,
  [out]          LPVOID   *ppv
);
```

Let's spot the most important parameters :

`[in] rclsid`

**The&#x20;**<mark style="color:green;">**CLSID**</mark>**&#x20;associated with the data and code that you will use to create the objects.**

`[in] dwClsContext`

**The context in which the executable code is to be run**. To enable a remote activation, include CLSCTX\_REMOTE\_SERVER. For more information on the context values and their use, see the [CLSCTX](https://docs.microsoft.com/en-us/windows/desktop/api/wtypesbase/ne-wtypesbase-clsctx) enumeration.

`[in] riid`

**Reference to the identifier of the interface**, which will be supplied in *<mark style="color:green;">**ppv**</mark>* on successful return. **This interface will be used to communicate with the class object**. Typically this value is <mark style="color:green;">**IID\_IClassFactory**</mark>, although other values such as IID\_IClassFactory2 which supports a form of licensing are allowed.&#x20;

`[out] ppv`

**The address of pointer variable that receives the interface pointer requested in&#x20;*****riid***. Upon successful return, <mark style="color:green;">**\***</mark>*<mark style="color:green;">**ppv**</mark>*<mark style="color:green;">**&#x20;**</mark><mark style="color:green;">**contains the requested interface pointer**</mark>.

This function return **S\_OK**  if **l**ocation and connection to the specified class object was successful.

Now, we will try to instantiate an object of the class {13709620-C279-11CE-A49E-444553540000} using **OleViewDotNet** which seems for me very abstract :

![instantiate an object of the class {13709620-C279-11CE-A49E-444553540000}](https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FpmNhg3AMSZTd07jAfns4%2Fdoneee.png?alt=media\&token=24431b37-d1af-488c-a5c9-e5702e0e1f2b)

## Hooking class factoring

In order to understand what's under the hood I decided to hook class factoring routine and practice what [Mr.Un1k0d3r](https://twitter.com/MrUn1k0d3r) teach us, so let’s take a more insightful look through WinDBG at how the calls are chained together. If we ask OLE32 about all the **CoGet\*** and **CreateI\*** used by **OleViewDotNet :**

```
0:008> x OLE32!CoGet*
00007ffb`2ffd4790 ole32!CoGetInterceptor (struct _GUID *, struct IUnknown *, struct _GUID *, void **)
00007ffb`2ff8e180 ole32!CoGetObject (wchar_t *, struct tagBIND_OPTS *, struct _GUID *, void **)
00007ffb`2ffc3830 ole32!CoGetSystemWow64DirectoryW (wchar_t *, unsigned int)
00007ffb`2ffa3350 ole32!CoGetInterceptorFromTypeInfo (struct _GUID *, struct IUnknown *, struct ITypeInfo *, struct _GUID *, void **)
00007ffb`2ff91070 ole32!CoGetInterceptorForOle32 (struct _GUID *, struct IUnknown *, struct _GUID *, void **)
0:008> x OLE32!CreateI*
00007ffb`2ffc38e0 ole32!CreateILockBytesOnHGlobalStub (void *, int, struct ILockBytes **)
00007ffb`2ff84c30 ole32!CreateItemMoniker (wchar_t *, wchar_t *, struct IMoniker **)

```

As you can notice above **OleViewDotNet** don't use Ol32.dll!CoGetClassObject, and you may encounter **CoCreateInstance** which is simply a wrapper function for CoGetClassObject and IClassFactory.

By googling little a bit I found this precious information mentioned on MSDN documentation that said:&#x20;

{% hint style="info" %}
You should not call [**DllGetClassObject** ](https://docs.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-dllgetclassobject)directly. When an object is defined in a DLL, [**CoGetClassObject**](https://docs.microsoft.com/en-us/windows/desktop/api/combaseapi/nf-combaseapi-cogetclassobject) calls the [**CoLoadLibrary**](https://docs.microsoft.com/en-us/windows/desktop/api/objbase/nf-objbase-coloadlibrary) function to load the DLL(in our cae this dll is shell32.dll), which, in turn, calls <mark style="color:green;">**DllGetClassObject**</mark>.
{% endhint %}

We can also verify the existence of this function through WinDBG :&#x20;

```
0:000> x 
00007ffb`3011e3f0 shell32!DllGetClassObject (void)
```

So we place a breakpoint at **SHELL32!DllGetClassObject** and let it run until we hit it:

```
0:000> bp SHELL32!DllGetClassObject
0:000> g
Breakpoint 0 hit
shell32!DllGetClassObject:
00007ffb`3011e3f0 4053            push    rbx
```

![](https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FvgKqOVfqdQd5Lltn0KwQ%2Fdoneee.png?alt=media\&token=ba5b70bf-d0ca-4131-abe4-84f1aa32208f)

We can so confirm that **OleViewDotNet**  is using **SHELL32!DllGetClassObject** for instantiating an object of the class with CLSID :  {13709620-C279-11CE-A49E-444553540000}

To gain a full picture of what's under the hood, we can use the nice (Trace and watch utility)‘**wt -l 2**’ WinDBG command to gain a two-level-depth hierarchical function call :

```
0:007> bp SHELL32!DllGetClassObject
0:007> g
Breakpoint 0 hit
shell32!DllGetClassObject:
00007ffb`3011e3f0 4053            push    rbx
0:000> wt -l 2
Tracing shell32!DllGetClassObject to return address 00007ffb`30df50cb
  491     0 [  0] shell32!DllGetClassObject
    6     0 [  1]   shell32!_security_check_cookie
  498     6 [  0] shell32!DllGetClassObject

504 instructions were executed in 503 events (0 from other threads)

Function Name                               Invocations MinInst MaxInst AvgInst
shell32!DllGetClassObject                             1     498     498     498
shell32!_security_check_cookie                        1       6       6       6

0 system calls were executed

combase!CClassCache::CDllPathEntry::GetClassObject+0x29 [inlined in combase!CClassCache::CDllPathEntry::DllGetClassObject+0x6b]:
00007ffb`30df50cb f605ae182a0002  test    byte ptr [combase!Microsoft_Windows_COM_PerfEnableBits (00007ffb`31096980)],2 ds:00007ffb`31096980=00

```

From the above result I deduced that **SHELL32!DllGetClassObject** is calling **combase!DllGetClassObject** thus I added an other breakpoint to confirm that result :&#x20;

```
0:009> bl
     0 e Disable Clear  00007ffb`3011e3f0     0001 (0001)  0:**** shell32!DllGetClassObject
     1 e Disable Clear  00007ffb`30e1ff90     0001 (0001)  0:**** combase!DllGetClassObject
0:009> g
Breakpoint 0 hit
shell32!DllGetClassObject:
00007ffb`3011e3f0 4053            push    rbx
0:000> g
Breakpoint 1 hit
combase!DllGetClassObject:
00007ffb`30e1ff90 48895c2408      mov     qword ptr [rsp+8],rbx ss:000000cf`9a6fc730=ffffffffff4441ce
```

Now I have a clear idea how I will craft my hooker :smile:

Below is a simplified diagram that aims to visualize the flow of events before and after **SHELL32!DllGetClassObject** is hooked :&#x20;

![](https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FFP91TNk3bv142yXMpH8k%2FUntitled%20Diagram.png?alt=media\&token=ae88ac04-b174-4e5c-87e6-0b1f43b3abef)

### **Before hooking**

Based on my debugging analysis when OleViewDotNet want to instantiate an object of the class mainly it jumps to **SHELL32!DllGetClassObject** then executing an other jump to **combase!DllGetClassObject :**&#x20;

![](https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2F5RrQmHeuxX52WWeCOv9N%2Fbeforehook.png?alt=media\&token=42c4e5d5-dbc6-4482-bd91-3ff5ef744fde)

Before moving to after hooking section let me show you the **DllGetClassObject** definition based on MSDN documentation :&#x20;

```cpp
HRESULT DllGetClassObject(
  [in]  REFCLSID rclsid,//The CLSID that will associate the correct data and code.
  [in]  REFIID   riid, //Usually, this is IID_IClassFactory, a reference to the identifier of the interface that the caller is to use to communicate with the class object.
  [out] LPVOID   *ppv //The address of a pointer variable that receives the interface pointer requested in riid. 
);
```

If you have already noticed that [**CoGetClassObject**](https://docs.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-cogetclassobject) parameters look like [**DllGetClassObject**](https://docs.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-dllgetclassobject)**.**

### **After hooking**

1. OleViewDotNet calls **shell32!DllGetClassObject** like before hooking.
2. OleViewDotNet looks up **shell32!DllGetClassObject** address but here is the magic, we patched dynamically this address to a malicious address that point on a rogue **comhook!HookedDllGetClassObject** function:

```
0:004> g
Breakpoint 0 hit
shell32!DllGetClassObject:
00007fff`1897e490 b8fa138469      mov     eax,offset comhook!HookedDllGetClassObject (00000000`698413fa)
0:000> u 00007fff`1897e490
shell32!DllGetClassObject:
00007fff`1897e490 b8fa138469      mov     eax,offset comhook!HookedDllGetClassObject (00000000`698413fa)
00007fff`1897e495 ffe0            jmp     rax
00007fff`1897e497 56              push    rsi
00007fff`1897e498 4157            push    r15
00007fff`1897e49a 4881ecb0020000  sub     rsp,2B0h
00007fff`1897e4a1 488b05d06f6600  mov     rax,qword ptr [shell32!_security_cookie (00007fff`18fe5478)]
00007fff`1897e4a8 4833c4          xor     rax,rsp
00007fff`1897e4ab 4889842490020000 mov     qword ptr [rsp+290h],rax
```

Take a look on line <mark style="color:red;">**7**</mark> and <mark style="color:red;">**8**</mark>**, the address** of **HookedDllGetClassObject is&#x20;**<mark style="color:red;">**0**</mark><mark style="color:red;">x</mark><mark style="color:red;">**698413fa**</mark>**,**  and if we disassemble it we will land into our malicious code and for poc purpose, **comhook!HookedDllGetClassObject** intercepts the **rclsid** parameter and execute pop up message holding the CLSID of the COM class :&#x20;

```
0:000> uf 00000000`698413fa
comhook!HookedDllGetClassObject:
00000000`698413fa 55              push    rbp
00000000`698413fb 4889e5          mov     rbp,rsp
00000000`698413fe 4883ec40        sub     rsp,40h
00000000`69841402 48894d10        mov     qword ptr [rbp+10h],rcx
00000000`69841406 48895518        mov     qword ptr [rbp+18h],rdx
00000000`6984140a 4c894520        mov     qword ptr [rbp+20h],r8
00000000`6984140e ba00010000      mov     edx,100h
00000000`69841413 b940000000      mov     ecx,40h
00000000`69841418 488b05057e0000  mov     rax,qword ptr [comhook!rdgco+0x190c (00000000`69849224)]
00000000`6984141f ffd0            call    rax
00000000`69841421 488945f8        mov     qword ptr [rbp-8],rax
00000000`69841425 488d45e8        lea     rax,[rbp-18h]
00000000`69841429 4889c2          mov     rdx,rax
00000000`6984142c 488b4d10        mov     rcx,qword ptr [rbp+10h]
00000000`69841430 488b05fd7e0000  mov     rax,qword ptr [comhook!rdgco+0x1a1c (00000000`69849334)]
00000000`69841437 ffd0            call    rax
00000000`69841439 488b55e8        mov     rdx,qword ptr [rbp-18h]
00000000`6984143d 488b45f8        mov     rax,qword ptr [rbp-8]
00000000`69841441 4989d1          mov     r9,rdx
00000000`69841444 4c8d05b52b0000  lea     r8,[comhook!Hook+0x2b5f (00000000`69844000)]
00000000`6984144b baff000000      mov     edx,0FFh
00000000`69841450 4889c1          mov     rcx,rax
00000000`69841453 e858ffffff      call    comhook+0x13b0 (00000000`698413b0)
00000000`69841458 488b45f8        mov     rax,qword ptr [rbp-8]
00000000`6984145c 41b901000000    mov     r9d,1
00000000`69841462 4c8d05c62b0000  lea     r8,[comhook!Hook+0x2b8e (00000000`6984402f)]
00000000`69841469 4889c2          mov     rdx,rax
00000000`6984146c b900000000      mov     ecx,0
00000000`69841471 488b05cc7e0000  mov     rax,qword ptr [comhook!rdgco+0x1a2c (00000000`69849344)]
00000000`69841478 ffd0            call    rax
00000000`6984147a 488d0597640000  lea     rax,[comhook!rdgco (00000000`69847918)]
00000000`69841481 488b00          mov     rax,qword ptr [rax]
00000000`69841484 488b4d20        mov     rcx,qword ptr [rbp+20h]
00000000`69841488 488b5518        mov     rdx,qword ptr [rbp+18h]
00000000`6984148c 4989c8          mov     r8,rcx
00000000`6984148f 488b4d10        mov     rcx,qword ptr [rbp+10h]
00000000`69841493 ffd0            call    rax
00000000`69841495 8945f4 uf       mov     dword ptr [rbp-0Ch],eax
00000000`69841498 8b45f4          mov     eax,dword ptr [rbp-0Ch]
00000000`6984149b 4883c440        add     rsp,40h
00000000`6984149f 5d              pop     rbp
00000000`698414a0 c3              ret
```

![](https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FOQBnvMwOUJ6D4W00w7in%2Fpopup.png?alt=media\&token=fbe054e8-4dbc-4ba2-a3ee-92204bacf48d)

3\. **comhook!HookedDllGetClassObject** at the end call **combase!DllGetClassObject** routine at line <mark style="color:blue;">**39**</mark> and if we can confirm that by adding a breakpoint at the address <mark style="color:blue;">**0**</mark><mark style="color:blue;">x</mark><mark style="color:blue;">**69841478**</mark>**:**

```
0:000> g
Breakpoint 2 hit
comhook!HookedDllGetClassObject+0x99:
00000000`69841493 ffd0            call    rax {combase!DllGetClassObject (00007fff`1a4cff90)}
```

### comhook.dll-x64

Frankly, I included this exercise in my research first to get familiar with known win32 API functions used to create COM objects and also simulate what Anti-malware and EDR software often utilize to  intercept suspicious calls by injecting their **dlls** into processes and make some checks.

In our context, I inject comhook.dll into OleViewDotNet that allows me to understand what's under the hood in the class factoring phase of any COM object creation.

Let me share the snippet code of my comhook.dll and explain the most relevant part of it :

#### Global variables :&#x20;

```cpp
BOOL hooked = FALSE;
typedef BOOL (WINAPI * DLLMAIN)( HINSTANCE, DWORD, LPVOID );
typedef HRESULT(*RealDllGetClassObject)(REFCLSID, REFIID, LPVOID*);
RealDllGetClassObject rdgco;
FARPROC shell32DllGetClassObject;
```

{% hint style="info" %}
The C programming language provides a keyword called **typedef**, which you can use to give a type a new name.
{% endhint %}

#### HookedDllGetClassObject()

```cpp
HRESULT HookedDllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv){
    
    CHAR *log = (CHAR*)GlobalAlloc(GPTR, 256);
    HRESULT hr;
    LPOLESTR os;
    StringFromCLSID(rclsid, &os);
    snprintf(log, 255, "HookedDllGetClassObject Called ARGS CLSID %ws\n", os);
    MessageBox(0,log,"Message from hooker",1);
    hr = rdgco(rclsid, riid, ppv);
    return hr;
}
```

#### Hook()

```cpp
VOID Hook()
{
     if(!hooked) {
        //Get the address of shell32!DllGetClassObject
        shell32DllGetClassObject =  GetProcAddress(LoadLibrary("shell32.dll"), "DllGetClassObject");
        //Get the address of combase!DllGetClassObject
        rdgco =  (RealDllGetClassObject)GetProcAddress(LoadLibrary("combase.dll"), "DllGetClassObject");
	   
        DWORD dwSize = 7;
        DWORD dwOld = 0;
        //Allocates the specified number of bytes from the heap.
        CHAR *patch = (CHAR*)GlobalAlloc(GPTR, dwSize);
        //Doing casting stuff
        CHAR *addr = (CHAR*)shell32DllGetClassObject;
        long long longHookedDllGetClassObject = (long long)HookedDllGetClassObject;
        DWORD dwHooked = (DWORD)longHookedDllGetClassObject;
        //Changes the protection of shell32DllGetClassObject addresss to be able to patch it.
        VirtualProtect((VOID*)shell32DllGetClassObject, dwSize, PAGE_EXECUTE_READWRITE, &dwOld);
        
        //The tricky part
        DWORD i = 0;
        DWORD position = 1;
        patch[0] = 0xb8;
        for(i; i < 4; i++) {
            CHAR current = dwHooked;
            patch[position++] = current;
            dwHooked >>= 8;
        }
        patch[5] = 0xff;
        patch[6] = 0xe0;
        
        //patch the address of shell32DllGetClassObject to point into HookedDllGetClassObject        
        memcpy(addr, patch, dwSize);
        VirtualProtect((VOID*)shell32DllGetClassObject, dwSize, PAGE_EXECUTE_READ, &dwOld);
    }
 
    hooked = TRUE;
}
```

I will explain the tricky part, roughly the idea is to patch the address of **shell32DllGetClassObject** to an address that will allow us to jump into **HookedDllGetClassObject.**

\+ The local variable <mark style="color:green;">**addr**</mark> hold the address of **shell32DllGetClassObject.**

**+** The local variable <mark style="color:green;">**dwHooked**</mark> hold the address of **HookedDllGetClassObject** which is <mark style="color:red;">**0**</mark><mark style="color:red;">x</mark><mark style="color:red;">**698413fa**</mark> which is represented <mark style="color:red;">**in 4 bytes**</mark>**.**

Now, we want that the patch point us in an address that perform the following instruction:

![](https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FVb6zNuGIajnVxcicVKnE%2Fbut.png?alt=media\&token=df99cd78-ace4-4d09-b89e-b668a48b5dc1)

Based on the above result our asm code is represented in **7 opcodes**, thus we fix <mark style="color:green;">**dwSize**</mark> to **7** and we allocate memory for the CHAR\* variable <mark style="color:red;">**patch**</mark> by this instruction :&#x20;

```
CHAR *patch = (CHAR*)GlobalAlloc(GPTR, dwSize);
```

{% hint style="info" %}
Keep in mind that when pushing stuff on the stack there is endianness format that should be take on consideration while storing <mark style="color:red;">**0**</mark><mark style="color:red;">x</mark><mark style="color:red;">**698413fa**</mark> on that stack.
{% endhint %}

The following figure explain what's happened in the tricky part &#x20;

![](https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FMFdCEmmR31HiVLDOq9wI%2Fshift.png?alt=media\&token=1e1be2df-ecb1-4f7b-9ef9-fec6ee07324e)

Finally, we will patch the address of  **shell32DllGetClassObject** by the address of **patch** variable through this instruction : memcpy(addr, patch, dwSize);

## COM via C(not C++)

The purpose of this section will be the implementation of those tasks in C language:

1\.      Obtain the “class factory” for our targeted CLSID. --> through **DllGetClassObject.**

2\.      Ask the class factory to instantiate an object of the class --> through **CreateInstance** method.

3\.      Get ShellExecute ID.

4\.      Initialize parameters to be used on Invoke method.

5\.      Pop the calc.

![OleViewDotNet pop calc through ShellExecute method](https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2Fpwv0IXvWhnBVD2wdRrav%2Fcalc.png?alt=media\&token=6cb452f1-02dc-41a3-b3f2-b03a960beeb1)

***Goal : Reach what OleViewDotNet did through C language***.

### C vs C++

COM is based on a *binary* **interoperability** standard, rather than a *language* interoperability standard. Any language supporting “**structure**” or “**record**” types containing **double-indirected access to a table of function pointers** is suitable.

That being said, COM can declare interface declarations for both C++ and C . The C++ definition of an interface, which in general is of the form:

```cpp
interface ISomeInterface{
	virtual RET_T  MemberFunction(ARG1_T arg1, ARG2_T arg2 /*, etc */);
	[Other member functions]
	...
	};
```

{% hint style="info" %}
Did you know that a struct can store a pointer to some function?
{% endhint %}

then the corresponding C declaration of that interface looks like :&#x20;

```cpp
typedef struct ISomeInterface
	{
	ISomeInterfaceVtbl *  pVtbl;
	} ISomeInterface;

typedef struct ISomeInterfaceVtbl ISomeInterfaceVtbl;
struct ISomeInterfaceVtbl
	{
	RET_T (*MemberFunction)(ISomeInterface * this, ARG1_T arg1,
		ARG2_T arg2 /*, etc */);
	[Other member functions]
	} ;
```

What we've done above is to recreate a C++ class, using plain C. The **ISomeInterface** struct is really a C++ class. A C++ class is really nothing more than a struct whose <mark style="color:green;">**first member is always a pointer to its VTable**</mark> (an array of function pointers) -- an array that contains pointers to all the functions inside of that class. <mark style="color:green;">**The first argument passed to an object's function is a pointer to the object (struct) itself. (This is referred to as the hidden "**</mark><mark style="color:green;">**`this`**</mark><mark style="color:green;">**" pointer.)**</mark>

### 1. Obtain the “class factory” for our targeted CLSID. --> through **DllGetClassObject**

Before a program can use any COM object, it must initialize COM, which is done by calling the function [<mark style="color:blue;">**CoInitialize**</mark>](https://docs.microsoft.com/en-us/windows/win32/api/objbase/nf-objbase-coinitialize). This need be done only once, so a good place to do it is at the very start of the program.

```cpp
DEFINE_GUID(clsid, 0x13709620, 0xc279, 0x11ce, 0xa4, 0x9e, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00);
```

The above is a macro. A `#define` in one of the Microsoft include files allows your compiler to compile the above into a 16 byte array.

Next, the program calls **DllGetClassObject** to get a pointer to *shell32.dll*'s `IClassFactory` object. Note that we pass the **`CLSID`** object's GUID as the first argument. We also pass a pointer to our variable `icf` which is where a pointer to the `IClassFactory` will be returned to us, if all goes well:

```cpp
#include <windows.h>
#include <stdio.h>
#include <initguid.h>
#include <stdint.h>
//gcc .\comfunc.c -o com.exe -lole32 -luuid -loleaut32

//The CLSID {13709620-C279-11CE-A49E-4445535400} associated with the data and code that we will use to create the object.
DEFINE_GUID(clsid, 0x13709620, 0xc279, 0x11ce, 0xa4, 0x9e, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00);

 int main(char argc, char **argv){
    
    LPOLESTR clsidstr = NULL;
    StringFromCLSID(&clsid, &clsidstr);
    printf("Our targeted CLSID is %ls\n", clsidstr);
    HRESULT hr;
    hr = CoInitialize(NULL);

    FARPROC DllGetClassObject = GetProcAddress(LoadLibrary("shell32.dll"), "DllGetClassObject");
    printf("DllGetClassObject is at 0x%p\n\n", DllGetClassObject);
    
    IClassFactory *icf = NULL;
    // Get shell32.DLL's IClassFactory
    hr = DllGetClassObject(&clsid, &IID_IClassFactory, (void **)&icf);

    if(hr != S_OK) {
            printf("DllGetClassObject failed to do something. Error %d HRESULT 0x%08x\n", GetLastError(), (unsigned int)hr);

            CoUninitialize();
            ExitProcess(0);          
    }
   //For debugging purposes 
    HMODULE shell32address = GetModuleHandle("shell32.dll");
    printf("shell32.dll address is :%p \tIClassFactory's Vtable address is:%p \n", shell32address,icf->lpVtbl);
    uint64_t val = (uint64_t)icf->lpVtbl - (uint64_t)shell32address;
    printf("The offset is 0x%p - 0x%p  = 0x%llx", icf->lpVtbl, shell32address, val);
    return 0;
 }
```

Now, If we compile the above code and run it, we will get a match between the resulted offset and the one shown in **OleViewDotNet** which prove that we have now a pointer to the VTable of `IClassFactory` :

![](https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FOWWEnlWM0gYmtjlxKRtR%2Foffset.png?alt=media\&token=0795f0d6-a89d-4c27-8304-73736ff610d5)

### 2. Ask the class factory to instantiate an object of the class through **CreateInstance** method

Once we have the `IClassFactory` object, we can call its `CreateInstance` function to get a **IDispatch** object. Note how we use the `IClassFactory` to call its `CreateInstance` function. We get the function via `IClassFactory`'s VTable. Also note that we pass the `IClassFactory` pointer as <mark style="color:green;">**the first argument**</mark>.

Note that we pass **IDispatch**'s VTable GUID as <mark style="color:green;">**the third argument**</mark>. And for <mark style="color:green;">**the fourth argument**</mark>, we pass a pointer to our variable `id` which is where a pointer to an **IDispatch**'s object will be returned to us, if all goes well:

```cpp
 // Create an IDispatch object
   IDispatch *id = NULL;
   hr = icf->lpVtbl->CreateInstance(icf, NULL, &IID_IDispatch, (void **)&id);
    if(hr != S_OK) {
            printf("CreateInstance failed to do something. Error %d HRESULT 0x%08x\n", GetLastError(), (unsigned int)hr);

            CoUninitialize();
            ExitProcess(0);          
    }
    printf("[+]IDispatch's Vtable address is:%p \n",id->lpVtbl);
   uint64_t val1 = (uint64_t)id->lpVtbl - (uint64_t)shell32address;
   printf("The offset IDispatch is 0x%p - 0x%p  = 0x%llx\n", id->lpVtbl , shell32address , val1);
```

Again compile and run : &#x20;

![](https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FXoZDsqD6j7F8Y3xnE2JV%2Fdoneee.png?alt=media\&token=22d7ce56-27d8-44f9-98c0-1009fbe790d7)

{% hint style="info" %}
**IDispatch** interface usage : Exposes objects, methods and properties to programming tools and other applications that support Automation.&#x20;
{% endhint %}

### 3. Get ShellExecute ID

Once we have the `IDispatch`  object, we can call its [**GetIDsOfNames**](https://docs.microsoft.com/en-us/windows/win32/api/oaidl/nf-oaidl-idispatch-getidsofnames) function to get the COM dispatch identifier (DISPID) of <mark style="color:red;">**ShellExecute**</mark> .

\
Note that we pass the `IDispatch` pointer as <mark style="color:green;">**the first argument**</mark>. We pass a reference of **IID\_NULL**  as <mark style="color:green;">**the second argument(**</mark>Reserved for future use. Must be IID\_NULL.<mark style="color:green;">**)**</mark>, for <mark style="color:green;">**the third  argument**</mark>, we pass <mark style="color:red;">**ShellExecute**</mark> as WCHAR to be mapped, for <mark style="color:green;">**the fourth argument**</mark> the count of the names to be mapped(**1** in our case), for <mark style="color:green;">**the fifth**</mark> <mark style="color:green;">**argument**</mark> the locale context in which to interpret the names. And <mark style="color:green;">**last argument**</mark> we pass the address of [<mark style="color:red;">**dispid**</mark> ](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.dispidattribute?redirectedfrom=MSDN\&view=net-6.0)which is the id value of <mark style="color:red;">**ShellExecute**</mark>  that will be returned to us, if all goes well:&#x20;

```cpp
// get function ID
   WCHAR *member = L"ShellExecute";
   DISPID dispid = 0;

    hr = id->lpVtbl->GetIDsOfNames(id, &IID_NULL, &member, 1, LOCALE_USER_DEFAULT, &dispid);
    if(hr != S_OK) {
            printf("GetIDsOfNames failed to do something. Error %d HRESULT 0x%08x\n", GetLastError(), (unsigned int)hr);

            CoUninitialize();
            ExitProcess(0);          
    }

    printf("DISPID 0x%08x\n", dispid);
```

Again compile and run : &#x20;

![](https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FG5lf0KWlAMheHxDIm3RK%2Fdone.png?alt=media\&token=23a1ca28-1bea-4309-83f5-fc126ae6c745)

### 4.Initialize parameters to be used on Invoke method&#x20;

According to MSDN, **Invoke** goal is to provide access to properties and methods exposed by an object and this is what we need to pop up the calc :&#x20;

```cpp
HRESULT Invoke(
  [in]      IDispatch  *this
  [in]      DISPID     dispIdMember,
  [in]      REFIID     riid,
  [in]      LCID       lcid,
  [in]      WORD       wFlags,
  [in, out] DISPPARAMS *pDispParams,
  [out]     VARIANT    *pVarResult,
  [out]     EXCEPINFO  *pExcepInfo,
  [out]     UINT       *puArgErr
);
```

In our situation, note that we pass the `IDispatch` pointer as <mark style="color:green;">**the 1 arg**</mark>. Then,we pass the **dispid** id of <mark style="color:red;">**ShellExecute**</mark>  as <mark style="color:green;">**the 2 arg**</mark>. We pass a reference of **IID\_NULL**  as <mark style="color:green;">**the 3 arg(**</mark>Reserved for future use. Must be IID\_NULL.<mark style="color:green;">**)**</mark>, for <mark style="color:green;">**the 4 arg**</mark> the locale context in which to interpret the names,  for <mark style="color:green;">**the 5 arg**</mark> flags describing the context of the **Invoke** call (in our case we pass **DISPATCH\_METHOD**).

<mark style="color:green;">**The 6 arg**</mark> pointer to a [**DISPPARAMS** ](https://docs.microsoft.com/en-us/windows/win32/api/oaidl/ns-oaidl-dispparams)structure containing **an array of arguments** passed <mark style="color:red;">**ShellExecute**</mark> , an array of argument DISPIDs for named arguments, and **counts** for the number of elements in the arrays.

```cpp
typedef struct tagDISPPARAMS {
  VARIANTARG *rgvarg;//An array of arguments.
  DISPID     *rgdispidNamedArgs;
  UINT       cArgs; //The number of arguments.
  UINT       cNamedArgs;
} DISPPARAMS;
```

{% hint style="info" %}
**VARIANTARG** describes arguments passed within DISPPARAMS, and **VARIANT** to specify variant data that cannot be passed by reference.
{% endhint %}

In our case, we need only to set up  2 elements to reach our goal :&#x20;

![](https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FJowMIO4FUmajLNPWelKZ%2Fintre.png?alt=media\&token=de866e4a-7586-47c4-b918-5f0a200f1d8d)

Before continuing let me highlight  some stuff regarding BSTR(Basic string or binary string):

{% hint style="info" %}
A BSTR (Basic string or binary string) is a string data type that is used by COM, Automation, and Interop functions. Use the BSTR data type in all interfaces that will be accessed from script.

A BSTR is a composite data type that consists of a **length prefix**, **a data string**, and **a terminator**. For more details check : <https://docs.microsoft.com/en-us/previous-versions/windows/desktop/automat/bstr>
{% endhint %}

```cpp
// initialize parameters

   //VARIANT describes arguments passed within DISPPARAMS.
    VARIANT args = { VT_EMPTY };
    args.vt = VT_BSTR;
    args.bstrVal = SysAllocString(L"calc");

    // Contains the arguments passed to ShellExecute method.
    DISPPARAMS dp = {&args, NULL, 1, 0};
```

At this stage, we prepared all the necessary ingredients to pop the calc using the invoke method; for the rest of the arguments that I did not mention just take a look on: <https://docs.microsoft.com/en-us/windows/win32/api/oaidl/nf-oaidl-idispatch-invoke>

### 5. Pop the calc&#x20;

```cpp
 VARIANT output = { VT_EMPTY };
 hr = id->lpVtbl->Invoke(id, dispid, &IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dp, &output, NULL, NULL);
     if(hr != S_OK) {
            printf("Invoke failed to do something. Error %d HRESULT 0x%08x\n", GetLastError(), (unsigned int)hr);
            CoUninitialize();
            ExitProcess(0);          
    }

    id->lpVtbl->Release(id);
    icf->lpVtbl->Release(icf);
    SysFreeString(args.bstrVal);
    CoUninitialize();
```

So next, we call the `IDispatch`'s `Release and IClassFactory`'s `Release` functions . Once we do this, our `id and icf` variables no longer contains a valid pointer to anything. It's garbage now. We call aslo `SysFreeString` to deallocates a string allocated previously.

Finally, we must call `CoUninitialize` to allow COM to clean up some internal stuff. This needs to be done once only, so it's best to do it at the end of our program (but only if `CoInitialize` succeeded).

#### Demo:

![](https://615064086-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MXlxki-LGPmhYCBAzg5%2Fuploads%2FDz91UppAujIVL7OiUIH4%2FVideo_2021-12-27_014804_edit.gif?alt=media\&token=050b4042-4b64-43ad-b5dd-792d1d3836c5)

## Conclusion

As you notice the blog was long, but I truly share with you all the things I learned regarding the internal of COM which represent a fundamental pillar for Windows as OS. (COM is a big ocean of course I did not cover all things like single thread apartment, proxy/stub, security aspects, I promise my next parts will be about that).

Since I’m very obsessed with Windows especially when I’m facing in security community like [James FORSHAW](https://twitter.com/tiraniddo) talks regarding COM, also [Matt Nelson’s](https://twitter.com/enigma0x3) blog that explain lateral movements through DCOM… as well as some AVs that expose misconfigure COM object that led to LPE and self-bypass a poc was done by [Denis Skvortcov](https://twitter.com/Denis_Skvortcov).

What I mentioned in the previous paragraph, combined with the fact that one day I tried to implement WMI using golang, but I failed that represents the reasons why I wrote this blog since I knew nothing about COM, this is how it works, and now we need to learn theory and basic stuff, also slow down and seek to deeply understand the topic. This patience will be fruitful since you can now explore and develop stuff with creativity.

**Final Note**: I am not a Windows Internal expert I'm just a learner, If you think I said anything incorrect anywhere, feel free to reach out to me and correct me, I would highly appreciate that. And finally, thank you very much for taking your time to read this post.

## References

{% embed url="<https://github.com/Seggaeman/DeveloperWorkshopCOMATL3>" %}

{% embed url="<https://www.codeproject.com/Articles/13601/COM-in-plain-C#VTABLE>" %}

{% embed url="<https://docs.microsoft.com/en-us/windows/win32/com/the-component-object-model>" %}

{% embed url="<https://www.educba.com/abstract-class-in-c-plus-plus>" %}

{% embed url="<https://www.codeproject.com/Articles/4732/COM-Interface-Basics>" %}

{% embed url="<https://www.ooportal.com/basic-com/module3/comClass-class-objects.php>" %}

{% embed url="<https://docs.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-cogetclassobject>" %}

{% embed url="<https://docs.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-dllgetclassobject>" %}

{% embed url="<https://ringzer0ctf.com/tool>" %}
