|Developer Documentation : COM OLE ActiveX hooking|
- General COM description
Content of dll/ocx
Basic objects VTBL
More complex objects VTBL
- Installing hooks
- Static hooks VS auto hooks
- 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.
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.
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
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
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
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)
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.
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)
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.
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
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)
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