2010-01-02 4 views
2

Я пытаюсь изменить поведение интерфейса IDispatch, уже присутствующего в системе. Для этого я планировал подключиться к v-таблице объектов во время выполнения и изменять указатели, чтобы вместо этого указывать на пользовательский метод hook.Hook IDispatch v-table в C++

Если я могу заставить это работать, я могу добавить новые методы и свойства к уже существующим объектам. Ницца.

Сначала я попытался подключиться к v-таблице для IUnknown (из которой IDispatch наследует), и это сработало нормально. Однако попытка изменения в IDispatch не работает вообще. Ничего не происходит вообще, код работает так же, как и без крючка.

Вот код, это очень просто, так что не должно быть никаких проблем, чтобы понять

#include <iostream> 
#include <windows.h> 
#include <Objbase.h> 
#pragma comment (lib,"Ole32.lib") 
using namespace std; 

HRESULT __stdcall typecount(IDispatch *self,UINT*u) 
{ 
    cout << "hook" << endl; 
    *u=1; 
    return S_OK; 
} 


int main() 
{ 
    CoInitialize(NULL); 

    // Get clsid from name 
    CLSID clsid; 
    CLSIDFromProgID(L"shell.application",&clsid); 

    // Create instance 
    IDispatch *obj=NULL; 
    CoCreateInstance(clsid,NULL,CLSCTX_INPROC_SERVER,__uuidof(IDispatch),(void**)&obj); 

    // Get vtable and offset in vtable for idispatch 
    void* iunknown_vtable= (void*)*((unsigned int*)obj); 
    // There are three entries in IUnknown, therefore add 12 to go to IDispatch 
    void* idispatch_vtable = (void*)(((unsigned int)iunknown_vtable)+12); 

    // Get pointer of first emtry in IDispatch vtable (GetTypeInfoCount) 
    unsigned int* v1 = (unsigned int*)iunknown_vtable; 

    // Change memory permissions so address can be overwritten 
    DWORD old; 
    VirtualProtect(v1,4,PAGE_EXECUTE_READWRITE,&old); 

    // Override v-table pointer 
    *v1 = (unsigned int) typecount; 

    // Try calling GetTypeInfo count, should now be hooked. But isn't works as usual 
    UINT num=0; 
    obj->GetTypeInfoCount(&num); 

/* 
    HRESULT hresult; 
    OLECHAR FAR* szMember = (OLECHAR*)L"MinimizeAll"; 
    DISPID dispid; 
    DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0}; 
    hresult = obj->GetIDsOfNames(IID_NULL, &szMember, 1, 
    LOCALE_SYSTEM_DEFAULT, &dispid) ; 
    hresult = obj->Invoke(dispid,IID_NULL,LOCALE_SYSTEM_DEFAULT,DISPATCH_METHOD,&dispparamsNoArgs, NULL, NULL, NULL); 
*/ 

} 

Спасибо заранее!

ответ

2
// Get pointer of first emtry in IDispatch vtable (GetTypeInfoCount) 
unsigned int* v1 = (unsigned int*)iunknown_vtable; 

это acturely зацепил QueryInterface из IUnknown.

После Invoke маршрут к вашей typecount

//obj->GetTypeInfoCount(&num); 
LPVOID dummy; 
obj->QueryInterface(IID_NULL, &dummy); 
+0

Doh! Я случайно набрал iunknown_vtable вместо idispatch_vtable. Спасибо за чистые глаза! – monoceres

1

Я думаю, вы должны перекодировать это быть переносимыми между 32 бит и 64 бит

Оригинал:

// There are three entries in IUnknown, therefore add 12 to go to IDispatch 
    void* idispatch_vtable = (void*)(((unsigned int)iunknown_vtable)+12); 

Portable:

// There are three entries in IUnknown, therefore add 3 pointers to go to IDispatch 
    void* idispatch_vtable = (void*)(((DWORD_PTR)iunknown_vtable) + (sizeof(void *) * 3));