1

我正在尝试挂钩 CopyItems 函数,它工作正常,但是当我尝试在回调函数中调用 Real CopyItems 函数时,它会崩溃,我的代码如下,请帮助我。

 PVOID GetInterfaceMethod(PVOID intf, DWORD methodIndex)
 {
  return *(PVOID*)(*(DWORD*)intf + methodIndex * 4);
 }

typedef HRESULT (WINAPI  *CopyItemsNext)(IUnknown *punkItems,IShellItem *psiDestinationFolder);
CopyItemsNext Real_CopyItems = NULL;
CopyItemsNext Actual_CopyItems;


HRESULT WINAPI CopyItemsCallback(IUnknown *punkItems,IShellItem *psiDestinationFolder)
{

    MessageBoxW(NULL,L"CopyItems Function Called", L"HookedCopyItemS", MB_OK);
    return Real_CopyItems(punkItems, psiDestinationFolder);
}


HRESULT WINAPI CoCreateInstanceCallback(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID *ppv)
{
   const char *IFileOperation_GUID = "{3AD05575-8857-4850-9277-11B85BDB8E09}";
   char GUIDString[64];

   HRESULT HR = Real_CoCreateInstance(rclsid, pUnkOuter, dwClsContext, riid, ppv);

   sprintf_s(GUIDString,64, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\0",
    rclsid.Data1, rclsid.Data2, rclsid.Data3,
    rclsid.Data4[0], rclsid.Data4[1],
    rclsid.Data4[2], rclsid.Data4[3],
    rclsid.Data4[4], rclsid.Data4[5],
    rclsid.Data4[6], rclsid.Data4[7]);

   if(strcmp(GUIDString, IFileOperation_GUID) == 0)
   {
       MessageBoxA(NULL, "IFileOperation_GUID Found", GUIDString, MB_OK);

       if(Real_CopyItems == NULL)
       {
        Actual_CopyItems = (CopyItemsNext)GetInterfaceMethod(*ppv, 17);
        MessageBoxA(NULL,"AFTER GetInterfaceMethod", "TEST", MB_OK);

        if (MH_CreateHook(Actual_CopyItems, &CopyItemsCallback, reinterpret_cast<void**>(&Real_CopyItems)) != MH_OK)
        {
            MessageBoxW(NULL, L"Failed CreateHook Real_CopyItem", L"Info!", MB_ICONWARNING|MB_OK);
        }
        if (MH_EnableHook(Actual_CopyItems) != MH_OK)
        {
            MessageBoxW(NULL, L"Failed EnableHook Real_CopyItem", L"Info!", MB_ICONWARNING|MB_OK);
        }
    }
}
return HR;
}

//DllMain Function 
BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
    if (MH_Initialize() != MH_OK)
    {
        MessageBoxW(NULL, L"Failed Initialize", L"Info!", MB_ICONWARNING|MB_OK);    
    }
    if (MH_CreateHook(&CoCreateInstance, &CoCreateInstanceCallback, reinterpret_cast<void**>(&Real_CoCreateInstance)) != MH_OK)
    {
        MessageBoxW(NULL,L"Failed MH_CreateHook CoCreateInstance",L"Info!",MB_ICONWARNING|MB_OK);
    }
    if (MH_EnableHook(&CoCreateInstance) != MH_OK)
    {
        MessageBoxW(NULL,L"Failed MH_EnableHook StartDocA",L"Info!",MB_ICONWARNING|MB_OK);
    }
    break;

case DLL_PROCESS_DETACH:
    if (MH_Uninitialize() != MH_OK)
    {               
    }
    if (MH_DisableHook(Actual_CopyItems) != MH_OK)
    {
    }
    if (MH_DisableHook(&CoCreateInstance) != MH_OK)
    {
    }

    break;
}
return TRUE;
}

在 CopyItemsCallback 函数内的上述代码中,我正在显示消息框只是为了确认天气该函数没有得到钩子,所以我在调用 Real CopyItems 函数之后得到了那个消息框,但它正在崩溃,所以请检查是什么我的代码的问题。

4

1 回答 1

1

IFileOperation::CopyItems 是 COM 方法,而不是常规的 Win32 函数,因此您需要区别对待 CoCreateInstance,后者是普通的 Win32 API。

当您使用 C++ 语法调用 COM 方法时,您看不到的是作为隐藏参数在幕后传递的“this”指针(与接口指针相同)。但是如果你想使用 C 风格的代码调用 COM 方法,你必须手动处理这个问题。

因此,您对 CopyItems 函数的定义应如下所示:

typedef HRESULT (STDMETHODCALLTYPE *CopyItemsNext)(IFileOperation * pThis, IUnknown *punkItems, IShellItem *psiDestinationFolder);

...并且当您调用“真正的”时,您必须将该 pThis 作为第一个参数传递。

请注意,此技巧是特定于 COM 的,通常不能以这种方式处理 C++ 方法。碰巧 COM 被设计为可以从普通 C 中使用,因此 COM 要求像普通参数一样传递“this”指针。(COM 方法用 STDMETHODCALLTYPE 标记,这告诉编译器将它们与没有它的方法区别对待。)但是,对于非 COM C++ 类,编译器可能会做其他事情,例如在寄存器中传递 this 指针。

--

顺便说一句,请注意 GetInterfaceMethod 中的 DWORD 仅适用于 32 位窗口;如果您想要一个始终是指针大小的类型,然后可以使用 32 位或 64 位代码,请使用 DWORD_PTR。

于 2012-08-17T06:14:22.767 回答