1、新建名稱爲CServerHook的MFC動態庫,選擇MFC擴展DLL選項,點擊完成。
2、系統自動生成ServerHook.cpp文件,但沒有ServerHook.h文件,該文件需要手動添加。
3、建立導出類CServerHook,ServerHook.h文件內容如下:
BOOL _declspec(dllexport) CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam);枚舉窗口回調函數
void _declspec(dllexport) gKillProcessByPid( DWORD dwPid );//根據進程ID銷燬該進程
void _declspec(dllexport) gGetProcessByWindowTitle();//枚舉窗口名稱,得到對應進程Id
void _declspec(dllexport) gSetFilePath(char* strPath); //向dll中傳遞路徑
void _declspec(dllexport) gSetTimer(); //在dll中創建Timer
class __declspec(dllexport) CServerHook : public CObject
{
public:
CServerHook(); //鉤子類的構造函數
virtual ~CServerHook(); //鉤子類的析構函數
public:
BOOL StartHook(); //安裝鉤子函數
BOOL StopHook(); //卸載鉤子函數
};
4、ServerHook.cpp文件內容如下:
#include "stdafx.h"
#include <afxdllx.h>
#include "ServerHook.h"
#define _WIN32_WINNT 0x0500
#include <windows.h>
#include <stdio.h>
#define _SECOND 10000000
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#pragma data_seg("mydata")
HHOOK glhHook=NULL; //安裝的鍵盤勾子句柄
HINSTANCE glhInstance=NULL; //DLL實例句柄
char last_char ='q';
char g_chArr[MAX_PATH] = {0}; //保存傳遞進來的程序相對路徑
#pragma data_seg()
LRESULT CALLBACK KeyboardProc(int nCode,WPARAM wParam,LPARAM lParam);
static AFX_EXTENSION_MODULE ServerHookDLL = { NULL, NULL };
CString g_szCurPath = _T("");
CString g_strFlashMagazine = _T("");
CString g_strFlashDM = _T("");
DWORD wndTemp = 0;
int iFlag = 0;
HWND hwnd;
HWND m_hwndFind[100] = { NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
int m_num = 0 ;
TCHAR m_store[MAX_PATH];
typedef struct _MYTimer {
TCHAR *szText;
DWORD dwValue;
} MYTIMER;
VOID CALLBACK TimerAPCProc(
LPVOID lpArg, // Data value
DWORD dwTimerLowValue, // Timer low value
DWORD dwTimerHighValue ) // Timer high value
{
MYTIMER *pMyData = (MYTIMER *)lpArg;
printf( "Message: %s/nValue: %d/n/n", pMyData->szText,
pMyData->dwValue );
MessageBeep(0);
}
extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
// Remove this if you use lpReserved
UNREFERENCED_PARAMETER(lpReserved);
if (dwReason == DLL_PROCESS_ATTACH)
{
TRACE0("SERVERHOOK.DLL Initializing!/n");
// Extension DLL one-time initialization
if (!AfxInitExtensionModule(ServerHookDLL, hInstance))
return 0;
// Insert this DLL into the resource chain
// NOTE: If this Extension DLL is being implicitly linked to by
// an MFC Regular DLL (such as an ActiveX Control)
// instead of an MFC application, then you will want to
// remove this line from DllMain and put it in a separate
// function exported from this Extension DLL. The Regular DLL
// that uses this Extension DLL should then explicitly call that
// function to initialize this Extension DLL. Otherwise,
// the CDynLinkLibrary object will not be attached to the
// Regular DLL's resource chain, and serious problems will
// result.
new CDynLinkLibrary(ServerHookDLL);
glhInstance=hInstance;
}
else if (dwReason == DLL_PROCESS_DETACH)
{
TRACE0("SERVERHOOK.DLL Terminating!/n");
// Terminate the library before destructors are called
AfxTermExtensionModule(ServerHookDLL);
}
return 1; // ok
}
CServerHook::CServerHook()
{
}
CServerHook::~CServerHook()
{
if (glhHook)
{
UnhookWindowsHookEx(glhHook);
}
}
BOOL CServerHook::StartHook()
{
BOOL bResult=FALSE;
glhHook=SetWindowsHookEx(WH_KEYBOARD,KeyboardProc,glhInstance,0);
/*============================================================
HHOOK SetWindowsHookEx( int idHook,HOOKPROC lpfn, INSTANCE hMod,DWORD dwThreadId )
參數idHook表示鉤子類型,它是和鉤子函數類型一一對應的。
比如,WH_KEYBOARD表示安裝的是鍵盤鉤子,WH_MOUSE表示是鼠標鉤子等等。
Lpfn是鉤子函數的地址。
HMod是鉤子函數所在的實例的句柄。對於線程鉤子,該參數爲NULL;對於系統鉤子,
該參數爲鉤子函數所在的DLL句柄。
dwThreadId 指定鉤子所監視的線程的線程號。對於全局鉤子,該參數爲NULL。
SetWindowsHookEx返回所安裝的鉤子句柄。
值得注意的是線程鉤子和系統鉤子的鉤子函數的位置有很大的差別。
線程鉤子一般在當前線程或者當前線程派生的線程內,
而系統鉤子必須放在獨立的動態鏈接庫中,實現起來要麻煩一些。
===========================================================*/
if(glhHook!=NULL)
bResult=TRUE;
return bResult;
}
//卸載鉤子
BOOL CServerHook::StopHook()
{
BOOL bResult=FALSE;
if(glhHook)
{
bResult= UnhookWindowsHookEx(glhHook);
if(bResult)
glhHook=NULL;
}
return bResult;
}
//鍵盤鉤子函數
LRESULT CALLBACK KeyboardProc(int nCode,WPARAM wParam,LPARAM lParam)
{
char ch = 0;
if( ((DWORD)lParam&0x40000000) && (HC_ACTION==nCode) ) //有鍵按下
{
if( (wParam == VK_F4)||(wParam==VK_SPACE)||(wParam==VK_RETURN)||(wParam>=0x2f ) &&(wParam<=0x100) )
{
if (wParam==VK_RETURN)
{
ch='/n';
}
else
{
BYTE ks[256];
GetKeyboardState(ks);
WORD w;
UINT scan=0;
ToAscii(wParam,scan,ks,&w,0);
ch =char(w);
}
}
if (nCode >= 0)
{
if ( ch != last_char )
{
g_szCurPath = g_chArr;
g_strFlashDM = g_chArr;
g_strFlashDM += _T("flash//DM//");
g_strFlashMagazine = g_chArr;
g_strFlashMagazine += _T("flash//Magazine//");
gGetProcessByWindowTitle();
switch(iFlag)
{
case 1:
if (ch == 'a')
{
last_char = ch;
ShellExecute(NULL,"open",g_strFlashDM + _T("bank.exe"),NULL,g_strFlashDM,SW_SHOW);
gKillProcessByPid(wndTemp);
}
else if (ch == 'b')
{
last_char = ch;
ShellExecute(NULL,"open",g_strFlashDM + _T("discount.exe"),NULL,g_strFlashDM,SW_SHOW);
gKillProcessByPid(wndTemp);
}
else if (ch == 'c')
{
//last_char = ch;
ShellExecute(NULL,"open",g_szCurPath + _T("BirthFlash.exe"),NULL,g_szCurPath,SW_SHOW);
gKillProcessByPid(wndTemp);
}
else if (ch == 'd')
{
//last_char = ch;
ShellExecute(NULL,"open",g_szCurPath + _T("GamesFlash.exe"),NULL,g_szCurPath,SW_SHOW);
gKillProcessByPid(wndTemp);
}
else if (ch == 'f')
{
last_char = ch;
ShellExecute(NULL,"open",g_szCurPath + _T("Terminal.exe"),NULL,g_szCurPath,SW_SHOW);
gKillProcessByPid(wndTemp);
}
else if (ch == 'q')
{
last_char = ch;
ShellExecute(NULL,"open",g_strFlashMagazine + _T("magazine.exe"),NULL,g_strFlashMagazine,SW_SHOW);
gKillProcessByPid(wndTemp);
}
break;
case 2:
break;
case 3:
break;
case 4:
if (ch == 'q')
{
last_char = ch;
ShellExecute(NULL,"open",g_strFlashMagazine + _T("magazine.exe"),NULL,g_strFlashMagazine,SW_SHOW);
gKillProcessByPid(wndTemp);
}
break;
default:
break;
}
}
}
}
return CallNextHookEx(glhHook,nCode,wParam,lParam);
}
//枚舉窗口
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
DWORD wndPid;
CString Title;
if(::GetWindowLong(hwnd,GWL_STYLE)& WS_VISIBLE)
{
m_hwndFind[m_num] = hwnd;//record the HWND handle into array
m_num++;//count start
}
// This gets the windows handle and pid of enumerated window.
GetWindowThreadProcessId( hwnd, &wndPid );
// This gets the windows title text
// from the window, using the window handle
CWnd::FromHandle( hwnd )->GetWindowText(Title);
BOOL bFlag = FALSE;
if (Title.CompareNoCase("Terminal") == 0)
{
bFlag = TRUE;
iFlag = 4;
wndTemp = wndPid;
}
else if( Title.CompareNoCase( "Macromedia Flash Player 8" ) == 0)
{
bFlag = TRUE;
iFlag = 1;
wndTemp = wndPid;
}
else if (Title.CompareNoCase("SelBirth") == 0 || Title.CompareNoCase("BirthFlash") == 0)
{
bFlag = TRUE;
iFlag = 2;
wndTemp = wndPid;
}
else if (Title.CompareNoCase("SelGames") == 0 || Title.CompareNoCase("GamesFlash") == 0)
{
bFlag = TRUE;
iFlag = 3;
wndTemp = wndPid;
}
else
{
iFlag = 0;
}
// this makes sure that the PID matches that PID we started, and window
// text exists, before we kill it . I don't think this is really needed,
// I included it because some apps have more than one window.
if ( bFlag)
{
return false;
}
else
{
// Keep enumerating
return true;
}
}
//根據進程ID終止進程
void gKillProcessByPid(DWORD dwPid)
{
HANDLE ps = OpenProcess( SYNCHRONIZE|PROCESS_TERMINATE,FALSE, dwPid);
DWORD wExit;
::GetExitCodeProcess(ps,&wExit);
::TerminateProcess(ps,wExit);
}
void gGetProcessByWindowTitle()
{
EnumWindows( EnumWindowsProc, NULL );
}
//設置程序相對路徑
void gSetFilePath( char* strPath)
{
strcpy( g_chArr, strPath );
}
void gSetTimer()
{
HANDLE hTimer;
BOOL bSuccess;
__int64 qwDueTime;
LARGE_INTEGER liDueTime;
MYTIMER TimerData;
TCHAR szError[255];
TimerData.szText = "This is my data.";
TimerData.dwValue = 100;
if ( hTimer = CreateWaitableTimer(
NULL, // Default security attributes
FALSE, // Create auto-reset timer
"MyTimer" ) ) // Name of waitable timer
{
// Create an integer that will be used to signal the timer
// 5 seconds from now.
qwDueTime = -5 * _SECOND;
// Copy the relative time into a LARGE_INTEGER.
liDueTime.LowPart = (DWORD) ( qwDueTime & 0xFFFFFFFF );
liDueTime.HighPart = (LONG) ( qwDueTime >> 32 );
bSuccess = SetWaitableTimer(
hTimer, // Handle to the timer object
&liDueTime, // When timer will become signaled
2000, // Periodic timer interval of 2 seconds
TimerAPCProc, // Completion routine
&TimerData, // Argument to the completion routine
FALSE ); // Do not restore a suspended system
if ( bSuccess )
{
do
{
gGetProcessByWindowTitle();
if (iFlag == 0)
{
g_strFlashMagazine = g_chArr;
g_strFlashMagazine += _T("flash//Magazine//");
ShellExecute(NULL,"open",g_strFlashMagazine + _T("magazine.exe"),NULL,g_strFlashMagazine,SW_SHOW);
Sleep(2000);
}
SleepEx(INFINITE,TRUE);
} while(1);
}
else
{
wsprintf( szError, "SetWaitableTimer failed with Error /
%d.", GetLastError() );
MessageBox( NULL, szError, "Error", MB_ICONEXCLAMATION );
}
}
else
{
wsprintf( szError, "CreateWaitableTimer failed with Error %d.",
GetLastError() );
MessageBox( NULL, szError, "Error", MB_ICONEXCLAMATION );
}
}
5、在ServerHook.def中加入:
SECTIONS
mydata READ WRITE SHARED
6、編譯生成dll和LIB文件。
7、在另一個工程中對其進行調用,即可實現鉤子功能。