线程创建过程--初始化篇


  1. CreateThread(用户空间函数)
    直接调用CreateRemoteThread函数
    View Code
    HANDLE
    STDCALL
    CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,
                 DWORD dwStackSize,
                 LPTHREAD_START_ROUTINE lpStartAddress,
                 LPVOID lpParameter,
                 DWORD dwCreationFlags,
                 LPDWORD lpThreadId)
    {
        /* Act as if we're going to create a remote thread in ourselves */
        return CreateRemoteThread(NtCurrentProcess(),
                                  lpThreadAttributes,
                                  dwStackSize,
                                  lpStartAddress,
                                  lpParameter,
                                  dwCreationFlags,
                                  lpThreadId);
    }

     

  2. CreateRemoteThread函数,主要有下面几个过程

    a)创建用户空间堆栈
    b)初始化CONTEXT结构体
    c)初始化OBJECT_ATTRIBUTES结构体,此结构体在创建线程对象的时候使用。
    d)调用NtCreateThread,进入内核空间。

    View Code
    HANDLE
    STDCALL
    CreateRemoteThread(HANDLE hProcess,
                       LPSECURITY_ATTRIBUTES lpThreadAttributes,
                       DWORD dwStackSize,
                       LPTHREAD_START_ROUTINE lpStartAddress,
                       LPVOID lpParameter,
                       DWORD dwCreationFlags,
                       LPDWORD lpThreadId)
    {
        NTSTATUS Status;
        INITIAL_TEB InitialTeb;
        CONTEXT Context;
        CLIENT_ID ClientId;
        OBJECT_ATTRIBUTES LocalObjectAttributes;
        POBJECT_ATTRIBUTES ObjectAttributes;
        HANDLE hThread;
        ULONG Dummy;
        
        DPRINT("CreateRemoteThread: hProcess: %ld dwStackSize: %ld lpStartAddress"
                ": %p lpParameter: %lx, dwCreationFlags: %lx\n", hProcess, 
                dwStackSize, lpStartAddress, lpParameter, dwCreationFlags);
        
        /* Clear the Context */
        RtlZeroMemory(&Context, sizeof(CONTEXT));
        
        /* Write PID */
        ClientId.UniqueProcess = hProcess;
        
        /* Create the Stack */
        Status = BasepCreateStack(hProcess,
                                  dwStackSize,
                                  dwCreationFlags & STACK_SIZE_PARAM_IS_A_RESERVATION ?
                                  dwStackSize : 0,
                                  &InitialTeb);    
        if(!NT_SUCCESS(Status))
        {
            SetLastErrorByStatus(Status);
            return NULL;
        }
        
        /* Create Initial Context */
        BasepInitializeContext(&Context,
                               lpParameter,
                               lpStartAddress,
                               InitialTeb.StackBase,
                               1);
        
        /* initialize the attributes for the thread object */
        ObjectAttributes = BasepConvertObjectAttributes(&LocalObjectAttributes,
                                                        lpThreadAttributes,
                                                        NULL);
        
        /* Create the Kernel Thread Object */
        Status = NtCreateThread(&hThread,
                                THREAD_ALL_ACCESS,
                                ObjectAttributes,
                                hProcess,
                                &ClientId,
                                &Context,
                                &InitialTeb,
                                TRUE);
        if(!NT_SUCCESS(Status))
        {
            BasepFreeStack(hProcess, &InitialTeb);
            SetLastErrorByStatus(Status);
            return NULL;
        }
        
        #ifdef SXS_SUPPORT_ENABLED
        /* Are we in the same process? */
        if (Process = NtCurrentProcess())
        {
            PTEB Teb;
            PVOID ActivationContextStack;
            PTHREAD_BASIC_INFORMATION ThreadBasicInfo;
            PACTIVATION_CONTEXT_BASIC_INFORMATION ActivationCtxInfo;
            ULONG_PTR Cookie;
            
            /* Get the TEB */
            Status = NtQueryInformationThread(hThread,
                                              ThreadBasicIformation,
                                              &ThreadBasicInfo,
                                              sizeof(ThreadBasicInfo),
                                              NULL);
                                              
            /* Allocate the Activation Context Stack */
            Status = RtlAllocateActivationContextStack(&ActivationContextStack);
            Teb = ThreadBasicInfo.TebBaseAddress;
            
            /* Save it */
            Teb->ActivationContextStackPointer = ActivationContextStack;
            
            /* Query the Context */
            Status = RtlQueryInformationActivationContext(1,
                                                          0,
                                                          NULL,
                                                          ActivationContextBasicInformation,
                                                          &ActivationCtxInfo,
                                                          sizeof(ActivationCtxInfo),
                                                          NULL);
                                                          
            /* Does it need to be activated? */
            if (!ActivationCtxInfo.hActCtx)
            {
                /* Activate it */
                Status = RtlActivateActivationContextEx(1,
                                                        Teb,
                                                        ActivationCtxInfo.hActCtx,
                                                        &Cookie);
            }
        }
        #endif
        
        /* FIXME: Notify CSR */
    
        /* Success */
        if(lpThreadId) *lpThreadId = (DWORD)ClientId.UniqueThread;
        
        /* Resume it if asked */
        if (!(dwCreationFlags & CREATE_SUSPENDED))
        {
            NtResumeThread(hThread, &Dummy);
        }
        
        /* Return handle to thread */
        return hThread;
    }

    2.1 BasepInitializeContext函数

          要注意的是EAX,EBX,EIP寄存器的设置,EIP设置为BaseThreadStartupThunk了,而用户指定的起始地址保存到EAX中了,线程参数保存在EBX中。

    View Code
    VOID
    STDCALL
    BasepInitializeContext(IN PCONTEXT Context,
                           IN PVOID Parameter,
                           IN PVOID StartAddress,
                           IN PVOID StackAddress,
                           IN ULONG ContextType)
    {
        DPRINT("BasepInitializeContext: %p\n", Context);
        
        /* Setup the Initial Win32 Thread Context */
        Context->Eax = (ULONG)StartAddress;
        Context->Ebx = (ULONG)Parameter;
        Context->Esp = (ULONG)StackAddress;
        /* The other registers are undefined */
    
        /* Setup the Segments */
        Context->SegFs = KGDT_R3_TEB | RPL_MASK;
        Context->SegEs = KGDT_R3_DATA | RPL_MASK;
        Context->SegDs = KGDT_R3_DATA | RPL_MASK;
        Context->SegCs = KGDT_R3_CODE | RPL_MASK;
        Context->SegSs = KGDT_R3_DATA | RPL_MASK;
        Context->SegGs = 0;
    
        /* Set the EFLAGS */
        Context->EFlags = 0x3000; /* IOPL 3 */
    
        if (ContextType == 1)      /* For Threads */
        {
            Context->Eip = (ULONG)BaseThreadStartupThunk;
        }
        else if (ContextType == 2) /* For Fibers */
        {
            //Context->Eip = (ULONG)BaseFiberStartup;
        }
        else                       /* For first thread in a Process */
        {
            Context->Eip = (ULONG)BaseProcessStartThunk;
        }
        
        /* Set the Context Flags */
        Context->ContextFlags = CONTEXT_FULL;
        
        /* Give it some room for the Parameter */
        Context->Esp -= sizeof(PVOID);
    }

     

  3. NtCreateThread(内核空间函数)  
    调用PspCreateThread函数
    View Code
    NTSTATUS
    NTAPI
    NtCreateThread(OUT PHANDLE ThreadHandle,
                   IN ACCESS_MASK DesiredAccess,
                   IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
                   IN HANDLE ProcessHandle,
                   OUT PCLIENT_ID ClientId,
                   IN PCONTEXT ThreadContext,
                   IN PINITIAL_TEB InitialTeb,
                   IN BOOLEAN CreateSuspended)
    {
        INITIAL_TEB SafeInitialTeb;
        NTSTATUS Status = STATUS_SUCCESS;
        PAGED_CODE();
        PSTRACE(PS_THREAD_DEBUG,
                "ProcessHandle: %p Context: %p\n", ProcessHandle, ThreadContext);
    
        /* Check if this was from user-mode */
        if (KeGetPreviousMode() != KernelMode)
        {
            /* Make sure that we got a context */
            if (!ThreadContext) return STATUS_INVALID_PARAMETER;
    
            /* Protect checks */
            _SEH_TRY
            {
                /* Make sure the handle pointer we got is valid */
                ProbeForWriteHandle(ThreadHandle);
    
                /* Check if the caller wants a client id */
                if(ClientId)
                {
                    /* Make sure we can write to it */
                    ProbeForWrite(ClientId, sizeof(CLIENT_ID), sizeof(ULONG));
                }
    
                /* Make sure that the entire context is readable */
                ProbeForRead(ThreadContext, sizeof(CONTEXT), sizeof(ULONG));
    
                /* Check the Initial TEB */
                ProbeForRead(InitialTeb, sizeof(INITIAL_TEB), sizeof(ULONG));
                SafeInitialTeb = *InitialTeb;
            }
            _SEH_HANDLE
            {
                Status = _SEH_GetExceptionCode();
            }
            _SEH_END;
            if (!NT_SUCCESS(Status)) return Status;
        }
        else
        {
            /* Use the Initial TEB as is */
            SafeInitialTeb = *InitialTeb;
        }
    
        /* Call the shared function */
        return PspCreateThread(ThreadHandle,
                               DesiredAccess,
                               ObjectAttributes,
                               ProcessHandle,
                               NULL,
                               ClientId,
                               ThreadContext,
                               &SafeInitialTeb,
                               CreateSuspended,
                               NULL,
                               NULL);
    }

     

  4. PspCreateThread函数
    代码比较长,我们只要关注两个地方:
    a)创建线程对象
      
        /* Create Thread Object */
        Status = ObCreateObject(PreviousMode,
                                PsThreadType,
                                ObjectAttributes,
                                PreviousMode,
                                NULL,
                                sizeof(ETHREAD),
                                0,
                                0,
                                (PVOID*)&Thread);

    b)调用KeInitThread函数初始化线程,我们看到,对于系统线程和用户线程,他们的入口地址是不一样的。
    用户线程的入口地址是PspUserThreadStartup,系统线程的入口地址是PspSystemThreadStartup.

       if (ThreadContext)
        {
            /* User-mode Thread, create Teb */
            TebBase = MmCreateTeb(Process, &Thread->Cid, InitialTeb);
            if (!TebBase)
            {
                /* Failed to create the TEB. Release rundown and dereference */
                ExReleaseRundownProtection(&Process->RundownProtect);
                ObDereferenceObject(Thread);
                return STATUS_INSUFFICIENT_RESOURCES;
            }
    
            /* Set the Start Addresses */
    #if defined(_M_IX86)
            Thread->StartAddress = (PVOID)ThreadContext->Eip;
            Thread->Win32StartAddress = (PVOID)ThreadContext->Eax;
    #elif defined(_M_PPC)
    #error Not implemented yet for PPC architecture!
    #elif defined(_M_MIPS)
            for (;;);
    #else
    #error Unknown architecture
    #endif
    
            /* Let the kernel intialize the Thread */
            Status = KeInitThread(&Thread->Tcb,
                                  NULL,
                                  PspUserThreadStartup,
                                  NULL,
                                  Thread->StartAddress,
                                  ThreadContext,
                                  TebBase,
                                  &Process->Pcb);
        }
        else
        {
            /* System Thread */
            Thread->StartAddress = StartRoutine;
            PspSetCrossThreadFlag(Thread, CT_SYSTEM_THREAD_BIT);
    
            /* Let the kernel intialize the Thread */
            Status = KeInitThread(&Thread->Tcb,
                                  NULL,
                                  PspSystemThreadStartup,
                                  StartRoutine,
                                  StartContext,
                                  NULL,
                                  NULL,
         

     

  5. View Code
    NTSTATUS
    NTAPI
    PspCreateThread(OUT PHANDLE ThreadHandle,
                    IN ACCESS_MASK DesiredAccess,
                    IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
                    IN HANDLE ProcessHandle,
                    IN PEPROCESS TargetProcess,
                    OUT PCLIENT_ID ClientId,
                    IN PCONTEXT ThreadContext,
                    IN PINITIAL_TEB InitialTeb,
                    IN BOOLEAN CreateSuspended,
                    IN PKSTART_ROUTINE StartRoutine OPTIONAL,
                    IN PVOID StartContext OPTIONAL)
    {
        HANDLE hThread;
        PEPROCESS Process;
        PETHREAD Thread;
        PTEB TebBase = NULL;
        KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
        NTSTATUS Status, AccessStatus;
        HANDLE_TABLE_ENTRY CidEntry;
        ACCESS_STATE LocalAccessState;
        PACCESS_STATE AccessState = &LocalAccessState;
        AUX_DATA AuxData;
        BOOLEAN Result, SdAllocated;
        PSECURITY_DESCRIPTOR SecurityDescriptor;
        SECURITY_SUBJECT_CONTEXT SubjectContext;
        PAGED_CODE();
        PSTRACE(PS_THREAD_DEBUG,
                "ThreadContext: %p TargetProcess: %p ProcessHandle: %p\n",
                ThreadContext, TargetProcess, ProcessHandle);
    
        /* If we were called from PsCreateSystemThread, then we're kernel mode */
        if (StartRoutine) PreviousMode = KernelMode;
    
        /* Reference the Process by handle or pointer, depending on what we got */
        if (ProcessHandle)
        {
            /* Normal thread or System Thread */
            Status = ObReferenceObjectByHandle(ProcessHandle,
                                               PROCESS_CREATE_THREAD,
                                               PsProcessType,
                                               PreviousMode,
                                               (PVOID*)&Process,
                                               NULL);
            PSREFTRACE(Process);
        }
        else
        {
            /* System thread inside System Process, or Normal Thread with a bug */
            if (StartRoutine)
            {
                /* Reference the Process by Pointer */
                ObReferenceObject(TargetProcess);
                Process = TargetProcess;
                Status = STATUS_SUCCESS;
            }
            else
            {
                /* Fake ObReference returning this */
                Status = STATUS_INVALID_HANDLE;
            }
        }
    
        /* Check for success */
        if (!NT_SUCCESS(Status)) return Status;
    
        /* Also make sure that User-Mode isn't trying to create a system thread */
        if ((PreviousMode != KernelMode) && (Process == PsInitialSystemProcess))
        {
            /* Fail */
            ObDereferenceObject(Process);
            return STATUS_INVALID_HANDLE;
        }
    
        /* Create Thread Object */
        Status = ObCreateObject(PreviousMode,
                                PsThreadType,
                                ObjectAttributes,
                                PreviousMode,
                                NULL,
                                sizeof(ETHREAD),
                                0,
                                0,
                                (PVOID*)&Thread);
        if (!NT_SUCCESS(Status))
        {
            /* We failed; dereference the process and exit */
            ObDereferenceObject(Process);
            return Status;
        }
    
        /* Zero the Object entirely */
        RtlZeroMemory(Thread, sizeof(ETHREAD));
    
        /* Initialize rundown protection */
        ExInitializeRundownProtection(&Thread->RundownProtect);
    
        /* Initialize exit code */
        Thread->ExitStatus = STATUS_PENDING;
    
        /* Set the Process CID */
        Thread->ThreadsProcess = Process;
        Thread->Cid.UniqueProcess = Process->UniqueProcessId;
    
        /* Create Cid Handle */
        CidEntry.Object = Thread;
        CidEntry.GrantedAccess = 0;
        Thread->Cid.UniqueThread = ExCreateHandle(PspCidTable, &CidEntry);
        if (!Thread->Cid.UniqueThread)
        {
            /* We couldn't create the CID, dereference the thread and fail */
            ObDereferenceObject(Thread);
            return STATUS_INSUFFICIENT_RESOURCES;
        }
    
        /* Save the read cluster size */
        Thread->ReadClusterSize = MmReadClusterSize;
    
        /* Initialize the LPC Reply Semaphore */
        KeInitializeSemaphore(&Thread->LpcReplySemaphore, 0, 1);
    
        /* Initialize the list heads and locks */
        InitializeListHead(&Thread->LpcReplyChain);
        InitializeListHead(&Thread->IrpList);
        InitializeListHead(&Thread->PostBlockList);
        InitializeListHead(&Thread->ActiveTimerListHead);
        KeInitializeSpinLock(&Thread->ActiveTimerListLock);
    
        /* Acquire rundown protection */
        if (!ExAcquireRundownProtection (&Process->RundownProtect))
        {
            /* Fail */
            ObDereferenceObject(Thread);
            return STATUS_PROCESS_IS_TERMINATING;
        }
    
        /* Now let the kernel initialize the context */
        if (ThreadContext)
        {
            /* User-mode Thread, create Teb */
            TebBase = MmCreateTeb(Process, &Thread->Cid, InitialTeb);
            if (!TebBase)
            {
                /* Failed to create the TEB. Release rundown and dereference */
                ExReleaseRundownProtection(&Process->RundownProtect);
                ObDereferenceObject(Thread);
                return STATUS_INSUFFICIENT_RESOURCES;
            }
    
            /* Set the Start Addresses */
    #if defined(_M_IX86)
            Thread->StartAddress = (PVOID)ThreadContext->Eip;
            Thread->Win32StartAddress = (PVOID)ThreadContext->Eax;
    #elif defined(_M_PPC)
    #error Not implemented yet for PPC architecture!
    #elif defined(_M_MIPS)
            for (;;);
    #else
    #error Unknown architecture
    #endif
    
            /* Let the kernel intialize the Thread */
            Status = KeInitThread(&Thread->Tcb,
                                  NULL,
                                  PspUserThreadStartup,
                                  NULL,
                                  Thread->StartAddress,
                                  ThreadContext,
                                  TebBase,
                                  &Process->Pcb);
        }
        else
        {
            /* System Thread */
            Thread->StartAddress = StartRoutine;
            PspSetCrossThreadFlag(Thread, CT_SYSTEM_THREAD_BIT);
    
            /* Let the kernel intialize the Thread */
            Status = KeInitThread(&Thread->Tcb,
                                  NULL,
                                  PspSystemThreadStartup,
                                  StartRoutine,
                                  StartContext,
                                  NULL,
                                  NULL,
                                  &Process->Pcb);
        }
    
        /* Check if we failed */
        if (!NT_SUCCESS(Status))
        {
            /* Delete the TEB if we had done */
            if (TebBase) MmDeleteTeb(Process, TebBase);
    
            /* Release rundown and dereference */
            ExReleaseRundownProtection(&Process->RundownProtect);
            ObDereferenceObject(Thread);
            return Status;
        }
    
        /* Lock the process */
        KeEnterCriticalRegion();
        ExAcquirePushLockExclusive(&Process->ProcessLock);
    
        /* Make sure the proces didn't just die on us */
        if (Process->ProcessDelete) goto Quickie;
    
        /* Check if the thread was ours, terminated and it was user mode */
        if ((Thread->Terminated) &&
            (ThreadContext) &&
            (Thread->ThreadsProcess == Process))
        {
            /* Cleanup, we don't want to start it up and context switch */
            goto Quickie;
        }
    
        /*
         * Insert the Thread into the Process's Thread List
         * Note, this is the ETHREAD Thread List. It is removed in
         * ps/kill.c!PspExitThread.
         */
        InsertTailList(&Process->ThreadListHead, &Thread->ThreadListEntry);
        Process->ActiveThreads++;
    
        /* Start the thread */
        KeStartThread(&Thread->Tcb);
    
        /* Release the process lock */
        ExReleasePushLockExclusive(&Process->ProcessLock);
        KeLeaveCriticalRegion();
    
        /* Release rundown */
        ExReleaseRundownProtection(&Process->RundownProtect);
    
        /* Notify WMI */
        //WmiTraceProcess(Process, TRUE);
        //WmiTraceThread(Thread, InitialTeb, TRUE);
    
        /* Notify Thread Creation */
        PspRunCreateThreadNotifyRoutines(Thread, TRUE);
    
        /* Reference ourselves as a keep-alive */
        ObReferenceObjectEx(Thread, 2);
    
        /* Suspend the Thread if we have to */
        if (CreateSuspended) KeSuspendThread(&Thread->Tcb);
    
        /* Check if we were already terminated */
        if (Thread->Terminated) KeForceResumeThread(&Thread->Tcb);
    
        /* Create an access state */
        Status = SeCreateAccessStateEx(NULL,
                                       ThreadContext ?
                                       PsGetCurrentProcess() : Process,
                                       &LocalAccessState,
                                       &AuxData,
                                       DesiredAccess,
                                       &PsThreadType->TypeInfo.GenericMapping);
        if (!NT_SUCCESS(Status))
        {
            /* Access state failed, thread is dead */
            PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT);
    
            /* If we were suspended, wake it up */
            if (CreateSuspended) KeResumeThread(&Thread->Tcb);
    
            /* Dispatch thread */
            KeReadyThread(&Thread->Tcb);
    
            /* Dereference completely to kill it */
            ObDereferenceObjectEx(Thread, 2);
            return Status;
        }
    
        /* Insert the Thread into the Object Manager */
        Status = ObInsertObject(Thread,
                                AccessState,
                                DesiredAccess,
                                0,
                                NULL,
                                &hThread);
    
        /* Delete the access state if we had one */
        if (AccessState) SeDeleteAccessState(AccessState);
    
        /* Check for success */
        if (NT_SUCCESS(Status))
        {
            /* Wrap in SEH to protect against bad user-mode pointers */
            _SEH_TRY
            {
                /* Return Cid and Handle */
                if (ClientId) *ClientId = Thread->Cid;
                *ThreadHandle = hThread;
            }
            _SEH_HANDLE
            {
                /* Get the exception code */
                Status = _SEH_GetExceptionCode();
    
                /* Thread insertion failed, thread is dead */
                PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT);
    
                /* If we were suspended, wake it up */
                if (CreateSuspended) KeResumeThread(&Thread->Tcb);
    
                /* Dispatch thread */
                KeReadyThread(&Thread->Tcb);
    
                /* Dereference it, leaving only the keep-alive */
                ObDereferenceObject(Thread);
    
                /* Close its handle, killing it */
                ObCloseHandle(ThreadHandle, PreviousMode);
            }
            _SEH_END;
            if (!NT_SUCCESS(Status)) return Status;
        }
        else
        {
            /* Thread insertion failed, thread is dead */
            PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT);
    
            /* If we were suspended, wake it up */
            if (CreateSuspended) KeResumeThread(&Thread->Tcb);
        }
    
        /* Get the create time */
        KeQuerySystemTime(&Thread->CreateTime);
        ASSERT(!(Thread->CreateTime.HighPart & 0xF0000000));
    
        /* Make sure the thread isn't dead */
        if (!Thread->DeadThread)
        {
            /* Get the thread's SD */
            Status = ObGetObjectSecurity(Thread,
                                         &SecurityDescriptor,
                                         &SdAllocated);
            if (!NT_SUCCESS(Status))
            {
                /* Thread insertion failed, thread is dead */
                PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT);
    
                /* If we were suspended, wake it up */
                if (CreateSuspended) KeResumeThread(&Thread->Tcb);
    
                /* Dispatch thread */
                KeReadyThread(&Thread->Tcb);
    
                /* Dereference it, leaving only the keep-alive */
                ObDereferenceObject(Thread);
    
                /* Close its handle, killing it */
                ObCloseHandle(ThreadHandle, PreviousMode);
                return Status;
            }
    
            /* Create the subject context */
            SubjectContext.ProcessAuditId = Process;
            SubjectContext.PrimaryToken = PsReferencePrimaryToken(Process);
            SubjectContext.ClientToken = NULL;
    
            /* Do the access check */
            Result = SeAccessCheck(SecurityDescriptor,
                                   &SubjectContext,
                                   FALSE,
                                   MAXIMUM_ALLOWED,
                                   0,
                                   NULL,
                                   &PsThreadType->TypeInfo.GenericMapping,
                                   PreviousMode,
                                   &Thread->GrantedAccess,
                                   &AccessStatus);
    
            /* Dereference the token and let go the SD */
            ObFastDereferenceObject(&Process->Token,
                                    SubjectContext.PrimaryToken);
            ObReleaseObjectSecurity(SecurityDescriptor, SdAllocated);
    
            /* Remove access if it failed */
            if (!Result) Process->GrantedAccess = 0;
    
            /* Set least some minimum access */
            Thread->GrantedAccess |= (THREAD_TERMINATE |
                                      THREAD_SET_INFORMATION |
                                      THREAD_QUERY_INFORMATION);
        }
        else
        {
            /* Set the thread access mask to maximum */
            Thread->GrantedAccess = THREAD_ALL_ACCESS;
        }
    
        /* Dispatch thread */
        KeReadyThread(&Thread->Tcb);
    
        /* Dereference it, leaving only the keep-alive */
        ObDereferenceObject(Thread);
    
        /* Return */
        return Status;
    
        /* Most annoying failure case ever, where we undo almost all manually */
    Quickie:
        /* When we get here, the process is locked, unlock it */
        ExReleasePushLockExclusive(&Process->ProcessLock);
    
        /* Uninitailize it */
        KeUninitThread(&Thread->Tcb);
    
        /* If we had a TEB, delete it */
        if (TebBase) MmDeleteTeb(Process, TebBase);
    
        /* Release rundown protection, which we also hold */
        ExReleaseRundownProtection(&Process->RundownProtect);
    
        /* Dereference the thread and return failure */
        ObDereferenceObject(Thread);
        return STATUS_PROCESS_IS_TERMINATING;
    }

     

  6. KeInitThread函数,主要实现两个事情
    a) 创建系统堆栈
      
    /* Check if we have a kernel stack */
        if (!KernelStack)
        {
            /* We don't, allocate one */
            KernelStack = (PVOID)((ULONG_PTR)MmCreateKernelStack(FALSE) +
                                  KERNEL_STACK_SIZE);
            if (!KernelStack) return STATUS_INSUFFICIENT_RESOURCES;
    
            /* Remember for later */
            AllocatedStack = TRUE;
        }

     


    b)调用Ke386InitThreadWithContext函数,根据前面的调用,我们知道
      SystemRoutine:PspUserThreadStartup
      StartRoutine:NULL
      StartContext:BaseThreadStartupThunk
      Context: 前面CreateRemoteThread函数中初始化的Context,
     

          /* Initalize the Thread Context */
            Ke386InitThreadWithContext(Thread,
                                       SystemRoutine,
                                       StartRoutine,
                                       StartContext,
                                       Context);

    c)完整函数代码


    NTSTATUS
    NTAPI
    KeInitThread(IN OUT PKTHREAD Thread,
                 IN PVOID KernelStack,
                 IN PKSYSTEM_ROUTINE SystemRoutine,
                 IN PKSTART_ROUTINE StartRoutine,
                 IN PVOID StartContext,
                 IN PCONTEXT Context,
                 IN PVOID Teb,
                 IN PKPROCESS Process)
    {
        BOOLEAN AllocatedStack = FALSE;
        ULONG i;
        PKWAIT_BLOCK TimerWaitBlock;
        PKTIMER Timer;
        NTSTATUS Status;
    
        /* Initalize the Dispatcher Header */
        KeInitializeDispatcherHeader(&Thread->DispatcherHeader,
                                     ThreadObject,
                                     sizeof(KTHREAD) / sizeof(LONG),
                                     FALSE);
    
        /* Initialize the Mutant List */
        InitializeListHead(&Thread->MutantListHead);
    
        /* Initialize the wait blocks */
        for (i = 0; i< (THREAD_WAIT_OBJECTS + 1); i++)
        {
            /* Put our pointer */
            Thread->WaitBlock[i].Thread = Thread;
        }
    
        /* Set swap settings */
        Thread->EnableStackSwap = FALSE;//TRUE;
        Thread->IdealProcessor = 1;
        Thread->SwapBusy = FALSE;
        Thread->KernelStackResident = TRUE;
        Thread->AdjustReason = AdjustNone;
    
        /* Initialize the lock */
        KeInitializeSpinLock(&Thread->ThreadLock);
    
        /* Setup the Service Descriptor Table for Native Calls */
        Thread->ServiceTable = KeServiceDescriptorTable;
    
        /* Setup APC Fields */
        InitializeListHead(&Thread->ApcState.ApcListHead[0]);
        InitializeListHead(&Thread->ApcState.ApcListHead[1]);
        Thread->ApcState.Process = Process;
        Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState;
        Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState;
        Thread->ApcStateIndex = OriginalApcEnvironment;
        Thread->ApcQueueable = TRUE;
        KeInitializeSpinLock(&Thread->ApcQueueLock);
    
        /* Initialize the Suspend APC */
        KeInitializeApc(&Thread->SuspendApc,
                        Thread,
                        OriginalApcEnvironment,
                        KiSuspendNop,
                        KiSuspendRundown,
                        KiSuspendThread,
                        KernelMode,
                        NULL);
    
        /* Initialize the Suspend Semaphore */
        KeInitializeSemaphore(&Thread->SuspendSemaphore, 0, 2);
    
        /* Setup the timer */
        Timer = &Thread->Timer;
        KeInitializeTimer(Timer);
        TimerWaitBlock = &Thread->WaitBlock[TIMER_WAIT_BLOCK];
        TimerWaitBlock->Object = Timer;
        TimerWaitBlock->WaitKey = STATUS_TIMEOUT;
        TimerWaitBlock->WaitType = WaitAny;
        TimerWaitBlock->NextWaitBlock = NULL;
    
        /* Link the two wait lists together */
        TimerWaitBlock->WaitListEntry.Flink = &Timer->Header.WaitListHead;
        TimerWaitBlock->WaitListEntry.Blink = &Timer->Header.WaitListHead;
    
        /* Set the TEB */
        Thread->Teb = Teb;
    
        /* Check if we have a kernel stack */
        if (!KernelStack)
        {
            /* We don't, allocate one */
            KernelStack = (PVOID)((ULONG_PTR)MmCreateKernelStack(FALSE) +
                                  KERNEL_STACK_SIZE);
            if (!KernelStack) return STATUS_INSUFFICIENT_RESOURCES;
    
            /* Remember for later */
            AllocatedStack = TRUE;
        }
    
        /* Set the Thread Stacks */
        Thread->InitialStack = (PCHAR)KernelStack;
        Thread->StackBase = (PCHAR)KernelStack;
        Thread->StackLimit = (ULONG_PTR)KernelStack - KERNEL_STACK_SIZE;
        Thread->KernelStackResident = TRUE;
    
        /* ROS Mm HACK */
        MmUpdatePageDir((PEPROCESS)Process,
                        (PVOID)Thread->StackLimit,
                        KERNEL_STACK_SIZE);
        MmUpdatePageDir((PEPROCESS)Process, (PVOID)Thread, sizeof(ETHREAD));
    
    #if defined(_M_IX86)
        /* Enter SEH to avoid crashes due to user mode */
        Status = STATUS_SUCCESS;
        _SEH_TRY
        {
            /* Initalize the Thread Context */
            Ke386InitThreadWithContext(Thread,
                                       SystemRoutine,
                                       StartRoutine,
                                       StartContext,
                                       Context);
        }
        _SEH_HANDLE
        {
            /* Set failure status */
            Status = STATUS_UNSUCCESSFUL;
    
            /* Check if a stack was allocated */
            if (AllocatedStack)
            {
                /* Delete the stack */
                MmDeleteKernelStack(Thread->StackBase, FALSE);
                Thread->InitialStack = NULL;
            }
        }
        _SEH_END;
    #else
        Status = STATUS_SUCCESS;
    #endif
    
        /* Set the Thread to initalized */
        Thread->State = Initialized;
        return Status;
    }

     

  7. Ke386InitThreadWithContext函数
    a)函数先定义一个系统调用的框架
      
    InitFrame = (PKUINIT_FRAME)((ULONG_PTR)Thread->InitialStack -
                                        sizeof(KUINIT_FRAME));

    b)初始化框架中一些字段的值就OK了,至此线程初始化基本完整,函数返回CreateRemoteThread函数,CreateRemoteThread函数调用NtResumeThread函数,此时线程可以开始调度。


    View Code
    VOID
    NTAPI
    Ke386InitThreadWithContext(IN PKTHREAD Thread,
                               IN PKSYSTEM_ROUTINE SystemRoutine,
                               IN PKSTART_ROUTINE StartRoutine,
                               IN PVOID StartContext,
                               IN PCONTEXT ContextPointer)
    {
        PFX_SAVE_AREA FxSaveArea;
        PFXSAVE_FORMAT FxSaveFormat;
        PKSTART_FRAME StartFrame;
        PKSWITCHFRAME CtxSwitchFrame;
        PKTRAP_FRAME TrapFrame;
        CONTEXT LocalContext;
        PCONTEXT Context = NULL;
        ULONG ContextFlags;
    
        /* Check if this is a With-Context Thread */
        if (ContextPointer)
        {
            /* Set up the Initial Frame */
            PKUINIT_FRAME InitFrame;
            InitFrame = (PKUINIT_FRAME)((ULONG_PTR)Thread->InitialStack -
                                        sizeof(KUINIT_FRAME));
    
            /* Copy over the context we got */
            RtlCopyMemory(&LocalContext, ContextPointer, sizeof(CONTEXT));
            Context = &LocalContext;
            ContextFlags = CONTEXT_CONTROL;
    
            /* Zero out the trap frame and save area */
            RtlZeroMemory(&InitFrame->TrapFrame,
                          KTRAP_FRAME_LENGTH + sizeof(FX_SAVE_AREA));
    
            /* Setup the Fx Area */
            FxSaveArea = &InitFrame->FxSaveArea;
    
            /* Check if we support FXsr */
            if (KeI386FxsrPresent)
            {
                /* Get the FX Save Format Area */
                FxSaveFormat = (PFXSAVE_FORMAT)Context->ExtendedRegisters;
    
                /* Set an initial state */
                FxSaveFormat->ControlWord = 0x27F;
                FxSaveFormat->StatusWord = 0;
                FxSaveFormat->TagWord = 0;
                FxSaveFormat->ErrorOffset = 0;
                FxSaveFormat->ErrorSelector = 0;
                FxSaveFormat->DataOffset = 0;
                FxSaveFormat->DataSelector = 0;
                FxSaveFormat->MXCsr = 0x1F80;
            }
            else
            {
                /* Setup the regular save area */
                Context->FloatSave.ControlWord = 0x27F;
                Context->FloatSave.StatusWord = 0;
                Context->FloatSave.TagWord = -1;
                Context->FloatSave.ErrorOffset = 0;
                Context->FloatSave.ErrorSelector = 0;
                Context->FloatSave.DataOffset =0;
                Context->FloatSave.DataSelector = 0;
            }
    
            /* Check if the CPU has NPX */
            if (KeI386NpxPresent)
            {
                /* Set an intial NPX State */
                Context->FloatSave.Cr0NpxState = 0;
                FxSaveArea->Cr0NpxState = 0;
                FxSaveArea->NpxSavedCpu = 0;
    
                /* Now set the context flags depending on XMM support */
                ContextFlags |= (KeI386FxsrPresent) ? CONTEXT_EXTENDED_REGISTERS :
                                                      CONTEXT_FLOATING_POINT;
    
                /* Set the Thread's NPX State */
                Thread->NpxState = NPX_STATE_NOT_LOADED;
                Thread->DispatcherHeader.NpxIrql = PASSIVE_LEVEL;
            }
            else
            {
                /* We'll use emulation */
                FxSaveArea->Cr0NpxState = CR0_EM;
                Thread->NpxState = NPX_STATE_NOT_LOADED &~ CR0_MP;
            }
    
            /* Disable any debug regiseters */
            Context->ContextFlags &= ~CONTEXT_DEBUG_REGISTERS;
    
            /* Setup the Trap Frame */
            TrapFrame = &InitFrame->TrapFrame;
    
            /* Set up a trap frame from the context. */
            KeContextToTrapFrame(Context,
                                 NULL,
                                 TrapFrame,
                                 Context->ContextFlags | ContextFlags,
                                 UserMode);
    
            /* Set SS, DS, ES's RPL Mask properly */
            TrapFrame->HardwareSegSs |= RPL_MASK;
            TrapFrame->SegDs |= RPL_MASK;
            TrapFrame->SegEs |= RPL_MASK;
            TrapFrame->Dr7 = 0;
    
            /* Set the debug mark */
            TrapFrame->DbgArgMark = 0xBADB0D00;
    
            /* Set the previous mode as user */
            TrapFrame->PreviousPreviousMode = UserMode;
    
            /* Terminate the Exception Handler List */
            TrapFrame->ExceptionList = EXCEPTION_CHAIN_END;
    
            /* Setup the Stack for KiThreadStartup and Context Switching */
            StartFrame = &InitFrame->StartFrame;
            CtxSwitchFrame = &InitFrame->CtxSwitchFrame;
    
            /* Tell the thread it will run in User Mode */
            Thread->PreviousMode = UserMode;
    
            /* Tell KiThreadStartup of that too */
            StartFrame->UserThread = TRUE;
        }
        else
        {
            /* Set up the Initial Frame for the system thread */
            PKKINIT_FRAME InitFrame;
            InitFrame = (PKKINIT_FRAME)((ULONG_PTR)Thread->InitialStack -
                                        sizeof(KKINIT_FRAME));
    
            /* Setup the Fx Area */
            FxSaveArea = &InitFrame->FxSaveArea;
            RtlZeroMemory(FxSaveArea, sizeof(FX_SAVE_AREA));
    
            /* Check if we have Fxsr support */
            if (KeI386FxsrPresent)
            {
                /* Set the stub FX area */
                FxSaveArea->U.FxArea.ControlWord = 0x27F;
                FxSaveArea->U.FxArea.MXCsr = 0x1F80;
            }
            else
            {
                /* Set the stub FN area */
                FxSaveArea->U.FnArea.ControlWord = 0x27F;
                FxSaveArea->U.FnArea.TagWord = -1;
            }
    
            /* No NPX State */
            Thread->NpxState = NPX_STATE_NOT_LOADED;
    
            /* Setup the Stack for KiThreadStartup and Context Switching */
            StartFrame = &InitFrame->StartFrame;
            CtxSwitchFrame = &InitFrame->CtxSwitchFrame;
    
            /* Tell the thread it will run in Kernel Mode */
            Thread->PreviousMode = KernelMode;
    
            /* Tell KiThreadStartup of that too */
            StartFrame->UserThread = FALSE;
        }
    
        /* Now setup the remaining data for KiThreadStartup */
        StartFrame->StartContext = StartContext;
        StartFrame->StartRoutine = StartRoutine;
        StartFrame->SystemRoutine = SystemRoutine;
    
        /* And set up the Context Switch Frame */
        CtxSwitchFrame->RetAddr = KiThreadStartup;
        CtxSwitchFrame->ApcBypassDisable = TRUE;
        CtxSwitchFrame->ExceptionList = EXCEPTION_CHAIN_END;;
    
        /* Save back the new value of the kernel stack. */
        Thread->KernelStack = (PVOID)CtxSwitchFrame;
    }

     


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM