由于这两天在研究调试机制,所以记录下被调试线程的创建过程,如果哪里有遗漏,以后会再补充
线程创建过程分为两部分:
第一部分: 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);
}