Added support for message hook viewer to hook both 32 and 64 bit applications. Fixed filtering on the msg hook viewer Added custom filtering on msg hook viewer Added Process Id targetting on msg hook viewer Added SetMsgHook.exe command line app as an alternative way of starting msg hook viewer.
261 lines
9.1 KiB
C++
261 lines
9.1 KiB
C++
/*
|
|
* Copyright 2014, Synthuse.org
|
|
* Released under the Apache Version 2.0 License.
|
|
*
|
|
* last modified by ejakubowski7@gmail.com
|
|
*/
|
|
|
|
|
|
// MsgHook.cpp : Defines the exported functions for the DLL application.
|
|
//
|
|
#include "stdafx.h"
|
|
|
|
//to fix export declaration had to add .def file
|
|
LRESULT CALLBACK CwpHookProc(int nCode, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
COPYDATASTRUCT CDS;
|
|
HEVENT Event;
|
|
|
|
CDS.dwData = 0;
|
|
CDS.cbData = sizeof(Event);
|
|
CDS.lpData = &Event;
|
|
|
|
//if (nCode == HC_ACTION)
|
|
{
|
|
//For WH_CALLWNDPROC hook a pointer to a CWPSTRUCT structure that contains details about the message.
|
|
CWPSTRUCT *cwps = (CWPSTRUCT *)lParam;
|
|
Event.hWnd = cwps->hwnd;
|
|
Event.lParam = cwps->lParam;
|
|
Event.wParam = cwps->wParam;
|
|
Event.nCode = cwps->message;
|
|
Event.dwHookType = WH_CALLWNDPROC;
|
|
memset((void *)&Event.wParamStr, '\0', sizeof(TCHAR) * 25);
|
|
memset((void *)&Event.lParamStr, '\0', sizeof(TCHAR) * 25);
|
|
bool errorFlg = false;
|
|
if (cwps->message == WM_SETTEXT && cwps->lParam != 0 && cwps->wParam == 0)
|
|
{
|
|
if (IsWindowUnicode(Event.hWnd))
|
|
{
|
|
_tcsncpy_s(Event.lParamStr, 25, (const wchar_t*)Event.lParam, _TRUNCATE);
|
|
}
|
|
else
|
|
{
|
|
int asciiSize = (int)strlen((const char*)Event.lParam);
|
|
int unicodeSize = (int)_tcslen((const wchar_t*)Event.lParam);
|
|
if (unicodeSize > asciiSize)
|
|
_tcsncpy_s(Event.lParamStr, 25, (const wchar_t*)Event.lParam, _TRUNCATE);
|
|
else
|
|
{
|
|
int tstrLen = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)cwps->lParam, (int)strlen((LPCSTR)cwps->lParam), NULL, 0); //get t len
|
|
if (tstrLen > 24)
|
|
tstrLen = 24;
|
|
MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)cwps->lParam, (int)strlen((LPCSTR)cwps->lParam), Event.lParamStr, tstrLen); // convert char to tchar
|
|
}
|
|
}
|
|
}
|
|
|
|
//printf("debug: sending to hwnd (%ld) msg %d, wParam %ld, lParam %ld\n", pData->g_hWnd, Event.nCode, Event.wParam, Event.lParam);
|
|
if (cwps->hwnd != pData->g_hWnd)
|
|
{
|
|
BOOL bRes = (BOOL)SendMessage(pData->g_hWnd, WM_COPYDATA, 0, (LPARAM)(VOID*)&CDS); // ask the controlling program if the hook should be passed
|
|
}
|
|
}
|
|
return CallNextHookEx(pData->g_CwpHook, nCode, wParam, lParam); // pass hook to next handler
|
|
//return bRes; // Don't tell the other hooks about this message.
|
|
}
|
|
|
|
LRESULT CALLBACK MsgHookProc(int nCode, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
COPYDATASTRUCT CDS;
|
|
HEVENT Event;
|
|
|
|
CDS.dwData = 0;
|
|
CDS.cbData = sizeof(Event);
|
|
CDS.lpData = &Event;
|
|
|
|
if (nCode >=0 && nCode == HC_ACTION)
|
|
{
|
|
//For WH_GETMESSAGE hook a pointer to a MSG structure that contains details about the message.
|
|
MSG *msg = (MSG *)lParam;
|
|
Event.hWnd = msg->hwnd;
|
|
Event.lParam = msg->lParam;
|
|
Event.wParam = msg->wParam;
|
|
Event.nCode = msg->message;
|
|
Event.dwHookType = WH_GETMESSAGE;
|
|
memset((void *)&Event.wParamStr, '\0', sizeof(TCHAR) * 25);
|
|
memset((void *)&Event.lParamStr, '\0', sizeof(TCHAR) * 25);
|
|
//if (msg->message == WM_SETTEXT && msg->lParam != 0)
|
|
// _tcscpy_s(Event.lParamStr, 25, (const wchar_t*)Event.lParam);
|
|
//if (msg->message == WM_COMMAND || msg->message == WM_MENUCOMMAND) //infinite loop?
|
|
if (msg->hwnd != pData->g_hWnd)
|
|
{
|
|
BOOL bRes = (BOOL)SendMessage(pData->g_hWnd, WM_COPYDATA, 0, (LPARAM)(VOID*)&CDS); // ask the controlling program if the hook should be passed
|
|
}
|
|
}
|
|
|
|
return CallNextHookEx(pData->g_MsgHook, nCode, wParam, lParam); // pass hook to next handler
|
|
//return bRes; // Don't tell the other hooks about this message.
|
|
}
|
|
|
|
//support for 32-bit/64-bit apps means the dll might be different to match the process we want to see
|
|
extern "C" __declspec(dllexport) BOOL SetCustomMsgHookDll(const TCHAR * hookDll, const char * hookDllProcName)
|
|
{
|
|
HMODULE dll = LoadLibrary(hookDll); //should provide full dll path and filename
|
|
if (dll == NULL)
|
|
{
|
|
TCHAR errorStr[200];
|
|
_stprintf_s(errorStr, _T("Error loading hook library %s"), hookDll);
|
|
MessageBox(0, errorStr, _T("Set Hook Dll Error"), 0);
|
|
return false;
|
|
}
|
|
HOOKPROC addr = (HOOKPROC)GetProcAddress(dll, hookDllProcName); //should provide the 'CwpHookProc'
|
|
if (addr == NULL)
|
|
{
|
|
char errorStr[200];
|
|
sprintf_s(errorStr, "Error loading hook library procedure %s", hookDllProcName);
|
|
MessageBoxA(0, errorStr, "Set Hook Dll Error", 0);
|
|
return false;
|
|
}
|
|
pData->g_hInstance = dll;
|
|
pData->g_CwpHookProc = addr;
|
|
return true;
|
|
}
|
|
|
|
extern "C" __declspec(dllexport) BOOL SetMsgHook(HWND callerHWnd, DWORD threadId)
|
|
{
|
|
// if(bStartingProcess) // if we're just starting the DLL for the first time,
|
|
{
|
|
pData->g_hWnd = callerHWnd; // remember the windows and hook handle for further instances
|
|
if (pData->g_CwpHookProc == NULL)
|
|
pData->g_CwpHookProc = (HOOKPROC)CwpHookProc;
|
|
pData->g_CwpHook = SetWindowsHookEx(WH_CALLWNDPROC, pData->g_CwpHookProc, (HINSTANCE)pData->g_hInstance, threadId);
|
|
//pData->g_MsgHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)MsgHookProc, (HINSTANCE)pData->g_hInstance, threadId);
|
|
if (pData->g_CwpHook == NULL) {
|
|
TCHAR tmp[100];
|
|
_stprintf_s(tmp, _T("Last Error # %ld on threadId %ld"), GetLastError(), threadId);
|
|
MessageBox(0, tmp, _T("Set Hook Error"), 0);
|
|
}
|
|
|
|
return (pData->g_CwpHook != NULL); //pData->g_CwpHook != NULL &&
|
|
}
|
|
/*else
|
|
{
|
|
//MessageBox(0, _T("Error: Not starting process"), _T("Set Hook Error"), 0);
|
|
return false;
|
|
}*/
|
|
}
|
|
|
|
extern "C" __declspec(dllexport) HHOOK GetCurrentHookHandle()
|
|
{
|
|
return pData->g_CwpHook; //if NULL hook isn't running
|
|
}
|
|
|
|
extern "C" __declspec(dllexport) void SetGlobalDLLInstance(HANDLE dllInstance)
|
|
{
|
|
pData->g_hInstance = dllInstance;
|
|
}
|
|
|
|
extern "C" __declspec(dllexport) BOOL RemoveHook()
|
|
{
|
|
if (pData == NULL)
|
|
return false;
|
|
if(pData->g_MsgHook) // if the hook is defined
|
|
{
|
|
UnhookWindowsHookEx(pData->g_MsgHook);
|
|
pData->g_MsgHook = NULL;
|
|
}
|
|
if(pData->g_CwpHook) // if the hook is defined
|
|
{
|
|
BOOL ret = UnhookWindowsHookEx(pData->g_CwpHook);
|
|
pData->g_hWnd = NULL; // reset data
|
|
pData->g_CwpHook = NULL;
|
|
pData->g_CwpHookProc = NULL;
|
|
return ret;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
//testing if process 64 bit, needed to verify this dll can hook & attach to target process
|
|
typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
|
|
LPFN_ISWOW64PROCESS fnIsWow64Process;
|
|
|
|
extern "C" __declspec(dllexport) BOOL IsCurrentProcess64Bit()
|
|
{
|
|
return IsProcess64Bit(_getpid());
|
|
}
|
|
|
|
extern "C" __declspec(dllexport) BOOL IsProcess64Bit(DWORD procId)
|
|
{
|
|
SYSTEM_INFO stInfo;
|
|
GetNativeSystemInfo(&stInfo); // if native system is x86 skip wow64 test
|
|
if (stInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
|
|
return false; //printf( "Processor Architecture: Intel x86\n");
|
|
|
|
BOOL bIsWow64 = FALSE;
|
|
//IsWow64Process is not available on all supported versions of Windows.
|
|
//Use GetModuleHandle to get a handle to the DLL that contains the function
|
|
//and GetProcAddress to get a pointer to the function if available.
|
|
|
|
fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle(TEXT("kernel32")),"IsWow64Process");
|
|
if(fnIsWow64Process != NULL)
|
|
{
|
|
HANDLE procHandle = NULL;//GetCurrentProcess();
|
|
procHandle = OpenProcess(PROCESS_QUERY_INFORMATION, false, procId);
|
|
if (!fnIsWow64Process(procHandle, &bIsWow64))
|
|
{
|
|
//handle error
|
|
}
|
|
CloseHandle(procHandle);
|
|
if (bIsWow64) // NOT a native 64bit process
|
|
return false;
|
|
return true;// is a native 64bit process
|
|
}
|
|
return false; //some error finding function "IsWow64Process" assume not 64-bit
|
|
}
|
|
|
|
extern "C" __declspec(dllexport) DWORD GetProcessMainThreadId(DWORD procId)
|
|
{
|
|
|
|
#ifndef MAKEULONGLONG
|
|
#define MAKEULONGLONG(ldw, hdw) ((ULONGLONG(hdw) << 32) | ((ldw) & 0xFFFFFFFF))
|
|
#endif
|
|
#ifndef MAXULONGLONG
|
|
#define MAXULONGLONG ((ULONGLONG)~((ULONGLONG)0))
|
|
#endif
|
|
|
|
DWORD dwMainThreadID = 0;
|
|
ULONGLONG ullMinCreateTime = MAXULONGLONG;
|
|
//includes all threads in the system
|
|
HANDLE hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
|
|
if (hThreadSnap != INVALID_HANDLE_VALUE) {
|
|
THREADENTRY32 th32;
|
|
th32.dwSize = sizeof(THREADENTRY32);
|
|
BOOL bOK = TRUE;
|
|
//Enumerate all threads in the system and filter on th32OwnerProcessID = pid
|
|
for (bOK = Thread32First(hThreadSnap, &th32); bOK ; bOK = Thread32Next(hThreadSnap, &th32)) {
|
|
//if (th32.dwSize >= FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(th32.th32OwnerProcessID)) {
|
|
if (th32.th32OwnerProcessID == procId && (th32.dwSize >= FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(th32.th32OwnerProcessID))) {
|
|
//_tprintf(_T("DEBUG Enumerate Process (%ld) Thread Id: %ld\n"), procId, th32.th32ThreadID);
|
|
HANDLE hThread = OpenThread(THREAD_QUERY_INFORMATION, TRUE, th32.th32ThreadID);
|
|
if (hThread) {
|
|
FILETIME afTimes[4] = {0};
|
|
if (GetThreadTimes(hThread, &afTimes[0], &afTimes[1], &afTimes[2], &afTimes[3])) {
|
|
ULONGLONG ullTest = MAKEULONGLONG(afTimes[0].dwLowDateTime, afTimes[0].dwHighDateTime);
|
|
if (ullTest && ullTest < ullMinCreateTime) { //check each thread's creation time
|
|
ullMinCreateTime = ullTest;
|
|
dwMainThreadID = th32.th32ThreadID; // let it be main thread
|
|
}
|
|
}
|
|
CloseHandle(hThread); //must close opened thread
|
|
}
|
|
}
|
|
}
|
|
#ifndef UNDER_CE
|
|
CloseHandle(hThreadSnap); //close thread snapshot
|
|
#else
|
|
CloseToolhelp32Snapshot(hThreadSnap); //close thread snapshot
|
|
#endif
|
|
}
|
|
return dwMainThreadID; //returns main thread id or returns 0 if can't find it
|
|
} |