Quantcast
Channel: 看雪安全论坛
Viewing all articles
Browse latest Browse all 9556

【原创】Hook CreateTextServices

$
0
0
大牛飘过,最近想到了CreateTextServices来记录消息
首先想办法注入到QQ进程内,我是劫持HummerEngine.dll

以前大家都是调用ITextServices::TxGetText获取消息记录,而我想到了Hook ITextServices的虚函数表,我Hook它三个成员函数TxSendMessage、TxGetText、TxSetText。

我们以前追加编辑框文本的时候都是先发生EM_SETSEL,再发生EM_REPLACESEL。QQ的无窗口编辑控件也是如此,因此我们只要拦截ITextServices::TxSendMessage,就能记录到聊天记录。

但是Hook了ITextServices::TxSendMessage了,却得不到聊天的窗口句柄,因此我只能以this指针为文件名来追加消息记录。Hook ITextServices::TxSendMessage有个好处,只要在编辑框里面有的内容都能记录下来,就不怕对方清屏了。另外QQ可能有很多无窗口编辑框,但只有聊天消息的编辑框的文本模式为TM_RICHTEXT,发生EM_GETTEXTMODE消息判断下就行了

剩下的是代码,大家凑合着看,反正我在64位QQ2013sp1可以记录到,至于32位由于有保护的原因,不能劫持HummerEngine.dll

代码:

#include <Windows.h>
#include <Tchar.h>
#include <Stdio.h>
#include <Richedit.h>
#include <Textserv.h>

#include "mhook-lib\mhook.h"

#pragma comment(linker, "/EXPORT:RunQQHummerEngine=HummerEngineX.RunQQHummerEngine,PRIVATE")
#pragma comment(linker, "/EXPORT:UninitializeCom=HummerEngineX.UninitializeCom,PRIVATE")

typedef DWORD (WINAPIV *PGetSelfUin)(VOID);

HMODULE                g_hinst;
HMODULE                        g_hRiched20;
BOOL                        g_bInitial;
TCHAR                        g_szRecordPath[MAX_PATH];
DWORD                        g_dwUin;

PCreateTextServices                g_pfnCreateTextServices;
PGetSelfUin                                g_pfnGetSelfUin;

//追加文本文件
VOID AppendTextFile(LPTSTR pszFilePath, LPTSTR pszText)
{
        HANDLE                        hFile;
        DWORD                        dwFileSize;
        DWORD                        dwRetLen;

        hFile = CreateFile(pszFilePath,
                GENERIC_WRITE,
                0,
                NULL,
                OPEN_ALWAYS,
                FILE_ATTRIBUTE_NORMAL,
                NULL);
        if(hFile != INVALID_HANDLE_VALUE)
        {
                if(GetLastError() == ERROR_ALREADY_EXISTS)
                {
                        dwFileSize = GetFileSize(hFile, NULL);
                        SetFilePointer(hFile, dwFileSize, NULL, FILE_BEGIN);
                }
                else
                {
#ifdef UNICODE
                        UCHAR                        szBigUtf16Hd[] = {0xFF, 0xFE};

                        WriteFile(hFile, &szBigUtf16Hd, sizeof(szBigUtf16Hd), &dwRetLen, NULL);
#endif
                }

                WriteFile(hFile, pszText, lstrlen(pszText) * sizeof(TCHAR), &dwRetLen, NULL);

                CloseHandle(hFile);
        }
}

class CHookTextServices
{
public:
        HRESULT TxSendMessage(UINT msg, WPARAM wparam, LPARAM lparam, LRESULT *plresult)
        {
                ITextServices                *pTextServices = (ITextServices*)this;
               
                switch(msg)
                {
                case EM_REPLACESEL:
                        {
                                SYSTEMTIME                systemTime;
                                LPTSTR                        pszStr;
                                TCHAR                        szFormat[512];
                                LRESULT                        lRes;
                               
                                pszStr = (LPTSTR)lparam;
                                if(lstrcmpi(pszStr, _T("")) == 0)
                                        break;

                                if(g_bInitial == FALSE)
                                        break;

                                if((pTextServices->TxSendMessage(EM_GETTEXTMODE, 0, 0, &lRes) == S_OK) && (lRes & TM_RICHTEXT))
                                {
                                        GetSystemTime(&systemTime);
                                        wsprintf(szFormat, _T("%s\\%lu\\%02X%02X%02X%p.txt"),
                                                g_szRecordPath,
                                                g_dwUin,
                                                systemTime.wYear,
                                                systemTime.wMonth,
                                                systemTime.wDay,
                                                this);

                                        AppendTextFile(szFormat, (LPWSTR)lparam);
                                }
                        }
                        break;
                }
                return (pTextServices->*(g_pHookTextServices->TrueTxSendMessage))(msg, wparam, lparam, plresult);
        }

        HRESULT TxGetText(BSTR *pbstrText)
        {
                ITextServices                *pTextServices = (ITextServices*)this;
               
                return (pTextServices->*(g_pHookTextServices->TrueTxGetText))(pbstrText);
        }

        HRESULT TxSetText(LPCWSTR pszText)
        {
                ITextServices                *pTextServices = (ITextServices*)this;
               
                return (pTextServices->*(g_pHookTextServices->TrueTxSetText))(pszText);
        }

public:
        HRESULT (ITextServices::* TrueTxSendMessage)(UINT msg, WPARAM wparam, LPARAM lparam, LRESULT *plresult);
        HRESULT (ITextServices::* TrueTxGetText)(BSTR *pbstrText);
        HRESULT (ITextServices::* TrueTxSetText)(LPCWSTR pszText);

        HRESULT (CHookTextServices::* HookTxSendMessage)(UINT msg, WPARAM wparam, LPARAM lparam, LRESULT *plresult);
        HRESULT (CHookTextServices::* HookTxGetText)(BSTR *pbstrText);
        HRESULT (CHookTextServices::* HookTxSetText)(LPCWSTR pszText);

} *g_pHookTextServices;

VOID VFSet(LPVOID *ppVfPtr, LPVOID pAddr)
{
        DWORD                        dwOldProtect;
       
        if(VirtualProtect(ppVfPtr,
                sizeof(LPVOID),
                PAGE_EXECUTE_READWRITE,
                &dwOldProtect))
        {
                *ppVfPtr = pAddr;
                VirtualProtect(ppVfPtr,
                        sizeof(LPVOID),
                        dwOldProtect,
                        &dwOldProtect);
        }
}

HRESULT STDAPICALLTYPE NewCreateTextServices(
        IUnknown *punkOuter,
        ITextHost *pITextHost,
        IUnknown **ppUnk
        )
{
        HRESULT                                hr;
        LPIID                                pIID_ITS;
        ITextServices                *pTextServices;
        LPVOID                                *ppVtPtr;
        LPVOID                                *ppVfPtr;

        HMODULE                                hKernelUtil;
        TCHAR                                szFormat[512];
        DWORD                                cbValue;

        if(g_bInitial == FALSE)
        {
                if((hKernelUtil = GetModuleHandle(_T("KernelUtil.dll"))) &&
                        (g_pfnGetSelfUin = (PGetSelfUin)GetProcAddress(hKernelUtil, "?GetSelfUin@Contact@Util@@YAKXZ")))
                {
                        if(g_dwUin = g_pfnGetSelfUin())
                        {
                                //读取记录文件夹路径
                                cbValue = sizeof(g_szRecordPath);
                                if(ReadRegValue(HKEY_LOCAL_MACHINE,
                                        _T("SOFTWARE\\QQMsg"),
                                        _T("RecordFilePath"),
                                        g_szRecordPath,
                                        &cbValue))
                                {
                                        g_bInitial = TRUE;

                                        wsprintf(szFormat, _T("%s\\%lu"), g_szRecordPath, g_dwUin);
                                        CreateDirectory(szFormat, NULL);
                                }
                        }
                }
        }

        hr = g_pfnCreateTextServices(punkOuter,
                pITextHost,
                ppUnk);
        if(hr == S_OK)
        {
                pIID_ITS = (LPIID)GetProcAddress(g_hRiched20, "IID_ITextServices");
                if((*ppUnk)->QueryInterface(*pIID_ITS,
                        (LPVOID*)&pTextServices) == S_OK)
                {
                        if(g_pHookTextServices == NULL)//虚函数Hook应用于所有实例,因此只需Hook一遍就行了
                        {
                                g_pHookTextServices = new CHookTextServices;

                                ppVtPtr = *(LPVOID**)pTextServices;

                                ppVfPtr = &ppVtPtr[3];
                                *(LPVOID*)&g_pHookTextServices->TrueTxSendMessage = *ppVfPtr;
                                g_pHookTextServices->HookTxSendMessage = &CHookTextServices::TxSendMessage;
                                VFSet(ppVfPtr, *(LPVOID*)&g_pHookTextServices->HookTxSendMessage);
                               
                                ppVfPtr = &ppVtPtr[13];
                                *(LPVOID*)&g_pHookTextServices->TrueTxGetText = *ppVfPtr;
                                g_pHookTextServices->HookTxGetText = &CHookTextServices::TxGetText;
                                VFSet(ppVfPtr, *(LPVOID*)&g_pHookTextServices->HookTxGetText);
                               
                                ppVfPtr = &ppVtPtr[14];
                                *(LPVOID*)&g_pHookTextServices->TrueTxSetText = *ppVfPtr;
                                g_pHookTextServices->HookTxSetText = &CHookTextServices::TxSetText;
                                VFSet(ppVfPtr, *(LPVOID*)&g_pHookTextServices->HookTxSetText);
                        }
                       
                        pTextServices->Release();
                }
        }

        return hr;
}

BOOL WINAPI DllMain(
        HINSTANCE hinstDLL,
        DWORD fdwReason,
        LPVOID lpvReserved
        )
{
        switch(fdwReason)
        {
        case DLL_PROCESS_ATTACH://加载dll;
                {
                        g_hinst = hinstDLL;                       
                        g_hRiched20 = LoadLibrary(_T("RICHED20.DLL"));

                        g_pfnCreateTextServices = (PCreateTextServices)GetProcAddress(g_hRiched20, "CreateTextServices");
                        Mhook_SetHook((PVOID*)&g_pfnCreateTextServices, NewCreateTextServices);
                }
                break;
        case DLL_PROCESS_DETACH://释放dll
                {
                        Mhook_Unhook((PVOID*)&g_pfnCreateTextServices);
                        g_pfnCreateTextServices = NULL;

                        FreeLibrary(g_hRiched20);
                }
                break;
        case DLL_THREAD_ATTACH://新建线程
                {
                }
                break;
        case DLL_THREAD_DETACH://线程退出
                {
                }
                break;
        }

        return TRUE;
}


Viewing all articles
Browse latest Browse all 9556

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>