DbgkCreateThread
首先我们需要替换的是 rdmsr, wrmsr替换掉系统的sysenter跳转地址. 这样整个SSDT表函数都处于被我们的监控当中.
一个新的进程创建线程的时候就会调用到DbgkCreateThread.DbgkCreateThread可以发出两种消息, 一种进程创建,和线程创建消息.
当然, ntdll.dll的消息也在此列.DbgkCreateThread函数内部主要是判断进程是否有PSF_CREATE_REPORTED_BIT标记, 如果有那么就发送进程创建消息, 如果没有那么就发送线程创建消息, 他们都会调用到 DbgkpSendApiMessage 函数.
DbgkpSendApiMessage函数内部做的事情也不多. 主要是挂起线程和恢复线程一类的事情. 然后调用了更底层的DbgkpQueueMessage函数.
DbgkpQueueMessage函数内部大体逻辑就是将消息封装好, 插入队列, 等待R3过来取. 差不多就是这些.下面的代码是ReactOS的代码.
VOID NTAPI DbgkCreateThread(IN PETHREAD Thread, IN PVOID StartAddress) { PEPROCESS Process = PsGetCurrentProcess(); ULONG ProcessFlags; IMAGE_INFO ImageInfo; PIMAGE_NT_HEADERS NtHeader; POBJECT_NAME_INFORMATION ModuleName; UNICODE_STRING NtDllName; NTSTATUS Status; PVOID DebugPort; DBGKM_MSG ApiMessage; PDBGKM_CREATE_THREAD CreateThread = &ApiMessage.CreateThread; PDBGKM_CREATE_PROCESS CreateProcess = &ApiMessage.CreateProcess; PDBGKM_LOAD_DLL LoadDll = &ApiMessage.LoadDll; OBJECT_ATTRIBUTES ObjectAttributes; IO_STATUS_BLOCK IoStatusBlock; PTEB Teb; PAGED_CODE(); /* Sanity check */ ASSERT(Thread == PsGetCurrentThread()); // // 获取是否要调用LoadImageNotifyRoutines标记 // ProcessFlags = PspSetProcessFlag(Process, PSF_CREATE_REPORTED_BIT | PSF_IMAGE_NOTIFY_DONE_BIT); // // 如果进程标记中有设置PSF_IMAGE_NOTIFY_DONE_BIT 并且系统中开启了LoadImageNotifyRoutines服务 // 这个if 和调试没有关系, 不管. // if (!(ProcessFlags & PSF_IMAGE_NOTIFY_DONE_BIT) && (PsImageNotifyEnabled)) { /* It hasn't.. set up the image info for the process */ ImageInfo.Properties = 0; ImageInfo.ImageAddressingMode = IMAGE_ADDRESSING_MODE_32BIT; ImageInfo.ImageBase = Process->SectionBaseAddress; ImageInfo.ImageSize = 0; ImageInfo.ImageSelector = 0; ImageInfo.ImageSectionNumber = 0; /* Get the NT Headers */ NtHeader = RtlImageNtHeader(Process->SectionBaseAddress); if (NtHeader) { /* Set image size */ ImageInfo.ImageSize = NtHeader->OptionalHeader.SizeOfImage; } /* Get the image name */ Status = MmGetFileNameForSection(Process->SectionObject, &ModuleName); if (NT_SUCCESS(Status)) { /* Call the notify routines and free the name */ PspRunLoadImageNotifyRoutines(&ModuleName->Name, Process->UniqueProcessId, &ImageInfo); ExFreePool(ModuleName); } else { /* Call the notify routines */ PspRunLoadImageNotifyRoutines(NULL, Process->UniqueProcessId, &ImageInfo); } /* Setup the info for ntdll.dll */ ImageInfo.Properties = 0; ImageInfo.ImageAddressingMode = IMAGE_ADDRESSING_MODE_32BIT; ImageInfo.ImageBase = PspSystemDllBase; ImageInfo.ImageSize = 0; ImageInfo.ImageSelector = 0; ImageInfo.ImageSectionNumber = 0; /* Get the NT Headers */ NtHeader = RtlImageNtHeader(PspSystemDllBase); if (NtHeader) { /* Set image size */ ImageInfo.ImageSize = NtHeader->OptionalHeader.SizeOfImage; } /* Call the notify routines */ RtlInitUnicodeString(&NtDllName, L"\\SystemRoot\\System32\\ntdll.dll"); PspRunLoadImageNotifyRoutines(&NtDllName, Process->UniqueProcessId, &ImageInfo); } // // 这里才真的关于调试部分的代码 // DebugPort = Process->DebugPort; if (!DebugPort) return; // // 如果调试设置了创建进程通知消息 // if (!(ProcessFlags & PSF_CREATE_REPORTED_BIT)) { // // CreateProcess 是R0这边传递调试消息的主要结构. 既然是创建进程 // 那么线程当然都是空了 // CreateProcess->InitialThread.SubSystemKey = 0; CreateProcess->InitialThread.StartAddress = NULL; // // 填写新进程的句柄 // CreateProcess->SubSystemKey = 0; CreateProcess->FileHandle = DbgkpSectionToFileHandle(Process-> SectionObject); // // 其他一些信息 // CreateProcess->BaseOfImage = Process->SectionBaseAddress; CreateProcess->DebugInfoFileOffset = 0; CreateProcess->DebugInfoSize = 0; // // 这些信息其实也不重要, 程序入口, 符号表的地址和数量 // NtHeader = RtlImageNtHeader(Process->SectionBaseAddress); if (NtHeader) { // // 根据PE信息获取入口 // CreateProcess->InitialThread.StartAddress = (PVOID)((ULONG_PTR)NtHeader->OptionalHeader.ImageBase + NtHeader->OptionalHeader.AddressOfEntryPoint); // // 获取调试信息表地址 // CreateProcess->DebugInfoFileOffset = NtHeader->FileHeader. PointerToSymbolTable; // // 获取调试信息的数量 // CreateProcess->DebugInfoSize = NtHeader->FileHeader. NumberOfSymbols; } // 这边开始设置 ApiMessage.h.u1.Length = sizeof(DBGKM_MSG) << 16 | (8 + sizeof(DBGKM_CREATE_PROCESS)); ApiMessage.h.u2.ZeroInit = 0; ApiMessage.h.u2.s2.Type = LPC_DEBUG_EVENT; ApiMessage.ApiNumber = DbgKmCreateProcessApi; // // 这个函数是内核里面分发调试消息的主要函数了, 后面一个参数表示 // 是否要冻结进程的所有线程 // DbgkpSendApiMessage(&ApiMessage, FALSE); // // 内核这边其实会给R3关闭句柄, 所以R3那边其实不用操心的 // ObCloseHandle(CreateProcess->FileHandle, KernelMode); // // 我们看到, 其实创建进程的时候, 默认就会发送nt.dll的LoadDll消息 // LoadDll->BaseOfDll = PspSystemDllBase; LoadDll->DebugInfoFileOffset = 0; LoadDll->DebugInfoSize = 0; LoadDll->NamePointer = NULL; // // 获取nt.dll的调试符号偏移和大小. PspSystemDllBase真神奇 // NtHeader = RtlImageNtHeader(PspSystemDllBase); if (NtHeader) { /* Fill out debug information */ LoadDll->DebugInfoFileOffset = NtHeader-> FileHeader.PointerToSymbolTable; LoadDll->DebugInfoSize = NtHeader->FileHeader.NumberOfSymbols; } // // 保存一点nt.dll的信息 // Teb = Thread->Tcb.Teb; if (Teb) { /* Copy the system library name and link to it */ wcsncpy(Teb->StaticUnicodeBuffer, L"ntdll.dll", sizeof(Teb->StaticUnicodeBuffer) / sizeof(WCHAR)); Teb->NtTib.ArbitraryUserPointer = Teb->StaticUnicodeBuffer; /* Return it in the debug event as well */ LoadDll->NamePointer = &Teb->NtTib.ArbitraryUserPointer; } // // 获取nt.dll的句柄 // InitializeObjectAttributes(&ObjectAttributes, &PsNtDllPathName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE | OBJ_FORCE_ACCESS_CHECK, NULL, NULL); Status = ZwOpenFile(&LoadDll->FileHandle, GENERIC_READ | SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT); if (NT_SUCCESS(Status)) { // // 句柄也有了. 有酒有肉了. 可以发送DLL加载消息了 // ApiMessage.h.u1.Length = sizeof(DBGKM_MSG) << 16 | (8 + sizeof(DBGKM_LOAD_DLL)); ApiMessage.h.u2.ZeroInit = 0; ApiMessage.h.u2.s2.Type = LPC_DEBUG_EVENT; ApiMessage.ApiNumber = DbgKmLoadDllApi; /* Send the message */ DbgkpSendApiMessage(&ApiMessage, TRUE); // // 同样的, R3不需要关闭句柄, 以前真是纠结啊. // ObCloseHandle(LoadDll->FileHandle, KernelMode); } } else { // // 如果不是首次创建进程, 那么也好办, 直接发送线程创建消息就可以了 // CreateThread->SubSystemKey = 0; CreateThread->StartAddress = StartAddress; /* Setup the API Message */ ApiMessage.h.u1.Length = sizeof(DBGKM_MSG) << 16 | (8 + sizeof(DBGKM_CREATE_THREAD)); ApiMessage.h.u2.ZeroInit = 0; ApiMessage.h.u2.s2.Type = LPC_DEBUG_EVENT; ApiMessage.ApiNumber = DbgKmCreateThreadApi; /* Send the message */ DbgkpSendApiMessage(&ApiMessage, TRUE); } } NTSTATUS NTAPI DbgkpSendApiMessage(IN OUT PDBGKM_MSG ApiMsg, IN BOOLEAN SuspendProcess) { NTSTATUS Status; BOOLEAN Suspended = FALSE; PAGED_CODE(); // 看看是否需要挂起整个线程. if (SuspendProcess) { Suspended = DbgkpSuspendProcess(); } // // 将调试包设置成忙状态 // ApiMsg->ReturnedStatus = STATUS_PENDING; // // 设置进程的PSF_CREATE_REPORTED_BIT位 // PspSetProcessFlag(PsGetCurrentProcess(), PSF_CREATE_REPORTED_BIT); // // 将调试消息插入队列中 // Status = DbgkpQueueMessage(PsGetCurrentProcess(), PsGetCurrentThread(), ApiMsg, 0, NULL); // // 刷新指令缓存 // ZwFlushInstructionCache(NtCurrentProcess(), NULL, 0); // // 如果挂起了线程, 那么还需要重新恢复线程运行 // if (Suspended) { DbgkpResumeProcess(); } return Status; } NTSTATUS NTAPI DbgkpQueueMessage(IN PEPROCESS Process, IN PETHREAD Thread, IN PDBGKM_MSG Message, IN ULONG Flags, IN PDEBUG_OBJECT TargetObject OPTIONAL) { PDEBUG_EVENT DebugEvent; DEBUG_EVENT LocalDebugEvent; PDEBUG_OBJECT DebugObject; NTSTATUS Status; BOOLEAN NewEvent; PAGED_CODE(); // // 检测是否需要分配调试事件句柄, 根据调试, 从来就没有进来过. 忽略 // NewEvent = (Flags & DEBUG_EVENT_NOWAIT) ? TRUE : FALSE; if (NewEvent) { /* Allocate it */ DebugEvent = ExAllocatePoolWithTag(NonPagedPool, sizeof(DEBUG_EVENT), 'EgbD'); if (!DebugEvent) return STATUS_INSUFFICIENT_RESOURCES; /* Set flags */ DebugEvent->Flags = Flags | DEBUG_EVENT_INACTIVE; /* Reference the thread and process */ ObReferenceObject(Thread); ObReferenceObject(Process); /* Set the current thread */ DebugEvent->BackoutThread = PsGetCurrentThread(); /* Set the debug object */ DebugObject = TargetObject; } else { /* Use the debug event on the stack */ DebugEvent = &LocalDebugEvent; DebugEvent->Flags = Flags; // // 获取调试消息发送自旋锁 // ExAcquireFastMutex(&DbgkpProcessDebugPortMutex); // 调试对象 DebugObject = Process->DebugPort; // // 这里检测是否要跳过某些消息, 显然是没有什么用的. // switch (Message->ApiNumber) { /* Process or thread creation */ case DbgKmCreateThreadApi: case DbgKmCreateProcessApi: /* Make sure we're not skipping creation messages */ if (Thread->SkipCreationMsg) DebugObject = NULL; break; /* Process or thread exit */ case DbgKmExitThreadApi: case DbgKmExitProcessApi: /* Make sure we're not skipping exit messages */ if (Thread->SkipTerminationMsg) DebugObject = NULL; /* No special handling for other messages */ default: break; } } // // 初始化调试信息发送完成事件 // KeInitializeEvent(&DebugEvent->ContinueEvent, SynchronizationEvent, FALSE); DebugEvent->Process = Process; DebugEvent->Thread = Thread; DebugEvent->ApiMsg = *Message; DebugEvent->ClientId = Thread->Cid; // // 检测调试端口是否正常 // if (!DebugObject) { /* Fail */ Status = STATUS_PORT_NOT_SET; } else { // // 这是进程内调试对象获取的自旋锁 // ExAcquireFastMutex(&DebugObject->Mutex); // // 检测调试器目前是否激活 // if (!DebugObject->DebuggerInactive) { // // 插入进程的调试端口事件链表 // InsertTailList(&DebugObject->EventList, &DebugEvent->EventList); // // 事件置位, 这是干什么用的事件呢? // if (!NewEvent) { /* Signal it */ KeSetEvent(&DebugObject->EventsPresent, IO_NO_INCREMENT, FALSE); } /* Set success */ Status = STATUS_SUCCESS; } else { // // 没有调试 // Status = STATUS_DEBUGGER_INACTIVE; } /* Release the object lock */ ExReleaseFastMutex(&DebugObject->Mutex); } /* Check if we had acquired the port lock */ if (!NewEvent) { // // 这里释放快速互斥锁 // ExReleaseFastMutex(&DbgkpProcessDebugPortMutex); /* Check if we got here through success */ if (NT_SUCCESS(Status)) { // // 等待R3那边过来取消息 // KeWaitForSingleObject(&DebugEvent->ContinueEvent, Executive, KernelMode, FALSE, NULL); /* Copy API Message back */ *Message = DebugEvent->ApiMsg; /* Set return status */ Status = DebugEvent->Status; } } else { /* Check if we failed */ if (!NT_SUCCESS(Status)) { /* Dereference the process and thread */ ObDereferenceObject(Thread); ObDereferenceObject(Process); /* Free the debug event */ ExFreePool(DebugEvent); } } return Status; }
发表评论
Warning: Undefined variable $user_ID in /www/wwwroot/joenchen.com/wp-content/themes/x-agan/comments.php on line 66
您必须登录 才能进行评论。