#include "dbgkp.h"
#pragma hdrstop
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, DbgkInitialize)
#pragma alloc_text(PAGE, NtCreateDebugObject)
#pragma alloc_text(PAGE, NtDebugActiveProcess)
#pragma alloc_text(PAGE, NtRemoveProcessDebug)
#pragma alloc_text(PAGE, NtWaitForDebugEvent)
#pragma alloc_text(PAGE, NtDebugContinue)
#pragma alloc_text(PAGE, NtSetInformationDebugObject)
#pragma alloc_text(PAGE, DbgkpDeleteObject)
#pragma alloc_text(PAGE, DbgkpCloseObject)
#pragma alloc_text(PAGE, DbgkCopyProcessDebugPort)
#pragma alloc_text(PAGE, DbgkOpenProcessDebugPort)
#pragma alloc_text(PAGE, DbgkpSetProcessDebugObject)
#pragma alloc_text(PAGE, DbgkpQueueMessage)
#pragma alloc_text(PAGE, DbgkpOpenHandles)
#pragma alloc_text(PAGE, DbgkClearProcessDebugObject)
#pragma alloc_text(PAGE, DbgkpConvertKernelToUserStateChange)
#pragma alloc_text(PAGE, DbgkpMarkProcessPeb)
#pragma alloc_text(PAGE, DbgkpFreeDebugEvent)
#pragma alloc_text(PAGE, DbgkpPostFakeProcessCreateMessages)
#pragma alloc_text(PAGE, DbgkpPostFakeModuleMessages)
#pragma alloc_text(PAGE, DbgkpPostFakeThreadMessages)
#pragma alloc_text(PAGE, DbgkpWakeTarget)
#pragma alloc_text(PAGE, DbgkpPostAdditionalThreadMessages)
#endif
FAST_MUTEX DbgkpProcessDebugPortMutex;
POBJECT_TYPE DbgkDebugObjectType = NULL;
NTSTATUS
DbgkInitialize (
VOID
)
{
NTSTATUS Status;
UNICODE_STRING Name;
OBJECT_TYPE_INITIALIZER oti = {0};
GENERIC_MAPPING GenericMapping = {STANDARD_RIGHTS_READ | DEBUG_READ_EVENT,
STANDARD_RIGHTS_WRITE | DEBUG_PROCESS_ASSIGN,
STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE,
DEBUG_ALL_ACCESS};
PAGED_CODE ();
ExInitializeFastMutex (&DbgkpProcessDebugPortMutex);
RtlInitUnicodeString (&Name, L
"DebugObject"
);
oti.Length =
sizeof
(oti);
oti.SecurityRequired = TRUE;
oti.InvalidAttributes = 0;
oti.PoolType = NonPagedPool;
oti.DeleteProcedure = DbgkpDeleteObject;
oti.CloseProcedure = DbgkpCloseObject;
oti.ValidAccessMask = DEBUG_ALL_ACCESS;
oti.GenericMapping = GenericMapping;
oti.DefaultPagedPoolCharge = 0;
oti.DefaultNonPagedPoolCharge = 0;
Status = ObCreateObjectType (&Name, &oti, NULL, &DbgkDebugObjectType);
if
(!NT_SUCCESS (Status)) {
return
Status;
}
return
Status;
}
VOID
DbgkpDeleteObject (
IN
PVOID
Object
)
{
#if DBG
PDEBUG_OBJECT DebugObject;
#endif
PAGED_CODE();
#if DBG
DebugObject = Object;
ASSERT (IsListEmpty (&DebugObject->EventList));
#else
UNREFERENCED_PARAMETER(Object);
#endif
}
VOID
DbgkpMarkProcessPeb (
PEPROCESS Process
)
{
KAPC_STATE ApcState;
PAGED_CODE ();
if
(ExAcquireRundownProtection (&Process->RundownProtect)) {
if
(Process->Peb != NULL) {
KeStackAttachProcess(&Process->Pcb, &ApcState);
ExAcquireFastMutex (&DbgkpProcessDebugPortMutex);
try
{
Process->Peb->BeingDebugged = (
BOOLEAN
)(Process->DebugPort != NULL ? TRUE : FALSE);
#if defined(_WIN64)
if
(Process->Wow64Process != NULL) {
PPEB32 Peb32 = (PPEB32)Process->Wow64Process->Wow64;
if
(Peb32 != NULL) {
Peb32->BeingDebugged = Process->Peb->BeingDebugged;
}
}
#endif
} except (EXCEPTION_EXECUTE_HANDLER) {
}
ExReleaseFastMutex (&DbgkpProcessDebugPortMutex);
KeUnstackDetachProcess(&ApcState);
}
ExReleaseRundownProtection (&Process->RundownProtect);
}
}
VOID
DbgkpWakeTarget (
IN PDEBUG_EVENT DebugEvent
)
{
PETHREAD 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
((DebugEvent->Flags&DEBUG_EVENT_NOWAIT) == 0) {
KeSetEvent (&DebugEvent->ContinueEvent, 0, FALSE);
}
else
{
DbgkpFreeDebugEvent (DebugEvent);
}
}
VOID
DbgkpCloseObject (
IN PEPROCESS Process,
IN
PVOID
Object,
IN ACCESS_MASK GrantedAccess,
IN
ULONG_PTR
ProcessHandleCount,
IN
ULONG_PTR
SystemHandleCount
)
{
PDEBUG_OBJECT DebugObject = Object;
PDEBUG_EVENT DebugEvent;
PLIST_ENTRY ListPtr;
BOOLEAN
Deref;
PAGED_CODE ();
UNREFERENCED_PARAMETER (GrantedAccess);
UNREFERENCED_PARAMETER (ProcessHandleCount);
if
(SystemHandleCount > 1) {
return
;
}
ExAcquireFastMutex (&DebugObject->Mutex);
DebugObject->Flags |= DEBUG_OBJECT_DELETE_PENDING;
ListPtr = DebugObject->EventList.Flink;
InitializeListHead (&DebugObject->EventList);
ExReleaseFastMutex (&DebugObject->Mutex);
KeSetEvent (&DebugObject->EventsPresent, 0, FALSE);
for
(Process = PsGetNextProcess (NULL);
Process != NULL;
Process = PsGetNextProcess (Process)) {
if
(Process->DebugPort == DebugObject) {
Deref = FALSE;
ExAcquireFastMutex (&DbgkpProcessDebugPortMutex);
if
(Process->DebugPort == DebugObject) {
Process->DebugPort = NULL;
Deref = TRUE;
}
ExReleaseFastMutex (&DbgkpProcessDebugPortMutex);
if
(Deref) {
DbgkpMarkProcessPeb (Process);
if
(DebugObject->Flags&DEBUG_OBJECT_KILL_ON_CLOSE) {
PsTerminateProcess (Process, STATUS_DEBUGGER_INACTIVE);
}
ObDereferenceObject (DebugObject);
}
}
}
while
(ListPtr != &DebugObject->EventList) {
DebugEvent = CONTAINING_RECORD (ListPtr, DEBUG_EVENT, EventList);
ListPtr = ListPtr->Flink;
DebugEvent->Status = STATUS_DEBUGGER_INACTIVE;
DbgkpWakeTarget (DebugEvent);
}
}
VOID
DbgkCopyProcessDebugPort (
IN PEPROCESS TargetProcess,
IN PEPROCESS SourceProcess
)
{
PDEBUG_OBJECT DebugObject;
PAGED_CODE ();
TargetProcess->DebugPort = NULL;
if
(SourceProcess->DebugPort != NULL) {
ExAcquireFastMutex (&DbgkpProcessDebugPortMutex);
DebugObject = SourceProcess->DebugPort;
if
(DebugObject != NULL && (SourceProcess->Flags&PS_PROCESS_FLAGS_NO_DEBUG_INHERIT) == 0) {
ExAcquireFastMutex (&DebugObject->Mutex);
if
((DebugObject->Flags&DEBUG_OBJECT_DELETE_PENDING) == 0) {
ObReferenceObject (DebugObject);
TargetProcess->DebugPort = DebugObject;
}
ExReleaseFastMutex (&DebugObject->Mutex);
}
ExReleaseFastMutex (&DbgkpProcessDebugPortMutex);
}
}
NTSTATUS
DbgkOpenProcessDebugPort (
IN PEPROCESS Process,
IN KPROCESSOR_MODE PreviousMode,
OUT
HANDLE
*pHandle
)
{
PDEBUG_OBJECT DebugObject;
NTSTATUS Status;
PAGED_CODE ();
Status = STATUS_PORT_NOT_SET;
if
(Process->DebugPort != NULL) {
ExAcquireFastMutex (&DbgkpProcessDebugPortMutex);
DebugObject = Process->DebugPort;
if
(DebugObject != NULL) {
ObReferenceObject (DebugObject);
}
ExReleaseFastMutex (&DbgkpProcessDebugPortMutex);
if
(DebugObject != NULL) {
Status = ObOpenObjectByPointer (DebugObject,
0,
NULL,
MAXIMUM_ALLOWED,
DbgkDebugObjectType,
PreviousMode,
pHandle);
if
(!NT_SUCCESS (Status)) {
ObDereferenceObject (DebugObject);
}
}
}
return
Status;
}
NTSTATUS
NtCreateDebugObject (
OUT
PHANDLE
DebugObjectHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN
ULONG
Flags
)
{
NTSTATUS Status;
HANDLE
Handle;
KPROCESSOR_MODE PreviousMode;
PDEBUG_OBJECT DebugObject;
PAGED_CODE();
PreviousMode = KeGetPreviousMode();
try
{
if
(PreviousMode != KernelMode) {
ProbeForWriteHandle (DebugObjectHandle);
}
*DebugObjectHandle = NULL;
} except (ExSystemExceptionFilter ()) {
return
GetExceptionCode ();
}
if
(Flags & ~DEBUG_KILL_ON_CLOSE) {
return
STATUS_INVALID_PARAMETER;
}
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;
}
Status = ObInsertObject (DebugObject,
NULL,
DesiredAccess,
0,
NULL,
&Handle);
if
(!NT_SUCCESS (Status)) {
return
Status;
}
try
{
*DebugObjectHandle = Handle;
} except (ExSystemExceptionFilter ()) {
Status = GetExceptionCode ();
}
return
Status;
}
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);
}
NTSTATUS
DbgkpQueueMessage (
IN PEPROCESS Process,
IN PETHREAD 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;
if
(ApiMsg->ApiNumber == DbgKmCreateThreadApi ||
ApiMsg->ApiNumber == DbgKmCreateProcessApi) {
if
(Thread->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_SKIP_CREATION_MSG) {
DebugObject = NULL;
}
}
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
{
ExAcquireFastMutex (&DebugObject->Mutex);
if
((DebugObject->Flags&DEBUG_OBJECT_DELETE_PENDING) == 0) {
InsertTailList (&DebugObject->EventList, &DebugEvent->EventList);
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;
}
NTSTATUS
DbgkClearProcessDebugObject (
IN PEPROCESS 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);
}
if
(DebugObject) {
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);
while
(!IsListEmpty (&TempList)) {
Entry = RemoveHeadList (&TempList);
DebugEvent = CONTAINING_RECORD (Entry, DEBUG_EVENT, EventList);
DebugEvent->Status = STATUS_DEBUGGER_INACTIVE;
DbgkpWakeTarget (DebugEvent);
}
}
return
Status;
}
NTSTATUS
DbgkpSetProcessDebugObject (
IN PEPROCESS Process,
IN PDEBUG_OBJECT DebugObject,
IN NTSTATUS MsgStatus,
IN PETHREAD LastThread
)
{
NTSTATUS Status;
PETHREAD ThisThread;
LIST_ENTRY TempList;
PLIST_ENTRY Entry;
PDEBUG_EVENT DebugEvent;
BOOLEAN
First;
PETHREAD Thread;
BOOLEAN
GlobalHeld;
PETHREAD FirstThread;
PAGED_CODE ();
ThisThread = PsGetCurrentThread ();
InitializeListHead (&TempList);
First = TRUE;
GlobalHeld = FALSE;
if
(!NT_SUCCESS (MsgStatus)) {
LastThread = NULL;
Status = MsgStatus;
}
else
{
Status = STATUS_SUCCESS;
}
if
(NT_SUCCESS (Status)) {
while
(1) {
GlobalHeld = TRUE;
ExAcquireFastMutex (&DbgkpProcessDebugPortMutex);
if
(Process->DebugPort != NULL) {
Status = STATUS_PORT_ALREADY_SET;
break
;
}
Process->DebugPort = DebugObject;
ObReferenceObject (LastThread);
Thread = PsGetNextProcessThread (Process, LastThread);
if
(Thread != NULL) {
Process->DebugPort = NULL;
ExReleaseFastMutex (&DbgkpProcessDebugPortMutex);
GlobalHeld = FALSE;
ObDereferenceObject (LastThread);
Status = DbgkpPostFakeThreadMessages (Process,
DebugObject,
Thread,
&FirstThread,
&LastThread);
if
(!NT_SUCCESS (Status)) {
LastThread = NULL;
break
;
}
ObDereferenceObject (FirstThread);
}
else
{
break
;
}
}
}
ExAcquireFastMutex (&DebugObject->Mutex);
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
(NT_SUCCESS (Status) && Thread->GrantedAccess != 0 && !IS_SYSTEM_THREAD (Thread)) {
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
DbgkpPostFakeThreadMessages (
IN PEPROCESS Process,
IN PDEBUG_OBJECT DebugObject,
IN PETHREAD StartThread,
OUT PETHREAD *pFirstThread,
OUT PETHREAD *pLastThread
)
{
NTSTATUS Status;
PETHREAD 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;
if
(LastThread != NULL) {
ObDereferenceObject (LastThread);
}
LastThread = Thread;
ObReferenceObject (LastThread);
if
(ExAcquireRundownProtection (&Thread->RundownProtect)) {
Flags |= DEBUG_EVENT_RELEASE;
if
(!IS_SYSTEM_THREAD (Thread)) {
Status1 = PsSuspendThread (Thread, NULL);
if
(NT_SUCCESS (Status1)) {
Flags |= DEBUG_EVENT_SUSPEND;
}
}
}
else
{
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) {
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;
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
DbgkpPostFakeModuleMessages (
IN PEPROCESS Process,
IN PETHREAD Thread,
IN PDEBUG_OBJECT DebugObject)
{
PPEB Peb = 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++) {
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) {
}
#if defined(_WIN64)
if
(Process->Wow64Process != NULL && Process->Wow64Process->Wow64 != NULL) {
PPEB32 Peb32;
PPEB_LDR_DATA32 Ldr32;
PLIST_ENTRY32 LdrHead32, LdrNext32;
PLDR_DATA_TABLE_ENTRY32 LdrEntry32;
PWCHAR
pSys;
Peb32 = (PPEB32)Process->Wow64Process->Wow64;
try
{
Ldr32 = (
PVOID
) UlongToPtr(Peb32->Ldr);
LdrHead32 = &Ldr32->InLoadOrderModuleList;
ProbeForReadSmallStructure (LdrHead32,
sizeof
(LIST_ENTRY32),
sizeof
(
UCHAR
));
for
(LdrNext32 = (
PVOID
) UlongToPtr(LdrHead32->Flink), i = 0;
LdrNext32 != LdrHead32 && i < 500;
LdrNext32 = (
PVOID
) UlongToPtr(LdrNext32->Flink), i++) {
if
(i > 0) {
RtlZeroMemory (&ApiMsg,
sizeof
(ApiMsg));
LdrEntry32 = CONTAINING_RECORD (LdrNext32, LDR_DATA_TABLE_ENTRY32, InLoadOrderLinks);
ProbeForReadSmallStructure (LdrEntry32,
sizeof
(LDR_DATA_TABLE_ENTRY32),
sizeof
(
UCHAR
));
ApiMsg.ApiNumber = DbgKmLoadDllApi;
ApiMsg.u.LoadDll.BaseOfDll = (
PVOID
) UlongToPtr(LdrEntry32->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)) {
ASSERT (
sizeof
(L
"SYSTEM32"
) ==
sizeof
(WOW64_SYSTEM_DIRECTORY_U));
pSys = wcsstr (Name.Buffer, L
"\\SYSTEM32\\"
);
if
(pSys != NULL) {
RtlCopyMemory (pSys+1,
WOW64_SYSTEM_DIRECTORY_U,
sizeof
(WOW64_SYSTEM_DIRECTORY_U) -
sizeof
(UNICODE_NULL));
}
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 (LdrNext32,
sizeof
(LIST_ENTRY32),
sizeof
(
UCHAR
));
}
} except (EXCEPTION_EXECUTE_HANDLER) {
}
}
#endif
return
STATUS_SUCCESS;
}
NTSTATUS
DbgkpPostFakeProcessCreateMessages (
IN PEPROCESS Process,
IN PDEBUG_OBJECT DebugObject,
IN PETHREAD *pLastThread
)
{
NTSTATUS Status;
KAPC_STATE ApcState;
PETHREAD Thread;
PETHREAD LastThread;
PAGED_CODE ();
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
NtDebugActiveProcess (
IN
HANDLE
ProcessHandle,
IN
HANDLE
DebugObjectHandle
)
{
NTSTATUS Status;
KPROCESSOR_MODE PreviousMode;
PDEBUG_OBJECT DebugObject;
PEPROCESS Process;
PETHREAD LastThread;
PAGED_CODE ();
PreviousMode = KeGetPreviousMode();
Status = ObReferenceObjectByHandle (ProcessHandle,
PROCESS_SET_PORT,
PsProcessType,
PreviousMode,
&Process,
NULL);
if
(!NT_SUCCESS (Status)) {
return
Status;
}
if
(Process == PsGetCurrentProcess () || Process == PsInitialSystemProcess) {
ObDereferenceObject (Process);
return
STATUS_ACCESS_DENIED;
}
Status = ObReferenceObjectByHandle (DebugObjectHandle,
DEBUG_PROCESS_ASSIGN,
DbgkDebugObjectType,
PreviousMode,
&DebugObject,
NULL);
if
(NT_SUCCESS (Status)) {
if
(ExAcquireRundownProtection (&Process->RundownProtect)) {
Status = DbgkpPostFakeProcessCreateMessages (Process,
DebugObject,
&LastThread);
Status = DbgkpSetProcessDebugObject (Process,
DebugObject,
Status,
LastThread);
ExReleaseRundownProtection (&Process->RundownProtect);
}
else
{
Status = STATUS_PROCESS_IS_TERMINATING;
}
ObDereferenceObject (DebugObject);
}
ObDereferenceObject (Process);
return
Status;
}
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;
}
VOID
DbgkpOpenHandles (
PDBGUI_WAIT_STATE_CHANGE WaitStateChange,
PEPROCESS Process,
PETHREAD Thread
)
{
NTSTATUS Status;
PEPROCESS CurrentProcess;
HANDLE
OldHandle;
PAGED_CODE ();
switch
(WaitStateChange->NewState) {
case
DbgCreateThreadStateChange :
Status = ObOpenObjectByPointer (Thread,
0,
NULL,
THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME | \
THREAD_QUERY_INFORMATION | THREAD_SET_INFORMATION | THREAD_TERMINATE |
READ_CONTROL | SYNCHRONIZE,
PsThreadType,
KernelMode,
&WaitStateChange->StateInfo.CreateThread.HandleToThread);
if
(!NT_SUCCESS (Status)) {
WaitStateChange->StateInfo.CreateThread.HandleToThread = NULL;
}
break
;
case
DbgCreateProcessStateChange :
Status = ObOpenObjectByPointer (Thread,
0,
NULL,
THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME | \
THREAD_QUERY_INFORMATION | THREAD_SET_INFORMATION | THREAD_TERMINATE |
READ_CONTROL | SYNCHRONIZE,
PsThreadType,
KernelMode,
&WaitStateChange->StateInfo.CreateProcessInfo.HandleToThread);
if
(!NT_SUCCESS (Status)) {
WaitStateChange->StateInfo.CreateProcessInfo.HandleToThread = NULL;
}
Status = ObOpenObjectByPointer (Process,
0,
NULL,
PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION |
PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION | PROCESS_SET_INFORMATION |
PROCESS_CREATE_THREAD | PROCESS_TERMINATE |
READ_CONTROL | SYNCHRONIZE,
PsProcessType,
KernelMode,
&WaitStateChange->StateInfo.CreateProcessInfo.HandleToProcess);
if
(!NT_SUCCESS (Status)) {
WaitStateChange->StateInfo.CreateProcessInfo.HandleToProcess = NULL;
}
OldHandle = WaitStateChange->StateInfo.CreateProcessInfo.NewProcess.FileHandle;
if
(OldHandle != NULL) {
CurrentProcess = PsGetCurrentProcess ();
Status = ObDuplicateObject (CurrentProcess,
OldHandle,
CurrentProcess,
&WaitStateChange->StateInfo.CreateProcessInfo.NewProcess.FileHandle,
0,
0,
DUPLICATE_SAME_ACCESS,
KernelMode);
if
(!NT_SUCCESS (Status)) {
WaitStateChange->StateInfo.CreateProcessInfo.NewProcess.FileHandle = NULL;
}
ObCloseHandle (OldHandle, KernelMode);
}
break
;
case
DbgLoadDllStateChange :
OldHandle = WaitStateChange->StateInfo.LoadDll.FileHandle;
if
(OldHandle != NULL) {
CurrentProcess = PsGetCurrentProcess ();
Status = ObDuplicateObject (CurrentProcess,
OldHandle,
CurrentProcess,
&WaitStateChange->StateInfo.LoadDll.FileHandle,
0,
0,
DUPLICATE_SAME_ACCESS,
KernelMode);
if
(!NT_SUCCESS (Status)) {
WaitStateChange->StateInfo.LoadDll.FileHandle = NULL;
}
ObCloseHandle (OldHandle, KernelMode);
}
break
;
default
:
break
;
}
}
VOID
DbgkpConvertKernelToUserStateChange (
PDBGUI_WAIT_STATE_CHANGE WaitStateChange,
PDEBUG_EVENT DebugEvent)
{
PAGED_CODE ();
WaitStateChange->AppClientId = DebugEvent->ClientId;
switch
(DebugEvent->ApiMsg.ApiNumber) {
case
DbgKmExceptionApi :
switch
(DebugEvent->ApiMsg.u.Exception.ExceptionRecord.ExceptionCode) {
case
STATUS_BREAKPOINT :
WaitStateChange->NewState = DbgBreakpointStateChange;
break
;
case
STATUS_SINGLE_STEP :
WaitStateChange->NewState = DbgSingleStepStateChange;
break
;
default
:
WaitStateChange->NewState = DbgExceptionStateChange;
break
;
}
WaitStateChange->StateInfo.Exception = DebugEvent->ApiMsg.u.Exception;
break
;
case
DbgKmCreateThreadApi :
WaitStateChange->NewState = DbgCreateThreadStateChange;
WaitStateChange->StateInfo.CreateThread.NewThread = DebugEvent->ApiMsg.u.CreateThread;
break
;
case
DbgKmCreateProcessApi :
WaitStateChange->NewState = DbgCreateProcessStateChange;
WaitStateChange->StateInfo.CreateProcessInfo.NewProcess = DebugEvent->ApiMsg.u.CreateProcessInfo;
DebugEvent->ApiMsg.u.CreateProcessInfo.FileHandle = NULL;
break
;
case
DbgKmExitThreadApi :
WaitStateChange->NewState = DbgExitThreadStateChange;
WaitStateChange->StateInfo.ExitThread = DebugEvent->ApiMsg.u.ExitThread;
break
;
case
DbgKmExitProcessApi :
WaitStateChange->NewState = DbgExitProcessStateChange;
WaitStateChange->StateInfo.ExitProcess = DebugEvent->ApiMsg.u.ExitProcess;
break
;
case
DbgKmLoadDllApi :
WaitStateChange->NewState = DbgLoadDllStateChange;
WaitStateChange->StateInfo.LoadDll = DebugEvent->ApiMsg.u.LoadDll;
DebugEvent->ApiMsg.u.LoadDll.FileHandle = NULL;
break
;
case
DbgKmUnloadDllApi :
WaitStateChange->NewState = DbgUnloadDllStateChange;
WaitStateChange->StateInfo.UnloadDll = DebugEvent->ApiMsg.u.UnloadDll;
break
;
default
:
ASSERT (FALSE);
}
}
NTSTATUS
NtWaitForDebugEvent (
IN
HANDLE
DebugObjectHandle,
IN
BOOLEAN
Alertable,
IN PLARGE_INTEGER Timeout OPTIONAL,
OUT PDBGUI_WAIT_STATE_CHANGE WaitStateChange
)
{
NTSTATUS Status;
KPROCESSOR_MODE PreviousMode;
PDEBUG_OBJECT DebugObject;
LARGE_INTEGER Tmo = {0};
LARGE_INTEGER StartTime = {0};
DBGUI_WAIT_STATE_CHANGE tWaitStateChange = {0};
PEPROCESS Process;
PETHREAD Thread;
PLIST_ENTRY Entry, Entry2;
PDEBUG_EVENT DebugEvent, DebugEvent2;
BOOLEAN
GotEvent;
PAGED_CODE ();
PreviousMode = KeGetPreviousMode();
try
{
if
(ARGUMENT_PRESENT (Timeout)) {
if
(PreviousMode != KernelMode) {
ProbeForReadSmallStructure (Timeout,
sizeof
(*Timeout),
sizeof
(
UCHAR
));
}
Tmo = *Timeout;
Timeout = &Tmo;
KeQuerySystemTime (&StartTime);
}
if
(PreviousMode != KernelMode) {
ProbeForWriteSmallStructure (WaitStateChange,
sizeof
(*WaitStateChange),
sizeof
(
UCHAR
));
}
} except (ExSystemExceptionFilter ()) {
return
GetExceptionCode ();
}
Status = ObReferenceObjectByHandle (DebugObjectHandle,
DEBUG_READ_EVENT,
DbgkDebugObjectType,
PreviousMode,
&DebugObject,
NULL);
if
(!NT_SUCCESS (Status)) {
return
Status;
}
Process = NULL;
Thread = NULL;
while
(1) {
Status = KeWaitForSingleObject (&DebugObject->EventsPresent,
Executive,
PreviousMode,
Alertable,
Timeout);
if
(!NT_SUCCESS (Status) || Status == STATUS_TIMEOUT || Status == STATUS_ALERTED || Status == STATUS_USER_APC) {
break
;
}
GotEvent = FALSE;
DebugEvent = NULL;
ExAcquireFastMutex (&DebugObject->Mutex);
if
((DebugObject->Flags&DEBUG_OBJECT_DELETE_PENDING) == 0) {
for
(Entry = DebugObject->EventList.Flink;
Entry != &DebugObject->EventList;
Entry = Entry->Flink) {
DebugEvent = CONTAINING_RECORD (Entry, DEBUG_EVENT, EventList);
if
((DebugEvent->Flags&(DEBUG_EVENT_READ|DEBUG_EVENT_INACTIVE)) == 0) {
GotEvent = TRUE;
for
(Entry2 = DebugObject->EventList.Flink;
Entry2 != Entry;
Entry2 = Entry2->Flink) {
DebugEvent2 = CONTAINING_RECORD (Entry2, DEBUG_EVENT, EventList);
if
(DebugEvent->ClientId.UniqueProcess == DebugEvent2->ClientId.UniqueProcess) {
DebugEvent->Flags |= DEBUG_EVENT_INACTIVE;
DebugEvent->BackoutThread = NULL;
GotEvent = FALSE;
break
;
}
}
if
(GotEvent) {
break
;
}
}
}
if
(GotEvent) {
Process = DebugEvent->Process;
Thread = DebugEvent->Thread;
ObReferenceObject (Thread);
ObReferenceObject (Process);
DbgkpConvertKernelToUserStateChange (&tWaitStateChange, DebugEvent);
DebugEvent->Flags |= DEBUG_EVENT_READ;
}
else
{
KeClearEvent (&DebugObject->EventsPresent);
}
Status = STATUS_SUCCESS;
}
else
{
Status = STATUS_DEBUGGER_INACTIVE;
}
ExReleaseFastMutex (&DebugObject->Mutex);
if
(NT_SUCCESS (Status)) {
if
(GotEvent == FALSE) {
if
(Tmo.QuadPart < 0) {
LARGE_INTEGER NewTime;
KeQuerySystemTime (&NewTime);
Tmo.QuadPart = Tmo.QuadPart + (NewTime.QuadPart - StartTime.QuadPart);
StartTime = NewTime;
if
(Tmo.QuadPart >= 0) {
Status = STATUS_TIMEOUT;
break
;
}
}
}
else
{
DbgkpOpenHandles (&tWaitStateChange, Process, Thread);
ObDereferenceObject (Thread);
ObDereferenceObject (Process);
break
;
}
}
else
{
break
;
}
}
ObDereferenceObject (DebugObject);
try
{
*WaitStateChange = tWaitStateChange;
} except (ExSystemExceptionFilter ()) {
Status = GetExceptionCode ();
}
return
Status;
}
NTSTATUS
NtDebugContinue (
IN
HANDLE
DebugObjectHandle,
IN PCLIENT_ID ClientId,
IN NTSTATUS ContinueStatus
)
{
NTSTATUS Status;
PDEBUG_OBJECT DebugObject;
PDEBUG_EVENT DebugEvent, FoundDebugEvent;
KPROCESSOR_MODE PreviousMode;
CLIENT_ID Clid;
PLIST_ENTRY Entry;
BOOLEAN
GotEvent;
PreviousMode = KeGetPreviousMode();
try
{
if
(PreviousMode != KernelMode) {
ProbeForReadSmallStructure (ClientId,
sizeof
(*ClientId),
sizeof
(
UCHAR
));
}
Clid = *ClientId;
} except (ExSystemExceptionFilter ()) {
return
GetExceptionCode ();
}
switch
(ContinueStatus) {
case
DBG_EXCEPTION_HANDLED :
case
DBG_EXCEPTION_NOT_HANDLED :
case
DBG_TERMINATE_THREAD :
case
DBG_TERMINATE_PROCESS :
case
DBG_CONTINUE :
break
;
default
:
return
STATUS_INVALID_PARAMETER;
}
Status = ObReferenceObjectByHandle (DebugObjectHandle,
DEBUG_READ_EVENT,
DbgkDebugObjectType,
PreviousMode,
&DebugObject,
NULL);
if
(!NT_SUCCESS (Status)) {
return
Status;
}
GotEvent = FALSE;
FoundDebugEvent = NULL;
ExAcquireFastMutex (&DebugObject->Mutex);
for
(Entry = DebugObject->EventList.Flink;
Entry != &DebugObject->EventList;
Entry = Entry->Flink) {
DebugEvent = CONTAINING_RECORD (Entry, DEBUG_EVENT, EventList);
if
(DebugEvent->ClientId.UniqueProcess == Clid.UniqueProcess) {
if
(!GotEvent) {
if
(DebugEvent->ClientId.UniqueThread == Clid.UniqueThread &&
(DebugEvent->Flags&DEBUG_EVENT_READ) != 0) {
RemoveEntryList (Entry);
FoundDebugEvent = DebugEvent;
GotEvent = TRUE;
}
}
else
{
DebugEvent->Flags &= ~DEBUG_EVENT_INACTIVE;
KeSetEvent (&DebugObject->EventsPresent, 0, FALSE);
break
;
}
}
}
ExReleaseFastMutex (&DebugObject->Mutex);
ObDereferenceObject (DebugObject);
if
(GotEvent) {
FoundDebugEvent->ApiMsg.ReturnedStatus = ContinueStatus;
FoundDebugEvent->Status = STATUS_SUCCESS;
DbgkpWakeTarget (FoundDebugEvent);
}
else
{
Status = STATUS_INVALID_PARAMETER;
}
return
Status;
}
NTSTATUS
NtSetInformationDebugObject (
IN
HANDLE
DebugObjectHandle,
IN DEBUGOBJECTINFOCLASS DebugObjectInformationClass,
IN
PVOID
DebugInformation,
IN
ULONG
DebugInformationLength,
OUT
PULONG
ReturnLength OPTIONAL
)
{
KPROCESSOR_MODE PreviousMode;
NTSTATUS Status;
PDEBUG_OBJECT DebugObject;
ULONG
Flags;
PreviousMode = KeGetPreviousMode();
try
{
if
(PreviousMode != KernelMode) {
ProbeForRead (DebugInformation,
DebugInformationLength,
sizeof
(
ULONG
));
if
(ARGUMENT_PRESENT (ReturnLength)) {
ProbeForWriteUlong (ReturnLength);
}
}
if
(ARGUMENT_PRESENT (ReturnLength)) {
*ReturnLength = 0;
}
switch
(DebugObjectInformationClass) {
case
DebugObjectFlags : {
if
(DebugInformationLength !=
sizeof
(
ULONG
)) {
if
(ARGUMENT_PRESENT (ReturnLength)) {
*ReturnLength =
sizeof
(
ULONG
);
}
return
STATUS_INFO_LENGTH_MISMATCH;
}
Flags = *(
PULONG
) DebugInformation;
break
;
}
default
: {
return
STATUS_INVALID_PARAMETER;
}
}
} except (ExSystemExceptionFilter ()) {
return
GetExceptionCode ();
}
switch
(DebugObjectInformationClass) {
case
DebugObjectFlags : {
if
(Flags & ~DEBUG_KILL_ON_CLOSE) {
return
STATUS_INVALID_PARAMETER;
}
Status = ObReferenceObjectByHandle (DebugObjectHandle,
DEBUG_SET_INFORMATION,
DbgkDebugObjectType,
PreviousMode,
&DebugObject,
NULL);
if
(!NT_SUCCESS (Status)) {
return
Status;
}
ExAcquireFastMutex (&DebugObject->Mutex);
if
(Flags&DEBUG_KILL_ON_CLOSE) {
DebugObject->Flags |= DEBUG_OBJECT_KILL_ON_CLOSE;
}
else
{
DebugObject->Flags &= ~DEBUG_OBJECT_KILL_ON_CLOSE;
}
ExReleaseFastMutex (&DebugObject->Mutex);
ObDereferenceObject (DebugObject);
}
}
return
STATUS_SUCCESS;
}
## dbgkport.c
```c
#include "dbgkp.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, DbgkpSendApiMessage)
#pragma alloc_text(PAGE, DbgkForwardException)
#pragma alloc_text(PAGE, DbgkpSendApiMessageLpc)
#endif
NTSTATUS
DbgkpSendApiMessage(
IN OUT PDBGKM_APIMSG ApiMsg,
IN
BOOLEAN
SuspendProcess
)
{
NTSTATUS st;
PEPROCESS Process;
PAGED_CODE();
if
( SuspendProcess ) {
SuspendProcess = DbgkpSuspendProcess();
}
ApiMsg->ReturnedStatus = STATUS_PENDING;
Process = PsGetCurrentProcess();
PS_SET_BITS (&Process->Flags, PS_PROCESS_FLAGS_CREATE_REPORTED);
st = DbgkpQueueMessage (Process, PsGetCurrentThread (), ApiMsg, 0, NULL);
ZwFlushInstructionCache (NtCurrentProcess (), NULL, 0);
if
( SuspendProcess ) {
DbgkpResumeProcess();
}
return
st;
}
NTSTATUS
DbgkpSendApiMessageLpc(
IN OUT PDBGKM_APIMSG ApiMsg,
IN
PVOID
Port,
IN
BOOLEAN
SuspendProcess
)
{
NTSTATUS st;
ULONG_PTR
MessageBuffer[PORT_TOTAL_MAXIMUM_MESSAGE_LENGTH/
sizeof
(
ULONG_PTR
)];
PAGED_CODE();
if
( SuspendProcess ) {
SuspendProcess = DbgkpSuspendProcess();
}
ApiMsg->ReturnedStatus = STATUS_PENDING;
PS_SET_BITS (&PsGetCurrentProcess()->Flags, PS_PROCESS_FLAGS_CREATE_REPORTED);
st = LpcRequestWaitReplyPortEx (Port,
(PPORT_MESSAGE) ApiMsg,
(PPORT_MESSAGE) &MessageBuffer[0]);
ZwFlushInstructionCache(NtCurrentProcess(), NULL, 0);
if
(NT_SUCCESS (st)) {
RtlCopyMemory(ApiMsg,MessageBuffer,
sizeof
(*ApiMsg));
}
if
(SuspendProcess) {
DbgkpResumeProcess();
}
return
st;
}
DECLSPEC_NOINLINE
BOOLEAN
DbgkForwardException(
IN PEXCEPTION_RECORD ExceptionRecord,
IN
BOOLEAN
DebugException,
IN
BOOLEAN
SecondChance
)
{
PEPROCESS Process;
PVOID
Port;
DBGKM_APIMSG m;
PDBGKM_EXCEPTION args;
NTSTATUS st;
BOOLEAN
LpcPort;
PAGED_CODE();
args = &m.u.Exception;
DBGKM_FORMAT_API_MSG(m,DbgKmExceptionApi,
sizeof
(*args));
Process = PsGetCurrentProcess();
if
(DebugException) {
if
(PsGetCurrentThread()->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_HIDEFROMDBG) {
Port = NULL;
}
else
{
Port = Process->DebugPort;
}
LpcPort = FALSE;
}
else
{
Port = Process->ExceptionPort;
m.h.u2.ZeroInit = LPC_EXCEPTION;
LpcPort = TRUE;
}
if
(Port == NULL) {
return
FALSE;
}
args->ExceptionRecord = *ExceptionRecord;
args->FirstChance = !SecondChance;
if
(LpcPort) {
st = DbgkpSendApiMessageLpc(&m,Port,DebugException);
}
else
{
st = DbgkpSendApiMessage(&m,DebugException);
}
if
(!NT_SUCCESS(st) ||
((DebugException) &&
(m.ReturnedStatus == DBG_EXCEPTION_NOT_HANDLED || !NT_SUCCESS(m.ReturnedStatus)))) {
return
FALSE;
}
else
{
return
TRUE;
}
}