- 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); }
- 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); }
- 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); }
- 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,
-
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; }
- 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; }
- 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; }