17

I'm reversing malware and it uses COM, which I evidently don't know. My question is how to find out what method is called using ppv (and objectstublessclient?)

push    offset ppv      ; Address of pointer variable that receives the interface pointer requested in riid
push    offset IShellWindows 
push    7              
push    0               
push    offset rclsid   
call    ds:_CoCreateInstance

mov     ebx, eax
mov     eax, num4
movsx   edx, num8
add     eax, edx
sub     eax, 0Ch
cmp     ebx, eax        ; S_OK, operation successful
jnz     exit

lea     eax, [ebp+var_C]    ;?
push    eax
mov     eax, ppv
push    eax
mov     edi, [eax]
call    dword ptr [edi+1Ch] ; ObjectStublessClient7

I guessed that the last called function is objectStublessClient7 given that there are three methods(queryinterface etc) and then objectStublessClient's (and code looks like it). (Is that right?)

According to this Microsoft article:

ObjectStubless simply calls into ObjectStublessClient, passing the method index (from ecx) as a parameter. Finally, ObjectStublessClient teases out the format strings from the vtable and jumps to NdrClientCall2. Like NdrStubCall2, this RPCRT4.DLL routine performs the interpretive marshaling and unmarshaling just as if a compiled proxy and stub were in use.

What does ObjectStublessClient actually do in simple words? Calls a method by its index? If so, then in my case it will be OnActivate of IShellWindows interface? It looks like the arguments don't match (does the first one look like this?)

0

1 Answer 1

21

The traditional way to determine the function pointed to by [edi+1Ch] is as follows:

Find the Interface Definition Language (IDL) file for the given interface. In your case, the interface is IShellWindows. According to the documentation for IShellWindows, its interface is defined in IDL file Exdisp.idl. That IDL file is included in the Windows SDK (downloadable for free), and will be installed to a location such as C:\Program Files\Microsoft SDKs\Windows\v7.1A\Include\Exdisp.idl. You can open that Exdisp.idl file with a text editor to see the Interface Definition of IShellWindows:

[
    uuid(85CB6900-4D95-11CF-960C-0080C7F4EE85),     // IID_IShellWindows
    helpstring("Definition of interface IShellWindows"),
    oleautomation,
    dual,
    odl,
]
interface IShellWindows : IDispatch
{
    //Properties
    [propget, helpstring("Get count of open Shell windows")]
    HRESULT Count([out, retval] long *Count);

    //Methods
    [id(0), helpstring("Return the shell window for the given index")]
    HRESULT Item([in,optional] VARIANT index, [out, retval]IDispatch **Folder);

    [id(-4), helpstring("Enumerates the figures")]
    HRESULT _NewEnum([out, retval] IUnknown **ppunk);

    // Some private hidden members to allow shell windows to add and
    // remove themself from the list.  We mark them hidden to keep
    // random VB apps from trying to Register...
    [helpstring("Register a window with the list"), hidden]
    HRESULT Register([in] IDispatch *pid,
                     [in] long hwnd,
                     [in] int swClass,
                     [out]long *plCookie);

    [helpstring("Register a pending open with the list"), hidden]
    HRESULT RegisterPending([in] long lThreadId,
                     [in] VARIANT* pvarloc,     // will hold pidl that is being opened.
                     [in] VARIANT* pvarlocRoot, // Optional root pidl
                     [in] int swClass,
                     [out]long *plCookie);

    [helpstring("Remove a window from the list"), hidden]
    HRESULT Revoke([in]long lCookie);
    // As an optimization, each window notifies the new location
    // only when
    //  (1) it's being deactivated
    //  (2) getFullName is called (we overload it to force update)
    [helpstring("Notifies the new location"), hidden]
    HRESULT OnNavigate([in]long lCookie, [in] VARIANT* pvarLoc);
    [helpstring("Notifies the activation"), hidden]
    HRESULT OnActivated([in]long lCookie, [in] VARIANT_BOOL fActive);
    [helpstring("Find the window based on the location"), hidden]
    HRESULT FindWindowSW([in] VARIANT* pvarLoc,
                         [in] VARIANT* pvarLocRoot, /* unused */
                         [in] int swClass,
                         [out] long * phwnd,
                         [in] int swfwOptions,
                         [out,retval] IDispatch** ppdispOut);
    [helpstring("Notifies on creation and frame name set"), hidden]
    HRESULT OnCreated([in]long lCookie,[in] IUnknown *punk);

    [helpstring("Used by IExplore to register different processes"), hidden]
    HRESULT ProcessAttachDetach([in] VARIANT_BOOL fAttach);
}

We can see that the IShellWindows interface has the following vtable entries:

- Count()
- Item()
- _NewEnum()
- Register()
- RegisterPending()
- Revoke()
- OnNavigate()
- OnActivated()
- FindWindowSW()
- OnCreated()
- ProcessAttachDetach()

However, you can also see in the IDL that the IShellWindows interface inherits from IDispatch. IDispatch has the following vtable entries (from OAIdl.idl):

- GetTypeInfoCount()
- GetTypeInfo()
- GetIDsOfNames()
- Invoke()

The IDL for IDispatch in OAIdl.idl also specifies that IDispatch inherits from IUnknown. IUnknown has the following vtable entries (from Unknwn.idl):

- QueryInterface()
- AddRef()
- Release()

So now we know that IShellWindows inherits from IDispatch, which inherits from IUnknown. As such, the full layout of the vtable for IShellWindows is as follows:

*ppv+00h = QueryInterface()
*ppv+04h = AddRef()
*ppv+08h = Release()
*ppv+0Ch = GetTypeInfoCount()
*ppv+10h = GetTypeInfo()
*ppv+14h = GetIDsOfNames()
*ppv+18h = Invoke()
*ppv+1Ch = Count()
*ppv+20h = Item()
*ppv+24h = _NewEnum()
*ppv+28h = Register()
...

Looking back at your code, we see a call to *ppv+1Ch, which we see from our constructed vtable above is a call to the function IShellWindows::Count(), and &var_C is the pointer to IShellWindows::Count()'s [out, retval] long *Count parameter.


The dynamic way to determine the function pointed to by [edi+1Ch] is as follows:

Run your code above in a debugger, set a breakpoint on call dword ptr [edi+1Ch], and see what function that instruction calls.


The easiest way to determine the function pointed to by [edi+1Ch] is as follows:

Use COMView (wayback machine link to COMView) to inspect the IShellWindows interface:

<code>IShellWindows</code> vtable in COMView

You can see in the screenshot above that the function at vtable offset 28 (1Ch) is Count().

3
  • 2
    I forgot to mention, you also might be able to tell IDA to interpret ppv as an IShellWindows* variable, in which case IDA will show you that [ppv+1C] is a call to IShellWindows::Count(). Commented Sep 22, 2013 at 16:58
  • 3
    Good answer! As Jason stated in his comment, once you know the type name for some variable, IDA will often know about it if it's a standard Windows COM type. In this case, you'd go to the ppv variable in the data section (highlight that token and press enter) and then press 'y' to enter the type IShellWindows *. From there, IDA's parameter-tracking algorithms will pick up many of the references and automatically and fill them in for you. (Those algorithms aren't perfect -- they can't be due to mathematical impossibility issues involved -- so you may still have to fill some in manually). Commented Sep 25, 2013 at 21:26
  • ComView doesn't seem to run. Can someone confirm if this works?
    – Nuzzolilo
    Commented Jul 7, 2020 at 7:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.