Функция CopyItems Hook падает
Я пытаюсь перехватить функцию CopyItems, она работает нормально, но когда я пытаюсь вызвать реальную функцию 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, но там происходит сбой, поэтому, пожалуйста, проверьте, что проблема с моим кодом.
1 ответ
IFileOperation::CopyItems - это метод COM, а не обычная функция Win32, поэтому вам нужно обращаться с ним иначе, чем с CoCreateInstance, который является простым Win32 API.
Когда вы вызываете метод COM с использованием синтаксиса C++, вы не видите, что указатель "this" (такой же, как указатель на интерфейс) передается за сцену как скрытый параметр. Но если вы хотите вызвать метод COM с использованием кода в стиле C, вам придется справиться с этим вручную.
Поэтому ваше определение функции CopyItems должно выглядеть примерно так:
typedef HRESULT (STDMETHODCALLTYPE *CopyItemsNext)(IFileOperation * pThis, IUnknown *punkItems, IShellItem *psiDestinationFolder);
... и когда вы вызываете реальный, вам нужно передать это pThis в качестве первого параметра.
Обратите внимание, что этот прием специфичен для COM, в общем случае вы не можете относиться к методам C++ таким образом. Просто так получается, что COM был спроектирован так, чтобы его можно было использовать из простого C, поэтому COM требует, чтобы указатель 'this' передавался так же, как и обычный параметр. (Методы COM помечены STDMETHODCALLTYPE, что говорит компилятору обрабатывать их иначе, чем методы без него.) Однако для не-COM классов C++ компилятор может делать что-то еще, например, передавать указатель this в регистр.
-
Кстати, обратите внимание, что DWORD в вашем GetInterfaceMethod будет работать только на 32-битных окнах; используйте DWORD_PTR, если вы хотите тип, который всегда имеет размер указателя и который затем будет работать с 32-битным или 64-битным кодом.