Developer Documentation : COM OLE ActiveX hooking

In all the following we will use "COM", but all applies to COM, OLE and ActiveX (OCX)

   - General COM description
       Content of dll/ocx
       Basic objects VTBL
       More complex objects VTBL
   - Installing hooks
   - Static hooks VS auto hooks
       Static hooking
       Auto hooking

   - ULM of HookCom.dll main classes

General COM description

Content of dll/ocx

COM objects are defined in dll or ocx. The registry will find matching dll/ocx automatically when you provide a Class Identifier (CLSID).
A single dll/ocx can contain one or more objects, each one implementing one or more interfaces like shown below.

Dll / OCX content

Notice: As you can see interfaces can be shared by objects. This is realy important for hooking because a single interface hook will catch multiple objects actions.

An interface pointer is a pointer on a virtual functions table (VTBL), an array of functions addresses.
Let's see some VTBL examples.



Basic objects VTBL

The VTBL (virtual functions table) is a table of function pointers, such as an implementation of virtual functions table pointer of a C++ class.
The pointers in the VTBL point to the object methods.
So in the easiest cases we have following COM VTBL layout.

If an interface A is derived only from IUnknown we have

pInterfaceA
QueryInterface
AddRef
Release
InterfaceA_Method_1
InterfaceA_Method_2
...
InterfaceA_Method_N

In this case we have pInterfaceA==pIUnknown

If an interface B is derived from IDispatch we have

pInterfaceB
QueryInterface
AddRef
Release
GetTypeInfoCount
GetTypeInfo
GetIDsOfNames
Invoke
InterfaceB_Method_1
InterfaceB_Method_2
...
InterfaceB_Method_N

In this case we have pInterfaceB==pIUnknown==pIDispatch




More complex obects VTBL

The previous examples shown in Basic objects VTBL hide some objects complexity.
First the pointer of the real C++ object implementing interfaces is before first interface VTBL pointer that mean you can have something like

C++ object representation
pObject
C++ Object VTBL
Object_Virtual_Method_1
Object_Virtual_Method_2
...
Object_Virtual_Method_N
C++ Object members
pIUnknown
QueryInterface
AddRef
Release

The second thing you must know about COM, is that interfaces virtual functions tables are not always merged like shown in examples of Basic objects VTBL.
That means a single object can have multiple basics interfaces (like IUnknown).
In that case the full object definition can be
C++ object representation
pObject
C++ Object VTBL
Object_Virtual_Method_1
Object_Virtual_Method_2
...
Object_Virtual_Method_N
C++ Object members
pIUnknown
QueryInterface
AddRef
Release
pInterfaceA
QueryInterface
AddRef
Release
InterfaceA_Method_1
InterfaceA_Method_2
...
InterfaceA_Method_N
pInterfaceB
QueryInterface
AddRef
Release
GetTypeInfoCount
GetTypeInfo
GetIDsOfNames
Invoke
InterfaceB_Method_1
InterfaceB_Method_2
...
InterfaceB_Method_N

In such conditions, we can get multiple VTBL addresses for same basic interfaces methods (like the IUnknwon methods in previous example).
And in this case pIUnknown!=pInterfaceA!=pInterfaceB

By the way, if we want to hook IUnknown methods, as there is multiple VTBL for the IUnknown interface, we have to install our hooks in all the IUnknown VTBL(s). With the previous object, we have to install all the following hooks

C++ object representation
pObject
C++ Object VTBL
Object_Virtual_Method_1
Object_Virtual_Method_2
...
Object_Virtual_Method_N
C++ Object members
pIUnknown
QueryInterface_Hook
AddRef_Hook
Release_Hook
pInterfaceA
QueryInterface_Hook
AddRef_Hook
Release_Hook
InterfaceA_Method_1
InterfaceA_Method_2
...
InterfaceA_Method_N
pInterfaceB
QueryInterface_Hook
AddRef_Hook
Release_Hook
GetTypeInfoCount
GetTypeInfo
GetIDsOfNames
Invoke
InterfaceB_Method_1
InterfaceB_Method_2
...
InterfaceB_Method_N


Object Identifying

If InterfaceC is derived from InterfaceA when you do
pInterfaceC->QueryInterface(IID_InterfaceA,&pInterfaceA), the given pInterfaceA is generally the InterfaceA part of InterfaceC.

Microsoft asks developpers that the pInterfaceXX->QueryInterface(IID_IUnknown,&pInterfaceIUnknwon) to always return same pIUnknown pointer, to help identifying objects; but in real world it appears to happen only sometimes.

So if we want to spy objects life we have to uniquely identify them using an array containing all queried interfaces.
For each created object we have to maintain an array like (example is given for the previous object)

pIUnknown::IUnknown IID_IUnknown
pInterfaceA::IUnknown IID_IUnknown
pInterfaceA::IA IID_IA
pInterfaceB::IUnknown IID_IUnknown
pInterfaceB::IDispatch IID_IDispatch
pInterfaceB::IB IID_IB




Installing hooks

As documentation says: interface pointer is a pointer on a VTLB, and VTBL is an array of pointer to methods.
So as soon as we get an interface pointer we get VTBL array.
Next to install hook we just have to change VTBL array values, replacing original method pointers, by pointer to our associated hook.
Object before hooking
pInterfaceA
QueryInterface
AddRef
Release
InterfaceA_Method_1
InterfaceA_Method_2
...
InterfaceA_Method_N

Object after hooking

pInterfaceA
QueryInterface_Hook
AddRef_Hook
Release_Hook
InterfaceA_Method_1_Hook
InterfaceA_Method_2_Hook
...
InterfaceA_Method_N_Hook


By changing VTBL values, hooks are multithread safe



Static hooks VS Auto hooks

The hooking mechanism is known : we have to change VTBL values.
That's great, but VTBL are located in dll/ocx of the associated object.

So, now we have to know when dll is loaded/unloaded.
The answer is simple :
dll is loaded at first object creation and unloaded when it is no more use, that means when all objects are released.

Knowing this we got two ways to hook objects:
  - create an object of the type we want to hook to force dll loading and avoid it to be unloaded (until we release our object). (this method is called COM Static hooking in WinAPIOverride)
  - spy objects creation by hooking APIs or methods of interfaces creating COM objects (this method is called COM Auto hooking in WinAPIOverride)

Static hooking :

Creating an object requires us to exactly know which kind of object we want to hook; and we will hook only this object.
The great advantage is that we don't need to spy any API, and we won't catch other objects methods call.

For creating a static hook, we need
  - CLSID and IID to create the specified object
  - VTBL index of the method to hook (to find VTBL value to change)

Static Hook

Notice : As some interfaces are shared according to controls, we may still get some noisy calls for base interfaces.


Auto hooking :

Notice : COM hooking thanks to API spying has already been described in an old article called "Spying on COM Objects" written by Dmitri Leman in 1999. You can found it (with it's sample source code) on Windows Developer Network / Windows Developer Magazine / Archives / 1999 / July 1999.


Objects creation spying allows us to catch all created objects; but we need to take care : we have to look at objects dll unloading and reloading to remove and reinstall VTBL hooks.
Warning : dll reloading can occur at another base address, meaning we have to recompute all addresses to hook.

Object creation spying is done thanks to a set of API (like CoCreateInstance, CoCreateInstanceEx, OleCreate).
All these APIs always provide us three things :
  - class identifier CLSID
  - interface identifier IID
  - pointer to the returned interface

Notice : spyed API are defined in Auto Monitoring COM Objects Creation File Syntax

As these APIs give us pointer to the returned interface, we get VTBL address, and as IID is provided, we can load the associated interface monitoring file.

Interesting hooks that are installed on each interfaces:
As all interfaces are derived from IUnknown, we always can add the following hooks for each interface
1) To spy object life, we need to add a hook on the IUnkown::Release method.

2) To hook new interfaces and load associated monitoring files, we need to add a hook on the IUnknown::QueryInterface.
Doing this, each time an interface is queried, we can do the same things as we just do.
And as before calling any method on an interface, we have to had previously called QueryInterface, method are hooked before any call.

Auto Hook

Norice : As some interfaces are shared according to controls, hooks may be already installed for interface by an object of another class

IDispatch Parsing :

The goal of COM, OLE and ActiveX object is reuse. So, generally object expose their public methods to developpers and container application by Type Library files (.tlb), or IDispatch interface.
As tlb files are not always provided to users, I have decided to use IDispatch to find published methods.

So as soon as a new class object is created, we try to query the IDispatch interface, to find published methods addresses and descriptions.
In case of success, and according to your COM options, hooks are auto installed for described methods.
This way allows to monitor interface even no monitoring file is associated to it.

Hook installation is possible as IDispatch member specifies there VTBL offset (oVft field of FUNCDESC structure).
VTBL index can be found thanks to VTBL offset with the easy convertion : Index=FUNCDESC.oVft/4 (in 32 bits).
So has we have method VTBL index and method description (used to get parameters names and required method stack size),
we can install a hook as described in Installing hooks

IDispatch interface returned by QueryInterface(IID_IDispatch,...) is not always the exposed object IDispatch interface.
So you must not hook the vtbl of returned IDispatch pointer, but the vtbl of interface returned by QueryInterface(IID_Exposed_By_IDispatch, ...), [else you have a nice bug like WinApiOverride for versions before 5.1]

pObject
pIDispatch
returned by QueryInterface(IID_IDispatch)
QueryInterface
AddRef
Release
...
pInterface X
QueryInterface
AddRef
Release
...
pInterface Exposed by IDispatch

This is this VTBL we must patch


Notice : it is implementing IDispatch too


QueryInterface
AddRef
Release
Release
IDispatch methods
InterfaceA_Method_1
InterfaceA_Method_2
...
InterfaceA_Method_N


Some words about IDispatchEx :

IDispatchEx is a special interface we have to take care.
In fact IDispatchEx can remove it's own methods (IDispatchEx::DeleteMemberByName, IDispatchEx::DeleteMemberByDispID) or add new one(s) (IDispatchEx::GetDispID(bstrName, fdexNameCaseSensitive, &dispid)).

In case of method(s) adding or removal, the hooks will not monitor correct functions.
What's why currently WinAPIOverride hook only IUnknown interface for objects supporting this interface. (IUnknown hooks seem to be never affected by methods adding and removal)
I think it's quite not disturbing as objects supporting this interface are used in few cases, mainly for scripting technologies. (By the way Internet explorer use it for javascript "document" object of a web page).
For those who intend to hook such objects, they have to hook the IDispatchEx::DeleteMemberByName, IDispatchEx::DeleteMemberByDispID and IDispatchEx::GetDispID, to manually manages methods hooks.



ULM of HookCom.dll main classes