线程的创建过程
由于这两天在研究调试机制,所以记录下被调试线程的创建过程,如果哪里有遗漏,以后会再补充
线程创建过程分为两部分:
第一部分: CreateThread->NtCreateThread->PspCreateThread->KeInitThread->KiInitializeContextThread->KiThreadStartUp
第二部分:KiThreadStartUp->PspUserThreadStartup->DbgkCreateThread
PspCreateThread: This routine creates and initializes a thread object. It implements the foundation for NtCreateThread and for PsCreateSystemThread.
KeInitThread: This function initializes a thread object. The priority, affinity, and initial quantum are taken from the parent process object.
KiInitializeContextThread: This function initializes the machine dependent context of a thread object.
KiThreadStartUp:
; This routine is called at thread startup. Its function is to call the
; initial thread procedure. If control returns from the initial thread
; procedure and a user mode context was established when the thread
; was initialized, then the user mode context is restored and control
; is transferred to user mode. Otherwise a bugcheck will occur.
调试过程:DbgkCreateThread->DbgkpSendApiMessage(按需挂起线程)->DbgkpQueueMessage(内核事件唤醒,设置DEBUG_EVENT结构)
//创建线程或者进程信息 VOID DbgkCreateThread( PETHREAD Thread, PVOID StartAddress ) /*++ Routine Description: This function is called when a new thread begins to execute. If the thread has an associated DebugPort, then a message is sent thru the port. If this thread is the first thread in the process, then this event is translated into a CreateProcessInfo message. If a message is sent, then while the thread is awaiting a reply, all other threads in the process are suspended. Arguments: Thread - New thread just being started StartAddress - Supplies the start address for the thread that is starting. Return Value: None. --*/ { PVOID Port; DBGKM_APIMSG m; PDBGKM_CREATE_THREAD CreateThreadArgs; PDBGKM_CREATE_PROCESS CreateProcessArgs; PEPROCESS Process; PDBGKM_LOAD_DLL LoadDllArgs; NTSTATUS Status; OBJECT_ATTRIBUTES Obja; IO_STATUS_BLOCK IoStatusBlock; PIMAGE_NT_HEADERS NtHeaders; PTEB Teb; ULONG OldFlags; #if defined(_WIN64) PVOID Wow64Process; #endif PAGED_CODE(); Process = PsGetCurrentProcessByThread (Thread); #if defined(_WIN64) Wow64Process = Process->Wow64Process; #endif OldFlags = PS_TEST_SET_BITS (&Process->Flags, PS_PROCESS_FLAGS_CREATE_REPORTED|PS_PROCESS_FLAGS_IMAGE_NOTIFY_DONE); if ((OldFlags&PS_PROCESS_FLAGS_IMAGE_NOTIFY_DONE) == 0 && PsImageNotifyEnabled) { IMAGE_INFO ImageInfo; UNICODE_STRING UnicodeFileName; POBJECT_NAME_INFORMATION FileNameInfo; // // notification of main .exe // ImageInfo.Properties = 0; ImageInfo.ImageAddressingMode = IMAGE_ADDRESSING_MODE_32BIT; ImageInfo.ImageBase = Process->SectionBaseAddress; ImageInfo.ImageSize = 0; try { NtHeaders = RtlImageNtHeader (Process->SectionBaseAddress); if (NtHeaders) { #if defined(_WIN64) if (Wow64Process != NULL) { ImageInfo.ImageSize = DBGKP_FIELD_FROM_IMAGE_OPTIONAL_HEADER ((PIMAGE_NT_HEADERS32)NtHeaders, SizeOfImage); } else { #endif ImageInfo.ImageSize = DBGKP_FIELD_FROM_IMAGE_OPTIONAL_HEADER (NtHeaders, SizeOfImage); #if defined(_WIN64) } #endif } } except (EXCEPTION_EXECUTE_HANDLER) { ImageInfo.ImageSize = 0; } ImageInfo.ImageSelector = 0; ImageInfo.ImageSectionNumber = 0; Status = MmGetFileNameForSection (Process->SectionObject, &FileNameInfo); if (FileNameInfo != NULL) { PsCallImageNotifyRoutines (&FileNameInfo->Name, Process->UniqueProcessId, &ImageInfo); ExFreePool (FileNameInfo); } else { PsCallImageNotifyRoutines (NULL, Process->UniqueProcessId, &ImageInfo); } // // and of ntdll.dll // ImageInfo.Properties = 0; ImageInfo.ImageAddressingMode = IMAGE_ADDRESSING_MODE_32BIT; ImageInfo.ImageBase = PsSystemDllBase; ImageInfo.ImageSize = 0; try { NtHeaders = RtlImageNtHeader (PsSystemDllBase); if ( NtHeaders ) { #if defined(_WIN64) if (Wow64Process != NULL) { ImageInfo.ImageSize = DBGKP_FIELD_FROM_IMAGE_OPTIONAL_HEADER ((PIMAGE_NT_HEADERS32)NtHeaders, SizeOfImage); } else { #endif ImageInfo.ImageSize = DBGKP_FIELD_FROM_IMAGE_OPTIONAL_HEADER (NtHeaders, SizeOfImage); #if defined(_WIN64) } #endif } } except(EXCEPTION_EXECUTE_HANDLER) { ImageInfo.ImageSize = 0; } ImageInfo.ImageSelector = 0; ImageInfo.ImageSectionNumber = 0; RtlInitUnicodeString (&UnicodeFileName, L"\\SystemRoot\\System32\\ntdll.dll"); PsCallImageNotifyRoutines (&UnicodeFileName, Process->UniqueProcessId, &ImageInfo); } Port = Process->DebugPort; if (Port == NULL) { return; } // // Make sure we only get one create process message // if ((OldFlags&PS_PROCESS_FLAGS_CREATE_REPORTED) == 0) { // // This is a create process // CreateThreadArgs = &m.u.CreateProcessInfo.InitialThread; CreateThreadArgs->SubSystemKey = 0; CreateProcessArgs = &m.u.CreateProcessInfo; CreateProcessArgs->SubSystemKey = 0; CreateProcessArgs->FileHandle = DbgkpSectionToFileHandle( Process->SectionObject ); CreateProcessArgs->BaseOfImage = Process->SectionBaseAddress; CreateThreadArgs->StartAddress = NULL; CreateProcessArgs->DebugInfoFileOffset = 0; CreateProcessArgs->DebugInfoSize = 0; try { NtHeaders = RtlImageNtHeader(Process->SectionBaseAddress); if ( NtHeaders ) { #if defined(_WIN64) if (Wow64Process != NULL) { CreateThreadArgs->StartAddress = UlongToPtr (DBGKP_FIELD_FROM_IMAGE_OPTIONAL_HEADER ((PIMAGE_NT_HEADERS32)NtHeaders, ImageBase) + DBGKP_FIELD_FROM_IMAGE_OPTIONAL_HEADER ((PIMAGE_NT_HEADERS32)NtHeaders, AddressOfEntryPoint)); } else { #endif CreateThreadArgs->StartAddress = (PVOID) (DBGKP_FIELD_FROM_IMAGE_OPTIONAL_HEADER (NtHeaders, ImageBase) + DBGKP_FIELD_FROM_IMAGE_OPTIONAL_HEADER (NtHeaders, AddressOfEntryPoint)); #if defined(_WIN64) } #endif // // The following fields are safe for Wow64 as the offsets // are the same for a PE32+ as a PE32 header. // CreateProcessArgs->DebugInfoFileOffset = NtHeaders->FileHeader.PointerToSymbolTable; CreateProcessArgs->DebugInfoSize = NtHeaders->FileHeader.NumberOfSymbols; } } except (EXCEPTION_EXECUTE_HANDLER) { CreateThreadArgs->StartAddress = NULL; CreateProcessArgs->DebugInfoFileOffset = 0; CreateProcessArgs->DebugInfoSize = 0; } DBGKM_FORMAT_API_MSG(m,DbgKmCreateProcessApi,sizeof(*CreateProcessArgs)); DbgkpSendApiMessage(&m,FALSE); if (CreateProcessArgs->FileHandle != NULL) { ObCloseHandle(CreateProcessArgs->FileHandle, KernelMode); } LoadDllArgs = &m.u.LoadDll; LoadDllArgs->BaseOfDll = PsSystemDllBase; LoadDllArgs->DebugInfoFileOffset = 0; LoadDllArgs->DebugInfoSize = 0; LoadDllArgs->NamePointer = NULL; Teb = NULL; try { NtHeaders = RtlImageNtHeader(PsSystemDllBase); if ( NtHeaders ) { LoadDllArgs->DebugInfoFileOffset = NtHeaders->FileHeader.PointerToSymbolTable; LoadDllArgs->DebugInfoSize = NtHeaders->FileHeader.NumberOfSymbols; } // // Normaly the ntdll loaded fills in this pointer for the debug API's. We fake it here // as ntdll isn't loaded yet and it can't load itself. // Teb = Thread->Tcb.Teb; if (Teb != NULL) { wcsncpy (Teb->StaticUnicodeBuffer, L"ntdll.dll", sizeof (Teb->StaticUnicodeBuffer) / sizeof (Teb->StaticUnicodeBuffer[0])); Teb->NtTib.ArbitraryUserPointer = Teb->StaticUnicodeBuffer; LoadDllArgs->NamePointer = &Teb->NtTib.ArbitraryUserPointer; } } except (EXCEPTION_EXECUTE_HANDLER) { LoadDllArgs->DebugInfoFileOffset = 0; LoadDllArgs->DebugInfoSize = 0; LoadDllArgs->NamePointer = NULL; } // // Send load dll section for NT dll ! // InitializeObjectAttributes( &Obja, (PUNICODE_STRING)&PsNtDllPathName, OBJ_CASE_INSENSITIVE | OBJ_FORCE_ACCESS_CHECK | OBJ_KERNEL_HANDLE, NULL, NULL ); Status = ZwOpenFile( &LoadDllArgs->FileHandle, (ACCESS_MASK)(GENERIC_READ | SYNCHRONIZE), &Obja, &IoStatusBlock, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT ); if (!NT_SUCCESS (Status)) { LoadDllArgs->FileHandle = NULL; } DBGKM_FORMAT_API_MSG(m,DbgKmLoadDllApi,sizeof(*LoadDllArgs)); DbgkpSendApiMessage(&m,TRUE); if (LoadDllArgs->FileHandle != NULL) { ObCloseHandle(LoadDllArgs->FileHandle, KernelMode); } try { if (Teb != NULL) { Teb->NtTib.ArbitraryUserPointer = NULL; } } except (EXCEPTION_EXECUTE_HANDLER) { } } else { CreateThreadArgs = &m.u.CreateThread; CreateThreadArgs->SubSystemKey = 0; CreateThreadArgs->StartAddress = StartAddress; DBGKM_FORMAT_API_MSG (m,DbgKmCreateThreadApi,sizeof(*CreateThreadArgs)); DbgkpSendApiMessage (&m,TRUE); } }
//退出线程信息 VOID DbgkExitThread( NTSTATUS ExitStatus ) /*++ Routine Description: This function is called when a new thread terminates. At this point, the thread will no longer execute in user-mode. No other exit processing has occured. If a message is sent, then while the thread is awaiting a reply, all other threads in the process are suspended. Arguments: ExitStatus - Supplies the ExitStatus of the exiting thread. Return Value: None. --*/ { PVOID Port; DBGKM_APIMSG m; PDBGKM_EXIT_THREAD args; PEPROCESS Process; BOOLEAN Frozen; PAGED_CODE(); Process = PsGetCurrentProcess(); if (PsGetCurrentThread()->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_HIDEFROMDBG) { Port = NULL; } else { Port = Process->DebugPort; } if ( !Port ) { return; } if (PsGetCurrentThread()->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_DEADTHREAD) { return; } args = &m.u.ExitThread; args->ExitStatus = ExitStatus; DBGKM_FORMAT_API_MSG(m,DbgKmExitThreadApi,sizeof(*args)); Frozen = DbgkpSuspendProcess(); DbgkpSendApiMessage(&m,FALSE); if (Frozen) { DbgkpResumeProcess(); } }
//退出进程信息 VOID DbgkExitProcess( NTSTATUS ExitStatus ) /*++ Routine Description: This function is called when a process terminates. The address space of the process is still intact, but no threads exist in the process. Arguments: ExitStatus - Supplies the ExitStatus of the exiting process. Return Value: None. --*/ { PVOID Port; DBGKM_APIMSG m; PDBGKM_EXIT_PROCESS args; PEPROCESS Process; PAGED_CODE(); Process = PsGetCurrentProcess(); if (PsGetCurrentThread()->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_HIDEFROMDBG) { Port = NULL; } else { Port = Process->DebugPort; } if ( !Port ) { return; } if (PsGetCurrentThread()->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_DEADTHREAD) { return; } // // this ensures that other timed lockers of the process will bail // since this call is done while holding the process lock, and lock duration // is controlled by debugger // KeQuerySystemTime(&Process->ExitTime); args = &m.u.ExitProcess; args->ExitStatus = ExitStatus; DBGKM_FORMAT_API_MSG(m,DbgKmExitProcessApi,sizeof(*args)); DbgkpSendApiMessage(&m,FALSE); }
//加载DLL信息 VOID DbgkMapViewOfSection( IN PVOID SectionObject, IN PVOID BaseAddress, IN ULONG SectionOffset, IN ULONG_PTR ViewSize ) /*++ Routine Description: This function is called when the current process successfully maps a view of an image section. If the process has an associated debug port, then a load dll message is sent. Arguments: SectionObject - Supplies a pointer to the section mapped by the process. BaseAddress - Supplies the base address of where the section is mapped in the current process address space. SectionOffset - Supplies the offset in the section where the process' mapped view begins. ViewSize - Supplies the size of the mapped view. Return Value: None. --*/ { PVOID Port; DBGKM_APIMSG m; PDBGKM_LOAD_DLL LoadDllArgs; PEPROCESS Process; PIMAGE_NT_HEADERS NtHeaders; PAGED_CODE(); UNREFERENCED_PARAMETER (SectionOffset); UNREFERENCED_PARAMETER (ViewSize); if ( KeGetPreviousMode() == KernelMode ) { return; } Process = PsGetCurrentProcess(); if (PsGetCurrentThread()->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_HIDEFROMDBG) { Port = NULL; } else { Port = Process->DebugPort; } if ( !Port ) { return; } LoadDllArgs = &m.u.LoadDll; LoadDllArgs->FileHandle = DbgkpSectionToFileHandle(SectionObject); LoadDllArgs->BaseOfDll = BaseAddress; LoadDllArgs->DebugInfoFileOffset = 0; LoadDllArgs->DebugInfoSize = 0; // // The loader fills in the module name in this pointer before mapping // the section. It's a very poor linkage. // LoadDllArgs->NamePointer = &NtCurrentTeb()->NtTib.ArbitraryUserPointer; try { NtHeaders = RtlImageNtHeader (BaseAddress); if (NtHeaders != NULL) { LoadDllArgs->DebugInfoFileOffset = NtHeaders->FileHeader.PointerToSymbolTable; LoadDllArgs->DebugInfoSize = NtHeaders->FileHeader.NumberOfSymbols; } } except (EXCEPTION_EXECUTE_HANDLER) { LoadDllArgs->DebugInfoFileOffset = 0; LoadDllArgs->DebugInfoSize = 0; LoadDllArgs->NamePointer = NULL; } DBGKM_FORMAT_API_MSG(m,DbgKmLoadDllApi,sizeof(*LoadDllArgs)); DbgkpSendApiMessage(&m,TRUE); if (LoadDllArgs->FileHandle != NULL) { ObCloseHandle(LoadDllArgs->FileHandle, KernelMode); } }
//卸载DLL信息 VOID DbgkUnMapViewOfSection( IN PVOID BaseAddress ) /*++ Routine Description: This function is called when the current process successfully un maps a view of an image section. If the process has an associated debug port, then an "unmap view of section" message is sent. Arguments: BaseAddress - Supplies the base address of the section being unmapped. Return Value: None. --*/ { PVOID Port; DBGKM_APIMSG m; PDBGKM_UNLOAD_DLL UnloadDllArgs; PAGED_CODE(); if ( KeGetPreviousMode() == KernelMode ) { return; } if (PsGetCurrentThread()->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_HIDEFROMDBG) { Port = NULL; } else { Port = PsGetCurrentProcess()->DebugPort; } if ( !Port ) { return; } UnloadDllArgs = &m.u.UnloadDll; UnloadDllArgs->BaseAddress = BaseAddress; DBGKM_FORMAT_API_MSG(m,DbgKmUnloadDllApi,sizeof(*UnloadDllArgs)); DbgkpSendApiMessage(&m,TRUE); }