2017-02-11 35 views
-1

我創建了Credential Manager DLL以利用NPLogonNotify事件。我正在對Windows 7 Ultimate進行完全修補的實例進行測試。憑證管理器DLL在強制更改密碼時導致登錄掛起

當用戶登錄我的NPLogonNotify實現時,會產生一些使用CreateProcess的進程。這些進程是Windows應用程序,一切正常。

當我強制用戶在下次登錄時更改密碼時,他們更改密碼,系統掛起「更改密碼」。當用戶更改密碼時,在NPLoponNotify內部創建新進程的某些操作不會很好。

我已驗證它是NPLogonNotify代碼,通過註釋該導出中的所有代碼並測試強制密碼更改。如果我將所有代碼註釋掉了,那麼密碼更改就完美了,代碼會無限期地掛起。

下面是憑據管理器導出的函數

NPGetCaps

DWORD APIENTRY NPGetCaps(DWORD nIndex) 
{ 
    DWORD ret = 0; 
    switch (nIndex) 
    { 
    case WNNC_NET_TYPE: 
     ret = WNNC_CRED_MANAGER; // credential manager 
     break; 

    case WNNC_SPEC_VERSION: 
     // We are using version 5.1 of the spec. 
     ret = WNNC_SPEC_VERSION51; 
     break; 

    case WNNC_DRIVER_VERSION: 
     ret = 1; // This driver is version 1. 
     break; 

    case WNNC_START: 
     ret = 1; // We are already "started" 
     break; 
    } 

    return ret; 
} 

NPPasswordChangeNotify

DWORD APIENTRY NPPasswordChangeNotify(LPCWSTR lpAuthentInfoType, LPVOID lpAuthentInfo, LPCWSTR lpPreviousAuthentInfoType, LPVOID lpPreviousAuthentInfo, LPWSTR lpStationName, LPVOID StationHandle, DWORD dwChangeInfo) 
{ 
    return WN_SUCCESS; 
} 

注:以上功​​能對系統無影響H老化,我已經嘗試完全沒有出口,我仍然得到相同的結果。

NPLogonNotify

DWORD APIENTRY NPLogonNotify(PLUID lpLogon, LPCWSTR lpAuthentInfoType, LPVOID lpAuthentInfo, LPCWSTR lpPreviousAuthentInfoType, LPVOID lpPreviousAuthentInfo, LPWSTR lpStationName, LPVOID StationHandle, LPWSTR *lpLogonScript) 
{ 
    lpLogonScript = nullptr; 

    //auth type can help here to know what we're doing 
    if (lstrcmpi(lpAuthentInfoType, L"MSV1_0:Interactive") != 0 && lstrcmpiW(lpAuthentInfoType, L"Kerberos:Interactive")) 
     return WN_SUCCESS; 

    WCHAR filename[MAX_PATH]; 
    GetModuleFileName(g_Module, filename, MAX_PATH); 
    wcsrchr(filename, L'\\')[0] = L'\0'; 

    WCHAR exe1Filename[MAX_PATH]; 
    wsprintf(exe1Filename, L"%lS\\exe1.exe", filename); 

    STARTUPINFOW si = { 0 }; 
    PROCESS_INFORMATION pi = { 0 }; 
    si.cb = sizeof(STARTUPINFO); 

    if (CreateProcess((LPWSTR)exe1Filename, nullptr, nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi)) 
    { 
     WaitForInputIdle(pi.hProcess, INFINITE); 
     CloseHandle(pi.hThread); 
     CloseHandle(pi.hProcess); 
    } 

    MSV1_0_INTERACTIVE_LOGON *authInfo = (MSV1_0_INTERACTIVE_LOGON *)lpAuthentInfo; 

    si = { 0 }; 
    pi = { 0 }; 
    si.cb = sizeof(STARTUPINFO);  

    ((PWSTR)(&((char *)authInfo->UserName.Buffer)[authInfo->UserName.Length]))[0] = L'\0'; 

    WCHAR args[(UNLEN + 14) * 2]; 
    wsprintf(args, L"exe2.exe %lS", authInfo->UserName.Buffer); 

    WCHAR exe2Path[MAX_PATH]; 
    wsprintf(exe2Path, L"%lS\\exe2.exe", filename); 

    if (CreateProcess((LPWSTR)exe2Path, (LPWSTR)args, nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi)) 
    { 
     WaitForSingleObject(pi.hProcess, INFINITE); 
     CloseHandle(pi.hThread); 
     CloseHandle(pi.hProcess); 
    } 

    return WN_SUCCESS; 
} 

我知道,上面的代碼是非常糟糕的,沒有錯誤檢查,也不安全。我正在做這個測試和學習練習來了解更多關於Credential Managers的信息。

有誰知道爲什麼NPLogonNotify內的代碼在用戶登錄時可以完美工作,但是當用戶在登錄時被迫更改密碼時會完全掛起系統?

+0

掛在'WaitForInputIdle'或'WaitForSingleObject(pi.hProcess,INFINITE);'我只能評論這個和測試。如果真的掛在這裏(當你不等待時不掛機) - 在你單獨的進程中執行任務。我在之前(在當前winlogon桌面上)啓動調試器並在其下查看 – RbMm

+0

@RbMm好點,我將把它們拿出來看看。我認爲它甚至沒有達到這一點,因爲屏幕上沒有顯示任何內容,但它可能正在顯示,但是顯示爲其他內容或者沒有正常顯示,這會導致它出現凍結。我會用結果更新問題 – vane

+0

您是否嘗試過...調試? – conio

回答

1

我仍然不清楚爲什麼我的程序不會顯示在用戶密碼更改上,但我設法弄清楚如何解決它。我需要找出一種方法來確定登錄時撥打NPLogonNotify的呼叫與密碼更改時的呼叫之間的差異。

掛起的問題是因爲我打電話WaitForSingleObject等待我的程序退出,然後繼續運行程序,因爲密碼更改期間由於某種原因它只是隱藏起來並且難以處理。

有沒有文件,我可以發現,所以我可以檢查與下面的代碼登錄時更改密碼和通話時明確列出的通話之間的區別:

if (lpPreviousAuthentInfoType != NULL || lpPreviousAuthentInfo != NULL || lstrcmpi(lpStationName, L"Winsta0") != 0) 
    return WN_SUCCESS; 

這可能是過度,可能不是正確的方式,但我找不到任何文檔。基本上,在密碼更改時,lpPreviousAuthentInfoType將填充字符串(根據身份驗證的類型而不同)和空字符串(如果執行正常登錄)。 lpPreviousAuthentInfo將包含一個指向先前用戶憑據的指針,如果是正常登錄,則爲NULL。最後,lpStationName將在正常登錄時爲Winsta0,在密碼更改時爲SvcCtl(如果我沒記錯的話,我沒有寫下來)。