從Hook虛擬函式到HOOK COM API
阿新 • • 發佈:2018-11-08
// HookVtable.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <iostream> #include <memory.h> #include <windows.h> using namespace std; class Test{ private: HANDLE m_hProcess; DWORD m_dwOldProtectFlag; ULONG_PTR** m_pplVrtable; ULONG_PTR m_OldProcAddress; size_t m_sizeRead; MEMORY_BASIC_INFORMATION mbi; public: Test() :m_hProcess(NULL), m_dwOldProtectFlag(0), m_pplVrtable(NULL), m_OldProcAddress(0), m_sizeRead(0) { ZeroMemory(&mbi, sizeof(mbi)); } ~Test() { }; virtual void fun1() { cout <<this<<":"<< "fun1 called!" << endl; } virtual void fun2() { cout << this << ":" << "fun2 called!" << endl; } virtual void fun3() { cout << this << ":" << "fun3 called!" << endl; } void Hook(ULONG_PTR dwAddFun) { m_pplVrtable = (ULONG_PTR**)(this); m_hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ::GetCurrentProcessId()); if (VirtualQueryEx(m_hProcess, (LPVOID)(*m_pplVrtable), &mbi, sizeof(mbi)) != sizeof(mbi)) return; if (!VirtualProtectEx(m_hProcess, mbi.BaseAddress, 16, PAGE_EXECUTE_READWRITE, &m_dwOldProtectFlag)) return; ReadProcessMemory(m_hProcess, &(*m_pplVrtable)[1], &m_OldProcAddress, sizeof(ULONG_PTR), &m_sizeRead); (*m_pplVrtable)[1] = dwAddFun; } void UnHook() { DWORD dwTemp = 0; (*m_pplVrtable)[1] = m_OldProcAddress; VirtualProtectEx(m_hProcess, mbi.BaseAddress, 16, m_dwOldProtectFlag, &dwTemp); CloseHandle(m_hProcess); } }; void MyFun() { cout << "This is fake function" << endl; } int _tmain(int argc, _TCHAR* argv[]) { Test* pA = new Test; Test* pA2 = new Test; pA->Hook((ULONG_PTR)MyFun); pA->fun1(); pA->fun2(); pA2->fun2(); pA->UnHook(); pA->fun1(); pA->fun2(); pA2->fun2(); delete pA; return 0; }
同一個程序下 某個類的虛擬函式列表是唯一的, 所有類物件共享 ,類物件的this指標指向的第一個地址就是虛擬函式表的地址。
修改表中某個虛擬函式的地址就能修改所有類物件的函式跳轉 (虛擬函式的索引 是虛擬函式在類裡面的排序位置 由0開始)。
以上就是HOOK COM API的基本原理
測試一下吧
ITextServices* pTextServices = NULL; typedef HRESULT(ITextServices::*TrueTxSendMessage)(UINT msg, WPARAM wparam, LPARAM lparam, LRESULT *plresult); TrueTxSendMessage g_func = NULL; HRESULT STDMETHODCALLTYPE FakeTxSendMessage( UINT msg, WPARAM wparam, LPARAM lparam, LRESULT *plresult) { MessageBox(NULL, _T("FakeTxSendMessage"), _T("FakeTxSendMessage"), MB_OK); return (pTextServices->*(g_func))(msg,wparam,lparam,plresult); } HANDLE m_hProcess = NULL; DWORD** m_pplVrtable = NULL; DWORD m_dwOldProtectFlag = 0; DWORD m_OldProcAddress = 0; DWORD m_sizeRead = 0; MEMORY_BASIC_INFORMATION mbi = {0}; void Hook(DWORD dwAddFun, ITextServices* pITextServices) { m_pplVrtable = (DWORD**)(pITextServices); m_hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ::GetCurrentProcessId()); if (VirtualQueryEx(m_hProcess, (LPVOID)(*m_pplVrtable), &mbi, sizeof(mbi)) != sizeof(mbi)) return; if (!VirtualProtectEx(m_hProcess, mbi.BaseAddress, 16, PAGE_EXECUTE_READWRITE, &m_dwOldProtectFlag)) return; ReadProcessMemory(m_hProcess, &(*m_pplVrtable)[3], &m_OldProcAddress, sizeof(DWORD), &m_sizeRead); memcpy(&g_func, &m_OldProcAddress, sizeof(DWORD)); (*m_pplVrtable)[3] = dwAddFun; } void UnHook() { DWORD dwTemp = 0; (*m_pplVrtable)[3] = m_OldProcAddress; VirtualProtectEx(m_hProcess, mbi.BaseAddress, 16, m_dwOldProtectFlag, &dwTemp); CloseHandle(m_hProcess); } do { HRESULT hr; IUnknown* pUnk = NULL; // Create an instance of the application-defined object that implements the ITextHost interface. MyTextHost* pTextHost = new MyTextHost(g_hWnd); MyTextHost* pTextHost2 = new MyTextHost(g_hWnd); if (pTextHost == NULL) break; PCreateTextServices TextServicesProc = NULL; HMODULE hmodRichEdit = LoadLibrary(_T("Msftedit.dll")); // Retrieve the IID_ITextServices interface identifier from Msftedit.dll. IID* pIID_ITS = NULL; if (hmodRichEdit) { pIID_ITS = (IID*)(VOID*)GetProcAddress(hmodRichEdit, "IID_ITextServices"); TextServicesProc = (PCreateTextServices)GetProcAddress(hmodRichEdit, "CreateTextServices"); } if (TextServicesProc) { hr = TextServicesProc(NULL, pTextHost, &pUnk); } // Create an instance of the text services object. //hr = CreateTextServices(NULL, pTextHost, &pUnk); if (FAILED(hr)) break; // Retrieve the ITextServices interface. hr = pUnk->QueryInterface(*pIID_ITS, (void **)&pTextServices); Hook((ULONG_PTR)FakeTxSendMessage, pTextServices); //UnHook(); if (TextServicesProc) { hr = TextServicesProc(NULL, pTextHost2, &pUnk); hr = pUnk->QueryInterface(*pIID_ITS, (void **)&pTextServices); } pUnk->Release(); hr = pTextServices->TxSendMessage(WM_SETFOCUS, 0, 0, 0); if (FAILED(hr)) break; } while (0);
注意事項:
1,儲存原有虛擬函式的指標型別需要為類成員函式指標型別
typedef HRESULT(ITextServices::*TrueTxSendMessage)(UINT msg, WPARAM wparam, LPARAM lparam, LRESULT *plresult);
否則異常
2,要保證呼叫約定前後一致
HRESULT STDMETHODCALLTYPE FakeTxSendMessage(
UINT msg,
WPARAM wparam,
LPARAM lparam,
LRESULT *plresult)
{
MessageBox(NULL, _T("FakeTxSendMessage"), _T("FakeTxSendMessage"), MB_OK);
return (pTextServices->*(g_func))(msg,wparam,lparam,plresult);
}
否則異常
Thanks~