API挂钩COM对象函数?

Pau*_*ano 5 c++ com hook vtable api-hook

问候StackOverflowians,

正如此处所发现的,Windows 7具有一个错误,在该错误中,Windows资源管理器实例不会触发DISPID_BEFORENAVIGATE2事件.此事件允许在即将进行导航时通知shell扩展,并且(对我来说最重要的)有机会取消导航.我已经找了很长时间的解决方法,我想我找到了一个.但是,我想对它的安全性有一些看法.

我最近一直在玩API挂钩,我已经用它来为我的扩展程序挂钩一些函数了.我注意到IShellBrowser中有一个控制导航的功能.起初我以为你不能挂钩这样的东西,但在阅读COM对象布局后,我意识到应该可以通过从任何活动实例的vtable中抓取正确的函数指针来实现.果然,它像梦一样.设置挂钩后,所有资源管理器窗口中的所有导航都会在我的绕行功能中运行,我可以根据目标pidl决定是否拒绝它们.

所以我的问题是,我有什么理由不这样做吗?我从来没有听说过用于挂钩COM对象函数的API钩子.是否存在不起作用的情况?危险吗?(至少比常规的API挂钩更多)

相关代码如下.我正在使用MinHook,这是一个简约的挂钩库,它使用了经过验证的蹦床功能方法.

typedef HRESULT (WINAPI *BROWSEOBJECT)(IShellBrowser*, PCUIDLIST_RELATIVE, UINT);
HRESULT WINAPI DetourBrowseObject(IShellBrowser* _this, PCUIDLIST_RELATIVE pidl, UINT wFlags);
BROWSEOBJECT fpBrowseObject = NULL;
BROWSEOBJECT ShellBrowser_BrowseObject = NULL;

bool Initialize() {
    if(MH_Initialize() != MH_OK) {
        return false;
    }

    // Get a reference to an existing IShellBrowser.  Any instance will do.
    // ShellBrowser enum code taken from The Old New Thing
    IShellWindows *psw;
    BOOL fFound = FALSE;
    if (SUCCEEDED(CoCreateInstance(CLSID_ShellWindows, NULL, CLSCTX_ALL, IID_IShellWindows, (void**)&psw))) {
        VARIANT v;
        V_VT(&v) = VT_I4;
        IDispatch  *pdisp;
        for (V_I4(&v) = 0; !fFound && psw->Item(v, &pdisp) == S_OK; V_I4(&v)++) {
            IWebBrowserApp *pwba;
            if (SUCCEEDED(pdisp->QueryInterface(IID_IWebBrowserApp, (void**)&pwba))) {
                IServiceProvider *psp;
                if (SUCCEEDED(pwba->QueryInterface(IID_IServiceProvider, (void**)&psp))) {
                    IShellBrowser *psb;
                    if (SUCCEEDED(psp->QueryService(SID_STopLevelBrowser,IID_IShellBrowser, (void**)&psb))) {
                        fFound = true;

                        // Grab the 11th entry in the VTable, which is BrowseObject
                        void** vtable = (*(void***)(psb));
                        ShellBrowser_BrowseObject = (BROWSEOBJECT)(vtable[11]);
                        psb->Release();
                    }
                    psp->Release();
                }
                pwba->Release();
            }
            pdisp->Release();
        }
        psw->Release();
    }

    if(fFound) {
        if(MH_CreateHook(ShellBrowser_BrowseObject, &DetourBrowseObject, reinterpret_cast<void**>(&fpBrowseObject)) != MH_OK) {
            return false;
        }
        if(MH_EnableHook(ShellBrowser_BrowseObject) != MH_OK) {
            return false;
        }
    }
    return true;
}

HRESULT WINAPI DetourBrowseObject(IShellBrowser* _this, PCUIDLIST_RELATIVE pidl, UINT wFlags) {
    if(NavigateIsOkay(pidl, wFlags)) {
        return fpBrowseObject(_this, pidl, wFlags);
    }
    else {
        return S_FALSE;
    }    
}
Run Code Online (Sandbox Code Playgroud)

Jim*_*som 2

我从未听说过 API 挂钩用于挂钩 COM 对象函数。

COM 对象的成员函数实际上并没有那么不同,如果您坚持通常的挂钩准则,实际上可以很好地挂钩。几年前,我必须连接专有 CRM 解决方案的 COM 组件才能将其连接到数据库服务器。该应用程序运行良好,并且已经稳定运行了好几年。