FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

GitHub Viewer

#include "debug.h" #include "tools.h" #include "struct.h" #include POBJECT_TYPE DbgkDebugObjectType = NULL; FAST_MUTEX DbgkpProcessDebugPortMutex; PsGetNextProcessThreadProc PsGetNextProcessThread = NULL; MmGetFileNameForAddressProc MmGetFileNameForAddress = NULL; //KeAcquireQueuedSpinLockRaiseToSynchProc KeAcquireQueuedSpinLockRaiseToSynch = NULL;; KiWaitTestProc KiWaitTest = NULL;; KiUnlockDispatcherDatabaseProc KiUnlockDispatcherDatabase = NULL; KeAcquireQueuedSpinLockAtDpcLevelProc KeAcquireQueuedSpinLockAtDpcLevel = NULL; KeReleaseQueuedSpinLockFromDpcLevelProc KeReleaseQueuedSpinLockFromDpcLevel = NULL; KiInsertQueueApcProc KiInsertQueueApc = NULL; BOOLEAN initDebugVar() { //³õʼ»¯Ëø ExInitializeFastMutex(&DbgkpProcessDebugPortMutex); BOOLEAN isSuccess = FALSE; do { FindCode findCodes[3] = { 0 }; if (DbgkDebugObjectType == NULL) { initFindCodeStruct(&findCodes[0], "e9****8d45*5053536a*53ff75*ff75*ff35****ff75*e8****3bc30f*****8b45*33f6468970*8958*8958*c6***c6", 0, 0x16); DbgkDebugObjectType = (POBJECT_TYPE) (*(PULONG)(*(PULONG)(FindAddressByCode(findCodes, 1)))); KDP("DbgkDebugObjectType %x\r\n", DbgkDebugObjectType); if (DbgkDebugObjectType == NULL) { break; } } if (PsGetNextProcessThread == NULL) { initFindCodeStruct(&findCodes[0], "FF8B****8D77*8B0E83E1*8D51*8BC1F00FB1163BC10F85****8B45*85C074*8BB8", 0, -0x14); PsGetNextProcessThread = (PsGetNextProcessThreadProc)FindAddressByCode(findCodes, 1); KDP("PsGetNextProcessThread %x\r\n", PsGetNextProcessThread); if (PsGetNextProcessThread == NULL) { break; } } if (MmGetFileNameForAddress == NULL) { initFindCodeStruct(&findCodes[0], "8B4D*E8****85C075*BF****EB*8B50*B9****23D13BD174*8B40*85C074", 0, -0x20); MmGetFileNameForAddress = (POBJECT_TYPE)FindAddressByCode(findCodes, 1); KDP("MmGetFileNameForAddress %x\r\n", MmGetFileNameForAddress); if (MmGetFileNameForAddress == NULL) { break; } } if (KiWaitTest == NULL) { initFindCodeStruct(&findCodes[0], "33C9FF15****8B4D*8845*8D81****8A100FBEF285F674*FECA881075*80B9", 0, -7); ULONG func = FindAddressByCode(findCodes, 1); if (func == 0) { break; } //KeAcquireQueuedSpinLockRaiseToSynch = (KeAcquireQueuedSpinLockRaiseToSynchProc)(*(PULONG)(*(PULONG)(func + 0xb))); KiWaitTest = (KiInsertQueueApcProc)GetFunctionAddressByCodeAddress(func + 0x41); KiUnlockDispatcherDatabase = (KiUnlockDispatcherDatabaseProc)GetFunctionAddressByCodeAddress(func + 0x49); KDP("KiWaitTest %x\r\n", KiWaitTest); KDP("KiUnlockDispatcherDatabase %x\r\n", KiUnlockDispatcherDatabase); } if (KeAcquireQueuedSpinLockAtDpcLevel == NULL) { initFindCodeStruct(&findCodes[0], "8D8E****8D55*FF15****64A1****8D88****E8****0FBEBE****83FF*8B1D****0F84****80BE*****75", 0, -0xE); ULONG func = FindAddressByCode(findCodes, 1); if (func == 0) { break; } KeAcquireQueuedSpinLockAtDpcLevel = (KeAcquireQueuedSpinLockAtDpcLevelProc)GetFunctionAddressByCodeAddress(func + 0x29); KiInsertQueueApc = (KiWaitTestProc)GetFunctionAddressByCodeAddress(func + 0x68); KeReleaseQueuedSpinLockFromDpcLevel = (KeReleaseQueuedSpinLockFromDpcLevelProc)GetFunctionAddressByCodeAddress(func + 0x81); KDP("KeAcquireQueuedSpinLockAtDpcLevel %x\r\n", KeAcquireQueuedSpinLockAtDpcLevel); KDP("KiInsertQueueApc %x\r\n", KiInsertQueueApc); KDP("KeReleaseQueuedSpinLockFromDpcLevel %x\r\n", KeReleaseQueuedSpinLockFromDpcLevel); } //DbgBreakPoint(); isSuccess = TRUE; } while (0); return isSuccess; } int ExSystemExceptionFilter(VOID) { return(ExGetPreviousMode() != KernelMode ? EXCEPTION_EXECUTE_HANDLER: EXCEPTION_CONTINUE_SEARCH); } NTSTATUS NtCreateDebugObject( OUT PHANDLE DebugObjectHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, IN ULONG Flags ) { NTSTATUS Status = STATUS_SUCCESS; HANDLE Handle; KPROCESSOR_MODE PreviousMode; PDEBUG_OBJECT DebugObject = NULL; PAGED_CODE(); // // Get previous processor mode and probe output arguments if necessary. // Zero the handle for error paths. // PreviousMode = KeGetPreviousMode(); try { if (PreviousMode != KernelMode) { ProbeForWriteHandle(DebugObjectHandle); } *DebugObjectHandle = NULL; } except(ExSystemExceptionFilter()) { // If previous mode is kernel then don't handle the exception return GetExceptionCode(); } if (Flags & ~DEBUG_KILL_ON_CLOSE) { return STATUS_INVALID_PARAMETER; } // // Create a new debug object and initialize it. // //²éÕÒÌØÕ÷Âë Status = ObCreateObject(PreviousMode, DbgkDebugObjectType, ObjectAttributes, PreviousMode, NULL, sizeof(DEBUG_OBJECT), 0, 0, &DebugObject); if (!NT_SUCCESS(Status)) { return Status; } ExInitializeFastMutex(&DebugObject->Mutex); InitializeListHead(&DebugObject->EventList); KeInitializeEvent(&DebugObject->EventsPresent, NotificationEvent, FALSE); if (Flags & DEBUG_KILL_ON_CLOSE) { DebugObject->Flags = DEBUG_OBJECT_KILL_ON_CLOSE; } else { DebugObject->Flags = 0; } // // Insert the object into the handle table // Status = ObInsertObject(DebugObject, NULL, DesiredAccess, 0, NULL, &Handle); if (!NT_SUCCESS(Status)) { return Status; } try { *DebugObjectHandle = Handle; } except(ExSystemExceptionFilter()) { // // The caller changed the page protection or deleted the memory for the handle. // No point closing the handle as process rundown will do that and we don't know its still the same handle // Status = GetExceptionCode(); } return Status; } NTSTATUS NtDebugActiveProcess( IN HANDLE ProcessHandle, IN HANDLE DebugObjectHandle ) { NTSTATUS Status; KPROCESSOR_MODE PreviousMode; PDEBUG_OBJECT DebugObject; PMyEPROCESS Process; PETHREAD LastThread; PAGED_CODE(); PreviousMode = KeGetPreviousMode(); Status = ObReferenceObjectByHandle(ProcessHandle, PROCESS_SET_PORT, *PsProcessType, PreviousMode, &Process, NULL); if (!NT_SUCCESS(Status)) { return Status; } // // Don't let us debug ourselves or the system process. // if (Process == (PMyEPROCESS)PsGetCurrentProcess() || Process == (PMyEPROCESS)PsInitialSystemProcess) { ObDereferenceObject(Process); return STATUS_ACCESS_DENIED; } Status = ObReferenceObjectByHandle(DebugObjectHandle, DEBUG_PROCESS_ASSIGN, DbgkDebugObjectType, PreviousMode, &DebugObject, NULL); if (NT_SUCCESS(Status)) { // // We will be touching process address space. Block process rundown. // if (ExAcquireRundownProtection(&Process->RundownProtect)) { // // Post the fake process create messages etc. // Status = DbgkpPostFakeProcessCreateMessages(Process, DebugObject, &LastThread); // // Set the debug port. If this fails it will remove any faked messages. // Status = DbgkpSetProcessDebugObject(Process, DebugObject, Status, LastThread); ExReleaseRundownProtection(&Process->RundownProtect); } else { Status = STATUS_PROCESS_IS_TERMINATING; } ObDereferenceObject(DebugObject); } ObDereferenceObject(Process); return Status; } NTSTATUS DbgkpPostFakeProcessCreateMessages( IN PMyEPROCESS Process, IN PDEBUG_OBJECT DebugObject, IN PETHREAD *pLastThread ) { NTSTATUS Status; KAPC_STATE ApcState; PETHREAD Thread; PETHREAD LastThread; PAGED_CODE(); // // Attach to the process so we can touch its address space // KeStackAttachProcess(&Process->Pcb, &ApcState); Status = DbgkpPostFakeThreadMessages(Process, DebugObject, NULL, &Thread, &LastThread); if (NT_SUCCESS(Status)) { Status = DbgkpPostFakeModuleMessages(Process, Thread, DebugObject); if (!NT_SUCCESS(Status)) { ObDereferenceObject(LastThread); LastThread = NULL; } ObDereferenceObject(Thread); } else { LastThread = NULL; } KeUnstackDetachProcess(&ApcState); *pLastThread = LastThread; return Status; } NTSTATUS DbgkpSetProcessDebugObject( IN PMyEPROCESS Process, IN PDEBUG_OBJECT DebugObject, IN NTSTATUS MsgStatus, IN PMyETHREAD LastThread ) { NTSTATUS Status; PMyETHREAD ThisThread; LIST_ENTRY TempList; PLIST_ENTRY Entry; PDEBUG_EVENT DebugEvent; BOOLEAN First; PMyETHREAD Thread; BOOLEAN GlobalHeld; PMyETHREAD FirstThread; PAGED_CODE(); ThisThread = PsGetCurrentThread(); InitializeListHead(&TempList); First = TRUE; GlobalHeld = FALSE; if (!NT_SUCCESS(MsgStatus)) { LastThread = NULL; Status = MsgStatus; } else { Status = STATUS_SUCCESS; } // // Pick up any threads we missed // if (NT_SUCCESS(Status)) { while (1) { // // Acquire the debug port mutex so we know that any new threads will // have to wait to behind us. // GlobalHeld = TRUE; ExAcquireFastMutex(&DbgkpProcessDebugPortMutex); // // If the port has been set then exit now. // if (Process->DebugPort != NULL) { Status = STATUS_PORT_ALREADY_SET; break; } // // Assign the debug port to the process to pick up any new threads // Process->DebugPort = DebugObject; // // Reference the last thread so we can deref outside the lock // ObReferenceObject(LastThread); // // Search forward for new threads // Thread = PsGetNextProcessThread(Process, LastThread); if (Thread != NULL) { // // Remove the debug port from the process as we are // about to drop the lock // Process->DebugPort = NULL; ExReleaseFastMutex(&DbgkpProcessDebugPortMutex); GlobalHeld = FALSE; ObDereferenceObject(LastThread); // // Queue any new thread messages and repeat. // Status = DbgkpPostFakeThreadMessages(Process, DebugObject, Thread, &FirstThread, &LastThread); if (!NT_SUCCESS(Status)) { LastThread = NULL; break; } ObDereferenceObject(FirstThread); } else { break; } } } // // Lock the debug object so we can check its deleted status // ExAcquireFastMutex(&DebugObject->Mutex); // // We must not propagate a debug port thats got no handles left. // if (NT_SUCCESS(Status)) { if ((DebugObject->Flags&DEBUG_OBJECT_DELETE_PENDING) == 0) { PS_SET_BITS(&Process->Flags, PS_PROCESS_FLAGS_NO_DEBUG_INHERIT | PS_PROCESS_FLAGS_CREATE_REPORTED); ObReferenceObject(DebugObject); } else { Process->DebugPort = NULL; Status = STATUS_DEBUGGER_INACTIVE; } } for (Entry = DebugObject->EventList.Flink; Entry != &DebugObject->EventList; ) { DebugEvent = CONTAINING_RECORD(Entry, DEBUG_EVENT, EventList); Entry = Entry->Flink; if ((DebugEvent->Flags&DEBUG_EVENT_INACTIVE) != 0 && DebugEvent->BackoutThread == ThisThread) { Thread = DebugEvent->Thread; // // If the thread has not been inserted by CreateThread yet then don't // create a handle. We skip system threads here also // if (NT_SUCCESS(Status) && Thread->GrantedAccess != 0 && !IS_SYSTEM_THREAD(Thread)) { // // If we could not acquire rundown protection on this // thread then we need to suppress its exit message. // if ((DebugEvent->Flags&DEBUG_EVENT_PROTECT_FAILED) != 0) { PS_SET_BITS(&Thread->CrossThreadFlags, PS_CROSS_THREAD_FLAGS_SKIP_TERMINATION_MSG); RemoveEntryList(&DebugEvent->EventList); InsertTailList(&TempList, &DebugEvent->EventList); } else { if (First) { DebugEvent->Flags &= ~DEBUG_EVENT_INACTIVE; KeSetEvent(&DebugObject->EventsPresent, 0, FALSE); First = FALSE; } DebugEvent->BackoutThread = NULL; PS_SET_BITS(&Thread->CrossThreadFlags, PS_CROSS_THREAD_FLAGS_SKIP_CREATION_MSG); } } else { RemoveEntryList(&DebugEvent->EventList); InsertTailList(&TempList, &DebugEvent->EventList); } if (DebugEvent->Flags&DEBUG_EVENT_RELEASE) { DebugEvent->Flags &= ~DEBUG_EVENT_RELEASE; ExReleaseRundownProtection(&Thread->RundownProtect); } } } ExReleaseFastMutex(&DebugObject->Mutex); if (GlobalHeld) { ExReleaseFastMutex(&DbgkpProcessDebugPortMutex); } if (LastThread != NULL) { ObDereferenceObject(LastThread); } while (!IsListEmpty(&TempList)) { Entry = RemoveHeadList(&TempList); DebugEvent = CONTAINING_RECORD(Entry, DEBUG_EVENT, EventList); DbgkpWakeTarget(DebugEvent); } if (NT_SUCCESS(Status)) { DbgkpMarkProcessPeb(Process); } return Status; } NTSTATUS DbgkpPostFakeModuleMessages( IN PMyEPROCESS Process, IN PMyETHREAD Thread, IN PDEBUG_OBJECT DebugObject) { PMyPEB Peb = (PMyPEB)Process->Peb; PPEB_LDR_DATA Ldr; PLIST_ENTRY LdrHead, LdrNext; PLDR_DATA_TABLE_ENTRY LdrEntry; DBGKM_APIMSG ApiMsg; ULONG i; OBJECT_ATTRIBUTES oa; UNICODE_STRING Name; PIMAGE_NT_HEADERS NtHeaders; NTSTATUS Status; IO_STATUS_BLOCK iosb; PAGED_CODE(); if (Peb == NULL) { return STATUS_SUCCESS; } try { Ldr = Peb->Ldr; LdrHead = &Ldr->InLoadOrderModuleList; ProbeForReadSmallStructure(LdrHead, sizeof(LIST_ENTRY), sizeof(UCHAR)); for (LdrNext = LdrHead->Flink, i = 0; LdrNext != LdrHead && i < 500; LdrNext = LdrNext->Flink, i++) { // // First image got send with process create message // if (i > 0) { RtlZeroMemory(&ApiMsg, sizeof(ApiMsg)); LdrEntry = CONTAINING_RECORD(LdrNext, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); ProbeForReadSmallStructure(LdrEntry, sizeof(LDR_DATA_TABLE_ENTRY), sizeof(UCHAR)); ApiMsg.ApiNumber = DbgKmLoadDllApi; ApiMsg.u.LoadDll.BaseOfDll = LdrEntry->DllBase; ApiMsg.u.LoadDll.NamePointer = NULL; ProbeForReadSmallStructure(ApiMsg.u.LoadDll.BaseOfDll, sizeof(IMAGE_DOS_HEADER), sizeof(UCHAR)); NtHeaders = RtlImageNtHeader(ApiMsg.u.LoadDll.BaseOfDll); if (NtHeaders) { ApiMsg.u.LoadDll.DebugInfoFileOffset = NtHeaders->FileHeader.PointerToSymbolTable; ApiMsg.u.LoadDll.DebugInfoSize = NtHeaders->FileHeader.NumberOfSymbols; } Status = MmGetFileNameForAddress(NtHeaders, &Name); if (NT_SUCCESS(Status)) { InitializeObjectAttributes(&oa, &Name, OBJ_FORCE_ACCESS_CHECK | OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); Status = ZwOpenFile(&ApiMsg.u.LoadDll.FileHandle, GENERIC_READ | SYNCHRONIZE, &oa, &iosb, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_SYNCHRONOUS_IO_NONALERT); if (!NT_SUCCESS(Status)) { ApiMsg.u.LoadDll.FileHandle = NULL; } ExFreePool(Name.Buffer); } Status = DbgkpQueueMessage(Process, Thread, &ApiMsg, DEBUG_EVENT_NOWAIT, DebugObject); if (!NT_SUCCESS(Status) && ApiMsg.u.LoadDll.FileHandle != NULL) { ObCloseHandle(ApiMsg.u.LoadDll.FileHandle, KernelMode); } } ProbeForReadSmallStructure(LdrNext, sizeof(LIST_ENTRY), sizeof(UCHAR)); } } except(EXCEPTION_EXECUTE_HANDLER) { } return STATUS_SUCCESS; } VOID PsQuitNextProcessThread(IN PETHREAD Thread) { ObDereferenceObject(Thread); } NTSTATUS DbgkpPostFakeThreadMessages( IN PMyEPROCESS Process, IN PDEBUG_OBJECT DebugObject, IN PMyETHREAD StartThread, OUT PMyETHREAD *pFirstThread, OUT PMyETHREAD *pLastThread ) { NTSTATUS Status; PMyETHREAD Thread, FirstThread, LastThread; DBGKM_APIMSG ApiMsg; BOOLEAN First = TRUE; BOOLEAN IsFirstThread; PIMAGE_NT_HEADERS NtHeaders; ULONG Flags; NTSTATUS Status1; PAGED_CODE(); LastThread = FirstThread = NULL; Status = STATUS_UNSUCCESSFUL; if (StartThread != NULL) { First = FALSE; FirstThread = StartThread; ObReferenceObject(FirstThread); } else { StartThread = PsGetNextProcessThread(Process, NULL); First = TRUE; } for (Thread = StartThread; Thread != NULL; Thread = PsGetNextProcessThread(Process, Thread)) { Flags = DEBUG_EVENT_NOWAIT; // // Keep a track ont he last thread we have seen. // We use this as a starting point for new threads after we // really attach so we can pick up any new threads. // if (LastThread != NULL) { ObDereferenceObject(LastThread); } LastThread = Thread; ObReferenceObject(LastThread); // // Acquire rundown protection of the thread. // This stops the thread exiting so we know it can't send // it's termination message // if (ExAcquireRundownProtection(&Thread->RundownProtect)) { Flags |= DEBUG_EVENT_RELEASE; // // Suspend the thread if we can for the debugger // We don't suspend terminating threads as we will not be giving details // of these to the debugger. // if (!IS_SYSTEM_THREAD(Thread)) { Status1 = PsSuspendThread(Thread, NULL); if (NT_SUCCESS(Status1)) { Flags |= DEBUG_EVENT_SUSPEND; } } } else { // // Rundown protection failed for this thread. // This means the thread is exiting. We will mark this thread // later so it doesn't sent a thread termination message. // We can't do this now because this attach might fail. // Flags |= DEBUG_EVENT_PROTECT_FAILED; } RtlZeroMemory(&ApiMsg, sizeof(ApiMsg)); if (First && (Flags&DEBUG_EVENT_PROTECT_FAILED) == 0 && !IS_SYSTEM_THREAD(Thread) && Thread->GrantedAccess != 0) { IsFirstThread = TRUE; } else { IsFirstThread = FALSE; } if (IsFirstThread) { ApiMsg.ApiNumber = DbgKmCreateProcessApi; if (Process->SectionObject != NULL) { // system process doesn't have one of these! ApiMsg.u.CreateProcessInfo.FileHandle = DbgkpSectionToFileHandle(Process->SectionObject); } else { ApiMsg.u.CreateProcessInfo.FileHandle = NULL; } ApiMsg.u.CreateProcessInfo.BaseOfImage = Process->SectionBaseAddress; try { NtHeaders = RtlImageNtHeader(Process->SectionBaseAddress); if (NtHeaders) { ApiMsg.u.CreateProcessInfo.InitialThread.StartAddress = NULL; // Filling this in breaks MSDEV! // (PVOID)(NtHeaders->OptionalHeader.ImageBase + NtHeaders->OptionalHeader.AddressOfEntryPoint); ApiMsg.u.CreateProcessInfo.DebugInfoFileOffset = NtHeaders->FileHeader.PointerToSymbolTable; ApiMsg.u.CreateProcessInfo.DebugInfoSize = NtHeaders->FileHeader.NumberOfSymbols; } } except(EXCEPTION_EXECUTE_HANDLER) { ApiMsg.u.CreateProcessInfo.InitialThread.StartAddress = NULL; ApiMsg.u.CreateProcessInfo.DebugInfoFileOffset = 0; ApiMsg.u.CreateProcessInfo.DebugInfoSize = 0; } } else { ApiMsg.ApiNumber = DbgKmCreateThreadApi; ApiMsg.u.CreateThread.StartAddress = Thread->StartAddress; } Status = DbgkpQueueMessage(Process, Thread, &ApiMsg, Flags, DebugObject); if (!NT_SUCCESS(Status)) { if (Flags&DEBUG_EVENT_SUSPEND) { PsResumeThread(Thread, NULL); } if (Flags&DEBUG_EVENT_RELEASE) { ExReleaseRundownProtection(&Thread->RundownProtect); } if (ApiMsg.ApiNumber == DbgKmCreateProcessApi && ApiMsg.u.CreateProcessInfo.FileHandle != NULL) { ObCloseHandle(ApiMsg.u.CreateProcessInfo.FileHandle, KernelMode); } PsQuitNextProcessThread(Thread); break; } else if (IsFirstThread) { First = FALSE; ObReferenceObject(Thread); FirstThread = Thread; } } if (!NT_SUCCESS(Status)) { if (FirstThread) { ObDereferenceObject(FirstThread); } if (LastThread != NULL) { ObDereferenceObject(LastThread); } } else { if (FirstThread) { *pFirstThread = FirstThread; *pLastThread = LastThread; } else { Status = STATUS_UNSUCCESSFUL; } } return Status; } NTSTATUS DbgkpQueueMessage( IN PMyEPROCESS Process, IN PMyETHREAD Thread, IN OUT PDBGKM_APIMSG ApiMsg, IN ULONG Flags, IN PDEBUG_OBJECT TargetDebugObject ) { PDEBUG_EVENT DebugEvent; DEBUG_EVENT StaticDebugEvent; PDEBUG_OBJECT DebugObject; NTSTATUS Status; PAGED_CODE(); if (Flags&DEBUG_EVENT_NOWAIT) { DebugEvent = ExAllocatePoolWithQuotaTag(NonPagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE, sizeof(*DebugEvent), 'EgbD'); if (DebugEvent == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } DebugEvent->Flags = Flags | DEBUG_EVENT_INACTIVE; ObReferenceObject(Process); ObReferenceObject(Thread); DebugEvent->BackoutThread = PsGetCurrentThread(); DebugObject = TargetDebugObject; } else { DebugEvent = &StaticDebugEvent; DebugEvent->Flags = Flags; ExAcquireFastMutex(&DbgkpProcessDebugPortMutex); DebugObject = Process->DebugPort; // // See if this create message has already been sent. // if (ApiMsg->ApiNumber == DbgKmCreateThreadApi || ApiMsg->ApiNumber == DbgKmCreateProcessApi) { if (Thread->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_SKIP_CREATION_MSG) { DebugObject = NULL; } } // // See if this exit message is for a thread that never had a create // if (ApiMsg->ApiNumber == DbgKmExitThreadApi || ApiMsg->ApiNumber == DbgKmExitProcessApi) { if (Thread->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_SKIP_TERMINATION_MSG) { DebugObject = NULL; } } } KeInitializeEvent(&DebugEvent->ContinueEvent, SynchronizationEvent, FALSE); DebugEvent->Process = Process; DebugEvent->Thread = Thread; DebugEvent->ApiMsg = *ApiMsg; DebugEvent->ClientId = Thread->Cid; if (DebugObject == NULL) { Status = STATUS_PORT_NOT_SET; } else { // // We must not use a debug port thats got no handles left. // ExAcquireFastMutex(&DebugObject->Mutex); // // If the object is delete pending then don't use this object. // if ((DebugObject->Flags&DEBUG_OBJECT_DELETE_PENDING) == 0) { InsertTailList(&DebugObject->EventList, &DebugEvent->EventList); // // Set the event to say there is an unread event in the object // if ((Flags&DEBUG_EVENT_NOWAIT) == 0) { KeSetEvent(&DebugObject->EventsPresent, 0, FALSE); } Status = STATUS_SUCCESS; } else { Status = STATUS_DEBUGGER_INACTIVE; } ExReleaseFastMutex(&DebugObject->Mutex); } if ((Flags&DEBUG_EVENT_NOWAIT) == 0) { ExReleaseFastMutex(&DbgkpProcessDebugPortMutex); if (NT_SUCCESS(Status)) { KeWaitForSingleObject(&DebugEvent->ContinueEvent, Executive, KernelMode, FALSE, NULL); Status = DebugEvent->Status; *ApiMsg = DebugEvent->ApiMsg; } } else { if (!NT_SUCCESS(Status)) { ObDereferenceObject(Process); ObDereferenceObject(Thread); ExFreePool(DebugEvent); } } return Status; } VOID DbgkpMarkProcessPeb(PMyEPROCESS Process) { KAPC_STATE ApcState; PAGED_CODE(); // // Acquire process rundown protection as we are about to look at the processes address space // if (ExAcquireRundownProtection(&Process->RundownProtect)) { if (Process->Peb != NULL) { KeStackAttachProcess(&Process->Pcb, &ApcState); ExAcquireFastMutex(&DbgkpProcessDebugPortMutex); try { Process->Peb->BeingDebugged = (BOOLEAN)(Process->DebugPort != NULL ? TRUE : FALSE); } except(EXCEPTION_EXECUTE_HANDLER) { } ExReleaseFastMutex(&DbgkpProcessDebugPortMutex); KeUnstackDetachProcess(&ApcState); } ExReleaseRundownProtection(&Process->RundownProtect); } } VOID DbgkpWakeTarget(IN PDEBUG_EVENT DebugEvent) { PMyETHREAD Thread; Thread = DebugEvent->Thread; if ((DebugEvent->Flags&DEBUG_EVENT_SUSPEND) != 0) { PsResumeThread(DebugEvent->Thread, NULL); } if (DebugEvent->Flags&DEBUG_EVENT_RELEASE) { ExReleaseRundownProtection(&Thread->RundownProtect); } // // If we have an actual thread waiting then wake it up else free the memory. // if ((DebugEvent->Flags&DEBUG_EVENT_NOWAIT) == 0) { KeSetEvent(&DebugEvent->ContinueEvent, 0, FALSE); // Wake up waiting process } else { DbgkpFreeDebugEvent(DebugEvent); } //KeAcquireInStackQueuedSpinLockRaiseToSynch(NULL, NULL); } VOID DbgkpFreeDebugEvent(IN PDEBUG_EVENT DebugEvent) { NTSTATUS Status; PAGED_CODE(); switch (DebugEvent->ApiMsg.ApiNumber) { case DbgKmCreateProcessApi: if (DebugEvent->ApiMsg.u.CreateProcessInfo.FileHandle != NULL) { Status = ObCloseHandle(DebugEvent->ApiMsg.u.CreateProcessInfo.FileHandle, KernelMode); } break; case DbgKmLoadDllApi: if (DebugEvent->ApiMsg.u.LoadDll.FileHandle != NULL) { Status = ObCloseHandle(DebugEvent->ApiMsg.u.LoadDll.FileHandle, KernelMode); } break; } ObDereferenceObject(DebugEvent->Process); ObDereferenceObject(DebugEvent->Thread); ExFreePool(DebugEvent); } #define ASSERT_THREAD(object) ASSERT((object)->Header.Type == ThreadObject) #define ALERT_INCREMENT 2 // Alerted unwait priority increment #define BALANCE_INCREMENT 10 // Balance set priority increment #define RESUME_INCREMENT 0 // Resume thread priority increment #define TIMER_EXPIRE_INCREMENT 0 // Timer expiration priority increment ULONG KeResumeThread(__inout PMyETHREAD Thread) { KIRQL irql =KeAcquireQueuedSpinLockRaiseToSynch(0); ULONG count = Thread->Tcb.SuspendCount; do { if (count == 0) { break; } count--; Thread->Tcb.SuspendCount = count; if (count != 0) break; if (Thread->Tcb.FreezeCount != 0) break; Thread->Tcb.SuspendSemaphore.Header.SignalState += 1; KiWaitTest(&Thread->Tcb.SuspendSemaphore, 0); } while (0); KiUnlockDispatcherDatabase(irql); return count; } NTSTATUS PsResumeThread(IN PMyETHREAD Thread, OUT PULONG PreviousSuspendCount OPTIONAL) { ULONG LocalPreviousSuspendCount; PAGED_CODE(); LocalPreviousSuspendCount = (ULONG)KeResumeThread(&Thread->Tcb); if (ARGUMENT_PRESENT(PreviousSuspendCount)) { *PreviousSuspendCount = LocalPreviousSuspendCount; } return STATUS_SUCCESS; } ULONG KeSuspendThread(__inout PKTHREAD Thread) { PMyETHREAD ct = (PMyETHREAD)Thread; KLOCK_QUEUE_HANDLE lockHandle = {0}; KeAcquireInStackQueuedSpinLockRaiseToSynch(&ct->Tcb.ApcQueueLock, &lockHandle); PKPCR kpcr = GetCurrentKpcr(); KeAcquireQueuedSpinLockAtDpcLevel(kpcr->Prcb->LockQueue); ULONG count = ct->Tcb.SuspendCount; if (count == 0x7F) { KeReleaseQueuedSpinLockFromDpcLevel(kpcr->Prcb->LockQueue); KeReleaseInStackQueuedSpinLock(&lockHandle); ExRaiseStatus(STATUS_SUSPEND_COUNT_EXCEEDED); } if (ct->Tcb.ApcQueueable == TRUE) { ct->Tcb.SuspendCount += 1; if (count == 0 && ct->Tcb.FreezeCount == 0) { if (!KiInsertQueueApc(&ct->Tcb.SuspendApc, 0)) { ct->Tcb.SuspendSemaphore.Header.SignalState -= 1; } } } KeReleaseQueuedSpinLockFromDpcLevel(kpcr->Prcb->LockQueue); KeReleaseInStackQueuedSpinLock(&lockHandle); return count; } ULONG KeForceResumeThread(__inout PKTHREAD Thread) { PMyETHREAD ct = (PMyETHREAD)Thread; KIRQL irql = KeAcquireQueuedSpinLockRaiseToSynch(0); ULONG count = ct->Tcb.SuspendCount; ULONG fzcount = ct->Tcb.FreezeCount; count += fzcount; do { if (count == 0) { break; } ct->Tcb.SuspendSemaphore.Header.SignalState += 1; ct->Tcb.FreezeCount = 0; ct->Tcb.SuspendCount = 0; KiWaitTest(&ct->Tcb.SuspendSemaphore, 0); } while (0); KiUnlockDispatcherDatabase(irql); return count; } NTSTATUS PsSuspendThread(IN PMyETHREAD Thread,OUT PULONG PreviousSuspendCount OPTIONAL) { NTSTATUS Status; ULONG LocalPreviousSuspendCount = 0; PAGED_CODE(); if (Thread == PsGetCurrentThread()) { try { LocalPreviousSuspendCount = (ULONG)KeSuspendThread(&Thread->Tcb); Status = STATUS_SUCCESS; } except((GetExceptionCode() == STATUS_SUSPEND_COUNT_EXCEEDED) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { Status = GetExceptionCode(); } } else { // // Protect the remote thread from being rundown. // if (ExAcquireRundownProtection(&Thread->RundownProtect)) { // // Don't allow suspend if we are being deleted // if (Thread->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_TERMINATED) { Status = STATUS_THREAD_IS_TERMINATING; } else { try { LocalPreviousSuspendCount = (ULONG)KeSuspendThread(&Thread->Tcb); Status = STATUS_SUCCESS; } except((GetExceptionCode() == STATUS_SUSPEND_COUNT_EXCEEDED) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { Status = GetExceptionCode(); } // // If deletion was started after we suspended then wake up the thread // if (Thread->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_TERMINATED) { KeForceResumeThread(&Thread->Tcb); LocalPreviousSuspendCount = 0; Status = STATUS_THREAD_IS_TERMINATING; } } ExReleaseRundownProtection(&Thread->RundownProtect); } else { Status = STATUS_THREAD_IS_TERMINATING; } } if (ARGUMENT_PRESENT(PreviousSuspendCount)) { *PreviousSuspendCount = LocalPreviousSuspendCount; } return Status; } HANDLE DbgkpSectionToFileHandle(IN PVOID SectionObject) { NTSTATUS Status; OBJECT_ATTRIBUTES Obja; IO_STATUS_BLOCK IoStatusBlock; HANDLE Handle; POBJECT_NAME_INFORMATION FileNameInfo; PAGED_CODE(); Status = MmGetFileNameForSection(SectionObject, &FileNameInfo); if (!NT_SUCCESS(Status)) { return NULL; } InitializeObjectAttributes( &Obja, &FileNameInfo->Name, OBJ_CASE_INSENSITIVE | OBJ_FORCE_ACCESS_CHECK | OBJ_KERNEL_HANDLE, NULL, NULL ); Status = ZwOpenFile( &Handle, (ACCESS_MASK)(GENERIC_READ | SYNCHRONIZE), &Obja, &IoStatusBlock, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT ); ExFreePool(FileNameInfo); if (!NT_SUCCESS(Status)) { return NULL; } else { return Handle; } } NTSTATUS MmGetFileNameForSection(IN PSECTION SectionObject,OUT POBJECT_NAME_INFORMATION *FileNameInfo) { ULONG NumberOfBytes; ULONG AdditionalLengthNeeded; NTSTATUS Status; PFILE_OBJECT FileObject; NumberOfBytes = 1024; *FileNameInfo = NULL; if (SectionObject->u.Flags.Image == 0) { return STATUS_SECTION_NOT_IMAGE; } *FileNameInfo = ExAllocatePoolWithTag(PagedPool, NumberOfBytes, ' mM'); if (*FileNameInfo == NULL) { return STATUS_NO_MEMORY; } FileObject = SectionObject->Segment->ControlArea->FilePointer; Status = ObQueryNameString(FileObject, *FileNameInfo, NumberOfBytes, &AdditionalLengthNeeded); if (!NT_SUCCESS(Status)) { if (Status == STATUS_INFO_LENGTH_MISMATCH) { // // Our buffer was not large enough, retry just once with a larger // one (as specified by ObQuery). Don't try more than once to // prevent broken parse procedures which give back wrong // AdditionalLengthNeeded values from causing problems. // ExFreePool(*FileNameInfo); NumberOfBytes += AdditionalLengthNeeded; *FileNameInfo = ExAllocatePoolWithTag(PagedPool, NumberOfBytes, ' mM'); if (*FileNameInfo == NULL) { return STATUS_NO_MEMORY; } Status = ObQueryNameString(FileObject, *FileNameInfo, NumberOfBytes, &AdditionalLengthNeeded); if (NT_SUCCESS(Status)) { return STATUS_SUCCESS; } } ExFreePool(*FileNameInfo); *FileNameInfo = NULL; return Status; } return STATUS_SUCCESS; } NTSTATUS NtRemoveProcessDebug(IN HANDLE ProcessHandle,IN HANDLE DebugObjectHandle) { NTSTATUS Status; KPROCESSOR_MODE PreviousMode; PDEBUG_OBJECT DebugObject; PEPROCESS Process; PAGED_CODE(); PreviousMode = KeGetPreviousMode(); Status = ObReferenceObjectByHandle(ProcessHandle, PROCESS_SET_PORT, *PsProcessType, PreviousMode, &Process, NULL); if (!NT_SUCCESS(Status)) { return Status; } Status = ObReferenceObjectByHandle(DebugObjectHandle, DEBUG_PROCESS_ASSIGN, DbgkDebugObjectType, PreviousMode, &DebugObject, NULL); if (NT_SUCCESS(Status)) { Status = DbgkClearProcessDebugObject(Process, DebugObject); ObDereferenceObject(DebugObject); } ObDereferenceObject(Process); return Status; } NTSTATUS DbgkClearProcessDebugObject(IN PMyEPROCESS Process,IN PDEBUG_OBJECT SourceDebugObject) { NTSTATUS Status; PDEBUG_OBJECT DebugObject; PDEBUG_EVENT DebugEvent; LIST_ENTRY TempList; PLIST_ENTRY Entry; PAGED_CODE(); ExAcquireFastMutex(&DbgkpProcessDebugPortMutex); DebugObject = Process->DebugPort; if (DebugObject == NULL || (DebugObject != SourceDebugObject && SourceDebugObject != NULL)) { DebugObject = NULL; Status = STATUS_PORT_NOT_SET; } else { Process->DebugPort = NULL; Status = STATUS_SUCCESS; } ExReleaseFastMutex(&DbgkpProcessDebugPortMutex); if (NT_SUCCESS(Status)) { DbgkpMarkProcessPeb(Process); } // // Remove any events for this process and wake up the threads. // if (DebugObject) { // // Remove any events and queue them to a temporary queue // InitializeListHead(&TempList); ExAcquireFastMutex(&DebugObject->Mutex); for (Entry = DebugObject->EventList.Flink; Entry != &DebugObject->EventList; ) { DebugEvent = CONTAINING_RECORD(Entry, DEBUG_EVENT, EventList); Entry = Entry->Flink; if (DebugEvent->Process == Process) { RemoveEntryList(&DebugEvent->EventList); InsertTailList(&TempList, &DebugEvent->EventList); } } ExReleaseFastMutex(&DebugObject->Mutex); ObDereferenceObject(DebugObject); // // Wake up all the removed threads. // while (!IsListEmpty(&TempList)) { Entry = RemoveHeadList(&TempList); DebugEvent = CONTAINING_RECORD(Entry, DEBUG_EVENT, EventList); DebugEvent->Status = STATUS_DEBUGGER_INACTIVE; DbgkpWakeTarget(DebugEvent); } } return Status; }

Back | FazBrowse Home | New Git URL