winlogon源码分析 - Go语言中文社区

winlogon源码分析


 

转载请标明是引用于 http://blog.csdn.net/chenyujing1234 

欢迎大家拍砖!

 

 一、从WinMain开始分析

(1)  获得系统debug信息

NtQuerySystemInformation用于返回指定的系统信息。

NTSTATUS WINAPI NtQuerySystemInformation(
  _In_       SYSTEM_INFORMATION_CLASS SystemInformationClass,
  _Inout_    PVOID SystemInformation,
  _In_       ULONG SystemInformationLength,
  _Out_opt_  PULONG ReturnLength
);


如果是内核debugger使能或 NtCurrentPeb()->BeingDebugged为TRUE,那么设置设置异常处理函数并设置定时器。

SetUnhandledExceptionFilter( WinlogonUnhandledExceptionFilter );

        KernelDebuggerPresent = TRUE ;

        SetTimerQueueTimer( NULL,
                            WlpPeriodicBreak,
                            NULL,
                            60 * 1000,
                            60 * 1000,
                            FALSE );
ULONG
NTAPI
WlpPeriodicBreak(
    PVOID Param,
    BOOLEAN Timeout
    )
{
    LARGE_INTEGER ZeroExpiration;
    HANDLE hToken;
    DWORD ReturnLength;
    TOKEN_STATISTICS TokenStats;
    NTSTATUS Status;

    ZeroExpiration.QuadPart = 0;

    
    Status = NtOpenProcessToken(
                 NtCurrentProcess(),
                 TOKEN_QUERY,
                 &hToken
                 );

    if (NT_SUCCESS( Status )) {

        Status = NtQueryInformationToken (
                     hToken,
                     TokenStatistics,
                     &TokenStats,
                     sizeof( TOKEN_STATISTICS ),
                     &ReturnLength
                     );

        if (NT_SUCCESS( Status )) {

            if (RtlLargeIntegerEqualTo( TokenStats.ExpirationTime, ZeroExpiration )) {

                DbgBreakPoint();
            }
        }

        NtClose( hToken );
    }


    if (g_BreakinProcessId != 0) {
        Breakin(g_BreakinProcessId);    
    }    

    return(0);
}


定时器的处理函数中去获得当前TOKEN的TokenStatistics信息,然后取出结果中的TokenStats.ExpirationTime与ZeroExpiration相比。

if (RtlLargeIntegerEqualTo( TokenStats.ExpirationTime, ZeroExpiration ))



 

(1、1)RtlLargeIntegerEqualTo函数说明:

RtlLargeIntegerEqualTo用于大数比较,看两数是否相等。

BOOLEAN 
  RtlLargeIntegerEqualTo(
    IN LARGE_INTEGER  Operand1,
    IN LARGE_INTEGER  Operand2
    );




(1、2)DbgBreakPoint

它进入内核模式的调试器

VOID
NTAPI
  DbgBreakPoint(
    VOID 
    );



DbgBreakPoint是内核模式,它等价于DebugBreak。




 

(2)初始化debug支持和logging

 InitDebugSupport();
void
InitDebugSupport(void)
{
    LoadDebugParameters("WinlogonDebug");
    LoadDebugParameters("Winlogon");

}


(3)提升winlogon进程优先级,让自己更重要

/
    // Make ourselves more important
    //

    if (!SetProcessPriority())
    {
        ExitProcess( EXIT_INITIALIZATION_ERROR );
    }
BOOL SetProcessPriority(
    VOID
    )
{
    //
    // Bump us up to the high priority class
    //

    if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS)) {
        DebugLog((DEB_ERROR, "Failed to raise it's own process priority, error = %d", GetLastError()));
        return(FALSE);
    }

    //
    // Set this thread to high priority since we'll be handling all input
    //

    if (!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST)) {
        DebugLog((DEB_ERROR, "Failed to raise main thread priority, error = %d", GetLastError()));
        return(FALSE);
    }

    return(TRUE);
}


(3、1)SetPriorityClass API 说明

设置指定进程的优先级类,这个值和进程中的每个线程的优先级一起决定每个线程的基本优先级级别。

BOOL WINAPI SetPriorityClass(
  __in          HANDLE hProcess,
  __in          DWORD dwPriorityClass
);




 

(4) 映射TCPIP信息

UpdateTcpIpParameters只是做注册表操作。

//
    // Map the TCPIP information
    //

    UpdateTcpIpParameters();


 

(5)初始化全局变量和环境

//
    // Initialize the globals
    //

    if ( !InitializeGlobals(hInstance) )
    {
        ExitProcess( EXIT_INITIALIZATION_ERROR );
    }

(5、1) 先判断是不是终端的服务器

判断方法:根据共享数据USER_SHARED_DATA中的SuiteMast位和TerminalServer位决定。

如果是终端服务器那么通过NtQueryInformationProcess获是sessionId。

g_IsTerminalServer = !!(USER_SHARED_DATA->SuiteMask & (1 << TerminalServer));


    if (g_IsTerminalServer) {

        //
        // Query Winlogon's Session Id
        //

        if (!NT_SUCCESS(NtQueryInformationProcess(
                         NtCurrentProcess(),
                         ProcessSessionInformation,
                         &SessionInfo,
                         sizeof(SessionInfo),
                         NULL
                         ))) {

            ASSERT(FALSE);

            ExitProcess( EXIT_INITIALIZATION_ERROR );

        }

        g_SessionId = SessionInfo.SessionId;

    } else {

        //
        // For Non TerminaServer SessionId is always 0
        //
        g_SessionId = 0;

    }

如果是终端服务器,那么载入Winsta.dll并存储函数指针

    if (g_IsTerminalServer) {

        if (!InitializeMultiUserFunctionsPtrs()) {
            ExitProcess( EXIT_INITIALIZATION_ERROR );
        }
    }


 

(5、2)向windows登记,这样我们能创建windowstation等。

RegisterLogonProcess无法找到它的定义

//
    // Register with windows so we can create windowstation etc.
    //

    if (!RegisterLogonProcess(HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess), TRUE)) {
        DebugLog((DEB_ERROR, "could not register itself as logon processn"));
        return FALSE;
    }

NtCurrentTeb()来获取TEB的地址和PEB的地址。
(5、3 )获得sid,这样它能被放在ACLs中。

主要通过三个API函数:

RtlLengthRequiredSid获得要求的SID长;

RtlInitializeSid初始化SID;

RtlSubAuthoritySid             ;

//
    // Get our sid so it can be put on object ACLs
    //

    SidLength = RtlLengthRequiredSid(1);
    g_WinlogonSid = (PSID)Alloc(SidLength);
    ASSERTMSG("Winlogon failed to allocate memory for system sid", g_WinlogonSid != NULL);

    RtlInitializeSid(g_WinlogonSid,  &SystemSidAuthority, 1);
    *(RtlSubAuthoritySid(g_WinlogonSid, 0)) = SECURITY_LOCAL_SYSTEM_RID;


(5、4)获得安装信息

安装类型是从注册表中读出来的。

    //
    //  Get setup information
    //

    g_uSetupType = CheckSetupType() ;
    g_fExecuteSetup = (g_uSetupType == SETUPTYPE_FULL) ||
                      (g_uSetupType == SETUPTYPE_UPGRADE)


(5、5)获得电脑名字并设置环境变量,这样我们能在之后查看到它。

GetComputerName为系统API

// Get a copy of the computer name in *my* environment, so that we
    // can look at it later.
    //

    if (GetComputerName (szComputerName, &dwComputerNameSize)) {
        SetEnvironmentVariable(COMPUTERNAME_VARIABLE, (LPTSTR) szComputerName);
    }


(5、6)

 //
    // Set the default USERPROFILE and ALLUSERSPROFILE locations
    //

    if (g_fExecuteSetup) {
        DetermineProfilesLocation(((g_uSetupType == SETUPTYPE_FULL) ? TRUE : FALSE));
    }

    dwSize = ARRAYSIZE(szProfile);
    if (GetDefaultUserProfileDirectory (szProfile, &dwSize)) {
        SetEnvironmentVariable(USERPROFILE_VARIABLE, szProfile);
    }

    dwSize = ARRAYSIZE(szProfile);
    if (GetAllUsersProfileDirectory (szProfile, &dwSize)) {
        SetEnvironmentVariable(ALLUSERSPROFILE_VARIABLE, szProfile);
    }

(6)检查分页文件

//
    // Check the pagefile
    //

    if (!g_fExecuteSetup)
    {
        CreateTemporaryPageFile();
    }



(6、1)删除系统目录中的temppf.sys文件。

(6、2)检查看是否我们有一个分页文件,如果没有提醒用户

先用NtQuerySystemInformation查询页文件信息和系统表现系统,以它们的结果来判断是否有页文件。

 PfiStatus = NtQuerySystemInformation(
                SystemPageFileInformation,
                &pfi,
                sizeof(pfi),
                &ReturnLength
                );

    PiStatus = NtQuerySystemInformation(
                SystemPerformanceInformation,
                &PerfInfo,
                sizeof(PerfInfo),
                NULL
                );

(6、3)如果没有页文件,或总共提交的限制是最小的,那么我们创建一个增加折分页文件并告诉用户去做一些事情。
(6、3、1)创建临时的系统分页,

(6、3、2)创建一个20mb的分页文件。

创建成功后, 就把文件移动到新创建的分页文件中。

 st = NtCreatePagingFile(
                    (PUNICODE_STRING)&FileName,
                    &MinPagingFileSize,
                    &MaxPagingFileSize,
                    0
                    );

            if (!NT_SUCCESS( st )) {

                if ( FileSizeInMegabytes > 0 ) {
                    FileSizeInMegabytes -= 2;
                    MinPagingFileSize = RtlEnlargedIntegerMultiply(FileSizeInMegabytes,0x100000);
                    MaxPagingFileSize = MinPagingFileSize;
                    goto retry;
                }
            } else {
                MoveFileExW(PagingFileName.Buffer,NULL,MOVEFILE_DELAY_UNTIL_REBOOT);

            }


 

 (7)初始化安全模块

 //
    // Initialize security
    //

    if (!InitializeSecurity ())
    {
        ExitProcess( EXIT_SECURITY_INIT_ERROR );
    }


 

BOOL
InitializeSecurity(
    VOID)
{
    //
    // Set up our module globals
    //
    InitializeSecurityGlobals();

    //
    // Initialize the removable medial module
    //

    RmvInitializeRemovableMediaSrvcs();

    return TRUE;
}

 

(7、1)设置模块全局变量

初始化全局变量的内容(主要是通过RtlAllocateAndInitializeSid,指定不同的类型得到不同的SID:本地SID、admin SID、限制的SID)

VOID
InitializeSecurityGlobals(
    VOID
    )
{
    NTSTATUS Status;
    SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;


    //
    // Initialize the local sid for later
    //

    Status = RtlAllocateAndInitializeSid(
                    &gLocalSidAuthority,
                    1,
                    SECURITY_LOCAL_RID,
                    0, 0, 0, 0, 0, 0, 0,
                    &gLocalSid
                    );

    if (!NT_SUCCESS(Status)) {
        DebugLog((DEB_ERROR, "Failed to initialize local sid, status = 0x%lx", Status));
    }

    //
    // Initialize the admin sid for later
    //

    Status = RtlAllocateAndInitializeSid(
                    &gSystemSidAuthority,
                    2,
                    SECURITY_BUILTIN_DOMAIN_RID,
                    DOMAIN_ALIAS_RID_ADMINS,
                    0, 0, 0, 0, 0, 0,
                    &gAdminSid
                    );
    if (!NT_SUCCESS(Status)) {
        DebugLog((DEB_ERROR, "Failed to initialize admin alias sid, status = 0x%lx", Status));
    }

    Status = RtlAllocateAndInitializeSid(
                                 & NtAuthority ,
                                 1,
                                 SECURITY_RESTRICTED_CODE_RID,
                                 0, 0, 0, 0, 0, 0, 0,
                                 &gRestrictedSid
                                 );

    if (!NT_SUCCESS(Status)) {
        DebugLog((DEB_ERROR, "Failed to initialize restricted sid, status = 0x%lx", Status));
    }


}



 

(7、2)初始化可移除的中间模块

通过RtlAllocateAndInitializeSid,指定不同的类型(SECURITY_LOCAL_SYSTEM_RID、SECURITY_BUILTIN_DOMAIN_RID、SECURITY_BUILTIN_DOMAIN_RID)得到不同的SID。

 

BOOL
RmvInitializeRemovableMediaSrvcs(
    VOID
    )
{
    NTSTATUS
        Status;

    SID_IDENTIFIER_AUTHORITY
        NtAuthority = SECURITY_NT_AUTHORITY;


    //
    // See if we need to protect floppy and/or CDRom drives.
    //


    //
    // 初始化需要知道的SID
    //

    Status = RtlAllocateAndInitializeSid( &NtAuthority,
                                          1,
                                          SECURITY_LOCAL_SYSTEM_RID,
                                          0, 0, 0, 0, 0, 0, 0,
                                          &RmvpLocalSystemSid
                                          );

    if ( !NT_SUCCESS(Status) )
    {
        return FALSE ;
    }

    Status = RtlAllocateAndInitializeSid( &NtAuthority,
                                          2,
                                          SECURITY_BUILTIN_DOMAIN_RID,
                                          DOMAIN_ALIAS_RID_ADMINS,
                                          0, 0, 0, 0, 0, 0,
                                          &RmvpAdministratorsSid
                                          );

    if ( !NT_SUCCESS(Status) )
    {
        return FALSE ;
    }

    Status = RtlAllocateAndInitializeSid( &NtAuthority,
                                          2,
                                          SECURITY_BUILTIN_DOMAIN_RID,
                                          DOMAIN_ALIAS_RID_POWER_USERS,
                                          0, 0, 0, 0, 0, 0,
                                          &RmvpPowerUsersSid );

    if ( !NT_SUCCESS(Status) )
    {
        return FALSE ;
    }

    RtlInitUnicodeString( &RmvpNtfs, L"\ntfs" );
    RtlInitUnicodeString( &RmvpFat, L"\fat" );
    RtlInitUnicodeString( &RmvpCdfs, L"\cdfs" );

    return TRUE ;
}


 

(8)创建主终端

//
    // Create the primary terminal.
    //

    if (!CreatePrimaryTerminal())
    {
        DebugLog((DEB_TRACE_INIT, "CreatePrimaryTerminal failedn"));
        ExitProcess( EXIT_PRIMARY_TERMINAL_ERROR );
    }

(8、1)为terminal分配空间,并初始化成员变量

 //
    // Check mark
    //
    pTerm->CheckMark = TERMINAL_CHECKMARK;

    ZeroMemory(pTerm->Mappers, sizeof(WindowMapper) * MAX_WINDOW_MAPPERS);
    pTerm->cActiveWindow  = 0;
    pTerm->PendingSasHead = 0;
    pTerm->PendingSasTail = 0;

 

(8、2)  如果不是控制台模式,那么等待连接,并确保指向它的sessionId

gpfnWinStationWaitForConnect接口从winsta.dll获得

 

//
    // Wait here for the connection
    //
    if ( !g_Console  ) {
        if ( !gpfnWinStationWaitForConnect() ) {
            DebugLog((DEB_ERROR, "wait for connect failedn"));
            return(FALSE);
        }
    }


 

if (!g_Console) {
        if (!NT_SUCCESS(SetWinlogonDeviceMap(g_SessionId))) {
            ExitProcess( EXIT_DEVICE_MAP_ERROR );
        }
    }
/***************************************************************************
* SetWinlogonDeviceMap
*
* For non-console winlogon's, make them point to the session specific
* DeviceMap.
*
* History:
*  09-November-1997 SalimC     Created
***************************************************************************/
NTSTATUS
SetWinlogonDeviceMap( ULONG SessionId)
{
    NTSTATUS Status = STATUS_SUCCESS;
    WCHAR szSessionString[MAX_SESSION_PATH];
    UNICODE_STRING UnicodeString;
    OBJECT_ATTRIBUTES Obja;
    PROCESS_DEVICEMAP_INFORMATION ProcessDeviceMapInfo;
    HANDLE DosDevicesDirectory;



    if (SessionId == 0) {

       return STATUS_INVALID_PARAMETER;

    }

    swprintf(szSessionString,L"\Sessions\%ld\DosDevices",SessionId);

    RtlInitUnicodeString( &UnicodeString, szSessionString );


    InitializeObjectAttributes( &Obja,
                                &UnicodeString,
                                OBJ_CASE_INSENSITIVE,
                                NULL,
                                NULL
                              );

    Status = NtOpenDirectoryObject( &DosDevicesDirectory,
                                    DIRECTORY_ALL_ACCESS,
                                    &Obja
                                    );
    if (!NT_SUCCESS( Status )) {

         return Status;

    }



   //
   //  设置Winlogon的 ProcessDeviceMap 到会话指定的DosDevices 目录
   //

    ProcessDeviceMapInfo.Set.DirectoryHandle = DosDevicesDirectory;

    Status = NtSetInformationProcess( NtCurrentProcess(),
                                      ProcessDeviceMap,
                                      &ProcessDeviceMapInfo.Set,
                                      sizeof( ProcessDeviceMapInfo.Set )
                                    );

    NtClose(DosDevicesDirectory);


    return Status;

}


(8、3) 创建交互的window station
(8、3、1) 为WindowStation分配空间,并设置窗口名字为WinSta0

 //
    // Allocate space for a new WindowStation
    //
    pWS = LocalAlloc (LPTR, sizeof(WINDOWSTATION) +
                     (lstrlenW(WINDOW_STATION_NAME) + 1) * sizeof(WCHAR));
    if (!pWS) {
        DebugLog((DEB_ERROR, "Could not allocate windowstation structuren"));
        goto failCreateTerminal;
    }

    //
    // Save the name
    //
    pWS->lpWinstaName = (LPWSTR)((LPBYTE) pWS + sizeof(WINDOWSTATION));
    lstrcpyW (pWS->lpWinstaName, WINDOW_STATION_NAME);


(8、3、2)  用API  CreateWindowStationW  创建窗口station ,并设置它为进程的window station

 // Create the window station
    //
    pWS->hwinsta = CreateWindowStationW (WINDOW_STATION_NAME, 0, MAXIMUM_ALLOWED, NULL);
    if (!pWS->hwinsta) {
        DebugLog((DEB_ERROR, "Could not create the interactive windowstationn"));
        goto failCreateTerminal;
    }

    SetProcessWindowStation(pWS->hwinsta);


(8、3、3) 初始化winsta的安全性

InitializeWinstaSecurity完成初始化window station 安全性。

 InitializeWinstaSecurity(pWS);


(8、3、3、1)创建Ace列表,目的是跟踪对winsta的访问

pList = CreateAceList( 16 );

    if ( !pList )
    {
        return( FALSE );
    }

    pWS->Acl = pList;

(8、3、3、2) SetMyAce设置来定义winlogon的ACEs

eg:

SetMyAce(& ( pList->Aces[ pList->Active ++ ]),
             g_WinlogonSid,
             WINSTA_ALL,
             NO_PROPAGATE_INHERIT_ACE
             );

(8、3、3、3)AceListSetWinstaSecurity根据(8、3、3、2)定义的ACEs来设置winsta的安全性

这一特殊的安全描述符了:除非得到Winlogon的明确许可,否则没有其他的进程可以访问此窗口站。参考文章<<>>

BOOL
AceListSetWinstaSecurity(
    PMYACELIST          pList,
    DWORD               Count,
    HWINSTA             hWinsta )
{
    PSECURITY_DESCRIPTOR SecurityDescriptor;
    SECURITY_INFORMATION si;
    BOOL    Result;

    //
    // Create the security descriptor
    //

    SecurityDescriptor = CreateSecurityDescriptor(pList->Aces, Count );
    if (SecurityDescriptor == NULL) {
        DebugLog((DEB_ERROR, "failed to create winsta security descriptorn"));
        return(FALSE);
    }

    //
    // Set the DACL on the object
    //

    si = DACL_SECURITY_INFORMATION;
    Result = SetUserObjectSecurity(hWinsta, &si, SecurityDescriptor);

    //
    // Free up the security descriptor
    //

    DeleteSecurityDescriptor(SecurityDescriptor);

    //
    // Return success status
    //

    if (!Result) {
        DebugLog((DEB_ERROR, "failed to set windowstation securityn"));
    }
    return(Result);
}



(8、3、4) 创建winlogon的桌面及应用程序桌面

 //
    // Create winlogon's desktop
    //
    pWS->hdeskWinlogon = CreateDesktopW (WINLOGON_DESKTOP_NAME,
                                         NULL, NULL, 0, MAXIMUM_ALLOWED, NULL);
    if (!pWS->hdeskWinlogon) {
        DebugLog((DEB_ERROR, "Could not create winlogon's desktopn"));
        goto failCreateTerminal;
    }

    //
    // Create the application desktop
    //
    pWS->hdeskApplication = CreateDesktopW (APPLICATION_DESKTOP_NAME,
                                            NULL, NULL, 0, MAXIMUM_ALLOWED, NULL);
    if (!pWS->hdeskApplication) {
        DebugLog((DEB_ERROR, "Could not create application's desktopn"));
        goto failCreateTerminal;
    }


(8、3、5)设置winlogon桌面的安全性及应用程序桌面的安全性

方法与(8、3、3、2)(8、3、3、3)类似。

//
    // Set desktop security (no user access yet)
    //
    if (!SetWinlogonDesktopSecurity(pWS->hdeskWinlogon, g_WinlogonSid)) {
        DebugLog((DEB_ERROR, "Failed to set winlogon desktop securityn"));
    }
    if (!SetUserDesktopSecurity(pWS->hdeskApplication, NULL, g_WinlogonSid)) {
        DebugLog((DEB_ERROR, "Failed to set application desktop securityn"));
    }


(8、3、6)转换到winlogon的桌面

//
    // Switch to the winlogon desktop
    //
    SetActiveDesktop(pTerm, Desktop_Winlogon);


 

BOOL
SetActiveDesktop(
    PTERMINAL       pTerm,
    ActiveDesktops  Desktop)
{
    HDESK           hDesk;
    HDESK           hPrevious;
    DWORD           LengthNeeded;
    PWINDOWSTATION  pWS = pTerm->pWinStaWinlogon;

    if (Desktop == pWS->ActiveDesktop)
    {
        return(TRUE);
    }

    if (pWS->ActiveDesktop == Desktop_Application)
    {
        LockWindowStation(pWS->hwinsta);
        pWS->hdeskPrevious = OpenInputDesktop(0, FALSE, MAXIMUM_ALLOWED);

        if (!GetUserObjectInformation(  pWS->hdeskPrevious,
                                        UOI_NAME,
                                        pTerm->pszDesktop,
                                        pTerm->DesktopLength,
                                        &LengthNeeded) )
        {
            if (pTerm->DesktopLength != TYPICAL_STRING_LENGTH &&
                pTerm->DesktopLength != 0)
            {
                LocalFree( pTerm->pszDesktop );
                pTerm->pszDesktop = NULL;
                pTerm->DesktopLength = 0;
            }
            pTerm->pszDesktop = LocalAlloc( LMEM_FIXED, LengthNeeded );
            if (pTerm->pszDesktop)
            {
                pTerm->DesktopLength = LengthNeeded;

                if (!GetUserObjectInformation(  pWS->hdeskPrevious,
                                            UOI_NAME,
                                            pTerm->pszDesktop,
                                            pTerm->DesktopLength,
                                            &LengthNeeded))
                {
                    pTerm->pszDesktop[0] = 0;
                }
            }
            else
            {
                pTerm->DesktopLength = 0;
            }
        }

        DebugLog((DEB_TRACE, "Source desktop was %wsn", pTerm->pszDesktop));
    }

    switch (Desktop)
    {
        case Desktop_Winlogon:
            hDesk = pWS->hdeskWinlogon;
            break;
        case Desktop_ScreenSaver:
            hDesk = pWS->hdeskScreenSaver;
            break;
        case Desktop_Application:
            if (pWS->hdeskPrevious)
            {
                hDesk = pWS->hdeskPrevious;
            }
            else
            {
                hDesk = pWS->hdeskApplication;
            }
            break;
        default:
            DebugLog((DEB_ERROR, "Error:  Invalid desktop specified %dn", Desktop));
            return(FALSE);
    }
    if (SwitchDesktop(hDesk))
    {
        DebugLog((DEB_TRACE, "Switching desktop from %s to %sn",
                    DbgGetDesktopName(pWS->ActiveDesktop),
                    DbgGetDesktopName(Desktop) ));

        pWS->PreviousDesktop = pWS->ActiveDesktop;
        pWS->ActiveDesktop = Desktop;

        //
        // If we're switching back to the user's desktop, then unlock the
        // window station, so that the user can switch desktops again.  Also,
        // close our handle to the desktop.  Note!  Unlock before close, so
        // that if this is the last handle to the desktop, cleanup can occur
        // correctly.
        //

        if (pWS->ActiveDesktop == Desktop_Application)
        {
            UnlockWindowStation(pWS->hwinsta);
            if (pWS->hdeskPrevious)
            {
                DebugLog((DEB_TRACE, "Closing handle %x to users desktopn", pWS->hdeskPrevious));
                CloseDesktop(pWS->hdeskPrevious);
                pWS->hdeskPrevious = NULL;
            }
        }


        return(TRUE);
    }
    DebugLog((DEB_WARN, "Could not switch desktop!n"));
    return(FALSE);
}


(8、3、7) 保存terminal

(9)从注册表中检查是不是安全模式

(10)设置线程到winlogon的桌面

SetThreadDesktop为系统API

//
    //  Set this thread to winlogon's desktop
    //

    SetThreadDesktop( pTerm->pWinStaWinlogon->hdeskWinlogon );


(11)改变用户到‘system‘

 

// Change user to 'system'
    //
    if (!SecurityChangeUser(pTerm, NULL, NULL, g_WinlogonSid, FALSE)) {
        DebugLog((DEB_ERROR, "failed to set user to systemn"));
    }


 上面指定的UserLoggedOn为FALSE,在K、中也调用到SecurityChangeUser函数,它的UserLoggedOn为TRUE。

BOOL
SecurityChangeUser(
    PTERMINAL pTerm,
    HANDLE Token,
    PQUOTA_LIMITS Quotas OPTIONAL,
    PSID LogonSid,
    BOOL UserLoggedOn
    )
{
    PWINDOWSTATION pWS = pTerm->pWinStaWinlogon;
    LUID luidNone = { 0, 0 };

    //
    // Save the token for this windowstation
    //

    pWS->hToken = Token;

    //
    // Set appropriate protection on windows objects
    //

    if (UserLoggedOn || g_fExecuteSetup)
    {
        AddUserToWinsta( pWS,
                         LogonSid,
                         Token );

    }
    else
    {
        RemoveUserFromWinsta( pWS,
                              pWS->UserProcessData.UserToken );
    }

    SetUserDesktopSecurity(pWS->hdeskApplication,
                           LogonSid,
                           g_WinlogonSid);

    //
    // Setup new-process data
    //

    SetUserProcessData(&pWS->UserProcessData,
                       Token,
                       Quotas,
                       LogonSid,
                       g_WinlogonSid);

    //
    // Setup the appropriate new environment
    //

    if (UserLoggedOn) {

        //
        // Do nothing to the profile or environment.  Environment and profiles
        // are all handled in wlx.c:LogonAttempt and DoStartShell
        //

        pTerm->LogoffFlags = 0;
        pTerm->TickCount = GetTickCount();

    } else {

        //
        // Restore the system environment
        //

        CloseIniFileUserMapping(pTerm);

        //
        // ResetEnvironment if we are the console or
        // we are not logging off. This prevents screen paints during logout
        //
        if ( g_Console || !pTerm->MuGlobals.fLogoffInProgress )
            ResetEnvironment(pTerm);

        SetWindowStationUser(pWS->hwinsta, &luidNone, NULL, 0);

    }


    //
    // Store whether there is a real user logged on or not
    //

    pTerm->UserLoggedOn = UserLoggedOn;

    return(TRUE);
}

(12)如果是控制台, 建造网络提供者事件(当网络列表改变时,此事件被触发)

//
    // For the console winlogon, set the event that is toggled
    // when the network provider list changes
    //

    if (g_Console) {

        CreateNetworkProviderEvent();

    }


(13) 初始化通知列表和JobControl

 if ( !WlpInitializeNotifyList( pTerm ) ||
         !InitializeJobControl() ||
         !LogoffLockInit() )
    {
        ExitProcess( EXIT_NO_MEMORY );
    }


(14) 启动系统进行

//
    // Start the system processes
    //

    DebugLog((DEB_TRACE_INIT, "Execute system processes:n"));

    if (!ExecSystemProcesses())
    {
        DebugLog((DEB_TRACE_INIT, "ExecSystemProcesses failedn"));
        ExitProcess( EXIT_SYSTEM_PROCESS_ERROR );
    }

(15)在我们登陆之前启动APP桌面线程

#ifndef _WIN64

    StartAppDesktopThread(pTerm);

#endif // _WIN64


 

VOID StartAppDesktopThread(
    PTERMINAL pTerm)
{
    HANDLE hAppDesktopThread;
    DWORD  dwThreadId;

    if (gbADTRunning) {
        NDDETRACE(("NetddeAgentThread: aready runningn"));
        return;
    }
    
    hAppDesktopThread = CreateThread(NULL, 0, ApplicationDesktopThread,
                                     (LPVOID)pTerm, 0, &dwThreadId);

    CloseHandle(hAppDesktopThread);
}


ApplicationDesktopThread线程中做以下事情:

(15、1)设置线程运行在WinSta0Default

注意:在(10)是设置线程到winlogon的桌面。

SetThreadDesktop(pTerm->pWinStaWinlogon->hdeskApplication);

(15、2)初始化窗口数据并注册窗口类

初始化工作包括:注册窗口消息、获得IMM32.DLL模块的ImmDisableIme  接口 ,然后调用。

int NDDEAgntInit(
    VOID)


 

int NDDEAgntInit(
    VOID)
{
    WNDCLASS WndClass;

    wMsgNddeAgntExecRtn = RegisterWindowMessage(szAgentExecRtn);
    wMsgNddeAgntWakeUp  = RegisterWindowMessage(szAgentWakeUp);
    wMsgNddeAgntAlive   = RegisterWindowMessage(szAgentAlive);
    wMsgNddeAgntDying   = RegisterWindowMessage(szAgentDying);

    {
        WCHAR wszImmFile[MAX_PATH];
        BOOL (WINAPI* fpImmDisableIme)(DWORD);
        HMODULE hImm;

        GetImmFileName(wszImmFile);
        hImm = GetModuleHandleW(wszImmFile);
        if (hImm) {
            fpImmDisableIme = (BOOL (WINAPI*)(DWORD))GetProcAddress(hImm, "ImmDisableIme");
            if (fpImmDisableIme) {
#ifndef LATER
                fpImmDisableIme(0);
#else
                fpImmDisableIme(-1);
#endif
            }
        }
    }

    ZeroMemory(&WndClass, sizeof(WndClass));

    WndClass.lpszClassName = (LPTSTR)SZ_NDDEAGNT_CLASS;
    WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    WndClass.hInstance     = hInst;
    WndClass.lpfnWndProc   = NDDEAgntWndProc;

    RegisterClass(&WndClass);
    return TRUE;
}


(15、3) 创建窗口

g_hwndAppDesktopThread为   netdde 代理的主窗口。

  /*
     * now create the window
     */
    g_hwndAppDesktopThread = CreateWindowEx(WS_EX_TOPMOST, gszAppName,
        szTitle,
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        NULL,
        NULL,
        hInst,
        NULL);

(15、4)  清除任何未信任的共享。

  /* set up lpszServer for NDDEAPI calls */
    GetComputerName(szComputerName, &cbName);
    _tcscpy(lpszServer, TEXT("\\"));
    _tcscat(lpszServer, szComputerName);

    /*
     * clean up any trusted shares that have been modified or deleted
     * since we last ran for this user
     */
    if (IsServiceActive(&hSvcNetDDE, szNetDDE, FALSE)) {
        CleanupTrustedShares();
    }


(15、5)  分发窗口消息,进入消息循环

    while (GetMessage(&msg, 0, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }


 

 

 

 

 

 

 

 

 

(16) misc初始化,它需要在第一个terminal被创建时被调用。

 //
    // Finish some misc initialization.  Note:  This call can drop into setup
    //

    MiscInitialization(pTerm);


 

VOID MiscInitialization (PTERMINAL pTerm)
{
    DWORD Win31MigrationFlags;


    //
    // Decide what to do about setup
    //

    if (g_fExecuteSetup)
    {
        //
        // Init winmm
        //

#if !defined(_WIN64_LOGON)

        try
        {
            waveOutGetNumDevs();
        }
        except ( EXCEPTION_EXECUTE_HANDLER )
        {
            DebugLog(( DEB_ERROR, "Failed to initialize winmm, %xn", GetExceptionCode() ));
        }

#endif

        //
        // Run setup and reboot
        //

        ExecuteSetup(pTerm);
        EnablePrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE);
        NtShutdownSystem(ShutdownReboot);

    }
    else
    {
        //
        // In the case of running setup in mini-setup mode,
        // we want to be able to continue through and let the
        // user logon.
        //
        if(g_uSetupType == SETUPTYPE_NOREBOOT) {

            //
            // go execute setup
            //
            ExecuteSetup(pTerm);
        }

        //
        // Don't go any further if setup didn't complete fully.  If this
        // machine has not completed setup correctly, this will not return.
        //

        CheckForIncompleteSetup(g_pTerminals);
    }


    if (!IsWin9xUpgrade()) {
        //
        // Check to see if there is any WIN.INI or REG.DAT to migrate into
        // Windows/NT registry.
        //
        // This code is skipped when the previous OS was Win9x.
        //

        Win31MigrationFlags = QueryWindows31FilesMigration( Win31SystemStartEvent );
        if (Win31MigrationFlags != 0) {
            SynchronizeWindows31FilesAndWindowsNTRegistry( Win31SystemStartEvent,
                                                           Win31MigrationFlags,
                                                           NULL,
                                                           NULL
                                                         );
            InitSystemFontInfo();
        }
    }

#ifdef _X86_

    //
    // Do OS/2 Subsystem boot-time migration.
    // Only applicable to x86 builds.
    //

    Os2MigrationProcedure();

#endif


    //
    // Load those pesky fonts:
    //

    hFontThread = StartLoadingFonts();



    //
    // Check if we need to run setup's GUI repair code
    //

    CheckForRepairRequest ();
}



(17)。

//
    // Kick off a thread to watch the system dlls, initialize winmm, etc
    //

    if (g_Console) {
        hThread = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) InitializeSlowStuff,
                                NULL, 0, &dwThreadID);

        if (hThread) {
            SetThreadPriority (hThread, THREAD_PRIORITY_IDLE);
            CloseHandle (hThread);
        } else {
            InitializeSlowStuff (NULL);
        }
    }


 

DWORD InitializeSlowStuff (LPVOID dummy)
{

    //
    // initialize the dll hell watcher
    //

    Sleep(100);

    //
    // call the winmm guys so they can start their message window
    // and whatever else they need.
    //

#if !defined(_WIN64_LOGON)

    try
    {
        waveOutGetNumDevs();
    }
    except ( EXCEPTION_EXECUTE_HANDLER )
    {
        DebugLog(( DEB_ERROR, "Failed to initialize winmm, %xn", GetExceptionCode() ));
    }


#endif

    if (SfcInitProt( SFC_REGISTRY_DEFAULT, SFC_DISABLE_NORMAL, SFC_SCAN_NORMAL, SFC_QUOTA_DEFAULT, NULL, NULL )) {
#if DBG
        ExitProcess( EXIT_SYSTEM_PROCESS_ERROR );
#endif
    }



    return 0;
}



 

(18)载入GINA模块

(18、1)根据是是安全模式,如果是那么就直接从"%SystemRoot%\system32\msgina.dll"载入msgina.dll;

如果不是,那么从注册表GinaDLL字段中读取自定义DLL。

 if ( pTerm->SafeMode )
    {
        ExpandEnvironmentStringsW(
                    TEXT("%SystemRoot%\system32\msgina.dll"),
                    pszGinaName,
                    MAX_PATH );
    }
    else
    {
        GetProfileString(
            APPLICATION_NAME,
            GINA_KEY,
            TEXT("msgina.dll"),
            pszGinaName,
            MAX_PATH);

    }

(18、2)

LoadGinaDll负责载入msgina.dll库,并获得其中的接口地址;

然后调用pWlxNegotiate

 if (!LoadGinaDll (pTerm, pszGinaName)) {
        DebugLog((DEB_TRACE_INIT, "Failed to load ginan"));
        ExitProcess( EXIT_GINA_ERROR );
    }



 
(19)初始化SAS

//
    // Initialize the secure attention sequence
    //

    if (!SASInit(pTerm))
    {
        DebugLog((DEB_TRACE_INIT, "Failed to create sas windown"));
        ExitProcess( EXIT_SAS_WINDOW_ERROR );
    }

 

SASInit做了以下几件事:

(19、1)创建SAS窗口

pTerm->hwndSAS = CreateWindowEx(0L, szSASClass, TEXT("SAS window"),
            WS_OVERLAPPEDWINDOW,
            0, 0, 0, 0,
            NULL, NULL, g_hInstance, NULL);


(19、2)把终端指针存在窗口数据中

//
    // Store our terminal pointer in the window user data
    //

    SetWindowLongPtr(pTerm->hwndSAS, GWLP_USERDATA, (LONG_PTR)pTerm);

(19、3)把这个窗口设置为我们通知屏保和用户注销的窗口

//
    // Register this window with windows so we get notified for
    // screen-saver startup and user log-off
    //

    if (!SetLogonNotifyWindow(pTerm->hwndSAS)) {
        DebugLog((DEB_ERROR, "Failed to set logon notify window"));
        return FALSE;
    }


(20)初始化GPO支持和自动回滚支持

 InitializeGPOSupport( pTerm );

    InitializeAutoEnrollmentSupport ();

    WlAddInternalNotify(
                PokeComCtl32,
                WL_NOTIFY_LOGOFF,
                FALSE,
                FALSE,
                TEXT("Reset ComCtl32"),
                15 );


(21)进入主循环   (重点介绍)

此函数做的内容就是与GINA的交互。

//
    // Main loop
    //

    MainLoop (pTerm);

(21、1)  初始化GINA DLL库

 //
    // Initialize the gina dll
    //

    if (!InitializeGinaDll(pTerm))
    {
        DebugLog((DEB_ERROR, "InitializeGinaDll failedn"));
        return;
    }


 

BOOL
InitializeGinaDll(PTERMINAL  pTerm)
{

#if DBG
    if (TEST_FLAG(GinaBreakFlags, BREAK_INITIALIZE))
    {
        DebugLog((DEB_TRACE, "About to call WlxInitializen"));


        DebugBreak();
    }
#endif


    //
    // Perversely, this may not return.  The GINA may in fact call SASNotify
    // immediately, so update the state before we go in:
    //

    pTerm->WinlogonState = Winsta_NoOne;
    DebugLog((DEB_TRACE_STATE, "InitGina:  State is %d %sn", Winsta_NoOne, GetState(Winsta_NoOne)));

    if (!pTerm->Gina.pWlxInitialize(pTerm->pWinStaWinlogon->lpWinstaName,
                                pTerm,
                                NULL,
                                (PVOID) &WlxDispatchTable,
                                &pTerm->Gina.pGinaContext))


pWlxInitialize函数有五个参数:

A、winsta名字,[IN],由winlogon传GINA;

B、pTerm,[IN], PTERMINAL类型。 GINA调用分发表中的函数时,第一个参数为它。

C、NULL,[IN]

D、&WlxDispatchTable, 最重要的。[IN],GINA将调用从winlogon得到的分发表中的函数。

我们将在第二点中讲到。

WLX_DISPATCH_VERSION_1_3 WlxDispatchTable = {
    WlxUseCtrlAltDel,
    WlxSetContextPointer,
    WlxSasNotify,
    WlxSetTimeout,
    WlxAssignShellProtection,
    WlxMessageBox,
    WlxDialogBox,
    WlxDialogBoxParam,
    WlxDialogBoxIndirect,
    WlxDialogBoxIndirectParam,
    WlxSwitchDesktopToUser,
    WlxSwitchDesktopToWinlogon,
    WlxChangePasswordNotify,
    WlxGetSourceDesktop,
    WlxSetReturnDesktop,
    WlxCreateUserDesktop,
    WlxChangePasswordNotifyEx,
    WlxCloseUserDesktop,
    WlxSetOption,
    WlxGetOption,
    WlxWin31Migrate,
    WlxQueryClientCredentials,
    WlxQueryInetConnectorCredentials,
    WlxDisconnect,
    WlxQueryTerminalServicesData
};



E、&pTerm->Gina.pGinaContext, [OUT],接收GINA返回的GINA类的类指针。

(21、2)如果是控制台,那么等待各种服务、MUP、DS启动

  //
    // Wait for various services to start
    //

    if (g_Console) {
        WaitForServices(pTerm);
    }


等待的服务有:"SamSs"、TEXT("NETLOGON")、TEXT("RpcSs")、WaitForMUP (120000);、WaitForDS (120000);

在等待过程中有窗口提示。

VOID WaitForServices(
    PTERMINAL pTerm
    )
{

    HANDLE hDsReindexEvent ;
    ULONG SamWaitTime = 15000 ;

    if ( pTerm->SafeMode )
    {
        SamWaitTime = 120000 ;
    }

    StatusMessage(FALSE, 0, IDS_STATUS_SYSTEM_STARTUP );
    WaitForServiceToStart( TEXT("SamSs"), SamWaitTime);

    if ( pTerm->SafeMode )
    {
        //
        // In safe mode, no sense waiting for services that
        // are disabled to start.
        //

        return;
    }
    hDsReindexEvent = OpenEvent( SYNCHRONIZE,
                                 FALSE,
                                 L"NTDS.IndexRecreateEvent" );

    if ( hDsReindexEvent ) {
        StatusMessage( FALSE, 0, IDS_STATUS_DS_REINDEX );

        WaitForSingleObject( hDsReindexEvent, INFINITE );

        CloseHandle( hDsReindexEvent );
    }

    //
    // Wait for the network to start
    //

    StatusMessage (FALSE, 0, IDS_STATUS_NET_START);
    WaitForServiceToStart (SERVICE_NETLOGON, 120000);

    StatusMessage (TRUE, 0, IDS_STATUS_RPCSS_START);
    WaitForServiceToStart (TEXT("RpcSs"), 120000);

    StatusMessage (TRUE, 0, IDS_STATUS_MUP_START);
    WaitForMUP (120000);

    StatusMessage (TRUE, 0, IDS_STATUS_DS_START);
    WaitForDS (120000);
}


(21、3)启动profile映射API

//
    // Start profile mapping APIs
    //

    if (g_Console) {
        InitializeProfileMappingApi();
    }


(21、4)做网络访问向导事务

//
    // Do Net Access Wizard stuff
    //

    if ( CheckForNetAccessWizard(pTerm) )
    {
        // Reboot is required
        pTerm->LastGinaRet = (DWORD) WLX_SAS_ACTION_SHUTDOWN_REBOOT;
        return;
    }


 

BOOL
CheckForNetAccessWizard (
    PTERMINAL pTerm
    )
{
    BOOL fReboot = FALSE;
    HKEY hkeyWinlogon = NULL;
    LONG lResult;
    DWORD dwSize, dwType;
    ULONG uWizardType = NAW_NETID;          // NAW_NETID is not valid
    HINSTANCE hNetPlWiz;
    LPNETACCESSWIZARD pfnNetAccessWiz;
    DWORD dwWin9xUpgrade = 0;

    //
    // Do we have a post setup wizard entry?  Or a Win9x upgrade entry?
    //

    if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, WINLOGON_KEY,
                      0, KEY_READ | KEY_WRITE, &hkeyWinlogon) == ERROR_SUCCESS) {

        dwSize = sizeof(uWizardType);

        RegQueryValueEx (
            hkeyWinlogon,
            L"RunNetAccessWizard",
            NULL,
            &dwType,
            (LPBYTE) &uWizardType,
            &dwSize
            );

        dwSize = sizeof(dwWin9xUpgrade);

        RegQueryValueEx (
            hkeyWinlogon,
            L"SetWin9xUpgradePasswords",
            NULL,
            &dwType,
            (LPBYTE) &dwWin9xUpgrade,
            &dwSize
            );

    }

    //
    // check the wizard type, if its != NAW_NETID then we assume that we should
    // be starting the wizard for post setup.
    //

    if ( uWizardType != NAW_NETID || dwWin9xUpgrade )
    {
        //
        // Wait on the font loading thread here, so we don't inadvertantly re-enter
        // the stuff in user that gets confused.
        //

        if ( hFontThread )
        {
            WaitForSingleObject( hFontThread, INFINITE );
            CloseHandle( hFontThread );
            hFontThread = NULL;
        }

        //
        // wait for SAM to get its act together...
        //

        PAWaitForSamService();


        //
        // Get rid of the status UI so we don't overlap
        //

        RemoveStatusMessage(TRUE);


        if ( !dwWin9xUpgrade ) {
            //
            // lets load the network account wizard and set it off
            //

            hNetPlWiz = LoadLibrary(L"netplwiz.dll");
            if ( hNetPlWiz )
            {
                pfnNetAccessWiz = (LPNETACCESSWIZARD)GetProcAddress(hNetPlWiz, "NetAccessWizard");
                if ( pfnNetAccessWiz )
                    (*pfnNetAccessWiz)(NULL, uWizardType, &fReboot);

                FreeLibrary(hNetPlWiz);

                //
                // The wizard has completed, remove the value that
                // caused it to run
                //

                RegDeleteValue (hkeyWinlogon, L"RunNetAccessWizard");
            }

        } else {
            //
            // Launch the Win9x upgrade password UI
            //

            SetWin9xUpgradePasswords (pTerm);
        }
    }

    if ( hkeyWinlogon ) {
        RegCloseKey (hkeyWinlogon);
    }

    return fReboot;
}



(21、5)
发送启动通知。

//
    // Send the Startup notification
    //

    WlWalkNotifyList( pTerm, WL_NOTIFY_STARTUP );


WlWalkNotifyList会漫步通知列表,根据指定的标志调用操作。

VOID
WlWalkNotifyList(
    PTERMINAL Terminal,
    DWORD Operation
    )
{
    PLIST_ENTRY Scan ;
    PWLP_NOTIFICATION_OBJECT Notify;
    PWINDOWSTATION pWS = Terminal->pWinStaWinlogon ;
    HANDLE ThreadHandle ;
    DWORD tid ;
    BOOL bAsync;
    DWORD OperationMask ;
    PWLP_NOTIFY_BOOTSTRAP Boot ;
    WLP_NOTIFY_BOOTSTRAP LocalBoot ;


    OperationMask = WLP_NOTIFY_FLAG( Operation );

    LockNotifyList();

    Scan = NotifyList.Flink ;

    while ( Scan != &NotifyList )
    {
        Notify = CONTAINING_RECORD( Scan, WLP_NOTIFICATION_OBJECT, List );

        if ( Notify->Type & OperationMask )
        {

            //
            // Match.  Now, check the options.
            //

            if ( (Notify->Dll == NULL) &&
                 ((Notify->Type & WLP_NOTIFY_INTERNAL) == 0) )
            {
                //
                // Not snapped yet.  Snap it:
                //

                if ( !WlpSnapNotifyDll( Notify, OperationMask ) )
                {
                    //
                    // Couldn't snap this one.  Remove it and continue on:
                    //

                    Scan = Scan->Flink ;

                    RemoveEntryList( &Notify->List );

                    WlpDeleteNotificationObject( Notify );

                    continue;
                }
            }

            Boot = (PWLP_NOTIFY_BOOTSTRAP) LocalAlloc( LMEM_FIXED,
                            sizeof( WLP_NOTIFY_BOOTSTRAP ) );

            if ( Boot == NULL )
            {
                Scan = Scan->Flink ;

                continue;
            }

            bAsync = ( Notify->Type & WLP_NOTIFY_ASYNCHRONOUS ) ? TRUE : FALSE;

            if ( ( Operation == WL_NOTIFY_LOGOFF ) ||
                 ( Operation == WL_NOTIFY_SHUTDOWN ) )
            {
                bAsync = FALSE;
            }

            Boot->Notify = Notify ;
            Boot->Terminal = Terminal ;
            Boot->Operation = Operation ;

            ThreadHandle = CreateThread( 0, 0,
                                         WlpExecuteNotify,
                                         Boot,
                                         0,
                                         &tid );

            if ( ThreadHandle )
            {
                if ( !bAsync )
                {
                    DWORD WaitStatus ;
                    DWORD TotalWait = 0 ;

                    while ( TotalWait < Notify->dwMaxWait )
                    {
                        WaitStatus = WaitForSingleObject( ThreadHandle, 5000 );

                        if ( WaitStatus == STATUS_WAIT_0 )
                        {
                            break;
                        }

                        TotalWait += 5 ;

                    }
                }

                CloseHandle( ThreadHandle );
            }
            else 
            {
                LocalFree( Boot );
            }
        }

        Scan = Scan->Flink ;

    }

    UnlockNotifyList();
}


(21、6)进入循环

(21、6、1)

DealWithAutochkLogs();

DealWithAutochkLogs会枚举当前磁盘,并偿试着去处理它找到的任何的AUTOCHK logs。

  
    do {
        if ( GetDriveTypeW( pwszVolumeName ) == DRIVE_FIXED ) {
            wcscpy( pwszBootExFile, pwszVolumeName );
            wcscat( pwszBootExFile, L"bootex.log" );

            if ( TransferAutochkLogToEventLogIfAvailable( pwszBootExFile )) {
                DeleteFileW( pwszBootExFile );
            }
        }
        
    } while ( FindNextVolume( h, pwszVolumeName, MAX_PATH + 1 ));


TransferAutochkLogToEventLogIfAvailable的原理是从找到的文件中读取事件列表,并通过API  ReportEvent报错winlogon的事件。

(21、6、2)从注册表中获得verbose状态。

 QueryVerboseStatus();

(21、6、3) 调用GINA的pWlxRemoveStatusMessage移除状态提示对话框。

 RemoveStatusMessage(TRUE);
VOID
RemoveStatusMessage(
    BOOL bForce
    )
{

    //
    // Check if the gina is ready
    //

    if (!g_pTerminals || !g_pTerminals->Gina.pGinaContext) {
        return;
    }


    //
    // Remove the status message under these conditions:
    //
    // 1)  We are not in verbose status message mode
    // 2)  We are in verbose status message mode and bForce is true
    //

    if (!g_bVerboseStatus || (g_bVerboseStatus && bForce)) {
        g_pTerminals->Gina.pWlxRemoveStatusMessage(g_pTerminals->Gina.pGinaContext);
    }

}

(21、6、4)如果Term的winlogon状态是Winsta_NoOne,那么

 

A、设置对话框的当前超时时间;

WlxSetTimeout(pTerm, TIMEOUT_NONE);
BOOL
WINAPI
WlxSetTimeout(
    HANDLE  hWlx,
    DWORD   Timeout
    )
{
    PTERMINAL    pTerm;

    if (pTerm = VerifyHandle(hWlx))
    {
        if ((pTerm->WinlogonState == Winsta_NoOne_Display) ||
            (pTerm->WinlogonState == Winsta_Locked_Display) )
        {
            if (Timeout)
            {
                SetLastErrorEx(ERROR_INVALID_PARAMETER, SLE_ERROR);
                return(FALSE);
            }
        }
        pTerm->Gina.cTimeout = Timeout;
        TimeoutUpdateTopTimeout( Timeout );
        return(TRUE);
    }

    SetLastErrorEx(ERROR_INVALID_HANDLE, SLE_ERROR);
    return(FALSE);

}



B、调用GINA的pWlxDisplaySASNotice接口来显示SAS通知;即:

C、如果我们获得用户logooff通知,那么意味着我们已经关机,一个远程的关机会发生,它已经在sysshut.c里启动。

//
            if (pTerm->SasType == WLX_SAS_TYPE_USER_LOGOFF)
            {
                //
                // We are *done*
                //

                DebugLog(( DEB_TRACE_STATE, "Received Logoff, setting state to %sn",
                                    GetState(Winsta_Shutdown) ));

                break;
            }


D、如果我们获得一个超时的SAS,那么

 

(21、6、5) 偿试登陆

 WlxResult = LogonAttempt(pTerm);

A、为新的登陆创建一个登陆SID

pLogonSid = CreateLogonSid(NULL);

CreateLogonid做了以下事情:

首先,产生一个本地的唯一的ID;

Status = NtAllocateLocallyUniqueId(&Luid);

然后,为SID分配空间;

Length = RtlLengthRequiredSid(SECURITY_LOGON_IDS_RID_COUNT);

    Sid = (PSID)Alloc(Length);

最后,将唯一的ID来填充SID空间。

RtlInitializeSid(Sid, &gSystemSidAuthority, SECURITY_LOGON_IDS_RID_COUNT);

        ASSERT(SECURITY_LOGON_IDS_RID_COUNT == 3);

        *(RtlSubAuthoritySid(Sid, 0)) = SECURITY_LOGON_IDS_RID;
        *(RtlSubAuthoritySid(Sid, 1 )) = Luid.HighPart;
        *(RtlSubAuthoritySid(Sid, 2 )) = Luid.LowPart;


B、如果不是控制台。

gpfnWinStationSetInformation是winsta.dll中的接口。

 if (!g_Console) {
        //
        //  BUGBUG Disabling winstations should be in terminal
                        
版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/chenyujing1234/article/details/7973618
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2021-05-17 20:58:06
  • 阅读 ( 1481 )
  • 分类:Go

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢