大家知道,Ctrl+Alt+Del是Win2k/NT操作系统默认的系统登录/注销组合键序列,系统级别很高。在应用程序中,想要屏蔽掉该键序列的响应或得到这个"按下"事件,难度是相当大的。本例介绍了一种简单易行的方法,实现在用户登录成功后,按下Ctrl+Alt+Del不再弹出"Windows安全"对话框。需要读者朋友注意的是,本实例必须运行在Windows 2000环境下。
一、 实现方法
首先介绍一下Winlogon。Windows 2000/NT有三种系统状态:没有用户登录状态、用户成功登录状态以及工作站锁定状态。Winlogon是Windows 2000/NT操作系统提供交互式登录支持的组件。Winlogon有三个组成部分:可执行文件winlogon.exe,提供图形界面认证功能的动态库Gina Dll,以及一些网络服务提供动态库Network Provider Dll。参考模型如下:
![]() |
winlogon.exe处理一些下层导出的接口函数,而认证策略是在Gina Dll中独立设计的。在系统启动时,Gina Dll被winlogon.exe装载。Microsoft提供了一个默认的Gina Dll--Winnt/system32/msgina.dll,提供了标准的用户名、密码认证模式。Gina Dll是可替换的,用户可以设计自己的Gina Dll,以提供其他如智能卡、视网膜、指纹或其他一些认证机制。
开发自定义的Gina Dll。必须实现并导出与winlogon.exe交互的18个标准函数接口,包括WlxNegotiate、WlxInitialize、WlxLoggedOnSAS等(其他函数接口请参考Msdn)。其中WlxNegotiate是winlogon.exe调用的第一个接口函数,进行必要的版本判断,随后调用的是WlxInitialize,主要完成winlogon.exe特定版本的函数分派表向Gina Dll的传递。笔者还要说明的是WlxLoggedOnSAS函数,这个函数主要的功能是,当winlogon在登录成功状态下,接收到SAS事件,于是调用这个函数进行SAS事件的识别以及进行各事件的相应处理。
自定义Gina Dll的使用。比如开发的Gina Dll文件名为MyGina.dll。将该文件放到以下路径:Winnt/system32。并修改注册表,如下:
Key Name: /HKEY_LOCAL_MACHINE/Software/Microsoft/Windows NT/CurrentVersion/ Winlogon Value Name: GinaDLL Value Type: [REG_SZ] Value: MyGina.dll |
重新启动计算机MyGina.dll即投入使用。在用户登录成功状态下,按下Ctrl+Alt+Del时系统不再弹出"Widows安全"对话框。由于并不需要改变用户名、密码这种标准的认证模式,所以可以仍然使用msgina.dll中导出的函数接口,而对WlxLoggedOnSAS函数的实现进行必要的改变,不管接收到什么SAS事件,该函数直接返回WLX_SAS_ACTION_NONE而不做其他处理。
二、编程步骤
1、启动Visual C++6.0,新建一个项目,选择MFC AppWizard(dll),项目名输入为MyGina,按下"OK"后,选择Regular DLL with MFC statically linked,按下"Finish";
2、使用Class Wizard重载CmyGinaApp类的InitInstance()和ExitInstance()两个函数,并注意在Stdafx.h中加入#include <Winwlx.h>;
3、在MyGina.h文件中说明"extern CMyGinaApp theApp",以便于程序其他地方对theApp的引用;在类CMyGinaApp中定义成员变量(具体内容见代码部分);
4、添加代码,编译程序。
三、程序代码
// //MyGina.h : main header file for the MYGINA DLL #if !defined(AFX_MYGINA_H__5959C4FD_1D31_4E51_B3CD_B5649C8473B7__INCLUDED_) #define AFX_MYGINA_H__5959C4FD_1D31_4E51_B3CD_B5649C8473B7__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #ifndef __AFXWIN_H__ #error include 'stdafx.h' before including this file for PCH #endif #include "resource.h" // main symbols //定义的函数类型; typedef (WINAPI * NEGOTIATE) (DWORD,PDWORD); typedef (WINAPI * INITIALIZE) (LPWSTR,HANDLE,PVOID,PVOID,PVOID *); typedef (WINAPI * ACTIVATE_USHELL) (PVOID,PWSTR,PWSTR,PVOID); typedef (WINAPI * PARAM_PVOID) (PVOID); typedef (WINAPI * DISP_STATUS) (PVOID,HDESK,DWORD,PWSTR,PWSTR); typedef (WINAPI * GET_STATUS) (PVOID,DWORD *,PWSTR,DWORD); typedef (WINAPI * LOGON_SAS) (PVOID,DWORD,PVOID); typedef (WINAPI * LOGOUT_SAS) (PVOID,DWORD,PLUID,PSID,PDWORD, PHANDLE,PWLX_MPR_NOTIFY_INFO,PVOID *); typedef (WINAPI * NETWORK_LOAD) (PVOID,PWLX_MPR_NOTIFY_INFO); typedef (WINAPI * SCR_SAVER) (PVOID,BOOL *); typedef (WINAPI * SHUT_DOWN) (PVOID,DWORD); typedef (WINAPI * START_APP) (PVOID,PWSTR,PVOID,PWSTR); typedef (WINAPI * LOCKED_SAS) (PVOID,DWORD); class CMyGinaApp : public CWinApp { private: HMODULE hMsDll; public: NEGOTIATE MyWlxNegotiate; INITIALIZE MyWlxInitialize; ACTIVATE_USHELL MyWlxActivateUserShell; PARAM_PVOID MyWlxDisplayLockedNotice; PARAM_PVOID MyWlxDisplaySASNotice; DISP_STATUS MyWlxDisplayStatusMessage; GET_STATUS MyWlxGetStatusMessage; PARAM_PVOID MyWlxIsLockOk; PARAM_PVOID MyWlxIsLogoffOk; LOGON_SAS MyWlxLoggedOnSAS; LOGOUT_SAS MyWlxLoggedOutSAS; PARAM_PVOID MyWlxLogoff; NETWORK_LOAD MyWlxNetworkProviderLoad; PARAM_PVOID MyWlxRemoveStatusMessage; SCR_SAVER MyWlxScreenSaverNotify; SHUT_DOWN MyWlxShutdown; START_APP MyWlxStartApplication; LOCKED_SAS MyWlxWkstaLockedSAS; public: CMyGinaApp(); // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CMyGinaApp) public: virtual BOOL InitInstance(); virtual int ExitInstance(); //}}AFX_VIRTUAL //{{AFX_MSG(CMyGinaApp) // NOTE - the ClassWizard will add and remove member functions here. // DO NOT EDIT what you see in these blocks of generated code ! //}}AFX_MSG DECLARE_MESSAGE_MAP() }; extern CMyGinaApp theApp; #endif // #include "stdafx.h" #include "MyGina.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif /// CMyGinaApp BEGIN_MESSAGE_MAP(CMyGinaApp, CWinApp) //{{AFX_MSG_MAP(CMyGinaApp) // NOTE - the ClassWizard will add and remove mapping macros here. // DO NOT EDIT what you see in these blocks of generated code! //}}AFX_MSG_MAP END_MESSAGE_MAP() // CMyGinaApp construction CMyGinaApp::CMyGinaApp() { // 初始化各变量 hMsDll = NULL; MyWlxNegotiate = NULL; MyWlxInitialize = NULL; MyWlxActivateUserShell = NULL; MyWlxDisplayLockedNotice = NULL; MyWlxDisplaySASNotice = NULL; MyWlxDisplayStatusMessage = NULL; MyWlxGetStatusMessage = NULL; MyWlxIsLockOk = NULL; MyWlxIsLogoffOk = NULL; MyWlxLoggedOnSAS = NULL; MyWlxLoggedOutSAS = NULL; MyWlxLogoff = NULL; MyWlxNetworkProviderLoad = NULL; MyWlxRemoveStatusMessage = NULL; MyWlxScreenSaverNotify = NULL; MyWlxShutdown = NULL; MyWlxStartApplication = NULL; MyWlxWkstaLockedSAS = NULL; } CMyGinaApp theApp; BOOL CMyGinaApp::InitInstance() { // 得到默认的gina dll if (hMsDll == NULL) { hMsDll = ::LoadLibrary("msgina.dll"); } // 导入各个接口函数 if (hMsDll != NULL) { MyWlxNegotiate= (NEGOTIATE) GetProcAddress(hMsDll,"WlxNegotiate"); MyWlxInitialize= (INITIALIZE) GetProcAddress(hMsDll,"WlxInitialize"); MyWlxActivateUserShell= (ACTIVATE_USHELL)GetProcAddress(hMsDll,"WlxActivateUserShell"); MyWlxDisplayLockedNotice= (PARAM_PVOID)GetProcAddress(hMsDll,"WlxDisplayLockedNotice"); MyWlxDisplaySASNotice= (PARAM_PVOID)GetProcAddress(hMsDll,"WlxDisplaySASNotice"); MyWlxDisplayStatusMessage= (DISP_STATUS)GetProcAddress(hMsDll,"WlxDisplayStatusMessage"); MyWlxGetStatusMessage= (GET_STATUS)GetProcAddress(hMsDll,"WlxGetStatusMessage"); MyWlxIsLockOk= (PARAM_PVOID)GetProcAddress(hMsDll,"WlxIsLockOk"); MyWlxIsLogoffOk= (PARAM_PVOID)GetProcAddress(hMsDll,"WlxIsLogoffOk"); MyWlxLoggedOnSAS= (LOGON_SAS)GetProcAddress(hMsDll,"WlxLoggedOnSAS"); MyWlxLoggedOutSAS= (LOGOUT_SAS)GetProcAddress(hMsDll,"WlxLoggedOutSAS"); MyWlxLogoff= (PARAM_PVOID) GetProcAddress(hMsDll,"WlxLogoff"); MyWlxNetworkProviderLoad= (NETWORK_LOAD)GetProcAddress(hMsDll,"WlxNetworkProviderLoad"); MyWlxRemoveStatusMessage= (PARAM_PVOID)GetProcAddress(hMsDll,"WlxRemoveStatusMessage"); MyWlxScreenSaverNotify= (SCR_SAVER)GetProcAddress(hMsDll,"WlxScreenSaverNotify"); MyWlxShutdown= (SHUT_DOWN)GetProcAddress(hMsDll,"WlxShutdown"); MyWlxStartApplication= (START_APP)GetProcAddress(hMsDll,"WlxStartApplication"); MyWlxWkstaLockedSAS= (LOCKED_SAS)GetProcAddress(hMsDll,"WlxWkstaLockedSAS"); } return CWinApp::InitInstance(); } int CMyGinaApp::ExitInstance() { if (hMsDll != NULL) { ::FreeLibrary(hMsDll);//卸载动态链接库; hMsDll = NULL; } return CWinApp::ExitInstance(); } 消息处理函数的实现; #include "StdAfx.h" #include "MyGina.h" // Winlogon.exe调用的gina dll中的第一个函数 // 使gina dll确认是否支持当前版本的Winlogon.exe // 传递给winlogon.exe需要那个版本的接口函数 BOOL WINAPI WlxNegotiate(DWORD dwWinLogonVersion, PDWORD pdwDllVersion) { return theApp.MyWlxNegotiate(dwWinLogonVersion,pdwDllVersion); } // 初始化,winlogon.exe向gina dll传递需要版本的接口函数分配表 BOOL WINAPI WlxInitialize(LPWSTR lpWinsta,HANDLE hWlx,PVOID pvReserved,PVOID pWinlogonFunctions,PVOID * pWlxContext) { return theApp.MyWlxInitialize(lpWinsta,hWlx,pvReserved,pWinlogonFunctions,pWlxContext); } // 用户登陆成功后,Winlogon.exe调用该函数启动用户外壳程序 BOOL WINAPI WlxActivateUserShell(PVOID pWlxContext,PWSTR pszDesktopName,PWSTR pszMprLogonScript,PVOID pEnvironment) { return theApp.MyWlxActivateUserShell(pWlxContext,pszDesktopName,pszMprLogonScript,pEnvironment); } // 当系统处于锁定状态时,Winlogon.exe调用该函数 // 显示一些信息,如锁定者、锁定时间等 VOID WINAPI WlxDisplayLockedNotice(PVOID pWlxContext) { theApp.MyWlxDisplayLockedNotice(pWlxContext); } // 当没有任何用户登陆时,Winlogon.exe调用该函数显示一些提示信息 // 可以根据用户的动作模拟SAS事件的发送 VOID WINAPI WlxDisplaySASNotice(PVOID pWlxContext) { theApp.MyWlxDisplaySASNotice(pWlxContext); } // 当gina dll要显示一些信息时,Winlogon.exe调用该函数 // 直接返回TRUE表示信息已经显示 BOOL WINAPI WlxDisplayStatusMessage(PVOID pWlxContext, HDESK hDesktop, DWORD dwOptions, PWSTR pTitle, PWSTR pMessage) { return theApp.MyWlxDisplayStatusMessage(pWlxContext,hDesktop,dwOptions,pTitle,pMessage); // return TRUE; } // Winlogon.exe调用该函数得到gina dll显示的状态信息 // 直接返回TRUE表示信息已经接收 BOOL WINAPI WlxGetStatusMessage(PVOID pWlxContext, DWORD *pdwOptions, PWSTR pMessage, DWORD dwBufferSize) { return theApp.MyWlxGetStatusMessage(pWlxContext,pdwOptions,pMessage,dwBufferSize); // return TRUE; } // 在试图锁定工作站之前Winlogon.exe调用该函数,判断是否可以锁定 // 直接返回FALSE表示不能锁定 BOOL WINAPI WlxIsLockOk(PVOID pWlxContext) { return theApp.MyWlxIsLockOk(pWlxContext); // return FALSE; } // 在试图注销时Winlogon.exe调用该函数,判断能否注销 // 直接返回FALSE表示不能注销 BOOL WINAPI WlxIsLogoffOk(PVOID pWlxContext) { return theApp.MyWlxIsLogoffOk(pWlxContext); // return FALSE; } // 当系统处于登陆成功,没有锁定的状态下 // Winlogon接收到SAS事件,于是调用该函数 // 现屏蔽所有事件,直接返回 int WINAPI WlxLoggedOnSAS(PVOID pWlxContext, DWORD dwSasType, PVOID pReserved) { return WLX_SAS_ACTION_NONE; } // 在没有任何一个用户登陆的情况下,Winlogon.exe接收到SAS事件调用该函数 int WINAPI WlxLoggedOutSAS(PVOID pWlxContext, DWORD dwSasType, PLUID pAuthenticationId, PSID pLogonSid, PDWORD pdwOptions, PHANDLE phToken, PWLX_MPR_NOTIFY_INFO pMprNotifyInfo, PVOID * pProfile) { return theApp.MyWlxLoggedOutSAS(pWlxContext,dwSasType,pAuthenticationId, pLogonSid,pdwOptions,phToken,pMprNotifyInfo,pProfile); } // Winlogon.exe调用该函数,通知gina dll用户注销操作 // 允许gina dll做出相应的处理 VOID WINAPI WlxLogoff(PVOID pWlxContext) { theApp.MyWlxLogoff(pWlxContext); } // Winlogon.exe调用该函数收集有效的认证信息 // 返回TRUE表示用户被识别 BOOL WINAPI WlxNetworkProviderLoad(PVOID pWlxContext, PWLX_MPR_NOTIFY_INFO pNprNotifyInfo) { return theApp.MyWlxNetworkProviderLoad(pWlxContext,pNprNotifyInfo); // return TRUE; } // Winlogon.exe调用该函数,告诉gina dll停止显示状态信息 // 直接返回TRUE表示信息已经删除 BOOL WINAPI WlxRemoveStatusMessage(PVOID pWlxContext) { return theApp.MyWlxRemoveStatusMessage(pWlxContext); // return TRUE; } // 在屏保程序启动前一瞬Winlogon.exe调用该函数,允许gina dll同屏保程序交互 // 返回FALSE表示屏保程序不能启动 BOOL WINAPI WlxScreenSaverNotify(PVOID pWlxContext, BOOL *pSecure) { return theApp.MyWlxScreenSaverNotify(pWlxContext,pSecure); } // 在系统关闭之前,Winlogon.exe调用该函数 // 允许gina dll处理一些系统关闭前的处理 VOID WINAPI WlxShutdown(PVOID pWlxContext, DWORD ShutdownType) { theApp.MyWlxShutdown(pWlxContext,ShutdownType); } // 当系统要求在用户上下文中启动程序,Winlogon.exe调用该函数 // 这种情况发生在:浏览器非正常关闭需要重启或需要启动扩展的任务管理器 // 该接口gina dll可以选择性实现 BOOL WINAPI WlxStartApplication(PVOID pWlxContext,PWSTR pszDesktopName,PVOID pEnvironment,PWSTR pszCmdLine) { return theApp.MyWlxStartApplication(pWlxContext,pszDesktopName,pEnvironment,pszCmdLine); } // 在锁定状态下,Winlogon.exe接收到SAS事件调用该函数 int WINAPI WlxWkstaLockedSAS(PVOID pWlxContext, DWORD dwSasType) { return theApp.MyWlxWkstaLockedSAS(pWlxContext,dwSasType); } |
四、小结
本实例介绍了如何通过自定义一个DLL文件来屏蔽Windows2000下Ctrl+Alt+Del键的方法,对于读者朋友了解Windows的内幕性知识是有帮助的,当然,屏蔽Ctrl+Alt+Del键的方法不止这一种,本实例只是起一个抛砖引玉,开拓思路的作用。