作者:陆麟
转载请征得作者同意.如有BUG,请汇报.
2000.3.24
当NT启动LOGON时,LOGON会加载一些DLL.这些DLL就是GINA和一些NP.(关于大体的描述,在INSIDE
NT第二版里有描述.这里描述一些关键的小细节.)
GINA本身有注册表里的\HKEY_LOCAL_MACHINE\Software\Microsoft\Windows
NT\CurrentVersion\Winlogon\
里的键GinaDLL定义.该处的值为GINA的实际DLL名.GINA负责的乃是提供用户界面和搜集登录信息.通常对应LOGON进程最大的误解就是LOGON负责登录的验证,但是其实真正的验证是在LSA进行的.由于GINA本身能够获取纯文本形式的用户名和密码,所以黑白两道都对GINA青眼有加.但是正由于GINA本身被这么多的程序员盯住,任何人都不能保证自己开发的GINA不会在其他软件被人家的GINA替换调.这里我将先分析GINA,并且尝试给出另外的方法获取登录通知.
LOGON本身和LSA的联接需要调用
NTSTATUS
LsaRegisterLogonProcess(
IN PLSA_STRING LogonProcessName,
OUT PHANDLE LsaHandle,
OUT PLSA_OPERATIONAL_MODE SecurityMode
);
由于所有的LSA调用都是特权调用,连ADMINISTRATOR也没有权限调用该函数.LSA调用只有操作系统才能进行,这些都是出于安全的考虑.为了表明自己就是OS或者自己从属于OS的一部分,调用者必须具有SeTcbPrivilege特权.
当LsaRegisterLogonProcess成功后,调用者就获得的一个对LSA调用的令牌.现在,LSA已经知道,有个进程是登录进程,而且获得了他的注册名供审计用.现在,LOGON进程需要个GINA沟通了.因为验证需要通过GINA参与进行.根据MS的功能模块定义,GINA才是和LSA最终打交道的模块.
那么就看看如何和GINA沟通吧.
GINA通过EXPORT一个函数WlxNegotiate告诉LOGON自己的版本,并且得到LOGON的版本,用以支持不同的的协议集.当LOGON和GINA都认为对方的版本可以满足自己的运行需求时,GINA的WlxInitialize函数被调用.在该函数被调用时,GINA将获得LOGON提供的函数集.
NT3.51支持的函数集为
Typedef struct __win32_DISPATCH_VERSION_1_0 {
PWLX_USE_CTRL_ALT_DEL
WlxUseCtrlAltDel;
PWLX_SET_CONTEXT_POINTER
WlxSetContextPointer;
PWLX_SAS_NOTIFY
WlxSasNotify;
PWLX_SET_TIMEOUT
WlxSetTimeout;
PWLX_ASSIGN_SHELL_PROTECTION WlxAssignShellProtection;
PWLX_MESSAGE_BOX
WlxMessageBox;
PWLX_DIALOG_BOX
WlxDialogBox;
PWLX_DIALOG_BOX_PARAM
WlxDialogBoxParam;
PWLX_DIALOG_BOX_INDIRECT
WlxDialogBoxIndirect;
PWLX_DIALOG_BOX_INDIRECT_PARAM WlxDialogBoxIndirectParam;
PWLX_SWITCH_DESKTOP_TO_USERT WlxSwitchDesktopToUser;
PWLX_SWITCH_DESKTOP_TO_WINLOGON WlxSwitchDesktopToWinlogon;
PWLX_CHANGE_PASSWORD_NOTIFY WlxChangePasswordNotify;
} WLX_DISPATCH_VERSION_1_0;
NT4.0支持的函数集为
Typedef struct __win32_DISPATCH_VERSION_1_1 {
PWLX_USE_CTRL_ALT_DEL
WlxUseCtrlAltDel;
PWLX_SET_CONTEXT_POINTER
WlxSetContextPointer;
PWLX_SAS_NOTIFY
WlxSasNotify;
PWLX_SET_TIMEOUT
WlxSetTimeout;
PWLX_ASSIGN_SHELL_PROTECTION WlxAssignShellProtection;
PWLX_MESSAGE_BOX
WlxMessageBox;
PWLX_DIALOG_BOX
WlxDialogBox;
PWLX_DIALOG_BOX_PARAM
WlxDialogBoxParam;
PWLX_DIALOG_BOX_INDIRECT
WlxDialogBoxIndirect;
PWLX_DIALOG_BOX_INDIRECT_PARAM WlxDialogBoxIndirectParam;
PWLX_SWITCH_DESKTOP_TO_USERT WlxSwitchDesktopToUser;
PWLX_SWITCH_DESKTOP_TO_WINLOGON WlxSwitchDesktopToWinlogon;
PWLX_CHANGE_PASSWORD_NOTIFY WlxChangePasswordNotify;
PWLX_GET_SOURCE_DESKTOP
WlxGetSourceDesktop;
PWLX_SET_RETURN_DESKTOP
WlxSetReturnDesktop;
PWLX_CREATE_USER_DESKTOP
WlxCreateUserDesktop;
} WLX_DISPATCH_VERSION_1_1;
NT4.0SP4的函数集为
Typedef struct __win32_DISPATCH_VERSION_1_2 {
PWLX_USE_CTRL_ALT_DEL
WlxUseCtrlAltDel;
PWLX_SET_CONTEXT_POINTER
WlxSetContextPointer;
PWLX_SAS_NOTIFY
WlxSasNotify;
PWLX_SET_TIMEOUT
WlxSetTimeout;
PWLX_ASSIGN_SHELL_PROTECTION WlxAssignShellProtection;
PWLX_MESSAGE_BOX
WlxMessageBox;
PWLX_DIALOG_BOX
WlxDialogBox;
PWLX_DIALOG_BOX_PARAM
WlxDialogBoxParam;
PWLX_DIALOG_BOX_INDIRECT
WlxDialogBoxIndirect;
PWLX_DIALOG_BOX_INDIRECT_PARAM WlxDialogBoxIndirectParam;
PWLX_SWITCH_DESKTOP_TO_USERT WlxSwitchDesktopToUser;
PWLX_SWITCH_DESKTOP_TO_WINLOGON WlxSwitchDesktopToWinlogon;
PWLX_CHANGE_PASSWORD_NOTIFY WlxChangePasswordNotify;
PWLX_GET_SOURCE_DESKTOP
WlxGetSourceDesktop;
PWLX_SET_RETURN_DESKTOP
WlxSetReturnDesktop;
PWLX_CREATE_USER_DESKTOP
WlxCreateUserDesktop;
PWLX_CHANGE_PASSWORD_NOTIFY_EX WlxChangePasswordNotifyEx;
PWLX_CLOSE_USER_DESKTOP
WlxCloseUserDesktop;
} WLX_DISPATCH_VERSION_1_2
注意,在MSDN里声称1.2版函数表在WIN2000里启用是不对的.其实,从NT4SP4就开始了.并且,由于对应函数集支持的问题,很多第三方的GINA就被废了.导致系统不能启动.
WIN2000的函数集为
Typedef struct __win32_DISPATCH_VERSION_1_3 {
PWLX_USE_CTRL_ALT_DEL
WlxUseCtrlAltDel;
PWLX_SET_CONTEXT_POINTER
WlxSetContextPointer;
PWLX_SAS_NOTIFY
WlxSasNotify;
PWLX_SET_TIMEOUT
WlxSetTimeout;
PWLX_ASSIGN_SHELL_PROTECTION WlxAssignShellProtection;
PWLX_MESSAGE_BOX
WlxMessageBox;
PWLX_DIALOG_BOX
WlxDialogBox;
PWLX_DIALOG_BOX_PARAM
WlxDialogBoxParam;
PWLX_DIALOG_BOX_INDIRECT
WlxDialogBoxIndirect;
PWLX_DIALOG_BOX_INDIRECT_PARAM WlxDialogBoxIndirectParam;
PWLX_SWITCH_DESKTOP_TO_USERT WlxSwitchDesktopToUser;
PWLX_SWITCH_DESKTOP_TO_WINLOGON WlxSwitchDesktopToWinlogon;
PWLX_CHANGE_PASSWORD_NOTIFY WlxChangePasswordNotify;
PWLX_GET_SOURCE_DESKTOP
WlxGetSourceDesktop;
PWLX_SET_RETURN_DESKTOP
WlxSetReturnDesktop;
PWLX_CREATE_USER_DESKTOP
WlxCreateUserDesktop;
PWLX_CHANGE_PASSWORD_NOTIFY_EX WlxChangePasswordNotifyEx;
PWLX_CLOSE_USER_DESKTOP
WlxCloseUserDesktop;
PWLX_SET_OPTION
WlxSetOption;
PWLX_GET_OPTION
WlxGetOption;
PWLX_WIN31_MIGRATE
WlxWin31Migrate;
PWLX_QUERY_CLIENT_CREDENTIALS WlxQueryClientCredentials;
PWLX_QUERY_IC_CREDENTIALS
WlxQueryInetConnectorCredentials;
PWLX_DISCONNECT
WlxDisconnect;
} WLX_DISPATCH_VERSION_1_3;
这些函数在GINA本身的使用中将十分有用.当获取这些信息的同时,GINA通常会分配一些自己需要的内存.在MS自己的样板例程里,GINA需要分配一段内存,记录的是一些全局变量.这些变量的定义如下:
typedef struct _Globals {
BOOL
fAllowNewUser;
BOOL
fAutoLogonAtBoot;
BOOL
fAutoLogonAlways;
HANDLE
hUserToken;
PMiniAccount
pAccount;
} Globals, * PGlobals;
PMiniAccount指针指向自己更感兴趣的用户名和密码结构:
typedef struct _MiniAccount {
struct _MiniAccount * pNext;
PWSTR
pszUsername;
PWSTR
pszDomain;
PWSTR
pszPassword;
PWSTR
pszComment;
DWORD
IconId;
DWORD
Flags;
} MiniAccount, * PMiniAccount;
好了.今天就介绍到这里.下次继续讲解.