1. Hooks
The hooks are the back door that Windows left us. Filtering messages, such as shortcut keys, programs to monitor the keyboard, to get keyboard action, and then to judge.
Detailed Travel: http://blog.csdn.net/sunears/article/details/1861568
2. Hook usage
Add Hook: SetWindowsHookEx
Hhook WINAPI SetWindowsHookEx ( _in_ int idhook, _in_ HOOKPROC lpfn, _in_ hinstance Hmod, _in_ DWORD dwThreadID);
Idhook: hook type, the monitoring message here is Wh_callwndproc (SendMessage send), Wh_getmessage (PostMessage send), and gets the return value Wh_callwndprocret.
LPFN: A thread that monitors another process needs to define a hook callback function in the DLL
Hmod:dll handle
dwThreadID: The thread ID of the monitored process
Uninstall Hook: UnhookWindowsHookEx
BOOL WINAPI UnhookWindowsHookEx ( _in_ hhook hhk);
Hhk:setwindowshookex returned by Hhook
3. Spy + + Get the message
Log Messages for monitoring:
Finder: Find the window handle;
Message: Defines the type of receive message;
Output: Defines the output additional information for the message, where we add "original message parameter", "Original return value";
The example diagram is as follows:
Before the handle to receive the message, P/S/R is defined as follows, needless to say.
Spy + + Help:
| Code |
meaning |
| P |
Use the PostMessage function to send messages to the queue. There is no information available about the final disposition of the message. |
| S |
Use the SendMessage function to send a message. This means that the sender does not regain control until the receiver processes and returns the message. Therefore, the receiver can transfer a return value back to the sender. |
| S |
The message was sent, but security prevented access to the return value. |
| R |
Each "S" row has a corresponding "R" (return) row that lists the return value of the message. Sometimes a message call is nested, which means that one message handler sends another message. |
Spy + + uses hooks to intercept messages as well.
According to: http://www.yourdelphi.com/topic_372749_d537.htm
The WIN32 program does not handle different types of message, and for post messages (sent via PostMessage), it is handled by GetMessage, for send over message (Sent via SendMessage ), is handled by Callwndproc and executes callwndretproc after processing is completed, so it is necessary to hook and distinguish between the two types of message that need to handle three hook:wh_getmessage, Wh_callwndproc, and Wh_ simultaneously Callwndprocret.
So:
1, ' P ': The message sent by PostMessage can be obtained by wh_getmessage
2, ' S ': can get SendMessage send message via Wh_callwndproc
3, ' R ': Through Wh_callwndprocret you can get SendMessage results, which is what you want Iresult
So the idea of imitating Spy + + has come out.
Set 3 thread hooks, order monitor Wh_callwndproc, Wh_callwndprocret, Wh_getmessage.
4. Concrete implementation
MyCsdn.exe: main caller, user input exe to be monitored
Shared.dll: Functions shared by all DLLs
CallWndProcHook.dll:WH_CALLWNDPROC Monitoring
CallWndProcRetHook.dll:WH_CALLWNDPROCRET Monitoring
GetMessageHook.dll:WH_GETMESSAGE Monitoring
For boost, pay attention to adding boost libraries.
MyCsdn.exe: Get EXE process ID, get thread ID, load DLL, start hook
#include <iostream> #include <fstream> #include <Windows.h> #include <Shlobj.h> #include < boost/tokenizer.hpp> #include <process.h> #include <TlHelp32.h> #include <tchar.h> #include < Math.h>using namespace std;//get program main thread Iddword getthreadidbyprocessid (DWORD dwprocessid) {HANDLE Hthreadsnap =:: CreateToolhelp32Snapshot (Th32cs_snapthread, Dwprocessid); if (Hthreadsnap = = Invalid_handle_value) {return-1;} THREADENTRY32 te32 = {sizeof (TE32)};if (:: Thread32first (Hthreadsnap, &te32)) {do{if (Te32.th32ownerprocessid = = DWPROCESSID) {:: CloseHandle (HTHREADSNAP); return te32.th32threadid;}} while (:: Thread32next (Hthreadsnap, &te32));}::closehandle (hthreadsnap); return-1;} Get process Iddword getprocessidbyname (lpcwstr processName) {HANDLE hsnapshot = CreateToolhelp32Snapshot (Th32cs_ snapprocess,0); PROCESSENTRY32 PE; pe.dwsize = sizeof (PROCESSENTRY32); if (! Process32First (Hsnapshot,&pe)) {return NULL; } BOOL clearprocess = FALse;while (Process32Next (hsnapshot,&pe)) {if (!_tcsicmp (ProcessName, Pe.szexefile)) {:: Clo Sehandle (hsnapshot); return pe.th32processid;} }:: CloseHandle (hSnapShot); return-1;} BOOL g_bthreadrunning = true;void dllwinthread (lpvoid lP) {g_bthreadrunning = true;wchar_t wstrexe[256] = {0};cout << ; "The program to Hook:"; wcin >> Wstrexe;dword dwprocessid = Getprocessidbyname (Wstrexe); if (Dwprocessid = =-1) {g_bth readrunning = False;system ("pause"); return;} DWORD dwThreadID = Getthreadidbyprocessid (DWPROCESSID); typedef void (*starthook) (int); HINSTANCE hinst = LoadLibrary (TEXT ("CallWndProcHook.dll")); HInstance Hinst2 = LoadLibrary (TEXT ("GetMessageHook.dll")); HInstance Hinst3 = LoadLibrary (TEXT ("CallWndProcRetHook.dll")); Starthook cwpst = (starthook) GetProcAddress (hinst, "Startcallwndhook"); Starthook gmst = (starthook) GetProcAddress (Hinst2, "Startgetmessagehook"); Starthook Cwprst = (starthook) GetProcAddress (Hinst3, "Startcallwndrethook"); Cwpst (DwthreADID); Cwprst (dwThreadID); Gmst (dwthreadid); int ntimeout = 500;while (ntimeout--) {Sleep (100);} FreeLibrary (hinst); FreeLibrary (HINST3); FreeLibrary (hinst2); g_bthreadrunning = false;} int main (int argc, char **argv) {HANDLE hthread = CreateThread (null, 0, (lpthread_start_routine) dllwinthread,//thread function NULL, function parameter 0, NULL), while (g_bthreadrunning) {Sleep (50);} CloseHandle (Hthread); System ("pause"); return 0;}
Shared.dll: Using export symbols, for other DLLs common functions, write files, message translation, use to boost (my blog: Boost installation)
Shared.h
#ifdef shared_exports#define Shared_api __declspec (dllexport) #else # define SHARED_API __declspec (dllimport) #endif # Include <map> #include <string>using std::map;using std::string; Shared_api void Appenddebug (char *pfilename, LPVOID pBuf, int length); Shared_api void Showdebug (LPTSTR lpstrformat, ...); Shared_api void Initsymbolicmsg (Map<uint, string>&); Shared_api const char * GETSYMBOLICMSG (UINT message, Map<uint, string>&m);
Shared.cpp:
#include "stdafx.h" #include "Shared.h" #include <fstream> #include <tchar.h> #include <boost/ Tokenizer.hpp> using Std::ifstream; Shared_api void Appenddebug (char *pfilename, LPVOID pBuf, int length) {FILE *pfile;if (pfilename = = NULL) {fopen_s (&PFI Le, "C:\\Test.txt", "AB");} Else{fopen_s (&pfile, Pfilename, "AB");} if (pFile! = NULL) {fwrite (PBuf, sizeof (char), length, pFile); fclose (PFile);}} Shared_api void Showdebug (LPTSTR lpstrformat, ...)//display in VS Output {Va_list Valist;va_start (valist, Lpstrformat); TCHAR Szbuf[max_path * 2] = {0};_vstprintf_s (szbuf, MAX_PATH, Lpstrformat, valist); OutputDebugString (SZBUF);} The hexadecimal string is converted to decimal int hextodec (string strhex) {int nret = 0;if (strhex.at (1) = = ' x ') {strhex = Strhex.substr (2);} int nlen = Strhex.size (); int nbase = 1;int para = 0;char ch = 0;for (int i = nLen-1, bi = 0; I >= 0; I--, bi++) {ch = St rhex.at (i); if (ch >= ' 0 ' && ch <= ' 9 ') {para = ch-' 0 ';} else if (Ch >= ' a ' && ch <= ' F ') {para = ch-' a ' + 10;} ELSE if (CH >= ' a ' && ch <= ' F ') {para = ch-' a ' + 10;} else//illegal character {return-1;} Nret + = para * nbase;nbase *= 16;} return nret;} Shared_api void Initsymbolicmsg (Map<uint, string> &mapsymbolicmsgs) {ifstream Ifs;ifs.open ("C:\\ SymbolicMessages.h ", std::ios::in); Mapsymbolicmsgs.clear (); if (!ifs.is_open ()) {return;} Boost::char_separator<char> Custcs ("");//Specify char line[256] = {0};string Strline;while (!ifs.eof ()) { Ifs.getline (line, 255); strLine = line;//use "" Space to Split if (Strline.find ("#define")! = String::npos) && (strline.fi nd ("wm_") = String::npos)) {boost::tokenizer<boost::char_separator<char> > Tok (StrLine, Custcs); Boost:: tokenizer<boost::char_separator<char> >::iterator cit = Tok.begin (); cit++;if (cit = = tok.end ()) {continue;} String msg (*cit); cit++;if (cit = = tok.end ()) {continue;} String Val (*cit); UINT nval = Hextodec (val); if (nval = =-1) {continue;} Mapsymbolicmsgs.insert (Std::make_pair<uint, string> (Nval, msg));} memset (Line,0, 256);} Ifs.close ();} Shared_api const char * GETSYMBOLICMSG (UINT message, Map<uint, string> &mapsymbolicmsgs)//message converted to string {map< UINT, string>::const_iterator cit = Mapsymbolicmsgs.begin (); for (; CIT! = mapsymbolicmsgs.end (); cit++) {if (cit-> First = = message) {return (Cit->second). C_STR ();}} Return ("User_define");}
CallWndProc.dll: Monitoring Wh_callwndproc
Dllmain.cpp:
Dllmain.cpp: Defines the entry point for the DLL application. #include "stdafx.h" #include <stdio.h>void showdebug (LPTSTR lpstrformat, ...); void Stopcallwndhook (); extern hinstance G_hcwinst; BOOL apientry DllMain (hmodule hmodule, DWORD ul_reason_for_call, lpvoid lpreserved) {switch (ul_reason_ For_call) {Case dll_process_attach:g_hcwinst = hmodule;printf ("<callwndproc>process attach\n"); Static link, dynamic link loadlibrarybreak;case dll_thread_attach:printf ("<callwndproc>thread attach\n"); Thread loading Break;case dll_thread_detach:printf ("<callwndproc>thread detach\n"); Thread Uninstall Break;case dll_process_detach:printf ("<callwndproc>process detach\n"); Static link end, dynamic link FreeLibrary, program exit Stopcallwndhook (); Unload hook break;} return TRUE;}
CallWndProc.cpp:
#include "stdafx.h" #include <tchar.h> #include <string> #include <Windows.h> #include <stdio.h > #include ". /shared/shared.h "#pragma comment (lib,"). /debug/shared.lib ") hinstance G_hcwinst; Hhook G_hookcallwndproc; LRESULT CALLBACK callwndhookproc (int code,wparam wparam,lparam LPARAM) {static map<uint, string> mapsymbolicmsgs; Cannot share global variables for DLL if (code = = hc_action) {pcwpstruct PMSG = (pcwpstruct) lparam;//Wh_callwndprocchar buffer[200] = {0};if (ma Psymbolicmsgs.size () = = 0) {initsymbolicmsg (MAPSYMBOLICMSGS);} sprintf_s (buffer, "%08x s MSG:%s (%04x), WParam:%08x, LParam:%08x\n", Pmsg->hwnd, Getsymbolicmsg (Pmsg->message, M APSYMBOLICMSGS), pmsg->message, (int) pmsg->wparam, (int) pmsg->lparam); Appenddebug (NULL, buffer, strlen (buffer));} Return CallNextHookEx (NULL, Code, WParam, LParam);} void Startcallwndhook (int threadId) {G_hookcallwndproc = SetWindowsHookEx (Wh_callwndproc, Callwndhookproc, G_hCwInst, THREADID);} void Stopcallwndhook () {UnhookWindowsHookEx(G_hookcallwndproc);}
Callwndproc.def: Output function for the main program call
Libraryexportsstartcallwndhook @1
CallWndProcRetHook.dll, GetMessageHook.dll the same, no longer repeat.
Get the file fragment:
00000000 P Msg:wm_timer (0113), WPARAM:00006CFA, lparam:76c718b200000000 P Msg:wm_timer (0113), WPARAM:00006CFA, LParam : 76c718b2000a0956 S Msg:user_define (036A), wparam:00000000, lparam:00000000000a0956 R msg:user_define (036A), LResult: 0000000000060938 P Msg:wm_timer (0113), wparam:00000001, lparam:00000000000a0956 S msg:user_define (036A), wparam:0000 0000, lparam:00000000000a0956 R msg:user_define (036A), lresult:0000000000060938 S msg:wm_windowposchanging (0046), WPa ram:00000000, lparam:004bf6b400060938 R msg:wm_windowposchanging (0046), lresult:00000000000c0944 S Msg:wm_windowposc Hanging (0046), wparam:00000000, LPARAM:004BF6B4
See: Engineering
<Win32> using hooks to intercept messages with Spy + +