Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2233 lines
65 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. dbgkobj.c
  5. Abstract:
  6. This module houses routines to handle the debug object
  7. Author:
  8. Neill Clift (NeillC) 26-Apr-2000
  9. Revision History:
  10. --*/
  11. #include "dbgkp.h"
  12. #pragma hdrstop
  13. #ifdef ALLOC_PRAGMA
  14. #pragma alloc_text(INIT, DbgkInitialize)
  15. #pragma alloc_text(PAGE, NtCreateDebugObject)
  16. #pragma alloc_text(PAGE, NtDebugActiveProcess)
  17. #pragma alloc_text(PAGE, NtRemoveProcessDebug)
  18. #pragma alloc_text(PAGE, NtWaitForDebugEvent)
  19. #pragma alloc_text(PAGE, NtDebugContinue)
  20. #pragma alloc_text(PAGE, NtSetInformationDebugObject)
  21. #pragma alloc_text(PAGE, DbgkpDeleteObject)
  22. #pragma alloc_text(PAGE, DbgkpCloseObject)
  23. #pragma alloc_text(PAGE, DbgkCopyProcessDebugPort)
  24. #pragma alloc_text(PAGE, DbgkOpenProcessDebugPort)
  25. #pragma alloc_text(PAGE, DbgkpSetProcessDebugObject)
  26. #pragma alloc_text(PAGE, DbgkpQueueMessage)
  27. #pragma alloc_text(PAGE, DbgkpOpenHandles)
  28. #pragma alloc_text(PAGE, DbgkClearProcessDebugObject)
  29. #pragma alloc_text(PAGE, DbgkpConvertKernelToUserStateChange)
  30. #pragma alloc_text(PAGE, DbgkpMarkProcessPeb)
  31. #pragma alloc_text(PAGE, DbgkpFreeDebugEvent)
  32. #pragma alloc_text(PAGE, DbgkpPostFakeProcessCreateMessages)
  33. #pragma alloc_text(PAGE, DbgkpPostFakeModuleMessages)
  34. #pragma alloc_text(PAGE, DbgkpPostFakeThreadMessages)
  35. #pragma alloc_text(PAGE, DbgkpWakeTarget)
  36. #pragma alloc_text(PAGE, DbgkpPostAdditionalThreadMessages)
  37. #endif
  38. //
  39. // Define this to not suspend threads while attaching.
  40. // This makes race conditions more prevelent.
  41. //
  42. //#define DBGK_DONT_SUSPEND
  43. //
  44. // Non-pageable data
  45. //
  46. //
  47. // This mutex protects the debug port object of processes.
  48. //
  49. FAST_MUTEX DbgkpProcessDebugPortMutex;
  50. //
  51. // Pageable data
  52. //
  53. //#ifdef ALLOC_PRAGMA
  54. //#pragma data_seg("PAGEDATA")
  55. //#endif
  56. POBJECT_TYPE DbgkDebugObjectType = NULL;
  57. //#ifdef ALLOC_PRAGMA
  58. //#pragma data_seg()
  59. //#endif
  60. NTSTATUS
  61. DbgkInitialize (
  62. VOID
  63. )
  64. /*++
  65. Routine Description:
  66. Initialize the debug system
  67. Arguments:
  68. None
  69. Return Value:
  70. NTSTATUS - Status of operation
  71. --*/
  72. {
  73. NTSTATUS Status;
  74. UNICODE_STRING Name;
  75. OBJECT_TYPE_INITIALIZER oti = {0};
  76. GENERIC_MAPPING GenericMapping = {STANDARD_RIGHTS_READ | DEBUG_READ_EVENT,
  77. STANDARD_RIGHTS_WRITE | DEBUG_PROCESS_ASSIGN,
  78. STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE,
  79. DEBUG_ALL_ACCESS};
  80. PAGED_CODE ();
  81. ExInitializeFastMutex (&DbgkpProcessDebugPortMutex);
  82. RtlInitUnicodeString (&Name, L"DebugObject");
  83. oti.Length = sizeof (oti);
  84. oti.SecurityRequired = TRUE;
  85. oti.InvalidAttributes = 0;
  86. oti.PoolType = NonPagedPool;
  87. oti.DeleteProcedure = DbgkpDeleteObject;
  88. oti.CloseProcedure = DbgkpCloseObject;
  89. oti.ValidAccessMask = DEBUG_ALL_ACCESS;
  90. oti.GenericMapping = GenericMapping;
  91. oti.DefaultPagedPoolCharge = 0;
  92. oti.DefaultNonPagedPoolCharge = 0;
  93. Status = ObCreateObjectType (&Name, &oti, NULL, &DbgkDebugObjectType);
  94. if (!NT_SUCCESS (Status)) {
  95. return Status;
  96. }
  97. return Status;
  98. }
  99. VOID
  100. DbgkpDeleteObject (
  101. IN PVOID Object
  102. )
  103. /*++
  104. Routine Description:
  105. Called by the object manager when the last reference to the object goes away.
  106. Arguments:
  107. Object - Debug object being deleted
  108. Return Value:
  109. None.
  110. --*/
  111. {
  112. #if DBG
  113. PDEBUG_OBJECT DebugObject;
  114. #endif
  115. PAGED_CODE();
  116. #if DBG
  117. DebugObject = Object;
  118. ASSERT (IsListEmpty (&DebugObject->EventList));
  119. #else
  120. UNREFERENCED_PARAMETER(Object);
  121. #endif
  122. }
  123. VOID
  124. DbgkpMarkProcessPeb (
  125. PEPROCESS Process
  126. )
  127. /*++
  128. Routine Description:
  129. This routine writes the debug variable in the PEB
  130. Arguments:
  131. Process - Process that needs its PEB modified
  132. Return Value:
  133. None.
  134. --*/
  135. {
  136. KAPC_STATE ApcState;
  137. PAGED_CODE ();
  138. //
  139. // Acquire process rundown protection as we are about to look at the processes address space
  140. //
  141. if (ExAcquireRundownProtection (&Process->RundownProtect)) {
  142. if (Process->Peb != NULL) {
  143. KeStackAttachProcess(&Process->Pcb, &ApcState);
  144. ExAcquireFastMutex (&DbgkpProcessDebugPortMutex);
  145. try {
  146. Process->Peb->BeingDebugged = (BOOLEAN)(Process->DebugPort != NULL ? TRUE : FALSE);
  147. #if defined(_WIN64)
  148. if (Process->Wow64Process != NULL) {
  149. PPEB32 Peb32 = (PPEB32)Process->Wow64Process->Wow64;
  150. if (Peb32 != NULL) {
  151. Peb32->BeingDebugged = Process->Peb->BeingDebugged;
  152. }
  153. }
  154. #endif
  155. } except (EXCEPTION_EXECUTE_HANDLER) {
  156. }
  157. ExReleaseFastMutex (&DbgkpProcessDebugPortMutex);
  158. KeUnstackDetachProcess(&ApcState);
  159. }
  160. ExReleaseRundownProtection (&Process->RundownProtect);
  161. }
  162. }
  163. VOID
  164. DbgkpWakeTarget (
  165. IN PDEBUG_EVENT DebugEvent
  166. )
  167. {
  168. PETHREAD Thread;
  169. Thread = DebugEvent->Thread;
  170. if ((DebugEvent->Flags&DEBUG_EVENT_SUSPEND) != 0) {
  171. PsResumeThread (DebugEvent->Thread, NULL);
  172. }
  173. if (DebugEvent->Flags&DEBUG_EVENT_RELEASE) {
  174. ExReleaseRundownProtection (&Thread->RundownProtect);
  175. }
  176. //
  177. // If we have an actual thread waiting then wake it up else free the memory.
  178. //
  179. if ((DebugEvent->Flags&DEBUG_EVENT_NOWAIT) == 0) {
  180. KeSetEvent (&DebugEvent->ContinueEvent, 0, FALSE); // Wake up waiting process
  181. } else {
  182. DbgkpFreeDebugEvent (DebugEvent);
  183. }
  184. }
  185. VOID
  186. DbgkpCloseObject (
  187. IN PEPROCESS Process,
  188. IN PVOID Object,
  189. IN ACCESS_MASK GrantedAccess,
  190. IN ULONG ProcessHandleCount,
  191. IN ULONG SystemHandleCount
  192. )
  193. /*++
  194. Routine Description:
  195. Called by the object manager when a handle is closed to the object.
  196. Arguments:
  197. Process - Process doing the close
  198. Object - Debug object being deleted
  199. GrantedAccess - Access ranted for this handle
  200. ProcessHandleCount - Unused and unmaintained by OB
  201. SystemHandleCount - Current handle count for this object
  202. Return Value:
  203. None.
  204. --*/
  205. {
  206. PDEBUG_OBJECT DebugObject = Object;
  207. PDEBUG_EVENT DebugEvent;
  208. PLIST_ENTRY ListPtr;
  209. BOOLEAN Deref;
  210. PAGED_CODE ();
  211. UNREFERENCED_PARAMETER (GrantedAccess);
  212. UNREFERENCED_PARAMETER (ProcessHandleCount);
  213. //
  214. // If this isn't the last handle then do nothing.
  215. //
  216. if (SystemHandleCount > 1) {
  217. return;
  218. }
  219. ExAcquireFastMutex (&DebugObject->Mutex);
  220. //
  221. // Mark this object as going away and wake up any processes that are waiting.
  222. //
  223. DebugObject->Flags |= DEBUG_OBJECT_DELETE_PENDING;
  224. //
  225. // Remove any events and queue them to a temporary queue
  226. //
  227. ListPtr = DebugObject->EventList.Flink;
  228. InitializeListHead (&DebugObject->EventList);
  229. ExReleaseFastMutex (&DebugObject->Mutex);
  230. //
  231. // Wake anyone waiting. They need to leave this object alone now as its deleting
  232. //
  233. KeSetEvent (&DebugObject->EventsPresent, 0, FALSE);
  234. //
  235. // Loop over all processes and remove the debug port from any that still have it.
  236. // Debug port propogation was disabled by setting the delete pending flag above so we only have to do this
  237. // once. No more refs can appear now.
  238. //
  239. for (Process = PsGetNextProcess (NULL);
  240. Process != NULL;
  241. Process = PsGetNextProcess (Process)) {
  242. if (Process->DebugPort == DebugObject) {
  243. Deref = FALSE;
  244. ExAcquireFastMutex (&DbgkpProcessDebugPortMutex);
  245. if (Process->DebugPort == DebugObject) {
  246. Process->DebugPort = NULL;
  247. Deref = TRUE;
  248. }
  249. ExReleaseFastMutex (&DbgkpProcessDebugPortMutex);
  250. if (Deref) {
  251. DbgkpMarkProcessPeb (Process);
  252. //
  253. // If the caller wanted process deletion on debugger dying (old interface) then kill off the process.
  254. //
  255. if (DebugObject->Flags&DEBUG_OBJECT_KILL_ON_CLOSE) {
  256. PsTerminateProcess (Process, STATUS_DEBUGGER_INACTIVE);
  257. }
  258. ObDereferenceObject (DebugObject);
  259. }
  260. }
  261. }
  262. //
  263. // Wake up all the removed threads.
  264. //
  265. while (ListPtr != &DebugObject->EventList) {
  266. DebugEvent = CONTAINING_RECORD (ListPtr, DEBUG_EVENT, EventList);
  267. ListPtr = ListPtr->Flink;
  268. DebugEvent->Status = STATUS_DEBUGGER_INACTIVE;
  269. DbgkpWakeTarget (DebugEvent);
  270. }
  271. }
  272. VOID
  273. DbgkCopyProcessDebugPort (
  274. IN PEPROCESS TargetProcess,
  275. IN PEPROCESS SourceProcess
  276. )
  277. /*++
  278. Routine Description:
  279. Copies a debug port from one process to another.
  280. Arguments:
  281. TargetProcess - Process to move port to
  282. sourceProcess - Process to move port from
  283. Return Value:
  284. None
  285. --*/
  286. {
  287. PDEBUG_OBJECT DebugObject;
  288. PAGED_CODE ();
  289. TargetProcess->DebugPort = NULL; // New process. Needs no locks.
  290. if (SourceProcess->DebugPort != NULL) {
  291. ExAcquireFastMutex (&DbgkpProcessDebugPortMutex);
  292. DebugObject = SourceProcess->DebugPort;
  293. if (DebugObject != NULL && (SourceProcess->Flags&PS_PROCESS_FLAGS_NO_DEBUG_INHERIT) == 0) {
  294. //
  295. // We must not propogate a debug port thats got no handles left.
  296. //
  297. ExAcquireFastMutex (&DebugObject->Mutex);
  298. //
  299. // If the object is delete pending then don't propogate this object.
  300. //
  301. if ((DebugObject->Flags&DEBUG_OBJECT_DELETE_PENDING) == 0) {
  302. ObReferenceObject (DebugObject);
  303. TargetProcess->DebugPort = DebugObject;
  304. }
  305. ExReleaseFastMutex (&DebugObject->Mutex);
  306. }
  307. ExReleaseFastMutex (&DbgkpProcessDebugPortMutex);
  308. }
  309. }
  310. NTSTATUS
  311. DbgkOpenProcessDebugPort (
  312. IN PEPROCESS Process,
  313. IN KPROCESSOR_MODE PreviousMode,
  314. OUT HANDLE *pHandle
  315. )
  316. /*++
  317. Routine Description:
  318. References the target processes debug port.
  319. Arguments:
  320. Process - Process to reference debug port
  321. Return Value:
  322. PDEBUG_OBJECT - Referenced object or NULL
  323. --*/
  324. {
  325. PDEBUG_OBJECT DebugObject;
  326. NTSTATUS Status;
  327. PAGED_CODE ();
  328. Status = STATUS_PORT_NOT_SET;
  329. if (Process->DebugPort != NULL) {
  330. ExAcquireFastMutex (&DbgkpProcessDebugPortMutex);
  331. DebugObject = Process->DebugPort;
  332. if (DebugObject != NULL) {
  333. ObReferenceObject (DebugObject);
  334. }
  335. ExReleaseFastMutex (&DbgkpProcessDebugPortMutex);
  336. if (DebugObject != NULL) {
  337. Status = ObOpenObjectByPointer (DebugObject,
  338. 0,
  339. NULL,
  340. MAXIMUM_ALLOWED,
  341. DbgkDebugObjectType,
  342. PreviousMode,
  343. pHandle);
  344. if (!NT_SUCCESS (Status)) {
  345. ObDereferenceObject (DebugObject);
  346. }
  347. }
  348. }
  349. return Status;
  350. }
  351. NTSTATUS
  352. NtCreateDebugObject (
  353. OUT PHANDLE DebugObjectHandle,
  354. IN ACCESS_MASK DesiredAccess,
  355. IN POBJECT_ATTRIBUTES ObjectAttributes,
  356. IN ULONG Flags
  357. )
  358. /*++
  359. Routine Description:
  360. Creates a new debug object that maintains the context for a single debug session. Multiple processes may be
  361. associated with a single debug object.
  362. Arguments:
  363. DebugObjectHandle - Pointer to a handle to recive the output objects handle
  364. DesiredAccess - Required handle access
  365. ObjectAttributes - Standard object attributes structure
  366. Flags - Only one flag DEBUG_KILL_ON_CLOSE
  367. Return Value:
  368. NTSTATUS - Status of call.
  369. --*/
  370. {
  371. NTSTATUS Status;
  372. HANDLE Handle;
  373. KPROCESSOR_MODE PreviousMode;
  374. PDEBUG_OBJECT DebugObject;
  375. PAGED_CODE();
  376. //
  377. // Get previous processor mode and probe output arguments if necessary.
  378. // Zero the handle for error paths.
  379. //
  380. PreviousMode = KeGetPreviousMode();
  381. try {
  382. if (PreviousMode != KernelMode) {
  383. ProbeForWriteHandle (DebugObjectHandle);
  384. }
  385. *DebugObjectHandle = NULL;
  386. } except (ExSystemExceptionFilter ()) { // If previous mode is kernel then don't handle the exception
  387. return GetExceptionCode ();
  388. }
  389. if (Flags & ~DEBUG_KILL_ON_CLOSE) {
  390. return STATUS_INVALID_PARAMETER;
  391. }
  392. //
  393. // Create a new debug object and initialize it.
  394. //
  395. Status = ObCreateObject (PreviousMode,
  396. DbgkDebugObjectType,
  397. ObjectAttributes,
  398. PreviousMode,
  399. NULL,
  400. sizeof (DEBUG_OBJECT),
  401. 0,
  402. 0,
  403. &DebugObject);
  404. if (!NT_SUCCESS (Status)) {
  405. return Status;
  406. }
  407. ExInitializeFastMutex (&DebugObject->Mutex);
  408. InitializeListHead (&DebugObject->EventList);
  409. KeInitializeEvent (&DebugObject->EventsPresent, NotificationEvent, FALSE);
  410. if (Flags & DEBUG_KILL_ON_CLOSE) {
  411. DebugObject->Flags = DEBUG_OBJECT_KILL_ON_CLOSE;
  412. } else {
  413. DebugObject->Flags = 0;
  414. }
  415. //
  416. // Insert the object into the handle table
  417. //
  418. Status = ObInsertObject (DebugObject,
  419. NULL,
  420. DesiredAccess,
  421. 0,
  422. NULL,
  423. &Handle);
  424. if (!NT_SUCCESS (Status)) {
  425. return Status;
  426. }
  427. try {
  428. *DebugObjectHandle = Handle;
  429. } except (ExSystemExceptionFilter ()) {
  430. //
  431. // The caller changed the page protection or deleted the memory for the handle.
  432. // No point closing the handle as process rundown will do that and we don't know its still the same handle
  433. //
  434. Status = GetExceptionCode ();
  435. }
  436. return Status;
  437. }
  438. VOID
  439. DbgkpFreeDebugEvent (
  440. IN PDEBUG_EVENT DebugEvent
  441. )
  442. {
  443. NTSTATUS Status;
  444. PAGED_CODE ();
  445. switch (DebugEvent->ApiMsg.ApiNumber) {
  446. case DbgKmCreateProcessApi :
  447. if (DebugEvent->ApiMsg.u.CreateProcessInfo.FileHandle != NULL) {
  448. Status = ObCloseHandle (DebugEvent->ApiMsg.u.CreateProcessInfo.FileHandle, KernelMode);
  449. }
  450. break;
  451. case DbgKmLoadDllApi :
  452. if (DebugEvent->ApiMsg.u.LoadDll.FileHandle != NULL) {
  453. Status = ObCloseHandle (DebugEvent->ApiMsg.u.LoadDll.FileHandle, KernelMode);
  454. }
  455. break;
  456. }
  457. ObDereferenceObject (DebugEvent->Process);
  458. ObDereferenceObject (DebugEvent->Thread);
  459. ExFreePool (DebugEvent);
  460. }
  461. NTSTATUS
  462. DbgkpQueueMessage (
  463. IN PEPROCESS Process,
  464. IN PETHREAD Thread,
  465. IN OUT PDBGKM_APIMSG ApiMsg,
  466. IN ULONG Flags,
  467. IN PDEBUG_OBJECT TargetDebugObject
  468. )
  469. /*++
  470. Routine Description:
  471. Queues a debug message to the port for a user mode debugger to get.
  472. Arguments:
  473. Process - Process being debugged
  474. Thread - Thread making call
  475. ApiMsg - Message being sent and received
  476. NoWait - Don't wait for a responce. Buffer message and return.
  477. TargetDebugObject - Port to queue nowait messages to
  478. Return Value:
  479. NTSTATUS - Status of call.
  480. --*/
  481. {
  482. PDEBUG_EVENT DebugEvent;
  483. DEBUG_EVENT StaticDebugEvent;
  484. PDEBUG_OBJECT DebugObject;
  485. NTSTATUS Status;
  486. PAGED_CODE ();
  487. if (Flags&DEBUG_EVENT_NOWAIT) {
  488. DebugEvent = ExAllocatePoolWithQuotaTag (NonPagedPool|POOL_QUOTA_FAIL_INSTEAD_OF_RAISE,
  489. sizeof (*DebugEvent),
  490. 'EgbD');
  491. if (DebugEvent == NULL) {
  492. return STATUS_INSUFFICIENT_RESOURCES;
  493. }
  494. DebugEvent->Flags = Flags|DEBUG_EVENT_INACTIVE;
  495. ObReferenceObject (Process);
  496. ObReferenceObject (Thread);
  497. DebugEvent->BackoutThread = PsGetCurrentThread ();
  498. DebugObject = TargetDebugObject;
  499. } else {
  500. DebugEvent = &StaticDebugEvent;
  501. DebugEvent->Flags = Flags;
  502. ExAcquireFastMutex (&DbgkpProcessDebugPortMutex);
  503. DebugObject = Process->DebugPort;
  504. //
  505. // See if this create message has already been sent.
  506. //
  507. if (ApiMsg->ApiNumber == DbgKmCreateThreadApi ||
  508. ApiMsg->ApiNumber == DbgKmCreateProcessApi) {
  509. if (Thread->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_SKIP_CREATION_MSG) {
  510. DebugObject = NULL;
  511. }
  512. }
  513. //
  514. // See if this exit message is for a thread that never had a create
  515. //
  516. if (ApiMsg->ApiNumber == DbgKmExitThreadApi ||
  517. ApiMsg->ApiNumber == DbgKmExitProcessApi) {
  518. if (Thread->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_SKIP_TERMINATION_MSG) {
  519. DebugObject = NULL;
  520. }
  521. }
  522. }
  523. KeInitializeEvent (&DebugEvent->ContinueEvent, SynchronizationEvent, FALSE);
  524. DebugEvent->Process = Process;
  525. DebugEvent->Thread = Thread;
  526. DebugEvent->ApiMsg = *ApiMsg;
  527. DebugEvent->ClientId = Thread->Cid;
  528. if (DebugObject == NULL) {
  529. Status = STATUS_PORT_NOT_SET;
  530. } else {
  531. //
  532. // We must not use a debug port thats got no handles left.
  533. //
  534. ExAcquireFastMutex (&DebugObject->Mutex);
  535. //
  536. // If the object is delete pending then don't use this object.
  537. //
  538. if ((DebugObject->Flags&DEBUG_OBJECT_DELETE_PENDING) == 0) {
  539. InsertTailList (&DebugObject->EventList, &DebugEvent->EventList);
  540. //
  541. // Set the event to say there is an unread event in the object
  542. //
  543. if ((Flags&DEBUG_EVENT_NOWAIT) == 0) {
  544. KeSetEvent (&DebugObject->EventsPresent, 0, FALSE);
  545. }
  546. Status = STATUS_SUCCESS;
  547. } else {
  548. Status = STATUS_DEBUGGER_INACTIVE;
  549. }
  550. ExReleaseFastMutex (&DebugObject->Mutex);
  551. }
  552. if ((Flags&DEBUG_EVENT_NOWAIT) == 0) {
  553. ExReleaseFastMutex (&DbgkpProcessDebugPortMutex);
  554. if (NT_SUCCESS (Status)) {
  555. KeWaitForSingleObject (&DebugEvent->ContinueEvent,
  556. Executive,
  557. KernelMode,
  558. FALSE,
  559. NULL);
  560. Status = DebugEvent->Status;
  561. *ApiMsg = DebugEvent->ApiMsg;
  562. }
  563. } else {
  564. if (!NT_SUCCESS (Status)) {
  565. ObDereferenceObject (Process);
  566. ObDereferenceObject (Thread);
  567. ExFreePool (DebugEvent);
  568. }
  569. }
  570. return Status;
  571. }
  572. NTSTATUS
  573. DbgkClearProcessDebugObject (
  574. IN PEPROCESS Process,
  575. IN PDEBUG_OBJECT SourceDebugObject
  576. )
  577. /*++
  578. Routine Description:
  579. Remove a debug object from a process.
  580. Arguments:
  581. Process - Process to be debugged
  582. sourceDebugObject - Debug object to detach
  583. Return Value:
  584. NTSTATUS - Status of call.
  585. --*/
  586. {
  587. NTSTATUS Status;
  588. PDEBUG_OBJECT DebugObject;
  589. PDEBUG_EVENT DebugEvent;
  590. LIST_ENTRY TempList;
  591. PLIST_ENTRY Entry;
  592. PAGED_CODE ();
  593. ExAcquireFastMutex (&DbgkpProcessDebugPortMutex);
  594. DebugObject = Process->DebugPort;
  595. if (DebugObject == NULL || (DebugObject != SourceDebugObject && SourceDebugObject != NULL)) {
  596. DebugObject = NULL;
  597. Status = STATUS_PORT_NOT_SET;
  598. } else {
  599. Process->DebugPort = NULL;
  600. Status = STATUS_SUCCESS;
  601. }
  602. ExReleaseFastMutex (&DbgkpProcessDebugPortMutex);
  603. if (NT_SUCCESS (Status)) {
  604. DbgkpMarkProcessPeb (Process);
  605. }
  606. //
  607. // Remove any events for this process and wake up the threads.
  608. //
  609. if (DebugObject) {
  610. //
  611. // Remove any events and queue them to a temporary queue
  612. //
  613. InitializeListHead (&TempList);
  614. ExAcquireFastMutex (&DebugObject->Mutex);
  615. for (Entry = DebugObject->EventList.Flink;
  616. Entry != &DebugObject->EventList;
  617. ) {
  618. DebugEvent = CONTAINING_RECORD (Entry, DEBUG_EVENT, EventList);
  619. Entry = Entry->Flink;
  620. if (DebugEvent->Process == Process) {
  621. RemoveEntryList (&DebugEvent->EventList);
  622. InsertTailList (&TempList, &DebugEvent->EventList);
  623. }
  624. }
  625. ExReleaseFastMutex (&DebugObject->Mutex);
  626. ObDereferenceObject (DebugObject);
  627. //
  628. // Wake up all the removed threads.
  629. //
  630. while (!IsListEmpty (&TempList)) {
  631. Entry = RemoveHeadList (&TempList);
  632. DebugEvent = CONTAINING_RECORD (Entry, DEBUG_EVENT, EventList);
  633. DebugEvent->Status = STATUS_DEBUGGER_INACTIVE;
  634. DbgkpWakeTarget (DebugEvent);
  635. }
  636. }
  637. return Status;
  638. }
  639. NTSTATUS
  640. DbgkpSetProcessDebugObject (
  641. IN PEPROCESS Process,
  642. IN PDEBUG_OBJECT DebugObject,
  643. IN NTSTATUS MsgStatus,
  644. IN PETHREAD LastThread
  645. )
  646. /*++
  647. Routine Description:
  648. Attach a debug object to a process.
  649. Arguments:
  650. Process - Process to be debugged
  651. DebugObject - Debug object to attach
  652. MsgStatus - Status from queing the messages
  653. LastThread - Last thread seen in attach loop.
  654. Return Value:
  655. NTSTATUS - Status of call.
  656. --*/
  657. {
  658. NTSTATUS Status;
  659. PETHREAD ThisThread;
  660. LIST_ENTRY TempList;
  661. PLIST_ENTRY Entry;
  662. PDEBUG_EVENT DebugEvent;
  663. BOOLEAN First;
  664. PETHREAD Thread;
  665. BOOLEAN GlobalHeld;
  666. PETHREAD FirstThread;
  667. PAGED_CODE ();
  668. ThisThread = PsGetCurrentThread ();
  669. InitializeListHead (&TempList);
  670. First = TRUE;
  671. GlobalHeld = FALSE;
  672. if (!NT_SUCCESS (MsgStatus)) {
  673. LastThread = NULL;
  674. Status = MsgStatus;
  675. } else {
  676. Status = STATUS_SUCCESS;
  677. }
  678. //
  679. // Pick up any threads we missed
  680. //
  681. if (NT_SUCCESS (Status)) {
  682. while (1) {
  683. //
  684. // Acquire the debug port mutex so we know that any new threads will
  685. // have to wait to behind us.
  686. //
  687. GlobalHeld = TRUE;
  688. ExAcquireFastMutex (&DbgkpProcessDebugPortMutex);
  689. //
  690. // If the port has been set then exit now.
  691. //
  692. if (Process->DebugPort != NULL) {
  693. Status = STATUS_PORT_ALREADY_SET;
  694. break;
  695. }
  696. //
  697. // Assign the debug port to the process to pick up any new threads
  698. //
  699. Process->DebugPort = DebugObject;
  700. //
  701. // Reference the last thread so we can deref outside the lock
  702. //
  703. ObReferenceObject (LastThread);
  704. //
  705. // Search forward for new threads
  706. //
  707. Thread = PsGetNextProcessThread (Process, LastThread);
  708. if (Thread != NULL) {
  709. //
  710. // Remove the debug port from the process as we are
  711. // about to drop the lock
  712. //
  713. Process->DebugPort = NULL;
  714. ExReleaseFastMutex (&DbgkpProcessDebugPortMutex);
  715. GlobalHeld = FALSE;
  716. ObDereferenceObject (LastThread);
  717. //
  718. // Queue any new thread messages and repeat.
  719. //
  720. Status = DbgkpPostFakeThreadMessages (Process,
  721. DebugObject,
  722. Thread,
  723. &FirstThread,
  724. &LastThread);
  725. if (!NT_SUCCESS (Status)) {
  726. LastThread = NULL;
  727. break;
  728. }
  729. ObDereferenceObject (FirstThread);
  730. } else {
  731. break;
  732. }
  733. }
  734. }
  735. //
  736. // Lock the debug object so we can check its deleted status
  737. //
  738. ExAcquireFastMutex (&DebugObject->Mutex);
  739. //
  740. // We must not propogate a debug port thats got no handles left.
  741. //
  742. if (NT_SUCCESS (Status)) {
  743. if ((DebugObject->Flags&DEBUG_OBJECT_DELETE_PENDING) == 0) {
  744. PS_SET_BITS (&Process->Flags, PS_PROCESS_FLAGS_NO_DEBUG_INHERIT);
  745. ObReferenceObject (DebugObject);
  746. } else {
  747. Process->DebugPort = NULL;
  748. Status = STATUS_DEBUGGER_INACTIVE;
  749. }
  750. }
  751. for (Entry = DebugObject->EventList.Flink;
  752. Entry != &DebugObject->EventList;
  753. ) {
  754. DebugEvent = CONTAINING_RECORD (Entry, DEBUG_EVENT, EventList);
  755. Entry = Entry->Flink;
  756. if ((DebugEvent->Flags&DEBUG_EVENT_INACTIVE) != 0 && DebugEvent->BackoutThread == ThisThread) {
  757. Thread = DebugEvent->Thread;
  758. //
  759. // If the thread has not been inserted by CreateThread yet then don't
  760. // create a handle. We skip system threads here also
  761. //
  762. if (NT_SUCCESS (Status) && Thread->GrantedAccess != 0 && !IS_SYSTEM_THREAD (Thread)) {
  763. //
  764. // If we could not acquire rundown protection on this
  765. // thread then we need to supress its exit message.
  766. //
  767. if ((DebugEvent->Flags&DEBUG_EVENT_PROTECT_FAILED) != 0) {
  768. PS_SET_BITS (&Thread->CrossThreadFlags,
  769. PS_CROSS_THREAD_FLAGS_SKIP_TERMINATION_MSG);
  770. RemoveEntryList (&DebugEvent->EventList);
  771. InsertTailList (&TempList, &DebugEvent->EventList);
  772. } else {
  773. if (First) {
  774. DebugEvent->Flags &= ~DEBUG_EVENT_INACTIVE;
  775. KeSetEvent (&DebugObject->EventsPresent, 0, FALSE);
  776. First = FALSE;
  777. }
  778. DebugEvent->BackoutThread = NULL;
  779. PS_SET_BITS (&Thread->CrossThreadFlags,
  780. PS_CROSS_THREAD_FLAGS_SKIP_CREATION_MSG);
  781. }
  782. } else {
  783. RemoveEntryList (&DebugEvent->EventList);
  784. InsertTailList (&TempList, &DebugEvent->EventList);
  785. }
  786. if (DebugEvent->Flags&DEBUG_EVENT_RELEASE) {
  787. DebugEvent->Flags &= ~DEBUG_EVENT_RELEASE;
  788. ExReleaseRundownProtection (&Thread->RundownProtect);
  789. }
  790. }
  791. }
  792. ExReleaseFastMutex (&DebugObject->Mutex);
  793. if (GlobalHeld) {
  794. ExReleaseFastMutex (&DbgkpProcessDebugPortMutex);
  795. }
  796. if (LastThread != NULL) {
  797. ObDereferenceObject (LastThread);
  798. }
  799. while (!IsListEmpty (&TempList)) {
  800. Entry = RemoveHeadList (&TempList);
  801. DebugEvent = CONTAINING_RECORD (Entry, DEBUG_EVENT, EventList);
  802. DbgkpWakeTarget (DebugEvent);
  803. }
  804. if (NT_SUCCESS (Status)) {
  805. DbgkpMarkProcessPeb (Process);
  806. }
  807. return Status;
  808. }
  809. NTSTATUS
  810. DbgkpPostFakeThreadMessages (
  811. IN PEPROCESS Process,
  812. IN PDEBUG_OBJECT DebugObject,
  813. IN PETHREAD StartThread,
  814. OUT PETHREAD *pFirstThread,
  815. OUT PETHREAD *pLastThread
  816. )
  817. /*++
  818. Routine Description:
  819. This routine posts the faked initial process create, thread create messages
  820. Arguments:
  821. Process - Process to be debugged
  822. DebugObject - Debug object to queue messages to
  823. StartThread - Thread to start search from
  824. pFirstThread - First thread found in the list
  825. pLastThread - Last thread found in the list
  826. Return Value:
  827. None.
  828. --*/
  829. {
  830. NTSTATUS Status;
  831. PETHREAD Thread, FirstThread, LastThread;
  832. DBGKM_APIMSG ApiMsg;
  833. BOOLEAN First = TRUE;
  834. PIMAGE_NT_HEADERS NtHeaders;
  835. ULONG Flags;
  836. #if !defined (DBGK_DONT_SUSPEND)
  837. NTSTATUS Status1;
  838. #endif
  839. PAGED_CODE ();
  840. LastThread = FirstThread = NULL;
  841. Status = STATUS_UNSUCCESSFUL;
  842. if (StartThread != NULL) {
  843. First = FALSE;
  844. FirstThread = StartThread;
  845. ObReferenceObject (FirstThread);
  846. } else {
  847. StartThread = PsGetNextProcessThread (Process, NULL);
  848. First = TRUE;
  849. }
  850. for (Thread = StartThread;
  851. Thread != NULL;
  852. Thread = PsGetNextProcessThread (Process, Thread)) {
  853. Flags = DEBUG_EVENT_NOWAIT;
  854. //
  855. // Keep a track ont he last thread we have seen.
  856. // We use this as a starting point for new threads after we
  857. // really attach so we can pick up any new threads.
  858. //
  859. if (LastThread != NULL) {
  860. ObDereferenceObject (LastThread);
  861. }
  862. LastThread = Thread;
  863. ObReferenceObject (LastThread);
  864. //
  865. // Acquire rundown protection of the thread.
  866. // This stops the thread exiting so we know it can't send
  867. // it's termination message
  868. //
  869. if (ExAcquireRundownProtection (&Thread->RundownProtect)) {
  870. Flags |= DEBUG_EVENT_RELEASE;
  871. //
  872. // Suspend the thread if we can for the debugger
  873. // We don't suspend terminating threads as we will not be giving details
  874. // of these to the debugger.
  875. //
  876. #if !defined (DBGK_DONT_SUSPEND)
  877. if (!IS_SYSTEM_THREAD (Thread)) {
  878. Status1 = PsSuspendThread (Thread, NULL);
  879. if (NT_SUCCESS (Status1)) {
  880. Flags |= DEBUG_EVENT_SUSPEND;
  881. }
  882. }
  883. #endif
  884. } else {
  885. //
  886. // Rundown protection failed for this thread.
  887. // This means the thread is exiting. We will mark this thread
  888. // later so it doesn't sent a thread termination message.
  889. // We can't do this now because this attach might fail.
  890. //
  891. Flags |= DEBUG_EVENT_PROTECT_FAILED;
  892. }
  893. RtlZeroMemory (&ApiMsg, sizeof (ApiMsg));
  894. if (First) {
  895. ApiMsg.ApiNumber = DbgKmCreateProcessApi;
  896. if (Process->SectionObject != NULL) { // system process doesn't have one of these!
  897. ApiMsg.u.CreateProcessInfo.FileHandle = DbgkpSectionToFileHandle (Process->SectionObject);
  898. } else {
  899. ApiMsg.u.CreateProcessInfo.FileHandle = NULL;
  900. }
  901. ApiMsg.u.CreateProcessInfo.BaseOfImage = Process->SectionBaseAddress;
  902. try {
  903. NtHeaders = RtlImageNtHeader(Process->SectionBaseAddress);
  904. if (NtHeaders) {
  905. ApiMsg.u.CreateProcessInfo.InitialThread.StartAddress = NULL; // Filling this in breaks MSDEV!
  906. // (PVOID)(NtHeaders->OptionalHeader.ImageBase + NtHeaders->OptionalHeader.AddressOfEntryPoint);
  907. ApiMsg.u.CreateProcessInfo.DebugInfoFileOffset = NtHeaders->FileHeader.PointerToSymbolTable;
  908. ApiMsg.u.CreateProcessInfo.DebugInfoSize = NtHeaders->FileHeader.NumberOfSymbols;
  909. }
  910. } except (EXCEPTION_EXECUTE_HANDLER) {
  911. ApiMsg.u.CreateProcessInfo.InitialThread.StartAddress = NULL;
  912. ApiMsg.u.CreateProcessInfo.DebugInfoFileOffset = 0;
  913. ApiMsg.u.CreateProcessInfo.DebugInfoSize = 0;
  914. }
  915. } else {
  916. ApiMsg.ApiNumber = DbgKmCreateThreadApi;
  917. ApiMsg.u.CreateThread.StartAddress = Thread->StartAddress;
  918. }
  919. Status = DbgkpQueueMessage (Process,
  920. Thread,
  921. &ApiMsg,
  922. Flags,
  923. DebugObject);
  924. if (!NT_SUCCESS (Status)) {
  925. if (Flags&DEBUG_EVENT_SUSPEND) {
  926. PsResumeThread (Thread, NULL);
  927. }
  928. if (Flags&DEBUG_EVENT_RELEASE) {
  929. ExReleaseRundownProtection (&Thread->RundownProtect);
  930. }
  931. if (ApiMsg.ApiNumber == DbgKmCreateProcessApi && ApiMsg.u.CreateProcessInfo.FileHandle != NULL) {
  932. ObCloseHandle (ApiMsg.u.CreateProcessInfo.FileHandle, KernelMode);
  933. }
  934. PsQuitNextProcessThread (Thread);
  935. break;
  936. } else if (First) {
  937. First = FALSE;
  938. ObReferenceObject (Thread);
  939. FirstThread = Thread;
  940. }
  941. }
  942. if (!NT_SUCCESS (Status)) {
  943. if (FirstThread) {
  944. ObDereferenceObject (FirstThread);
  945. }
  946. if (LastThread != NULL) {
  947. ObDereferenceObject (LastThread);
  948. }
  949. } else {
  950. if (FirstThread) {
  951. *pFirstThread = FirstThread;
  952. *pLastThread = LastThread;
  953. } else {
  954. Status = STATUS_UNSUCCESSFUL;
  955. }
  956. }
  957. return Status;
  958. }
  959. NTSTATUS
  960. DbgkpPostFakeModuleMessages (
  961. IN PEPROCESS Process,
  962. IN PETHREAD Thread,
  963. IN PDEBUG_OBJECT DebugObject)
  964. /*++
  965. Routine Description:
  966. This routine posts the faked module load messages when we debug an active process.
  967. Arguments:
  968. ProcessHandle - Handle to a process to be debugged
  969. DebugObjectHandle - Handle to a debug object
  970. Return Value:
  971. None.
  972. --*/
  973. {
  974. PPEB Peb = Process->Peb;
  975. PPEB_LDR_DATA Ldr;
  976. PLIST_ENTRY LdrHead, LdrNext;
  977. PLDR_DATA_TABLE_ENTRY LdrEntry;
  978. DBGKM_APIMSG ApiMsg;
  979. ULONG i;
  980. OBJECT_ATTRIBUTES oa;
  981. UNICODE_STRING Name;
  982. PIMAGE_NT_HEADERS NtHeaders;
  983. NTSTATUS Status;
  984. IO_STATUS_BLOCK iosb;
  985. PAGED_CODE ();
  986. if (Peb == NULL) {
  987. return STATUS_SUCCESS;
  988. }
  989. try {
  990. Ldr = Peb->Ldr;
  991. LdrHead = &Ldr->InLoadOrderModuleList;
  992. ProbeForReadSmallStructure (LdrHead, sizeof (LIST_ENTRY), sizeof (UCHAR));
  993. for (LdrNext = LdrHead->Flink, i = 0;
  994. LdrNext != LdrHead && i < 500;
  995. LdrNext = LdrNext->Flink, i++) {
  996. //
  997. // First image got send with process create message
  998. //
  999. if (i > 0) {
  1000. RtlZeroMemory (&ApiMsg, sizeof (ApiMsg));
  1001. LdrEntry = CONTAINING_RECORD (LdrNext, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
  1002. ProbeForReadSmallStructure (LdrEntry, sizeof (LDR_DATA_TABLE_ENTRY), sizeof (UCHAR));
  1003. ApiMsg.ApiNumber = DbgKmLoadDllApi;
  1004. ApiMsg.u.LoadDll.BaseOfDll = LdrEntry->DllBase;
  1005. ProbeForReadSmallStructure (ApiMsg.u.LoadDll.BaseOfDll, sizeof (IMAGE_DOS_HEADER), sizeof (UCHAR));
  1006. NtHeaders = RtlImageNtHeader (ApiMsg.u.LoadDll.BaseOfDll);
  1007. if (NtHeaders) {
  1008. ApiMsg.u.LoadDll.DebugInfoFileOffset = NtHeaders->FileHeader.PointerToSymbolTable;
  1009. ApiMsg.u.LoadDll.DebugInfoSize = NtHeaders->FileHeader.NumberOfSymbols;
  1010. }
  1011. Status = MmGetFileNameForAddress (NtHeaders, &Name);
  1012. if (NT_SUCCESS (Status)) {
  1013. InitializeObjectAttributes (&oa,
  1014. &Name,
  1015. OBJ_FORCE_ACCESS_CHECK|OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE,
  1016. NULL,
  1017. NULL);
  1018. Status = ZwOpenFile (&ApiMsg.u.LoadDll.FileHandle,
  1019. GENERIC_READ|SYNCHRONIZE,
  1020. &oa,
  1021. &iosb,
  1022. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  1023. FILE_SYNCHRONOUS_IO_NONALERT);
  1024. if (!NT_SUCCESS (Status)) {
  1025. ApiMsg.u.LoadDll.FileHandle = NULL;
  1026. }
  1027. ExFreePool (Name.Buffer);
  1028. }
  1029. Status = DbgkpQueueMessage (Process,
  1030. Thread,
  1031. &ApiMsg,
  1032. DEBUG_EVENT_NOWAIT,
  1033. DebugObject);
  1034. if (!NT_SUCCESS (Status) && ApiMsg.u.LoadDll.FileHandle != NULL) {
  1035. ObCloseHandle (ApiMsg.u.LoadDll.FileHandle, KernelMode);
  1036. }
  1037. }
  1038. ProbeForReadSmallStructure (LdrNext, sizeof (LIST_ENTRY), sizeof (UCHAR));
  1039. }
  1040. } except (EXCEPTION_EXECUTE_HANDLER) {
  1041. }
  1042. #if defined(_WIN64)
  1043. if (Process->Wow64Process != NULL && Process->Wow64Process->Wow64 != NULL) {
  1044. PPEB32 Peb32;
  1045. PPEB_LDR_DATA32 Ldr32;
  1046. PLIST_ENTRY32 LdrHead32, LdrNext32;
  1047. PLDR_DATA_TABLE_ENTRY32 LdrEntry32;
  1048. PWCHAR pSys;
  1049. Peb32 = (PPEB32)Process->Wow64Process->Wow64;
  1050. try {
  1051. Ldr32 = (PVOID) UlongToPtr(Peb32->Ldr);
  1052. LdrHead32 = &Ldr32->InLoadOrderModuleList;
  1053. ProbeForReadSmallStructure (LdrHead32, sizeof (LIST_ENTRY32), sizeof (UCHAR));
  1054. for (LdrNext32 = (PVOID) UlongToPtr(LdrHead32->Flink), i = 0;
  1055. LdrNext32 != LdrHead32 && i < 500;
  1056. LdrNext32 = (PVOID) UlongToPtr(LdrNext32->Flink), i++) {
  1057. if (i > 0) {
  1058. RtlZeroMemory (&ApiMsg, sizeof (ApiMsg));
  1059. LdrEntry32 = CONTAINING_RECORD (LdrNext32, LDR_DATA_TABLE_ENTRY32, InLoadOrderLinks);
  1060. ProbeForReadSmallStructure (LdrEntry32, sizeof (LDR_DATA_TABLE_ENTRY32), sizeof (UCHAR));
  1061. ApiMsg.ApiNumber = DbgKmLoadDllApi;
  1062. ApiMsg.u.LoadDll.BaseOfDll = (PVOID) UlongToPtr(LdrEntry32->DllBase);
  1063. ProbeForReadSmallStructure (ApiMsg.u.LoadDll.BaseOfDll, sizeof (IMAGE_DOS_HEADER), sizeof (UCHAR));
  1064. NtHeaders = RtlImageNtHeader(ApiMsg.u.LoadDll.BaseOfDll);
  1065. if (NtHeaders) {
  1066. ApiMsg.u.LoadDll.DebugInfoFileOffset = NtHeaders->FileHeader.PointerToSymbolTable;
  1067. ApiMsg.u.LoadDll.DebugInfoSize = NtHeaders->FileHeader.NumberOfSymbols;
  1068. }
  1069. Status = MmGetFileNameForAddress (NtHeaders, &Name);
  1070. if (NT_SUCCESS (Status)) {
  1071. ASSERT (sizeof (L"SYSTEM32") == sizeof (WOW64_SYSTEM_DIRECTORY_U));
  1072. pSys = wcsstr (Name.Buffer, L"\\SYSTEM32\\");
  1073. if (pSys != NULL) {
  1074. RtlCopyMemory (pSys+1,
  1075. WOW64_SYSTEM_DIRECTORY_U,
  1076. sizeof(WOW64_SYSTEM_DIRECTORY_U) - sizeof(UNICODE_NULL));
  1077. }
  1078. InitializeObjectAttributes (&oa,
  1079. &Name,
  1080. OBJ_FORCE_ACCESS_CHECK|OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE,
  1081. NULL,
  1082. NULL);
  1083. Status = ZwOpenFile (&ApiMsg.u.LoadDll.FileHandle,
  1084. GENERIC_READ|SYNCHRONIZE,
  1085. &oa,
  1086. &iosb,
  1087. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  1088. FILE_SYNCHRONOUS_IO_NONALERT);
  1089. if (!NT_SUCCESS (Status)) {
  1090. ApiMsg.u.LoadDll.FileHandle = NULL;
  1091. }
  1092. ExFreePool (Name.Buffer);
  1093. }
  1094. Status = DbgkpQueueMessage (Process,
  1095. Thread,
  1096. &ApiMsg,
  1097. DEBUG_EVENT_NOWAIT,
  1098. DebugObject);
  1099. if (!NT_SUCCESS (Status) && ApiMsg.u.LoadDll.FileHandle != NULL) {
  1100. ObCloseHandle (ApiMsg.u.LoadDll.FileHandle, KernelMode);
  1101. }
  1102. }
  1103. ProbeForReadSmallStructure (LdrNext32, sizeof (LIST_ENTRY32), sizeof (UCHAR));
  1104. }
  1105. } except (EXCEPTION_EXECUTE_HANDLER) {
  1106. }
  1107. }
  1108. #endif
  1109. return STATUS_SUCCESS;
  1110. }
  1111. NTSTATUS
  1112. DbgkpPostFakeProcessCreateMessages (
  1113. IN PEPROCESS Process,
  1114. IN PDEBUG_OBJECT DebugObject,
  1115. IN PETHREAD *pLastThread
  1116. )
  1117. /*++
  1118. Routine Description:
  1119. This routine posts the faked initial process create, thread create and mudule load messages
  1120. Arguments:
  1121. ProcessHandle - Handle to a process to be debugged
  1122. DebugObjectHandle - Handle to a debug object
  1123. Return Value:
  1124. None.
  1125. --*/
  1126. {
  1127. NTSTATUS Status;
  1128. KAPC_STATE ApcState;
  1129. PETHREAD Thread;
  1130. PETHREAD LastThread;
  1131. PAGED_CODE ();
  1132. //
  1133. // Attach to the process so we can touch its address space
  1134. //
  1135. KeStackAttachProcess(&Process->Pcb, &ApcState);
  1136. Status = DbgkpPostFakeThreadMessages (Process,
  1137. DebugObject,
  1138. NULL,
  1139. &Thread,
  1140. &LastThread);
  1141. if (NT_SUCCESS (Status)) {
  1142. Status = DbgkpPostFakeModuleMessages (Process, Thread, DebugObject);
  1143. if (!NT_SUCCESS (Status)) {
  1144. ObDereferenceObject (LastThread);
  1145. LastThread = NULL;
  1146. }
  1147. ObDereferenceObject (Thread);
  1148. } else {
  1149. LastThread = NULL;
  1150. }
  1151. KeUnstackDetachProcess(&ApcState);
  1152. *pLastThread = LastThread;
  1153. return Status;
  1154. }
  1155. NTSTATUS
  1156. NtDebugActiveProcess (
  1157. IN HANDLE ProcessHandle,
  1158. IN HANDLE DebugObjectHandle
  1159. )
  1160. /*++
  1161. Routine Description:
  1162. Attach a debug object to a process.
  1163. Arguments:
  1164. ProcessHandle - Handle to a process to be debugged
  1165. DebugObjectHandle - Handle to a debug object
  1166. Return Value:
  1167. NTSTATUS - Status of call.
  1168. --*/
  1169. {
  1170. NTSTATUS Status;
  1171. KPROCESSOR_MODE PreviousMode;
  1172. PDEBUG_OBJECT DebugObject;
  1173. PEPROCESS Process;
  1174. PETHREAD LastThread;
  1175. PAGED_CODE ();
  1176. PreviousMode = KeGetPreviousMode();
  1177. Status = ObReferenceObjectByHandle (ProcessHandle,
  1178. PROCESS_SET_PORT,
  1179. PsProcessType,
  1180. PreviousMode,
  1181. &Process,
  1182. NULL);
  1183. if (!NT_SUCCESS (Status)) {
  1184. return Status;
  1185. }
  1186. //
  1187. // Don't let us debug ourselves or the system process.
  1188. //
  1189. if (Process == PsGetCurrentProcess () || Process == PsInitialSystemProcess) {
  1190. ObDereferenceObject (Process);
  1191. return STATUS_ACCESS_DENIED;
  1192. }
  1193. Status = ObReferenceObjectByHandle (DebugObjectHandle,
  1194. DEBUG_PROCESS_ASSIGN,
  1195. DbgkDebugObjectType,
  1196. PreviousMode,
  1197. &DebugObject,
  1198. NULL);
  1199. if (NT_SUCCESS (Status)) {
  1200. //
  1201. // We will be touching process address space. Block process rundown.
  1202. //
  1203. if (ExAcquireRundownProtection (&Process->RundownProtect)) {
  1204. //
  1205. // Post the fake process create messages etc.
  1206. //
  1207. Status = DbgkpPostFakeProcessCreateMessages (Process,
  1208. DebugObject,
  1209. &LastThread);
  1210. //
  1211. // Set the debug port. If this fails it will remove any faked messages.
  1212. //
  1213. Status = DbgkpSetProcessDebugObject (Process,
  1214. DebugObject,
  1215. Status,
  1216. LastThread);
  1217. ExReleaseRundownProtection (&Process->RundownProtect);
  1218. } else {
  1219. Status = STATUS_PROCESS_IS_TERMINATING;
  1220. }
  1221. ObDereferenceObject (DebugObject);
  1222. }
  1223. ObDereferenceObject (Process);
  1224. return Status;
  1225. }
  1226. NTSTATUS
  1227. NtRemoveProcessDebug (
  1228. IN HANDLE ProcessHandle,
  1229. IN HANDLE DebugObjectHandle
  1230. )
  1231. /*++
  1232. Routine Description:
  1233. Remove a debug object from a process.
  1234. Arguments:
  1235. ProcessHandle - Handle to a process currently being debugged
  1236. Return Value:
  1237. NTSTATUS - Status of call.
  1238. --*/
  1239. {
  1240. NTSTATUS Status;
  1241. KPROCESSOR_MODE PreviousMode;
  1242. PDEBUG_OBJECT DebugObject;
  1243. PEPROCESS Process;
  1244. PAGED_CODE ();
  1245. PreviousMode = KeGetPreviousMode();
  1246. Status = ObReferenceObjectByHandle (ProcessHandle,
  1247. PROCESS_SET_PORT,
  1248. PsProcessType,
  1249. PreviousMode,
  1250. &Process,
  1251. NULL);
  1252. if (!NT_SUCCESS (Status)) {
  1253. return Status;
  1254. }
  1255. Status = ObReferenceObjectByHandle (DebugObjectHandle,
  1256. DEBUG_PROCESS_ASSIGN,
  1257. DbgkDebugObjectType,
  1258. PreviousMode,
  1259. &DebugObject,
  1260. NULL);
  1261. if (NT_SUCCESS (Status)) {
  1262. Status = DbgkClearProcessDebugObject (Process,
  1263. DebugObject);
  1264. ObDereferenceObject (DebugObject);
  1265. }
  1266. ObDereferenceObject (Process);
  1267. return Status;
  1268. }
  1269. VOID
  1270. DbgkpOpenHandles (
  1271. PDBGUI_WAIT_STATE_CHANGE WaitStateChange,
  1272. PEPROCESS Process,
  1273. PETHREAD Thread
  1274. )
  1275. /*++
  1276. Routine Description:
  1277. Opens up process, thread and filehandles if need be for some of the requests
  1278. Arguments:
  1279. WaitStateChange - User mode format change block
  1280. Process - Pointer to target process
  1281. Thread - Pointer to target thread
  1282. Return Value:
  1283. None
  1284. --*/
  1285. {
  1286. NTSTATUS Status;
  1287. PEPROCESS CurrentProcess;
  1288. HANDLE OldHandle;
  1289. PAGED_CODE ();
  1290. switch (WaitStateChange->NewState) {
  1291. case DbgCreateThreadStateChange :
  1292. //
  1293. // We have the right to open up any thread in the process if we are allowed to debug it.
  1294. // Use kernel mode here so we are always granted it regardless of protection.
  1295. //
  1296. Status = ObOpenObjectByPointer (Thread,
  1297. 0,
  1298. NULL,
  1299. THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME | \
  1300. THREAD_QUERY_INFORMATION | THREAD_SET_INFORMATION | THREAD_TERMINATE |
  1301. READ_CONTROL | SYNCHRONIZE,
  1302. PsThreadType,
  1303. KernelMode,
  1304. &WaitStateChange->StateInfo.CreateThread.HandleToThread);
  1305. if (!NT_SUCCESS (Status)) {
  1306. WaitStateChange->StateInfo.CreateThread.HandleToThread = NULL;
  1307. }
  1308. break;
  1309. case DbgCreateProcessStateChange :
  1310. Status = ObOpenObjectByPointer (Thread,
  1311. 0,
  1312. NULL,
  1313. THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME | \
  1314. THREAD_QUERY_INFORMATION | THREAD_SET_INFORMATION | THREAD_TERMINATE |
  1315. READ_CONTROL | SYNCHRONIZE,
  1316. PsThreadType,
  1317. KernelMode,
  1318. &WaitStateChange->StateInfo.CreateProcessInfo.HandleToThread);
  1319. if (!NT_SUCCESS (Status)) {
  1320. WaitStateChange->StateInfo.CreateProcessInfo.HandleToThread = NULL;
  1321. }
  1322. Status = ObOpenObjectByPointer (Process,
  1323. 0,
  1324. NULL,
  1325. PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION |
  1326. PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION | PROCESS_SET_INFORMATION |
  1327. PROCESS_CREATE_THREAD | PROCESS_TERMINATE |
  1328. READ_CONTROL | SYNCHRONIZE,
  1329. PsProcessType,
  1330. KernelMode,
  1331. &WaitStateChange->StateInfo.CreateProcessInfo.HandleToProcess);
  1332. if (!NT_SUCCESS (Status)) {
  1333. WaitStateChange->StateInfo.CreateProcessInfo.HandleToProcess = NULL;
  1334. }
  1335. OldHandle = WaitStateChange->StateInfo.CreateProcessInfo.NewProcess.FileHandle;
  1336. if (OldHandle != NULL) {
  1337. CurrentProcess = PsGetCurrentProcess ();
  1338. Status = ObDuplicateObject (CurrentProcess,
  1339. OldHandle,
  1340. CurrentProcess,
  1341. &WaitStateChange->StateInfo.CreateProcessInfo.NewProcess.FileHandle,
  1342. 0,
  1343. 0,
  1344. DUPLICATE_SAME_ACCESS,
  1345. KernelMode);
  1346. if (!NT_SUCCESS (Status)) {
  1347. WaitStateChange->StateInfo.CreateProcessInfo.NewProcess.FileHandle = NULL;
  1348. }
  1349. ObCloseHandle (OldHandle, KernelMode);
  1350. }
  1351. break;
  1352. case DbgLoadDllStateChange :
  1353. OldHandle = WaitStateChange->StateInfo.LoadDll.FileHandle;
  1354. if (OldHandle != NULL) {
  1355. CurrentProcess = PsGetCurrentProcess ();
  1356. Status = ObDuplicateObject (CurrentProcess,
  1357. OldHandle,
  1358. CurrentProcess,
  1359. &WaitStateChange->StateInfo.LoadDll.FileHandle,
  1360. 0,
  1361. 0,
  1362. DUPLICATE_SAME_ACCESS,
  1363. KernelMode);
  1364. if (!NT_SUCCESS (Status)) {
  1365. WaitStateChange->StateInfo.LoadDll.FileHandle = NULL;
  1366. }
  1367. ObCloseHandle (OldHandle, KernelMode);
  1368. }
  1369. break;
  1370. default :
  1371. break;
  1372. }
  1373. }
  1374. VOID
  1375. DbgkpConvertKernelToUserStateChange (
  1376. PDBGUI_WAIT_STATE_CHANGE WaitStateChange,
  1377. PDEBUG_EVENT DebugEvent)
  1378. /*++
  1379. Routine Description:
  1380. Converts a kernel message to one the user expects
  1381. Arguments:
  1382. WaitStateChange - User mode format
  1383. DebugEvent - Debug event block to copy from
  1384. Return Value:
  1385. None
  1386. --*/
  1387. {
  1388. PAGED_CODE ();
  1389. WaitStateChange->AppClientId = DebugEvent->ClientId;
  1390. switch (DebugEvent->ApiMsg.ApiNumber) {
  1391. case DbgKmExceptionApi :
  1392. switch (DebugEvent->ApiMsg.u.Exception.ExceptionRecord.ExceptionCode) {
  1393. case STATUS_BREAKPOINT :
  1394. WaitStateChange->NewState = DbgBreakpointStateChange;
  1395. break;
  1396. case STATUS_SINGLE_STEP :
  1397. WaitStateChange->NewState = DbgSingleStepStateChange;
  1398. break;
  1399. default :
  1400. WaitStateChange->NewState = DbgExceptionStateChange;
  1401. break;
  1402. }
  1403. WaitStateChange->StateInfo.Exception = DebugEvent->ApiMsg.u.Exception;
  1404. break;
  1405. case DbgKmCreateThreadApi :
  1406. WaitStateChange->NewState = DbgCreateThreadStateChange;
  1407. WaitStateChange->StateInfo.CreateThread.NewThread = DebugEvent->ApiMsg.u.CreateThread;
  1408. break;
  1409. case DbgKmCreateProcessApi :
  1410. WaitStateChange->NewState = DbgCreateProcessStateChange;
  1411. WaitStateChange->StateInfo.CreateProcessInfo.NewProcess = DebugEvent->ApiMsg.u.CreateProcessInfo;
  1412. //
  1413. // clear out the handle in the message as we will close this when we duplicate.
  1414. //
  1415. DebugEvent->ApiMsg.u.CreateProcessInfo.FileHandle = NULL;
  1416. break;
  1417. case DbgKmExitThreadApi :
  1418. WaitStateChange->NewState = DbgExitThreadStateChange;
  1419. WaitStateChange->StateInfo.ExitThread = DebugEvent->ApiMsg.u.ExitThread;
  1420. break;
  1421. case DbgKmExitProcessApi :
  1422. WaitStateChange->NewState = DbgExitProcessStateChange;
  1423. WaitStateChange->StateInfo.ExitProcess = DebugEvent->ApiMsg.u.ExitProcess;
  1424. break;
  1425. case DbgKmLoadDllApi :
  1426. WaitStateChange->NewState = DbgLoadDllStateChange;
  1427. WaitStateChange->StateInfo.LoadDll = DebugEvent->ApiMsg.u.LoadDll;
  1428. //
  1429. // clear out the handle in the message as we will close this when we duplicate.
  1430. //
  1431. DebugEvent->ApiMsg.u.LoadDll.FileHandle = NULL;
  1432. break;
  1433. case DbgKmUnloadDllApi :
  1434. WaitStateChange->NewState = DbgUnloadDllStateChange;
  1435. WaitStateChange->StateInfo.UnloadDll = DebugEvent->ApiMsg.u.UnloadDll;
  1436. break;
  1437. default :
  1438. ASSERT (FALSE);
  1439. }
  1440. }
  1441. NTSTATUS
  1442. NtWaitForDebugEvent (
  1443. IN HANDLE DebugObjectHandle,
  1444. IN BOOLEAN Alertable,
  1445. IN PLARGE_INTEGER Timeout OPTIONAL,
  1446. OUT PDBGUI_WAIT_STATE_CHANGE WaitStateChange
  1447. )
  1448. /*++
  1449. Routine Description:
  1450. Waits for a debug event and returns it to the user if one arives
  1451. Arguments:
  1452. DebugObjectHandle - Handle to a debug object
  1453. Alertable - TRUE is the wait is to be alertable
  1454. Timeout - Operation timeout value
  1455. WaitStateChange - Returned debug event
  1456. Return Value:
  1457. Status of operation
  1458. --*/
  1459. {
  1460. NTSTATUS Status;
  1461. KPROCESSOR_MODE PreviousMode;
  1462. PDEBUG_OBJECT DebugObject;
  1463. LARGE_INTEGER Tmo = {0};
  1464. LARGE_INTEGER StartTime = {0};
  1465. DBGUI_WAIT_STATE_CHANGE tWaitStateChange = {0};
  1466. PEPROCESS Process;
  1467. PETHREAD Thread;
  1468. PLIST_ENTRY Entry, Entry2;
  1469. PDEBUG_EVENT DebugEvent, DebugEvent2;
  1470. BOOLEAN GotEvent;
  1471. PAGED_CODE ();
  1472. PreviousMode = KeGetPreviousMode();
  1473. try {
  1474. if (ARGUMENT_PRESENT (Timeout)) {
  1475. if (PreviousMode != KernelMode) {
  1476. ProbeForReadSmallStructure (Timeout, sizeof (*Timeout), sizeof (UCHAR));
  1477. }
  1478. Tmo = *Timeout;
  1479. Timeout = &Tmo;
  1480. KeQuerySystemTime (&StartTime);
  1481. }
  1482. if (PreviousMode != KernelMode) {
  1483. ProbeForWriteSmallStructure (WaitStateChange, sizeof (*WaitStateChange), sizeof (UCHAR));
  1484. }
  1485. } except (ExSystemExceptionFilter ()) { // If previous mode is kernel then don't handle the exception
  1486. return GetExceptionCode ();
  1487. }
  1488. Status = ObReferenceObjectByHandle (DebugObjectHandle,
  1489. DEBUG_READ_EVENT,
  1490. DbgkDebugObjectType,
  1491. PreviousMode,
  1492. &DebugObject,
  1493. NULL);
  1494. if (!NT_SUCCESS (Status)) {
  1495. return Status;
  1496. }
  1497. Process = NULL;
  1498. Thread = NULL;
  1499. while (1) {
  1500. Status = KeWaitForSingleObject (&DebugObject->EventsPresent,
  1501. Executive,
  1502. PreviousMode,
  1503. Alertable,
  1504. Timeout);
  1505. if (!NT_SUCCESS (Status) || Status == STATUS_TIMEOUT || Status == STATUS_ALERTED || Status == STATUS_USER_APC) {
  1506. break;
  1507. }
  1508. GotEvent = FALSE;
  1509. DebugEvent = NULL;
  1510. ExAcquireFastMutex (&DebugObject->Mutex);
  1511. //
  1512. // If the object is delete pending then return an error.
  1513. //
  1514. if ((DebugObject->Flags&DEBUG_OBJECT_DELETE_PENDING) == 0) {
  1515. for (Entry = DebugObject->EventList.Flink;
  1516. Entry != &DebugObject->EventList;
  1517. Entry = Entry->Flink) {
  1518. DebugEvent = CONTAINING_RECORD (Entry, DEBUG_EVENT, EventList);
  1519. //
  1520. // If this event has not been given back to the user yet and is not
  1521. // inactive then pass it back.
  1522. // We check to see if we have any other outstanding messages for this
  1523. // thread as this confuses VC. You can only get multiple events
  1524. // for the same thread for the attach faked messages.
  1525. //
  1526. if ((DebugEvent->Flags&(DEBUG_EVENT_READ|DEBUG_EVENT_INACTIVE)) == 0) {
  1527. GotEvent = TRUE;
  1528. for (Entry2 = DebugObject->EventList.Flink;
  1529. Entry2 != Entry;
  1530. Entry2 = Entry2->Flink) {
  1531. DebugEvent2 = CONTAINING_RECORD (Entry2, DEBUG_EVENT, EventList);
  1532. if (DebugEvent->ClientId.UniqueProcess == DebugEvent2->ClientId.UniqueProcess) {
  1533. //
  1534. // This event has the same process as an earlier event. Mark it as inactive.
  1535. //
  1536. DebugEvent->Flags |= DEBUG_EVENT_INACTIVE;
  1537. DebugEvent->BackoutThread = NULL;
  1538. GotEvent = FALSE;
  1539. break;
  1540. }
  1541. }
  1542. if (GotEvent) {
  1543. break;
  1544. }
  1545. }
  1546. }
  1547. if (GotEvent) {
  1548. Process = DebugEvent->Process;
  1549. Thread = DebugEvent->Thread;
  1550. ObReferenceObject (Thread);
  1551. ObReferenceObject (Process);
  1552. DbgkpConvertKernelToUserStateChange (&tWaitStateChange, DebugEvent);
  1553. DebugEvent->Flags |= DEBUG_EVENT_READ;
  1554. } else {
  1555. //
  1556. // No unread events there. Clear the event.
  1557. //
  1558. KeClearEvent (&DebugObject->EventsPresent);
  1559. }
  1560. Status = STATUS_SUCCESS;
  1561. } else {
  1562. Status = STATUS_DEBUGGER_INACTIVE;
  1563. }
  1564. ExReleaseFastMutex (&DebugObject->Mutex);
  1565. if (NT_SUCCESS (Status)) {
  1566. //
  1567. // If we woke up and found nothing
  1568. //
  1569. if (GotEvent == FALSE) {
  1570. //
  1571. // If timeout is a delta time then adjust it for the wait so far.
  1572. //
  1573. if (Tmo.QuadPart < 0) {
  1574. LARGE_INTEGER NewTime;
  1575. KeQuerySystemTime (&NewTime);
  1576. Tmo.QuadPart = Tmo.QuadPart + (NewTime.QuadPart - StartTime.QuadPart);
  1577. StartTime = NewTime;
  1578. if (Tmo.QuadPart >= 0) {
  1579. Status = STATUS_TIMEOUT;
  1580. break;
  1581. }
  1582. }
  1583. } else {
  1584. //
  1585. // Fixup needed handles. The caller could have guessed the thread id etc by now and made the target thread
  1586. // continue. This isn't a problem as we won't do anything damaging to the system in this case. The caller
  1587. // won't get the correct results but they set out to break us.
  1588. //
  1589. DbgkpOpenHandles (&tWaitStateChange, Process, Thread);
  1590. ObDereferenceObject (Thread);
  1591. ObDereferenceObject (Process);
  1592. break;
  1593. }
  1594. } else {
  1595. break;
  1596. }
  1597. }
  1598. ObDereferenceObject (DebugObject);
  1599. try {
  1600. *WaitStateChange = tWaitStateChange;
  1601. } except (ExSystemExceptionFilter ()) { // If previous mode is kernel then don't handle the exception
  1602. Status = GetExceptionCode ();
  1603. }
  1604. return Status;
  1605. }
  1606. NTSTATUS
  1607. NtDebugContinue (
  1608. IN HANDLE DebugObjectHandle,
  1609. IN PCLIENT_ID ClientId,
  1610. IN NTSTATUS ContinueStatus
  1611. )
  1612. /*++
  1613. Routine Description:
  1614. Coninues a stalled debugged thread
  1615. Arguments:
  1616. DebugObjectHandle - Handle to a debug object
  1617. ClientId - ClientId of thread tro continue
  1618. ContinueStatus - Status of continue
  1619. Return Value:
  1620. Status of operation
  1621. --*/
  1622. {
  1623. NTSTATUS Status;
  1624. PDEBUG_OBJECT DebugObject;
  1625. PDEBUG_EVENT DebugEvent, FoundDebugEvent;
  1626. KPROCESSOR_MODE PreviousMode;
  1627. CLIENT_ID Clid;
  1628. PLIST_ENTRY Entry;
  1629. BOOLEAN GotEvent;
  1630. PreviousMode = KeGetPreviousMode();
  1631. try {
  1632. if (PreviousMode != KernelMode) {
  1633. ProbeForReadSmallStructure (ClientId, sizeof (*ClientId), sizeof (UCHAR));
  1634. }
  1635. Clid = *ClientId;
  1636. } except (ExSystemExceptionFilter ()) { // If previous mode is kernel then don't handle the exception
  1637. return GetExceptionCode ();
  1638. }
  1639. switch (ContinueStatus) {
  1640. case DBG_EXCEPTION_HANDLED :
  1641. case DBG_EXCEPTION_NOT_HANDLED :
  1642. case DBG_TERMINATE_THREAD :
  1643. case DBG_TERMINATE_PROCESS :
  1644. case DBG_CONTINUE :
  1645. break;
  1646. default :
  1647. return STATUS_INVALID_PARAMETER;
  1648. }
  1649. Status = ObReferenceObjectByHandle (DebugObjectHandle,
  1650. DEBUG_READ_EVENT,
  1651. DbgkDebugObjectType,
  1652. PreviousMode,
  1653. &DebugObject,
  1654. NULL);
  1655. if (!NT_SUCCESS (Status)) {
  1656. return Status;
  1657. }
  1658. GotEvent = FALSE;
  1659. FoundDebugEvent = NULL;
  1660. ExAcquireFastMutex (&DebugObject->Mutex);
  1661. for (Entry = DebugObject->EventList.Flink;
  1662. Entry != &DebugObject->EventList;
  1663. Entry = Entry->Flink) {
  1664. DebugEvent = CONTAINING_RECORD (Entry, DEBUG_EVENT, EventList);
  1665. //
  1666. // Make sure the client ID matches and that the debugger saw all the events.
  1667. // We don't allow the caller to start a thread that it never saw a message for.
  1668. // This would do no harm but its probably a bug in the debugger.
  1669. //
  1670. if (DebugEvent->ClientId.UniqueProcess == Clid.UniqueProcess) {
  1671. if (!GotEvent) {
  1672. if (DebugEvent->ClientId.UniqueThread == Clid.UniqueThread &&
  1673. (DebugEvent->Flags&DEBUG_EVENT_READ) != 0) {
  1674. RemoveEntryList (Entry);
  1675. FoundDebugEvent = DebugEvent;
  1676. GotEvent = TRUE;
  1677. }
  1678. } else {
  1679. //
  1680. // VC breaks if it sees more than one event at a time
  1681. // for the same process.
  1682. //
  1683. DebugEvent->Flags &= ~DEBUG_EVENT_INACTIVE;
  1684. KeSetEvent (&DebugObject->EventsPresent, 0, FALSE);
  1685. break;
  1686. }
  1687. }
  1688. }
  1689. ExReleaseFastMutex (&DebugObject->Mutex);
  1690. ObDereferenceObject (DebugObject);
  1691. if (GotEvent) {
  1692. FoundDebugEvent->ApiMsg.ReturnedStatus = ContinueStatus;
  1693. FoundDebugEvent->Status = STATUS_SUCCESS;
  1694. DbgkpWakeTarget (FoundDebugEvent);
  1695. } else {
  1696. Status = STATUS_INVALID_PARAMETER;
  1697. }
  1698. return Status;
  1699. }
  1700. NTSTATUS
  1701. NtSetInformationDebugObject (
  1702. IN HANDLE DebugObjectHandle,
  1703. IN DEBUGOBJECTINFOCLASS DebugObjectInformationClass,
  1704. IN PVOID DebugInformation,
  1705. IN ULONG DebugInformationLength,
  1706. OUT PULONG ReturnLength OPTIONAL
  1707. )
  1708. /*++
  1709. Routine Description:
  1710. This function sets the state of a debug object.
  1711. Arguments:
  1712. ProcessHandle - Supplies a handle to a process object.
  1713. ProcessInformationClass - Supplies the class of information being
  1714. set.
  1715. ProcessInformation - Supplies a pointer to a record that contains the
  1716. information to set.
  1717. ProcessInformationLength - Supplies the length of the record that contains
  1718. the information to set.
  1719. Return Value:
  1720. NTSTATUS - Status of call
  1721. --*/
  1722. {
  1723. KPROCESSOR_MODE PreviousMode;
  1724. NTSTATUS Status;
  1725. PDEBUG_OBJECT DebugObject;
  1726. ULONG Flags;
  1727. PreviousMode = KeGetPreviousMode();
  1728. try {
  1729. if (PreviousMode != KernelMode) {
  1730. ProbeForRead (DebugInformation,
  1731. DebugInformationLength,
  1732. sizeof (ULONG));
  1733. if (ARGUMENT_PRESENT (ReturnLength)) {
  1734. ProbeForWriteUlong (ReturnLength);
  1735. }
  1736. }
  1737. if (ARGUMENT_PRESENT (ReturnLength)) {
  1738. *ReturnLength = 0;
  1739. }
  1740. switch (DebugObjectInformationClass) {
  1741. case DebugObjectFlags : {
  1742. if (DebugInformationLength != sizeof (ULONG)) {
  1743. if (ARGUMENT_PRESENT (ReturnLength)) {
  1744. *ReturnLength = sizeof (ULONG);
  1745. }
  1746. return STATUS_INFO_LENGTH_MISMATCH;
  1747. }
  1748. Flags = *(PULONG) DebugInformation;
  1749. break;
  1750. }
  1751. default : {
  1752. return STATUS_INVALID_PARAMETER;
  1753. }
  1754. }
  1755. } except (ExSystemExceptionFilter ()) {
  1756. return GetExceptionCode ();
  1757. }
  1758. switch (DebugObjectInformationClass) {
  1759. case DebugObjectFlags : {
  1760. if (Flags & ~DEBUG_KILL_ON_CLOSE) {
  1761. return STATUS_INVALID_PARAMETER;
  1762. }
  1763. Status = ObReferenceObjectByHandle (DebugObjectHandle,
  1764. DEBUG_SET_INFORMATION,
  1765. DbgkDebugObjectType,
  1766. PreviousMode,
  1767. &DebugObject,
  1768. NULL);
  1769. if (!NT_SUCCESS (Status)) {
  1770. return Status;
  1771. }
  1772. ExAcquireFastMutex (&DebugObject->Mutex);
  1773. if (Flags&DEBUG_KILL_ON_CLOSE) {
  1774. DebugObject->Flags |= DEBUG_OBJECT_KILL_ON_CLOSE;
  1775. } else {
  1776. DebugObject->Flags &= ~DEBUG_OBJECT_KILL_ON_CLOSE;
  1777. }
  1778. ExReleaseFastMutex (&DebugObject->Mutex);
  1779. ObDereferenceObject (DebugObject);
  1780. }
  1781. }
  1782. return STATUS_SUCCESS;
  1783. }