COM 接口方法

逆向工程 拆卸 视窗 电脑
2021-06-14 02:44:27

我正在逆转恶意软件,它使用 COM,我显然不知道。我的问题是如何找出使用 ppv(和 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

我猜最后一个调用的函数是 objectStublessClient7,因为有三种方法(查询接口等),然后是 objectStublessClient 的(代码看起来像它)。(是对的吗?)

根据这篇微软文章

ObjectStubless 只是调用 ObjectStublessClient,将方法索引(来自 ecx)作为参数传递。最后,ObjectStublessClient 从 vtable 中提取格式字符串并跳转到 NdrClientCall2。与 NdrStubCall2 一样,此 RPCRT4.DLL 例程执行解释性封送处理和解封处理,就像使用已编译的代理和存根一样。

ObjectStublessClient 用简单的话实际上做了什么?通过索引调用方法?如果是这样,那么在我的情况下它将是IShellWindows 界面的OnActivate 看起来参数不匹配(第一个看起来像this吗?)

1个回答

传统的方式来确定指向功能[edi+1Ch]如下:

查找给定接口接口定义语言 (IDL)文件。在您的情况下,界面是IShellWindows. 根据 的文档IShellWindows,它的接口是在 IDL 文件中定义的Exdisp.idl该 IDL 文件包含在Windows SDK(可免费下载)中,并将安装到诸如C:\Program Files\Microsoft SDKs\Windows\v7.1A\Include\Exdisp.idl. 您可以Exdisp.idl使用文本编辑器打开该文件以查看以下接口定义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);
}

我们可以看到IShellWindows接口有如下vtable条目:

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

但是,您也可以在 IDL 中看到IShellWindows接口继承自IDispatch. IDispatch具有以下 vtable 条目(来自OAIdl.idl):

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

IDispatchin的 IDLOAIdl.idl还指定IDispatch继承自IUnknown. IUnknown具有以下 vtable 条目(来自Unknwn.idl):

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

所以现在我们知道IShellWindows继承自IDispatch,继承自IUnknown. 因此,vtable 的完整布局IShellWindows如下:

*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()
...

回顾您的代码,我们看到对 的调用*ppv+1Ch,我们从上面构造的虚表中看到它是对函数的调用IShellWindows::Count(),并且&var_C是指向IShellWindows::Count()[out, retval] long *Count参数的指针


动态的方法来确定指向的函数[edi+1Ch]如下:

在调试器中运行上面的代码,在 上设置断点call dword ptr [edi+1Ch],然后查看指令调用的函数。


确定指向的函数最简单方法[edi+1Ch]如下:

使用COMView回到 COMView 的机器链接)检查IShellWindows界面:

<code>IShellWindows</code> COMView 中的 vtable

您可以在上面的屏幕截图中看到 vtable 偏移量 28 (1Ch) 处的函数是Count().