我正在逆转恶意软件,它使用了COM,我显然不知道。我的问题是如何找出使用ppv(和objectstublessclient?)调用的方法的方法。我猜最后一个调用的函数是objectStublessClient7,因为存在三种方法(queryinterface等),然后是objectStublessClient的(和代码类似)。 (是吗?)根据这篇Microsoft文章:


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):IDispatch中的OAIdl.idl的IDL还指定IDispatch继承自IUnknownIUnknown具有以下vtable条目(来自Unknwn.idl):

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


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

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


回头看一下您的代码,我们看到了对*ppv+1Ch的调用,从我们的代码中可以看到上面构造的vtable是对函数IShellWindows::Count()的调用,而&var_C是指向IShellWindows::Count()[out, retval] long *Count参数的指针。


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

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

使用COMView(到COMView的回溯机器链接)检查IShellWindows接口:您可以在上面的屏幕截图中看到vtable offset 28(1Ch)处的函数是Count()

评论


我忘了提一下,您也许还可以告诉IDA将ppv解释为IShellWindows *变量,在这种情况下,IDA将向您显示[ppv + 1C]是对IShellWindows :: Count()的调用。

–詹森·格夫纳(Jason Geffner)
2013年9月22日16:58

好答案!正如Jason在他的评论中所述,一旦您知道某个变量的类型名称,IDA就会经常知道它是否是标准Windows COM类型。在这种情况下,您将转到数据部分中的ppv变量(突出显示该令牌并按Enter),然后按“ y”输入类型IShellWindows *。从那里,IDA的参数跟踪算法将提取许多参考,并自动为您填充。 (这些算法并不是完美的-不可能是由于所涉及的数学上的不可能-因此您可能仍需要手动填写一些算法)。

–滚轴
2013年9月25日在21:26

ComView似乎没有运行。有人可以确认是否可行吗?

– Nuzzolilo
7月7日7:44