LOGON描述(3)

作者:陆麟
转载请征得作者同意.如有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;
好了.今天就介绍到这里.下次继续讲解.