在传统的方式来确定指向功能[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()
IDispatch
in的 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
界面:
您可以在上面的屏幕截图中看到 vtable 偏移量 28 (1Ch) 处的函数是Count()
.