第4章钩子函数和窗口子类化 联系客服

发布时间 : 星期三 文章第4章钩子函数和窗口子类化更新完毕开始阅读a478eed3240c844769eaee1b

够在进程的地址空间中得到函数的地址,就可以子类化进程的一切。这种实现的方法 实质上是一种跨进程的代码注入技术。

采用注册表是一种最简单的代码注入技术,在基于WindowsNT的操作系统中存 在着这样一个键:

HKEY_LOCAL_MACHINE\\Software\\Microsoft\\WindowsNT\\ CurrentVersion\\Windows\\APPINIT_DLLS

这个键会导致Windows加载动态链接库到系统中的每一个进程。为了实现子类 化,可以安装WH_CBT钩子,侦听HCBT_CREATEWND事件子类化指定的窗口。

由于动态链接库会自动加载到系统中的每一个进程中,所以它同样会给系统带来非常 大的开销,而且一个编写不好的动态链接库,会导致系统无法运行。

另外,对所有进程子类化的方法采用系统范围的全局钩子。当系统钩子被受它影 响的进程调用时,系统会自动把动态链接库加载它所在的地址空间。一旦动态链接库 注入到它所在的进程空间中,窗口子类化就容易实现了。

还有一种代码注入的方法,就是采用创建远程的方法。这涉及了OpenProcess、

WriteProcessMemory和CreateRemoteThread函数。在后面的章节会对子类化方法进行 详细介绍。

在Win32环境中,通过SetWindowLong和GetWindowLong返回的值可能不是原

来窗口的过程指针。Win32会返回一个数据结构类型指针,通过这个结构来调用实际 的窗口过程。这种情况在使用一个非Unicode编码的窗口过程来子类化一个Unicode 窗口时或者采用Unicode窗口过程去子类化一个ANSI窗口时就会发生。在这些情况 下操作系统会在窗口接收到的消息之间进行翻译和转换。在这种情况下,如果应用程 序直接使用这个结构指针,就会触发异常。惟一的办法是使用SetWindowLong或者使 用SetClassLong函数返回的窗口过程地址来调用CallWindowProc。

实例子类化是通过使用GWL_WNDPROC参数调用SetWindowLong实现的,应

用程序保存返回的地址以便以后调用时或者卸载时使用。为了实现进程间的窗口子类 化,子类化函数必须在动态链接库或者应用程序中输出。 例4-5Windows子类化实现。

LONGFARPASCALSubClassFunc(HWNDhWnd,UINTMessage,WPARAMwParam, LONGlParam);

FARPROClpfnOldWndProc; HWNDhEditWnd;

//创建一个文本框控件然后子类化

hEditWnd=CreateWindow(\WS_BORDER,0,0,50,50,hWndMain,NULL,hInst,NULL); //子类化实现

lpfnOldWndProc=(FARPROC)SetWindowLong(hEditWnd, GWL_WNDPROC,(DWORD)SubClassFunc); ..

//去除子类化

SetWindowLong(hEditWnd,GWL_WNDPROC,(DWORD)lpfnOldWndProc); LONGFARPASCALSubClassFunc(HWNDhWnd,UINTMessage, WPARAMwParam,LONGlParam) {

//当对话框中的文本框获得焦点时,默认的回车键动作将不再发生

if(Message==WM_GETDLGCODE)returnDLGC_WANTALLKEYS; returnCallWindowProc(lpfnOldWndProc,hWnd,Message,wParam, lParam); }

全局子类化类似于实例子类化,应用程序为了实现全局子类化一个窗口类,需要 调用SetClassLong。下面是一个全局子类化的实例。

LONGFARPASCALSubClassFunc(HWNDhWnd,UINTMessage,WORDwParam, LONGlParam);

FARPROClpfnOldClassWndProc; HWNDhEditWnd;

//创建一个文本框然后子类化

hEditWnd=CreateWindow(\hWndMain,NULL,hInst,NULL);

lpfnOldClassWndProc=(FARPROC)SetClassLong(hEditWnd,GCL_WNDPROC, (DWORD)

SubClassFunc); .. .

//去除子类

SetClassLong(hEditWnd,GWL_WNDPROC,(DWORD)lpfnOldClassWndProc); DestroyWindow(hEditWnd);

下面给出一个进程间子类化的例子,如图4-1所示。

例4-6进程间子类化应用举例。 #include #include #include HWNDh_Wnd; MSGmsg;

WNDCLASSwc; booldone; HWNDhwdesk;

HWNDarrcount[100]; intcount1;

HWNDh_wnd3; HWNDh_wnd6; HWNDh_wnd4; HWNDh_wnd5;

HWNDhHookedWindow;

typedefint(CALLBACK*sthndl)(HWND,HWND); sthndlSetHandle;

typedefint(CALLBACK*unsub)(); unsubUnSubClass;

typedefint(CALLBACK*filhndl)(HWND,int); filhndlFillHandleArray; staticHHOOKhWinHook; staticHINSTANCEhLib;

LRESULTWINAPIWndProc(HWND,UINT,WPARAM,LPARAM); boolSendKeys(char*sKeys) {

longlength=strlen(sKeys); intp;

for(p=0;p

if(sKeys[p]=='<') {

keybd_event(VK_SHIFT,0x45,KEYEVENTF_EXTENDEDKEY|0,0); keybd_event(188,0x45,KEYEVENTF_EXTENDEDKEY|0,0);

keybd_event(188,0x45,KEYEVENTF_EXTENDEDKEY|KEYEVENTF_KEYUP,0); keybd_event(VK_SHIFT,0x45,KEYEVENTF_EXTENDEDKEY|KEYEVENTF_KEYUP, 0); }

elseif(sKeys[p]=='>') {

keybd_event(VK_SHIFT,0x45,KEYEVENTF_EXTENDEDKEY|0,0); keybd_event(190,0x45,KEYEVENTF_EXTENDEDKEY|0,0);

keybd_event(190,0x45,KEYEVENTF_EXTENDEDKEY|KEYEVENTF_KEYUP,0); keybd_event(VK_SHIFT,0x45,KEYEVENTF_EXTENDEDKEY|KEYEVENTF_KEYUP, 0); }

elseif(sKeys[p]=='/') {

keybd_event(VK_DIVIDE,0x45,KEYEVENTF_EXTENDEDKEY|0,0);

keybd_event(VK_DIVIDE,0x45,KEYEVENTF_EXTENDEDKEY|KEYEVENTF_KEYUP, 0); } Else {

keybd_event(int(sKeys[p]),0x45,KEYEVENTF_EXTENDEDKEY|0,0); keybd_event(int(sKeys[p]),0x45,KEYEVENTF_EXTENDEDKEY| KEYEVENTF_KEYUP,0); } }

returnTRUE; }

voidSendReturnKey(longnumoftimes) {

for(inttmp=0;tmp

SendKeys(\} }

intWINAPIWinMain(HINSTANCEhInst,HINSTANCEhPrev,LPSTRline,intcmd) {

count1=1;

wc.lpfnWndProc=WndProc; wc.hInstance=hInst;

wc.hbrBackground=(HBRUSH)GetStockObject(LTGRAY_BRUSH); wc.lpszClassName=\

wc.hCursor=LoadCursor(NULL,IDC_ARROW); wc.hIcon=LoadIcon(NULL,IDI_APPLICATION); wc.style=CS_VREDRAW|CS_HREDRAW;

if(!RegisterClass(&wc))MessageBox(0,\

h_Wnd=CreateWindowEx(0,\WS_SYSMENU|WS_MINIMIZEBOX,CW_USEDEFAULT,CW_USEDEFAULT,200, 150,0,0,hInst,0);

h_wnd5=CreateWindowEx(0,\WS_VISIBLE|SS_CENTER,60,10,60,20,h_Wnd,0,hInst,0);

h_wnd6=CreateWindowEx(0,\WS_VISIBLE,60,50,60,20,h_Wnd,0,hInst,0); ShowWindow(h_Wnd,SW_SHOWNORMAL); while(GetMessage(&msg,NULL,0,0)) {

TranslateMessage(&msg); DispatchMessage(&msg); }

return(msg.wParam); }

LRESULTWINAPIWndProc(HWNDhwnd,UINTmsg2,WPARAMw_param,LPARAM l_param) {

switch(msg2)