Post

COM objects 101

What is COM ?

The Component Object Model is an object-based programming model designed to promote software interoperability; that is, to allow two or more applications or “components” to easily cooperate 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 running different operating systems.You define a custom COM library by designing the interfaces that your library implements. Consumers of your library can discover and use its features without any knowledge of your library’s deployment and implementation details.

Reflected-Parameter

What is the difference between COM and DCOM objects?

COM objects primarily operate at a local level, executing on the client’s machine. In contrast, DCOM (Distributed Component Object Model) functions on the server end. With DCOM, instructions are transmitted to the DCOM object, and execution occurs over the network. In simpler terms, DCOM can be referred to as COM via RPC (Remote Procedure Call)

Object Oriented in COM

Objects

An object is a specific instance of a class. In broader terms, a “class” serves as the blueprint for a set of interconnected data and functionalities designed for a specific shared goal. Typically, this goal involves providing services to external entities, or “clients,” seeking to utilize those services.

Interfaces

Interfaces define only how object should use that interface and what behavior is expected from an object through that interface. Interfaces do not specify any implementation details. Here’s a simple example in C++: An interface called IShape is defined with a pure virtual function draw(). An interface serves as a blueprint for classes that implement it but does not provide any implementation itself. Two concrete classes, Circle and Square, inherit from the IShape interface and provide their own implementations of the draw() function. These classes represent specific shapes.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>

// Interface defintion
class IShape {
public:
    virtual void draw() const = 0; // Pure virtual function
};

// Concrete class implementing the interface
class Circle : public IShape {
public:
    void draw() const override {
        std::cout << "Drawing a circle." << std::endl;
    }
};

// Another concrete class implementing the interface
class Square : public IShape {
public:
    void draw() const override {
        std::cout << "Drawing a square." << std::endl;
    }
};

// Client code using the interface
void drawShape(const IShape& shape) {
    shape.draw();
}

int main() {
    Circle circle;
    Square square;

    // Using the drawShape function with different shapes
    drawShape(circle);
    drawShape(square);

    return 0;
}

An interface is different from a class. While a class can create objects, an interface, on its own, cannot be used to create objects because it lacks any implementation. A COM object exposes its features through an interface, which serves as a collection of member functions defining the expected behavior for each function. It is not possible to create a instance of a COM interface independently. Instead, you must instantiate a class that implements the interface to leverage its functionalities. A client never has direct access to the COM object in its entirety. Instead, clients always access the object through clearly defined contracts: “the interfaces that the object supports, and only those interfaces”.

Clients only interact with pointers to interfaces: 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, called simply an interface pointer. The pointer is opaque, meaning that it hides all aspects of internal implementation. You cannot see any details about the object such as its state information, as opposed to C++ object pointers through which a client may directly access the object’s data. In COM, the client can only call functions of the interface to which it has a pointer. But instead of being a restriction, this is what allows COM to provide the efficient binary standard that enables location transparency.

An object can implement multiple interfaces, as shown below. Reflected-Parameter

when the client application want to interact with the object it must use a interface pointer interface. Reflected-Paarameter

The client maintains a pointer to the interface which is, in actuality, a pointer to a pointer to an array of pointers to the object’s implementations of the interface member functions the structure is illustrated in Figure below.

Reflected-Parameter By convention the pointer to the interface function table is called the pVtbl pointer. The table itself is generally referred to with the name vtbl for “virtual function table.” Reflected-Parameter

COM Object Components

COM Class : is identified by using a unique 128-bit Class ID (CLSID) that associates a class with a particular deployment in the file system, which for Windows is a DLL or EXE. A CLSID is a GUID, which means that no other class has the same CLSID. ProgID: is a programmer-friendly string representing an underlying CLSID. IID : interface identifier

You might ask How can I obtain a COM object? The registry key HKEY_CLASSES_ROOT\CLSID exposes all the information needed to enumerate COM objects, including the CLSID and ProgID as shown below . Moreover you can easily parse the com objects easily using oleviewdotnet

Reflected-Parameter In the image below, I am searching for the CLSID of the Shell Automation Service class. This class has multiple interfaces, with two important ones being IUnknown and IClassFactory.

Reflected-Paaaarameter S

IUnknown Interface

The Component Object Model (COM) defines a standardized interface from which all other interfaces must derive, and this is the IUnknown interface. It has a function called QueryInterface which takes a globally unique identifier (GUID) as a parameter and returns the address of a pointer to an interface. Additionally, it has two more functions used for reference counting: AddRef and Release

Reflected-Parameter

QueryInterface

When a client initially obtains access to an object, it receives a single interface pointer. To access other interfaces on the same object, the client uses the member function QueryInterface, present in all COM interfaces. This function facilitates interface negotiation, allowing the client to inquire about the services the object can provide by passing the unique identifier of the desired interface.

IClassFactory interface

The COM objects implement the Factory Design Pattern, which involves creating objects without exposing the creation logic to the client. The objects are referred to using a common interface, this is done using the IClassFactory interface. This interface inherits from the IUnknown interface, enabling it to manage the creation and retrieval of objects in a way that abstracts the underlying details from the client. Reflected-Parameter

How Does COM Works ?

  1. The client computer requests the remote computer to create an object by its CLSID or PROGID. If the client passes the APPID, the remote computer looks up the CLSID using the PROGID.
  2. The remote machine checks the APPID and verifies the client has permissions to create the object.
  3. DCOMLaunch.exe (if an EXE) or DLLHOST.exe (if a DLL) will create an instance of the class the client computer requested.
  4. Communication is successful! 5. The Client can now access all functions in the class on the remote computer

Fortunately, COM provides APIs to handle the heavy lifting for us. There are two functions: CoGetClassObject, which returns the class factory, and CoCreateInstance, which creates an instance of an object. Note. The CoCreateInstance function internally calls CoGetClassObject itself. It’s just a more convenient function for clients that want to create one object

There are two ways to initialize a COM object:

  1. The simplest method involves calling the COM function CoCreateInstance. This function creates an object of the given CLSID and returns an interface pointer of the requested type for the client.
  2. Alternatively, the client can obtain an interface pointer to the “Class Factory” object for a CLSID by calling CoGetClassObject. This class factory supports an interface called IClassFactory, allowing the client to request the manufacturing of an object of its class. At this point, the client has interface pointers for two separate objects—the class factory and an object of that class—each with its own reference counts.

To create an object through the class factory, as shown below in the image:

  1. Use CoGetClassObject to obtain an interface pointer to the “class factory” object associated with the given CLSID.
  2. Utilize the IClassFactory interface supported by the class factory to request the manufacturing of an object belonging to its class.
  3. return interface pointer to the client

Reflected-Parameter

Demo

In this section, I will demonstrate how to enumerate COM classes and invoke methods.

Enumerate COM Objects Using Powershell

The provided PowerShell command is using the Get-WmiObject cmdlet to query information about Component Object Model (COM) settings on a Windows system.

1
Get-WmiObject Win32_COMSetting | ? {$_.progid } | ft ProgId,Caption,InprocServer32 

Reflected-Parameter

Enumerating COM Object Methods

This command creates an instance of the COM object associated with the ProgID “WScript.Shell.1” using the Activator class. It does so by calling the CreateInstance method and passing the type obtained from the ProgID using GetTypeFromProgID.

1
$com = [activator]::CreateInstance([type]::GetTypeFromProgID(("WScript.Shell.1"))) | gm

Below are the methods exposed by WScript.Shell.1, along with their member types and definitions, which contain the parameters. Reflected-Parameter i have invoked the Exec Method to run the calculator

1
2
$com = [activator]::CreateInstance([type]::GetTypeFromProgID(("WScript.Shell.1")))
$com.Exec("calc.exe")

Reflected-Parameter

Resources

This post is licensed under CC BY 4.0 by the author.

Trending Tags