Windows: Modified implementation for Secure Desktop handling to overcome Windows 11 issues

We use only alphanumeric characters for the name in addition to the '_' character
We ensure the random desktop name doesn't already exist
We create the random desktop on the Secure Desktop thread and we look over SwitchDesktop until it works.
We call SetThreadDesktop (hOriginalDesk) in main thread once we finish
This commit is contained in:
Mounir IDRASSI 2023-10-08 01:55:07 +02:00
parent 22ac25dde7
commit c91e5792ef
No known key found for this signature in database
GPG Key ID: FC1B00364B3FE937

View File

@ -13782,7 +13782,7 @@ static BOOL GenerateRandomString (HWND hwndDlg, LPTSTR szName, DWORD maxCharsCou
bRet = RandgetBytesFull (hwndDlg, indexes, maxCharsCount + 1, TRUE, TRUE); bRet = RandgetBytesFull (hwndDlg, indexes, maxCharsCount + 1, TRUE, TRUE);
if (bRet) if (bRet)
{ {
static LPCTSTR chars = _T("0123456789@#$%^&_-*abcdefghijklmnopqrstuvwxyz"); static LPCTSTR chars = _T("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_");
DWORD i, charsLen = (DWORD) _tcslen (chars); DWORD i, charsLen = (DWORD) _tcslen (chars);
DWORD effectiveLen = (indexes[0] % (64 - 16)) + 16; // random length between 16 to 64 DWORD effectiveLen = (indexes[0] % (64 - 16)) + 16; // random length between 16 to 64
effectiveLen = (effectiveLen > maxCharsCount)? maxCharsCount : effectiveLen; effectiveLen = (effectiveLen > maxCharsCount)? maxCharsCount : effectiveLen;
@ -13864,7 +13864,9 @@ static unsigned int __stdcall SecureDesktopMonitoringThread( LPVOID lpThreadPara
{ {
if (GetUserObjectInformation (currentDesk, UOI_NAME, szName, dwLen, &dwLen)) if (GetUserObjectInformation (currentDesk, UOI_NAME, szName, dwLen, &dwLen))
{ {
if (0 != _wcsicmp (szName, szVCDesktopName)) if (0 == _wcsicmp(szName, L"Default")) // default input desktop for the interactive window station
bPerformSwitch = TRUE;
else if (0 != _wcsicmp (szName, szVCDesktopName))
bPerformSwitch = TRUE; bPerformSwitch = TRUE;
} }
free (szName); free (szName);
@ -13888,18 +13890,29 @@ static unsigned int __stdcall SecureDesktopThread( LPVOID lpThreadParameter )
SecureDesktopThreadParam* pParam = (SecureDesktopThreadParam*) lpThreadParameter; SecureDesktopThreadParam* pParam = (SecureDesktopThreadParam*) lpThreadParameter;
SecureDesktopMonitoringThreadParam monitorParam; SecureDesktopMonitoringThreadParam monitorParam;
BOOL bNewDesktopSet = FALSE; BOOL bNewDesktopSet = FALSE;
HDESK hSecureDesk;
DWORD desktopAccess = DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW | DESKTOP_READOBJECTS | DESKTOP_SWITCHDESKTOP | DESKTOP_WRITEOBJECTS;
hSecureDesk = CreateDesktop (pParam->szDesktopName, NULL, NULL, 0, desktopAccess, NULL);
if (!hSecureDesk)
{
return 0;
}
StringCbCopy(SecureDesktopName, sizeof (SecureDesktopName), pParam->szDesktopName);
pParam->hDesk = hSecureDesk;
// wait for SwitchDesktop to succeed before using it for current thread // wait for SwitchDesktop to succeed before using it for current thread
while (true) while (true)
{ {
if (SwitchDesktop (pParam->hDesk)) if (SwitchDesktop (hSecureDesk))
{ {
break; break;
} }
Sleep (SECUREDESKTOP_MONOTIR_PERIOD); Sleep (SECUREDESKTOP_MONOTIR_PERIOD);
} }
bNewDesktopSet = SetThreadDesktop (pParam->hDesk); bNewDesktopSet = SetThreadDesktop (hSecureDesk);
if (bNewDesktopSet) if (bNewDesktopSet)
{ {
@ -13909,7 +13922,7 @@ static unsigned int __stdcall SecureDesktopThread( LPVOID lpThreadParameter )
if (hStopEvent) if (hStopEvent)
{ {
monitorParam.szVCDesktopName = pParam->szDesktopName; monitorParam.szVCDesktopName = pParam->szDesktopName;
monitorParam.hVcDesktop = pParam->hDesk; monitorParam.hVcDesktop = hSecureDesk;
monitorParam.hStopEvent = hStopEvent; monitorParam.hStopEvent = hStopEvent;
hMonitoringThread = (HANDLE) _beginthreadex (NULL, 0, SecureDesktopMonitoringThread, (LPVOID) &monitorParam, 0, &monitoringThreadID); hMonitoringThread = (HANDLE) _beginthreadex (NULL, 0, SecureDesktopMonitoringThread, (LPVOID) &monitorParam, 0, &monitoringThreadID);
} }
@ -13986,18 +13999,36 @@ INT_PTR SecureDesktopDialogBoxParam(
if (bEffectiveUseSecureDesktop && !IsThreadInSecureDesktop(GetCurrentThreadId())) if (bEffectiveUseSecureDesktop && !IsThreadInSecureDesktop(GetCurrentThreadId()))
{ {
BOOL bRandomNameGenerated = FALSE;
HDESK existedDesk = NULL;
EnterCriticalSection (&csSecureDesktop); EnterCriticalSection (&csSecureDesktop);
bSecureDesktopOngoing = TRUE; bSecureDesktopOngoing = TRUE;
finally_do ({ bSecureDesktopOngoing = FALSE; LeaveCriticalSection (&csSecureDesktop); }); finally_do ({ bSecureDesktopOngoing = FALSE; LeaveCriticalSection (&csSecureDesktop); });
if (GenerateRandomString (hWndParent, szDesktopName, 64)) // ensure that the randomly generated name is not already used
do
{
if (existedDesk)
{
CloseDesktop (existedDesk);
existedDesk = NULL;
}
if (GenerateRandomString (hWndParent, szDesktopName, 64))
{
existedDesk = OpenDesktop (szDesktopName, 0, FALSE, GENERIC_READ);
if (!existedDesk)
{
bRandomNameGenerated = TRUE;
}
}
} while (existedDesk);
if (bRandomNameGenerated)
{ {
map<DWORD, BOOL> ctfmonBeforeList, ctfmonAfterList; map<DWORD, BOOL> ctfmonBeforeList, ctfmonAfterList;
DWORD desktopAccess = DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW | DESKTOP_READOBJECTS | DESKTOP_SWITCHDESKTOP | DESKTOP_WRITEOBJECTS; HDESK hOriginalDesk = NULL;
HDESK hSecureDesk; SecureDesktopThreadParam param;
HDESK hOriginalDesk = GetThreadDesktop (GetCurrentThreadId());
HDESK hInputDesk = NULL;
// wait for the input desktop to be available before switching to // wait for the input desktop to be available before switching to
// secure desktop. Under Windows 10, the user session can be started // secure desktop. Under Windows 10, the user session can be started
@ -14005,65 +14036,62 @@ INT_PTR SecureDesktopDialogBoxParam(
// case, we wait for the user to be really authenticated before starting // case, we wait for the user to be really authenticated before starting
// secure desktop mechanism // secure desktop mechanism
while (!(hInputDesk = OpenInputDesktop (0, TRUE, GENERIC_READ))) while (!(hOriginalDesk = OpenInputDesktop (0, TRUE, GENERIC_ALL)))
{ {
Sleep (SECUREDESKTOP_MONOTIR_PERIOD); Sleep (SECUREDESKTOP_MONOTIR_PERIOD);
} }
CloseDesktop (hInputDesk);
// get the initial list of ctfmon.exe processes before creating new desktop // get the initial list of ctfmon.exe processes before creating new desktop
GetCtfMonProcessIdList (ctfmonBeforeList); GetCtfMonProcessIdList (ctfmonBeforeList);
hSecureDesk = CreateDesktop (szDesktopName, NULL, NULL, 0, desktopAccess, NULL); param.hDesk = NULL;
if (hSecureDesk) param.szDesktopName = szDesktopName;
param.hInstance = hInstance;
param.lpTemplateName = lpTemplateName;
param.lpDialogFunc = lpDialogFunc;
param.dwInitParam = dwInitParam;
param.retValue = 0;
param.bDlgDisplayed = FALSE;
// use _beginthreadex instead of CreateThread because lpDialogFunc may be using the C runtime library
HANDLE hThread = (HANDLE) _beginthreadex (NULL, 0, SecureDesktopThread, (LPVOID) &param, 0, NULL);
if (hThread)
{ {
SecureDesktopThreadParam param; WaitForSingleObject (hThread, INFINITE);
CloseHandle (hThread);
param.hDesk = hSecureDesk;
param.szDesktopName = szDesktopName;
param.hInstance = hInstance;
param.lpTemplateName = lpTemplateName;
param.lpDialogFunc = lpDialogFunc;
param.dwInitParam = dwInitParam;
param.retValue = 0;
param.bDlgDisplayed = FALSE;
// use _beginthreadex instead of CreateThread because lpDialogFunc may be using the C runtime library if (param.bDlgDisplayed)
HANDLE hThread = (HANDLE) _beginthreadex (NULL, 0, SecureDesktopThread, (LPVOID) &param, 0, NULL);
if (hThread)
{ {
StringCbCopy(SecureDesktopName, sizeof (SecureDesktopName), szDesktopName); // dialog box was indeed displayed in Secure Desktop
retValue = param.retValue;
bSuccess = TRUE;
}
}
WaitForSingleObject (hThread, INFINITE); if (param.hDesk)
CloseHandle (hThread); {
while (!SwitchDesktop (hOriginalDesk))
if (param.bDlgDisplayed) {
{ Sleep (SECUREDESKTOP_MONOTIR_PERIOD);
// dialog box was indeed displayed in Secure Desktop
retValue = param.retValue;
bSuccess = TRUE;
}
// switch back to original desktop
SwitchDesktop (hOriginalDesk);
} }
CloseDesktop (hSecureDesk); SetThreadDesktop (hOriginalDesk);
// get the new list of ctfmon.exe processes in order to find the ID of the CloseDesktop (param.hDesk);
// ctfmon.exe instance that corresponds to the desktop we create so that }
// we can kill it, otherwise it would remain running
GetCtfMonProcessIdList (ctfmonAfterList);
for (map<DWORD, BOOL>::iterator It = ctfmonAfterList.begin(); // get the new list of ctfmon.exe processes in order to find the ID of the
It != ctfmonAfterList.end(); It++) // ctfmon.exe instance that corresponds to the desktop we create so that
// we can kill it, otherwise it would remain running
GetCtfMonProcessIdList (ctfmonAfterList);
for (map<DWORD, BOOL>::iterator It = ctfmonAfterList.begin();
It != ctfmonAfterList.end(); It++)
{
if (ctfmonBeforeList[It->first] != TRUE)
{ {
if (ctfmonBeforeList[It->first] != TRUE) // Kill process
{ KillProcess (It->first);
// Kill process
KillProcess (It->first);
}
} }
} }