第7章WinLogon编程
WinLogon是系统提供的一个重要进程,熟悉WinLogon编程,能够更好地对系统 进行控制。本章主要介绍GINA程序的编写。 7.1WinLogon概述
Windows环境的Logon程序是系统自行启动的重要进程,这个进程领先于外壳程 序运行,它主要用于对Windows工作站和相应桌面进行保护,确保存取权限。一般 地,本地系统拥有对这些对象存取的全部权限,只有通过登录界面的用户才能存取工 作站对象,完全存取应用程序桌面对象。
另外,WinLogon率先挂接了User32服务器,监视Ctrl+Alt+DelSAS(Secure
AttentionSequence)事件。WinLogon把SAS可用事件信息通知给GINAs,作为安全守 护序列或者作为它们的一部分。一般地,GINAs应该监视它们自己的SASs事件。然 而,任何支持标准Ctrl+Alt+Del安全守护的GINA程序,都将被WinLogon作为 WinLogon支持的SAS对象之一。
当WinLogon遇到SAS事件发生时,或者GINA把SAS通知给WinLogon时,
WinLogon就会设置相应的状态标志。改变WinLogon桌面,并调用其中一个GINA提 供的SAS处理函数。
当用户完成系统登录的时候,他们的配置信息被加载到注册表中。用户的信息将 使用HKEY_LOCAL_USER注册键。WinLogon的这些自动操作是在成功登录之后, 在激活最新登录用户的外壳程序之前。
用户登录时GINA负责为登录用户创建一个或者多个初始化进程。WinLogon为
GINA提供了支持,把最新登录用户的安全属性应用到他们创建的进程中。然而,对 于GINA可取的方法是调用Windows的CreateProcessAsUser函数,让系统提供这种 服务。
WinLogon会自动监视键盘和鼠标活动,决定什么时候激活屏幕保护程序。一旦 屏幕保护程序被激活,WinLogon会持续监视键盘和鼠标活动,决定什么时候终止屏 幕保护程序。如果屏幕保护程序启用了安全属性,WinLogon就会锁定工作站。当有 鼠标和键盘活动时,Winlogon会调用GINA的WlxDisplayLockedNotice函数,继续锁 定工作者。如果屏幕保护程序没有应用安全属性,任何键盘和鼠标活动都会终止屏幕 保护程序而不必通知给GINA。 7.2WinLogon通知包的创建
WinLogon通知包是一个动态链接库,这个动态链接库输出了一些函数,用于处
理WinLogon事件。比如说,用户登录到系统时,WinLogon会逐次调用通知包的登录 事件处理函数提供事件的信息。通知包中的事件处理函数的名称由开发者提供,但是 它的函数名称必须在注册表中注册,WinLogon会自动检查注册表,得到函数的名称。 用户不必为每一个WinLogon事件实现和注册全部的事件处理。每一种事件处理 函数都必须遵循事件处理函数规范。这种规范只有一个参数,即 WLX_NOTIFICATION_INFO结构类型。
WinLogon将忽略事件处理函数的输出,如果处理一个事件时需要和WinLogon交 互,应该使用Winlgon支持函数。
这些通知事件包括锁定、解锁、注销、登录、启动、关机、启动屏幕保护程序、 终止屏幕保护程序、启动外壳程序等。
开发WinLogon通知包可以作为开发Windows服务的替代方案,这种方法的好处
在于它可以得到许多用户活动的通知,而且编码要比使用WindowsNT服务简单得多。
创建一个WinLogon通知包需要创建一个动态链接库,为了让WinLogon知道这 个动态链接库,可以向注册表中加入适当的注册信息。
在程序实现中启动一个Win32程序,由于进程是由WinLogon启动的,该进程拥
有系统账号,因此用户是不能简单地通过终止任务结束这个进程的。这和WindowsNT 服务是一致的。用户可以在Logoff中通知处理时终止进程。如果进程需要保持激活, 可以使用EndProcessAtWinlogoff函数。如果希望这个进程为登录用户所有,则应该在 启动通知期间而不是logon通知中使用CreateProcessAsUser函数。 实现步骤如下:
(1)创建动态链接库。 //sample.cpp
#include
PROCESS_INFORMATIONg_pi;
TCHARg_szPath[]=_T(\SafeTerminateProcess(HANDLEhProcess,UINTuExitCode);
BOOLWINAPIDllMain(HINSTANCEhInstance,DWORDdwReason,LPVOID lpReserved) {
switch(dwReason) {
caseDLL_PROCESS_ATTACH: {
DisableThreadLibraryCalls(hInstance); }
break; }
returnTRUE; }
VOIDAPIENTRYStartProcessAtWinLogon(PWLX_NOTIFICATION_INFOpInfo) {
STARTUPINFOsi;
si.cb=sizeof(STARTUPINFO); si.lpReserved=NULL; si.lpTitle=NULL;
si.lpDesktop=\
si.dwX=si.dwY=si.dwXSize=si.dwYSize=0L; si.dwFlags=0;;
si.wShowWindow=SW_SHOW; si.lpReserved2=NULL; si.cbReserved2=0;
CreateProcess(NULL,g_szPath,NULL,NULL,FALSE, CREATE_NEW_CONSOLE,NULL,NULL,&si,&g_pi); }
VOIDAPIENTRYStopProcessAtWinLogoff(PWLX_NOTIFICATION_INFOpInfo)
{
SafeTerminateProcess(g_pi.hProcess,0xDEADBEEF); }
VOIDAPIENTRYYOUR_EVENT_HANDLERS(PWLX_NOTIFICATION_INFOpInfo) { } …
(2)实现输出函数。 sample.def EXPORTS
StartProcessAtWinLogon StopProcessAtWinLogoff
然后在编译选项中添加/def:\
(3)把编译好的sample.dll和sample.exp复制到WindowsNT的系统目录。 (4)添加注册表信息。 HKEY_LOCAL_MACHINE \\Software \\Microsoft \\WindowsNT \\CurrentVersion \\WinLogon \\Notify
\\NameOfProject
\\AsynchronousREG_DWORD0 \\DllnameREG_SZNameOfDll.dll \\ImpersonateREG_DWORD0
\\LogonREG_SZStartProcessAtWinLogon \\LogoffREG_SZStopProcessAtWinLogoff \\...REG_SZNameOfFunction
实际上如果用户打开注册表,就会发现在HKEY_LOCAL_MACHINE
\\SOFTWARE\\Microsoft\\WindowsNT\\CurrentVersion\\WinLogon\\Notify键下保存着多个 这样的子键。比如下面是导出的信息之一。 WindowsRegistryEditorVersion5.00
[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\WinLogon\\Notify]
[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\WinLogon\\Notify\\cscdll] \
\\
\\
\\
\\
创建WinLogon通知包,有很多用途。如果用户希望在特定条件下完成指定的功 能,比如用户希望在系统关闭的时候完成某些功能,这可能是最好的实现方法。 7.3GINA动态链接库编程
实现GINA(GraphicalIdentificationandAuthentication)动态链接库有很多用途,它
可实现对用户登录系统的接管,可以用来提供自己的Shell程序,实现自己的程序能 够排他运行,比如开机后只能运行一个程序。
实现GINA程序和创建WinLogon通知包一样,也需要编写一个动态链接库,这 个动态链接库必须实现GINA规定的有关函数。另外,为了让WinLogon找到这个动 态链接库,还必须在注册表中添加一个项,标识Gina动态链接库的名称,当然GINA 必须位于Windows的系统目录。
它要求在注册表下面的键下定义键项:
HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\WindowsNT\\CurrentVersion\\ WinLogon
项的名称为GinaDLL,项值为库的名称,库的文件名应该包含扩展名,但不需要 包含路径。 注意:
GINA是在系统启动时被加载的,如果这个程序加载失败,将导致系统崩溃,即
便是安全模式也无法实现修复。为了安全起见,用户最好准备两个操作系统,其中试 验的操作系统,最好安装在FAT32分区。如果启动失败,可以使用Windows系统本 身提供的MSGina.dll覆盖原来的GinaDLL文件,文件名不要变化。
正常启动后,检查代码,或者删除指定键。当没有这个键项时,系统将使用 MSGina.dll文件。
GINA动态链接库要求实现下面的输出函数: ●WlxActivateUserShell用于激活用户外壳程序。
●WlxDisplayLockedNotice允许GINADLL显示锁定信息。
●WlxDisplaySASNotice当没有用户登录时WinLogon会调用这个函数。 ●WlxDisplayStatusMessage当状态信息显示时WinLogon调用这个函数。 ●WlxGetConsoleSwitchCredentialsWinLogon调用这个函数去阅读当前登录用 户的证书以便实现目标会话的透明传输。
●WlxGetStatusMessageWinLogon调用这个函数显示当前的状态信息。 ●WlxInitialize初始化GINADLL。
●WlxIsLockOk验证当前工作站是否被锁定成功。 ●WlxIslogoffOk验证注销是否成功。
●WlxLoggedOnSAS当WinLogon收到一个安全守护序列事件时,会调用这个 函数,这时用户已经登录,但是工作站没有被锁定。
●WlxLoggedOutSAS当WinLogon收到一个SAS事件而用户没有登录时会调 用这个函数。
●WlxLogoff通知GINADLL,注销操作正在请求。
●WlxNegotiate预示当前版本的WinLogon可否和GINADLL一起使用。
●WlxNetworkProviderLoad当网络提供者被加载收集完有效的认证和识别信息 时,WinLogon会回调这个函数。
●WlxRemoveStatusMessageWinLogon调用这个函数通知GINA状态信息正在
被停止显示。
●WlxScreensaverNotify允许GINA和屏幕保护程序实现交互操作。
●WlxShutdownWinLogon会在关机前调用这个函数,允许GINA执行任何关 机前的操作,比如从阅读器中弹出智能卡。
●WlxStartApplication当系统需要一个应用程序在用户环境中启动时调用这个 函数。
●WlxWkstaLockedSAS当工作者被锁定时收到SAS通知时调用这个函数。
其中WlxNegotiate函数是必须实现的函数,这是WinLogon调用GINADLL的第 一个函数。
例7-1一个GINA链接库实现的框架。 #ifndefUNICODE #defineUNICODE #define_UNICODE #endif
#include\#include #include
#defineULONG_PTRunsignedlong
typedefstruct_WLX_CLIENT_CREDENTIALS_INFO {
DWORDdwType;
PWSTRpszUserName; PWSTRpszDomain; PWSTRpszPassword;
BOOLfPromptForPassword;
}WLX_CLIENT_CREDENTIALS_INFO_V1_0, *PWLX_CLIENT_CREDENTIALS_INFO_V1_0;
typedefBOOL(WINAPI*PWLX_CLOSE_USER_DESKTOP)( HANDLEhWlx,PWLX_DESKTOPpDesktop,HANDLEhToken); typedefBOOL(WINAPI*PWLX_SET_OPTION)(
HANDLEhWlx,DWORDOption,ULONG_PTRValue,ULONG_PTR *OldValue);
typedefBOOL(WINAPI*PWLX_GET_OPTION)(
HANDLEhWlx,DWORDOption,ULONG_PTR*Value);
typedefVOID(WINAPI*PWLX_WIN31_MIGRATE)(HANDLEhWlx); typedefBOOL(WINAPI*PWLX_QUERY_CLIENT_CREDENTIALS)( PWLX_CLIENT_CREDENTIALS_INFO_V1_0pCred);
typedefBOOL(WINAPI*PWLX_QUERY_IC_CREDENTIALS)( PWLX_CLIENT_CREDENTIALS_INFO_V1_0pCred); typedefBOOL(WINAPI*PWLX_DISCONNECT)(); #defineWLX_DIRECTORY_LENGTH1024
typedefstruct_WLX_TERMINAL_SERVICES_DATA {