視窗子類化的另類用法 - -
Tag: 視窗
http://kruglinski.blogchina.com
視窗子類化是一種非常有用的技術,通常它用在Windows GUI編程方面,我們用這種技術來建立新的控制項,比如讓SubClassing一個Edit控制項添加一些訊息處理讓它變成MaskEdit控制項等等.反過來想想如果我們SubClassing一個有ES_PASSWORD風格的視窗控制項,得到它的密碼是難是嗎?很簡單,不過是一句CallWindowProc調用,只不過在NT等系統上需要Inject一個DLL到目標進程來SubClassing一個進程中的視窗或是子視窗.
用Spy++看了一下,資源管理員裡列表視圖其實就是一個SysListView32控制項,我們現在就是要"建立一個新的SysListView32控制項",讓它不顯示帶有"VPN"字串的表徵圖.
先來看看三個API:
SetWindowLong
SetClassLong
CallWindowProc
SetWindowLong可以改變一個視窗執行個體的視窗過程,它的作用範圍僅僅是一個視窗.
SetClassLong雖然操作的是一個視窗控制代碼,但作用卻是對建立這個視窗的視窗類別進行修改,我們可以讓它修改進程範圍內某種視窗類別的視窗過程,這裡指的視窗類別是User32視窗對象類,而不是MFC或是VCL視窗封裝類.
順便提一下改變一個進程中的基本控制項類也可以影響到它的超類,比如Delphi VCL使用超類化來建立控制項,首先它會調用GetClassInfo得到某個類的系統視窗過程或風格等參數,比如SysListView32視窗類別,然後用得到參數再註冊(RegistetClass)一個TListView視窗類別,能夠在它GetClassInfo前先用SetClassLong子類化了某個視窗類別,就可以實現其超類(如,TListView)的訊息過濾.
而CallWindowProc通常在我們處理完訊息後再調用以實現控制項基本的功能,因為我們可沒有時間寫一個完整的EDIT控制項或是SysListView32控制項.
廢話不多說.
一個執行個體Explorer.dll,它在Explorer.exe進程字類化"SysListView32"視窗類別,然後過濾掉帶有"VPN"字串(不區分大小寫)的表徵圖,我使用了一個Magic Number,就是當表徵圖少於32個時才進行搜尋過濾,也就是說我假定系統中的網路連接不超過32個,這樣做是為了提高程式效能,我們不去搜尋很大的檔案夾.程式由VC++ 6.0 sp5編譯通過,Windows 2000 Professional下運行調試通過.使用方式是用遠程線程注入到explorer.exe進程即可,而後在explorer.exe新開啟/建立的視窗中生效.
///////////////////////////////////////////////
#include "stdafx.h"
#include <windows.h>
#include <CommCtrl.h>
#include <process.h>
#include <tchar.h>
#include <shlwapi.h>
#define MAGIC_NUMBER (0x20)
WNDPROC lpfnSupperClassProc=NULL;
__forceinline
void HideItem(HWND hListCtrl,DWORD dwItemcount)
{
LVITEM li={0};
char text[50]={0};
li.pszText=text;
li.cchTextMax=50;
for(DWORD i=0;i<dwItemcount;i++)
{
CallWindowProc(lpfnSupperClassProc,hListCtrl,LVM_GETITEMTEXT,i,(LPARAM)&li);
if(StrStrI(li.pszText,_T("vpn"))!=NULL)
CallWindowProc(lpfnSupperClassProc,hListCtrl,LVM_DELETEITEM,i,0);
}
}
LRESULT CALLBACK ListFilterProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
DWORD dwItemcount=0;
if(WM_PAINT==uMsg)
{
dwItemcount=CallWindowProc(lpfnSupperClassProc,hwnd,LVM_GETITEMCOUNT,0,0);
if(dwItemcount<MAGIC_NUMBER)
HideItem(hwnd,dwItemcount);
}
return CallWindowProc(lpfnSupperClassProc,hwnd,uMsg,wParam,lParam);
}
__forceinline
BOOL InstallListFilter()
{
BOOL bRet=FALSE;
HWND hWnd=NULL;
INITCOMMONCONTROLSEX cls={sizeof(INITCOMMONCONTROLSEX),ICC_WIN95_CLASSES};
bRet=InitCommonControlsEx(&cls);
if(bRet)
{
hWnd=CreateWindow(_T("SysListView32"),_T(""),WS_CAPTION|LVS_REPORT,0,0,0,0,NULL,NULL,NULL,NULL);
lpfnSupperClassProc=(WNDPROC)GetClassLong(hWnd,GCL_WNDPROC);
SetClassLong(hWnd,GCL_WNDPROC,(LONG)ListFilterProc);
DestroyWindow(hWnd);
}
return bRet;
}
BOOL APIENTRY DllMain(HANDLE hModule,DWORD ul_reason_for_call, LPVOID lpReserved)
{
if(DLL_PROCESS_ATTACH==ul_reason_for_call)
InstallListFilter();
return TRUE;
}