Spy++是如何獲取發往窗口的消息的?
就是我用了spy++抓了一個窗口,然後在spy++的窗口列表中右鍵選中的窗口,查看消息,可以看到一堆的消息。包括在窗口上的滑鼠事件等等,請問是如何實現的,原理是什麼?
======================================================================
感謝@蔣晟 @姚冬 ,分別從不同方面解決了問題。
本來想昨天寫的,發現已經有答案了,稍微補充一下細節。
IDA 粗看了一下 VS2015 社區版帶的 spyxx_amd64,用的是 SetWindowHookEx 設置了全局鉤子。實現代碼在 .text:140037A64 __int64 __fastcall SetMsgHook(int),一共設置了三個 hook: WH_GETMESSAGE, WH_CALLWNDPROC, WH_CALLWNDPROCRET。
三者都可以監視窗口消息,它們的區別是:
- WH_GETMESSAGE:監視由 GetMessage 或 PeekMessage 獲取的消息,但不能攔截或者修改消息參數;
- WH_CALLWNDPROC 可以在窗口接收到消息之前進行處理,修改參數,甚至丟棄消息;
- WH_CALLWNDPROCRET 在窗口已經處理完了消息的時候觸發。
詳見:Hooks Overview (Windows)
這三個 hook 對應的回調函數在 spyxxhk_amd64.dll 中實現,分別對應 SpyxxGetMsgProc, SpyxxCallWndProc 和 SpyxxCallWndRetProc。
這三個函數的具體實現非常相似,都是根據窗口的句柄獲取一些額外的信息,如 ClassName / WindowLong / ProcessId / ThreadId 等,投遞消息到日誌處理常式中。例如 SpyxxCallWndRetProc:
LRESULT __fastcall SpyxxCallWndRetProc(int nCode, WPARAM wParam, LPARAM lParam)
{
LPARAM v3; // rbx@1
int v4; // esi@1
LRESULT v5; // rdi@1
HWND v6; // rcx@5
DWORD v7; // eax@6
DWORD dwProcessId; // [sp+70h] [bp+18h]@6
__int64 v10; // [sp+78h] [bp+20h]@1
v3 = lParam;
v4 = nCode;
v5 = CallNextHookEx(ghhkRetHook, nCode, wParam, lParam);
v10 = v5;
if ( gfHookEnabled )
{
if ( !gfHookDisabled !v4 )
{
if ( v3 )
{
v6 = *(HWND *)(v3 + 32);
if ( v6 )
{
v7 = GetWindowThreadProcessId(v6, dwProcessId);
if ( dwProcessId != gpidSpyxx v7 != gtidSpyxx GetCurrentThreadId() != gtidSpyxx )
PostToSpyxxApp(
2,
*(void **)v3,
*(HWND *)(v3 + 32),
*(_DWORD *)(v3 + 24),
*(void **)(v3 + 16),
*(void **)(v3 + 8),
0,
0,
0);
}
}
}
}
return v5;
}
這個Windows SDK里有源代碼的Spy: Monitoring Messages with SPY
Windows高級編程指南 (豆瓣)
你應該去讀這本書,書的作者 Jeffrey Richter 就是Spy++的作者
書里詳細描述了Spy++技術的實現。setwindowlong 好像是 反正有winAPI的
推薦閱讀:
※很多人說MFC落伍了,那有什麼可以代替MFC?
※對於一個初學者,MFC和Qt哪個好下手?
※MFC為什麼難用,框架的敗筆是?
※DirectUI與GUI框架有什麼區別,如MFC,QT,wxWidgets的區別是什麼?
※電腦桌面背景可以總是前置嗎?
TAG:MicrosoftVisualStudio | MFC | Windows開發 | VisualC | Net開發 |