分享
 
 
 

Windows2000平台下混合编程屏蔽键盘事件

王朝system·作者佚名  2006-01-30
窄屏简体版  字體: |||超大  

关键词

Windows2000,VC++, C++Bulider, Visual Basic,HOOK,DLL

引言

在一些应用场合,比如基于Windows2000(以下简称Win2K)下开发工控软件需要,为了增强系统安全性,需要对键盘事件进行监控、屏蔽。满足控制系统安全性要求。作为一个Win2K后台监控软件的编写,需要注意如下要点:HOOK(键盘挂钩函数),DLL,MsgINA.dll,Shell_NotifyIcon(托盘函数)。为了提高软件编写效率,可以采用混合编程方式,即采用VC++/ C++Bulider 6.0编写DLL文件,采用Visual Basic编写客户端程序。

1 HOOK与DLL简介

1) HOOK

HOOK是一种反调函数。是Windows系统为应用程序提供用于监控系统各种事件消息的类中断程序。在系统消息机制里挂上用户自定义消息处理钩子(HOOK),达到对消息的过滤。Windows系统本身提供数个HOOK函数,为实现在Win2K/NT平台下的键盘屏蔽,要采用低级键盘HOOK,即WH_KEYBOARD_LL。此HOOK函数可以屏蔽Ctrl+Esc、Alt+Tab、和Alt+Esc等系统功能键,在WINNT SP3后的操作系统中都是支持的。设置HOOK需要用到SetWindowsHookEx()函数,在程序退出后,必须用UnhookWindowsHookEx()函数卸载掉HOOK。

2) DLL与Msgina.dll

DLL(动态链结库)是Microsoft Windows最重要组成之一。大多数与Windows相关程序,不是程式模块组模式,就是动态链结库模式。为实现对所有键盘事件的监控,必须将HOOK函数放在DLL文件中。

Windows本身就是由许多的DLL组成的,它所有的库模块也都设计成DLL。在Win2K在,为了屏蔽Ctrl+Alt+Del组合键,必须了解Msgina.dll。在Win2K系统中,微软采用Winlogon和GINA-Graphical Identification and Authentication提供交互式登录支持。登录成功后,按下Ctrl+Alt+Del组合键,系统将通过Winlogon调用Msgina.dll内部函数WlxLoggedOnSAS。所以要屏蔽Ctrl+Alt+Del组合键,则可以写一个新的GINA.dll,其中提供接口调用Msgina.dll,从而实现屏蔽。

3) Shell_NotifyIcon

客户端程序应该运行在后台,所以可以将其最小化在系统托盘中。采用Shell_NotifyIcon API函数用来添加、删除、更改系统托盘区(taskbar status area)的图标。

2 程序实现

在本文中,采用VC++6.开发系统GINA DLL, C++Bulider 6.0开发低层HOOK DLL,VB6.0开发客户端程序,实现混合编程。

1) 自定义GINA编写

因为自定义GINA编写资料较多,本文只简要介绍。自定义GINA可以采用VC++6.0开发。下面给出Windows2000 的Msgina内部函数表。表中函数将在自定义GINA中导入。

函数名

说明

WlxActivateUserShell

激活用户外壳程序

WlxDisPlayLockedNotice

允许GINA dll显示锁定信息

WlxDisPlaySASNotice

当没有用户登录时,winlogon调用此函数

WlxDisPlayStatusMessage

Winlogon用一个状态信息调用此函数进行显示

WlxGetConsoleSwitchCredentials

Winlogon调用此函数读取当前登录用户的信任信息,并透明的将它们传到目标会话

WlxGetStatusMessage

Winlogon调用此函数获取当前状态信息

WlxIntialize

针对指定的窗口位置进行GINA dll初始化

WlxIsLockOk

验证工作站正常锁定

WlxIslogoffOk

验证注销正常

WlxLoggedOnSAS

用户已登录并且工作站没有被加锁,若此时接收到SAS事件,则Winlogon调用此函数

WlxLoggedOutSAS

没有用户登录,若此时接收到SAS事件,则Winlogon调用此函数

WlxLogoff

请求注销操作时通知GINA dll

WlxNegotiate

表示当前的winlogon版本是否能使用GINA dll

WlxNetworkProviderLoad

在加载网络服务提供程序收集了身份和认证信息后,Winlogon调用此函数

WlxRemoveStatusMessage

Winlogon调用此函数告诉GINA dll停止显示状态信息

WlxScreensaverNotify

允许GINA与屏幕保护操作交互

WlxShutdown

在关闭之前Winlogon调用此函数,允许GINA实现任何关闭任务,例如从读卡器中退出智能卡

WlxStartApplication

当系统需要在用户的上下文中启动应用程序时调用此函数

WlxWkstalockedSAS

当工作站被锁定,如果接收到一个SAS,则Winlogon调用此函数

我们需要注意的是WlxLoggedOnSAS函数。屏蔽Ctrl+Alt+Del组合键代码将在调用该函数时添加。我们采用读取注册表键值来判断是否屏蔽,而该键值将在客户端程序中被操作。

// 当系统处于登陆成功,没有锁定的状态下

// Winlogon接收到SAS事件,于是调用该函数

int WINAPI WlxLoggedOnSAS(PVOID pWlxContext, DWORD dwSasType, PVOID pReserved)

{

HKEY hKey;

DWORD dwType=REG_DWORD; //定义读取数据类型:双字节

char content[4]; //所查询注册表键值的内容

DWORD dwLength=4;

//打开注册表键

if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,"SOFTWARE\\FCSKBLock\\KBConfig",

0,KEY_READ,&hKey)

==ERROR_SUCCESS)

{ //读取CtrlAltDel键值

if(RegQueryValueEx(hKey,"CtrlAltDel",NULL,&dwType,(unsigned char *)content,&dwLength)

==ERROR_SUCCESS)

{

if(* content==1)

return WLX_SAS_ACTION_NONE;//直接返回桌面程序,实现屏蔽

}

}

return theApp.MyWlxLoggedOnSAS(pWlxContext,dwSasType,pReserved ) ;

}

开发完成的自定义GINA.dll要放到Wint\system32文件夹中。并修改注册表:

键项名

\HKEY_LOCAL_MACHINE\Software\Microsoft\WindowsNT\CurrentVersion\Winlogon

子键名

myGina(任意名称均可)

子键类型

[REG_SZ]

子键值

myGina(自定义Gina的名称)

若GINADLL不存在,新建即可。

再重启计算机后myGina即为系统使用。

2) 全局HOOK、DLL编写

采用BORLAND C++Bulider 6.0(以下简称BCB)编写安装全局HOOK的DLL文件。BCB是一款优秀的C/C++语言开发工具,可以快速开发高质量的Windows程序。下面介绍简要步骤:

I. 利用BCB新建向导,建立一个DLL工程。在此DLL中我们将有条件的安放两个HOOK。一个用于捕获系统功能热键并屏蔽,另一个用作客户端程序的激活热键;

II. 在cpp里添加如下代码:

此段代码用于申明全局变量和导出函数。因为此DLL文件将被VB编写的客户端程序所调用,所以声明导出函数时需要将语句extern ”C” 放置在声明处。另外在BCB中默认的调用约定为__cdecl方式,而在VB中调用约定为__stdcall。

pragma argsused

//下面变量用于HOOK.cpp

static HHOOK hOldHook=0;/*记录上一个注册的键盘钩子*/

static HHOOK hOldHook2=0;/*记录上一个注册的键盘钩子*/

static HWND hProcWnd=0; /*记录客户程序的窗体*/

static HANDLE hInstance=0;/*DLL的句柄*/

//导出setHotKey

extern "C" __declspec(dllexport) char _stdcall ActivateKey(HWND hWnd,bool nCode,bool bWhich);

int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)

{

//用全局变量保存这个DLL的句柄

hInstance=hinst;

return 1;

}

因为客户端程序是作为后台运行的,所以我们需要给其安放个激活热键,以便用户在任何情况下通过热键呼出。所以必须通过DLL文件安放一个全局HOOK,用作激活热键。当用户按下激活热键后,DLL会截获消息并向指定的客户端程序发送激活消息。

//客户端程序热键---------------------------------------------------------------------------

LRESULT CALLBACK HotKeyProc(int nCode,WPARAM wParam,LPARAM lParam)

{

bool fEatKeystroke = FALSE;

//PKBDLLHOOKSTRUCT p = NULL;

if (nCode == HC_ACTION) {

switch (wParam)

{

case WM_KEYDOWN: case WM_SYSKEYDOWN:

case WM_KEYUP: case WM_SYSKEYUP:

PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT) lParam;

fEatKeystroke =

((p->flags & LLKHF_ALTDOWN) != 0)&& (p->vkCode==VK_F12);//自定义激活//热键: Alt+F12

break;

}

if(fEatKeystroke)

SendMessage(hProcWnd,WM_USER+200,2000,0); //用于激活客户程序的自定义消息

}

return(fEatKeystroke ? 1 : CallNextHookEx(NULL, nCode, wParam,

lParam));

}

此处为捕获、屏蔽系统功能热键的回调函数,用户可根据需要添加修改需要屏蔽的按键。

//屏蔽Ctrl+Esc/Alt+Tab/Win/F1/Alt+Esc等功能按键------------------------------------------------------------------

LRESULT CALLBACK ShieldKeyProc(int nCode,WPARAM wParam,LPARAM lParam)

{

bool fEatKeystroke = FALSE;

//PKBDLLHOOKSTRUCT p = NULL;

if (nCode == HC_ACTION)

{

switch (wParam) {

case WM_KEYDOWN: case WM_SYSKEYDOWN:

case WM_KEYUP: case WM_SYSKEYUP:

PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT) lParam;

fEatKeystroke =

(p->vkCode==VK_F1)||//F1

((p->vkCode == VK_TAB) && ((p->flags & LLKHF_ALTDOWN) != 0))|| //Alt+Tab

((p->vkCode == VK_ESCAPE) && ((p->flags & LLKHF_ALTDOWN) != 0)) || //Alt+Esc

((p->vkCode == VK_ESCAPE) && ((GetKeyState(VK_CONTROL) & 0x8000) != 0)) || //Ctrl+Esc

(((GetKeyState(VK_CONTROL) & 0x8000) != 0) && (p->vkCode == VK_SPACE))|| //Ctrl+Space

(((GetKeyState(VK_CONTROL) & 0x8000) != 0) && ((GetKeyState(VK_SHIFT) & 0x8000) != 0));

break;

}

}

return(fEatKeystroke ? 1 : CallNextHookEx(NULL, nCode, wParam,

lParam));

}

这个函数负责根据客户端调用参数,向系统注册、注销HOOK。HOOK必须在不要的时候卸载!

//HWND hWnd:客户端程序调用窗体的句柄,bool nCode:挂还是不挂HOOK的标志,bool bWhich:挂哪个HOOK的标志

char _stdcall ActivateKey(HWND hWnd,bool nCode,bool bWhich)

{

if (bWhich)

{

if(nCode) // 安放底层HOOK

{

hProcWnd=hWnd;//记录下这一个DLL是由哪个窗体调用的

hOldHook=SetWindowsHookEx(WH_KEYBOARD_LL,(HOOKPROC)ShieldKeyProc,hInstance,0); //记录下上一个DLL是由哪个窗体调用的

return(hOldHook != NULL? 1: 0 );

}

else // 卸下HOOK

UnhookWindowsHookEx(hOldHook);

}

else

{

if(nCode) // 安放HotHooK

{

hProcWnd=hWnd;//记录下这一个DLL是由哪个窗体调用的

hOldHook2=SetWindowsHookEx(WH_KEYBOARD_LL,(HOOKPROC)HotKeyProc,hInstance,0); //记录下上一个DLL是由哪个窗体调用的

return(hOldHook2 !=NULL ? 1: 0);

}

else // 卸下HOOK

UnhookWindowsHookEx(hOldHook2);

}

return true;

III. 以Release方式编译保存。

IV. 关于DLL调试可以参见有关文档。

3) 客户端程序

微软的 Visual Basic 因为其编写Windows界面程序的方便、灵活而成为我们开发客户端程序的首选。我们采用Visual Basic 6.0 中文企业版(以下简称VB)进行开发。VB本身并不直接支持DLL文件的开发,但提供了对DLL的调用功能。作为客户端程序,就是实现用户操作与程序调用DLL,API函数的转换。下面介绍简要步骤:

I. 工程建立

新建三个窗体.分别命名为:Form1,frmLogin,Dialog.

Form1作为主窗体界面布置如图<1>:

<1>

第一项采用API函数屏蔽任务栏;

第二项通过操作注册表,实现屏蔽Ctrl+Alt+Del组合键;

第三项通过调用开发的底层键盘HOOK DLL实现功能键的屏蔽。

密码设置项用于客户端程序激活需要密码情况。

frmLogin作为用户设置密码后,重新激活的登录窗体,如图<2>:

<2>

Dialog则作为”密码设置”窗体,如图<3>:

<3>

II. 代码流程:

本文给出主流程图。

说明:

i. 因为软件是基于Windows2000平台,所以启动后首先要判断系统平台;

ii. 考虑系统安全性,程序要检查是否已有远行实例;

iii. 因为要接受DLL文件发送的激活消息,所以可以在窗体加载事件中通过SetWindowLong函数在VB消息序列中添加自定义消息过滤函数。

SetWindowLong语法:

SetWindowLong(hwnd, GWL_WNDPROC, AddressOf SysMenuProc)

hwnd:当前窗体的句柄

GWL_WNDPROC:设置一个新的窗口消息处理过程的地址

AddressOf SysMenuProc:取新的窗口消息处理过程名称

返回值代表前个窗体消息处理过程。

SysMenuProc函数是个回调函数。必须声明定义在标准模块中。

iv. 程序最小化在系统托盘区编程利用Shell_NotifyIcon函数。

Shell_NotifyIcon语法可以参见微软的MSDN。添加系统托盘图标子程序放在窗体的Resize事件中。程序在退出时必须删除图标。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有