Tuesday, November 25, 2008

Reversing COM Objects

I've been working with a specific COM object lately trying to debug a potential vulnerability in it. So I thought I would mention a little bit about reversing COM objects. COM objects utilize specific methods for creation. Typically the functions CoCreateInstance() or CoCreateInstanceEx() are used to create these objects. There are more ways to create objects such at CoGetClassObject() but I'll leave that up to you to look into a little further. The following is the MSDN description of CoCreateInstance():

STDAPI CoCreateInstance(
REFCLSID rclsid,
LPUNKNOWN pUnkOuter,
DWORD dwClsContext,
REFIID riid,
LPVOID * ppv
);

rclsid

[in] CLSID associated with the data and code that will be used to create the object.

pUnkOuter

[in] If NULL, indicates that the object is not being created as part of an aggregate. If non-NULL, pointer to the aggregate object's IUnknown interface (the controlling IUnknown).

dwClsContext

[in] Context in which the code that manages the newly created object will run. The values are taken from the enumeration CLSCTX.

riid

[in] Reference to the identifier of the interface to be used to communicate with the object.

ppv

[out] Address of pointer variable that receives the interface pointer requested in riid. Upon successful return, *ppv contains the requested interface pointer. Upon failure, *ppv contains NULL.

Return Values

S_OK

An instance of the specified object class was successfully created.

REGDB_E_CLASSNOTREG

A specified class is not registered in the registration database. Also can indicate that the type of server you requested in the CLSCTX enumeration is not registered or the values for the server types in the registry are corrupt.

CLASS_E_NOAGGREGATION

This class cannot be created as part of an aggregate.

E_NOINTERFACE

The specified class does not implement the requested interface, or the controlling IUnknown does not expose the requested interface.


and here is the description of CoCreateInstanceEx()


HRESULT CoCreateInstanceEx(
REFCLSID rclsid,
IUnknown * punkOuter,
DWORD dwClsCtx,
COSERVERINFO * pServerInfo,
ULONG cmq,
MULTI_QI * pResults
);

Parameters

rclsid

[in] CLSID of the object to be created.

punkOuter

[in] When non-NULL, indicates the instance is being created as part of an aggregate, and punkOuter is to be used as the new instance's controlling IUnknown. Aggregation is currently not supported cross-process or cross-machine. When instantiating an object out of process, CLASS_E_NOAGGREGATION will be returned if punkOuter is non-NULL.

dwClsCtx

[in] Values taken from the CLSCTX enumeration.

pServerInfo

[in] Information about the computer on which to instantiate the object. May be NULL, in which case the object is instantiated on the local computer or at the computer specified in the registry under the class's RemoteServerName named value, according to the interpretation of the dwClsCtx parameter. See the CLSCTX documentation for details).

cmq

[in] Number of MULTI_QI structures in pResults. Must be greater than zero.

pResults

[in] Array of MULTI_QI structures. Each structure has three members: the identifier for a requested interface (pIID), the location to return the interface pointer (pItf) and the return value of the call to QueryInterface (hr).

Return Values

This function supports the standard return value E_INVALIDARG, as well as the following:

S_OK

Indicates success.

REGDB_E_CLASSNOTREG

A specified class is not registered in the registration database. Also can indicate that the type of server you requested in the CLSCTX enumeration is not registered or the values for the server types in the registry are corrupt.

CLASS_E_NOAGGREGATION

This class cannot be created as part of an aggregate.

CO_S_NOTALLINTERFACES

At least one, but not all of the interfaces requested in the pResults array were successfully retrieved. The hr field of each of the MULTI_QI structures in pResults indicates with S_OK or E_NOINTERFACE whether the specific interface was returned.

E_NOINTERFACE

None of the interfaces requested in the pResults array were successfully retrieved.


If you see calls to these functions it will provide your first clue about the object. Firstly you will have a pointer to the CLSID in memory which can be useful in identifying what object is being created. It is possible this will be dynamic in which case the only way to really know which CLSID is being used would be using a debugger and setting a break point at CoCreateInstance() or CoCreateInstanceEx(). This information alone should give you a fair amount of details about the object. You can use oleview to look at the interfaces of the object and get an idea of what methods the object provides.

So now you know which object is being created, you know what methods it provides. How do you find the code which implements these methods? Well the first thing to know is that we are looking for a virtual function table. Another important piece of information to know is that COM objects must support the IUnknown interface. Given this information we could start looking for references into the this pointer and looking at indirect calls. I would say though that the best way would be to use runtime debugging to find the vtable. The reason being you can step through the code at creation and quickly find the vtable. This method also allows you to set breakpoints on the functions within the vtable so that you can see which methods are being used. There are definitely other ways to go about this but this is perhaps the easiest method.

Anyway, this post is getting rather long so I will give it a break for now. I may post more on this subject later on.

4 comments:

TOTU said...

For loads of tools on reverse engineering / cracking, I found this site:

http://totu.eire-media.com

vishal vishwakarma said...

thank u for posting such a good information
Reverse Engineering in USA

jonas said...

https://www.blogger.com/comment.g?blogID=3359952960068218647&postID=6956122873604467519&page=1&token=1563259693467

jonas said...

Nice blog!!!!!!!.
ReverseEngineering