mirror of
https://github.com/HyperDbg/HyperDbg.git
synced 2026-07-11 18:19:36 +00:00
658 lines
20 KiB
C
658 lines
20 KiB
C
/**
|
|
* @file ThreadHolder.c
|
|
* @author Sina Karvandi (sina@hyperdbg.org)
|
|
* @brief User debugger's thread holder
|
|
* @details
|
|
*
|
|
* @version 0.1
|
|
* @date 2022-01-28
|
|
*
|
|
* @copyright This project is released under the GNU Public License v3.
|
|
*
|
|
*/
|
|
#include "pch.h"
|
|
|
|
/**
|
|
* @brief Pre allocate buffer for thread holder
|
|
*
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
ThreadHolderAllocateThreadHoldingBuffers()
|
|
{
|
|
//
|
|
// Request to allocate two buffer for holder of threads
|
|
//
|
|
PoolManagerRequestAllocation(sizeof(USERMODE_DEBUGGING_THREAD_HOLDER), 2, PROCESS_THREAD_HOLDER);
|
|
|
|
//
|
|
// As it might be called from an attaching request and never find a
|
|
// a chance to allocate it, we allocate it here as it's safe at PASSIVE_LEVEL
|
|
//
|
|
PoolManagerCheckAndPerformAllocationAndDeallocation();
|
|
}
|
|
|
|
/**
|
|
* @brief Assign a thread holder to process debugging details
|
|
*
|
|
* @param ProcessDebuggingDetail
|
|
* @return BOOLEAN
|
|
*/
|
|
BOOLEAN
|
|
ThreadHolderAssignThreadHolderToProcessDebuggingDetails(PUSERMODE_DEBUGGING_PROCESS_DETAILS ProcessDebuggingDetail)
|
|
{
|
|
PUSERMODE_DEBUGGING_THREAD_HOLDER ThreadHolder;
|
|
|
|
//
|
|
// Initialize the list entry of threads
|
|
//
|
|
InitializeListHead(&ProcessDebuggingDetail->ThreadsListHead);
|
|
|
|
//
|
|
// Add a thread holder here
|
|
//
|
|
ThreadHolder = (USERMODE_DEBUGGING_THREAD_HOLDER *)
|
|
PoolManagerRequestPool(PROCESS_THREAD_HOLDER, TRUE, sizeof(USERMODE_DEBUGGING_THREAD_HOLDER));
|
|
|
|
if (!ThreadHolder)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Add it to thread holder of the structure
|
|
//
|
|
InsertHeadList(&ProcessDebuggingDetail->ThreadsListHead, &(ThreadHolder->ThreadHolderList));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* @brief Check if there is any thread paused by checking process debugging details
|
|
*
|
|
* @param ProcessDebuggingDetail
|
|
* @return BOOLEAN
|
|
*/
|
|
BOOLEAN
|
|
ThreadHolderIsAnyPausedThreadInProcess(PUSERMODE_DEBUGGING_PROCESS_DETAILS ProcessDebuggingDetail)
|
|
{
|
|
PLIST_ENTRY TempList = 0;
|
|
|
|
TempList = &ProcessDebuggingDetail->ThreadsListHead;
|
|
|
|
while (&ProcessDebuggingDetail->ThreadsListHead != TempList->Flink)
|
|
{
|
|
TempList = TempList->Flink;
|
|
PUSERMODE_DEBUGGING_THREAD_HOLDER ThreadHolder =
|
|
CONTAINING_RECORD(TempList, USERMODE_DEBUGGING_THREAD_HOLDER, ThreadHolderList);
|
|
|
|
for (SIZE_T i = 0; i < MAX_THREADS_IN_A_PROCESS_HOLDER; i++)
|
|
{
|
|
if (ThreadHolder->Threads[i].ThreadId != NULL_ZERO && ThreadHolder->Threads[i].IsPaused)
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* @brief Unpause all threads in the process debugging details
|
|
*
|
|
* @param ProcessDebuggingDetail
|
|
* @return BOOLEAN
|
|
*/
|
|
BOOLEAN
|
|
ThreadHolderUnpauseAllThreadsInProcess(PUSERMODE_DEBUGGING_PROCESS_DETAILS ProcessDebuggingDetail)
|
|
{
|
|
PLIST_ENTRY TempList = 0;
|
|
BOOLEAN AtLeastOneThreadUnpaused = FALSE;
|
|
|
|
TempList = &ProcessDebuggingDetail->ThreadsListHead;
|
|
|
|
while (&ProcessDebuggingDetail->ThreadsListHead != TempList->Flink)
|
|
{
|
|
TempList = TempList->Flink;
|
|
PUSERMODE_DEBUGGING_THREAD_HOLDER ThreadHolder =
|
|
CONTAINING_RECORD(TempList, USERMODE_DEBUGGING_THREAD_HOLDER, ThreadHolderList);
|
|
|
|
for (SIZE_T i = 0; i < MAX_THREADS_IN_A_PROCESS_HOLDER; i++)
|
|
{
|
|
if (ThreadHolder->Threads[i].ThreadId != NULL_ZERO && ThreadHolder->Threads[i].IsPaused)
|
|
{
|
|
//
|
|
// At least one thread is paused, let's unpause it
|
|
//
|
|
ThreadHolder->Threads[i].IsPaused = FALSE;
|
|
AtLeastOneThreadUnpaused = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return AtLeastOneThreadUnpaused;
|
|
}
|
|
|
|
/**
|
|
* @brief Find the active threads of the process from process id
|
|
*
|
|
* @param ProcessId
|
|
* @param ThreadId
|
|
* @return PUSERMODE_DEBUGGING_THREAD_DETAILS
|
|
*/
|
|
PUSERMODE_DEBUGGING_THREAD_DETAILS
|
|
ThreadHolderGetProcessThreadDetailsByProcessIdAndThreadId(UINT32 ProcessId, UINT32 ThreadId)
|
|
{
|
|
PLIST_ENTRY TempList = 0;
|
|
PUSERMODE_DEBUGGING_PROCESS_DETAILS ProcessDebuggingDetail;
|
|
|
|
//
|
|
// First, find the process details
|
|
//
|
|
ProcessDebuggingDetail = AttachingFindProcessDebuggingDetailsByProcessId(ProcessId);
|
|
|
|
if (ProcessDebuggingDetail == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
TempList = &ProcessDebuggingDetail->ThreadsListHead;
|
|
|
|
while (&ProcessDebuggingDetail->ThreadsListHead != TempList->Flink)
|
|
{
|
|
TempList = TempList->Flink;
|
|
PUSERMODE_DEBUGGING_THREAD_HOLDER ThreadHolder =
|
|
CONTAINING_RECORD(TempList, USERMODE_DEBUGGING_THREAD_HOLDER, ThreadHolderList);
|
|
|
|
for (SIZE_T i = 0; i < MAX_THREADS_IN_A_PROCESS_HOLDER; i++)
|
|
{
|
|
if (ThreadHolder->Threads[i].ThreadId == ThreadId)
|
|
{
|
|
//
|
|
// The active thread's structure is found
|
|
//
|
|
return &ThreadHolder->Threads[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Active thread not found
|
|
//
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* @brief Find the first active threads of the process from process id
|
|
*
|
|
* @param ProcessId
|
|
* @return PUSERMODE_DEBUGGING_THREAD_DETAILS
|
|
*/
|
|
PUSERMODE_DEBUGGING_THREAD_DETAILS
|
|
ThreadHolderGetProcessFirstThreadDetailsByProcessId(UINT32 ProcessId)
|
|
{
|
|
PLIST_ENTRY TempList = 0;
|
|
PUSERMODE_DEBUGGING_PROCESS_DETAILS ProcessDebuggingDetail;
|
|
|
|
//
|
|
// First, find the process details
|
|
//
|
|
ProcessDebuggingDetail = AttachingFindProcessDebuggingDetailsByProcessId(ProcessId);
|
|
|
|
if (ProcessDebuggingDetail == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
TempList = &ProcessDebuggingDetail->ThreadsListHead;
|
|
|
|
while (&ProcessDebuggingDetail->ThreadsListHead != TempList->Flink)
|
|
{
|
|
TempList = TempList->Flink;
|
|
PUSERMODE_DEBUGGING_THREAD_HOLDER ThreadHolder =
|
|
CONTAINING_RECORD(TempList, USERMODE_DEBUGGING_THREAD_HOLDER, ThreadHolderList);
|
|
|
|
for (SIZE_T i = 0; i < MAX_THREADS_IN_A_PROCESS_HOLDER; i++)
|
|
{
|
|
if (ThreadHolder->Threads[i].ThreadId != NULL_ZERO)
|
|
{
|
|
//
|
|
// The active thread's structure is found
|
|
//
|
|
return &ThreadHolder->Threads[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Active thread not found
|
|
//
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* @brief Find the active process debugging detail from the thread id
|
|
*
|
|
* @param ThreadId
|
|
* @return PUSERMODE_DEBUGGING_PROCESS_DETAILS
|
|
*/
|
|
PUSERMODE_DEBUGGING_PROCESS_DETAILS
|
|
ThreadHolderGetProcessDebuggingDetailsByThreadId(UINT32 ThreadId)
|
|
{
|
|
PLIST_ENTRY TempList = 0;
|
|
PLIST_ENTRY TempList2 = 0;
|
|
|
|
TempList = &g_ProcessDebuggingDetailsListHead;
|
|
|
|
while (&g_ProcessDebuggingDetailsListHead != TempList->Flink)
|
|
{
|
|
TempList = TempList->Flink;
|
|
PUSERMODE_DEBUGGING_PROCESS_DETAILS ProcessDebuggingDetails =
|
|
CONTAINING_RECORD(TempList, USERMODE_DEBUGGING_PROCESS_DETAILS, AttachedProcessList);
|
|
|
|
//
|
|
// Search through all the active threads of this process
|
|
//
|
|
TempList2 = &ProcessDebuggingDetails->ThreadsListHead;
|
|
|
|
while (&ProcessDebuggingDetails->ThreadsListHead != TempList2->Flink)
|
|
{
|
|
TempList2 = TempList2->Flink;
|
|
PUSERMODE_DEBUGGING_THREAD_HOLDER ThreadHolder =
|
|
CONTAINING_RECORD(TempList2, USERMODE_DEBUGGING_THREAD_HOLDER, ThreadHolderList);
|
|
|
|
for (SIZE_T i = 0; i < MAX_THREADS_IN_A_PROCESS_HOLDER; i++)
|
|
{
|
|
if (ThreadHolder->Threads[i].ThreadId == ThreadId)
|
|
{
|
|
//
|
|
// The target thread is found, not let's return the process debugging
|
|
// details of this process
|
|
//
|
|
return ProcessDebuggingDetails;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Active thread not found
|
|
//
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* @brief Find or create user-mode debugging details for threads
|
|
*
|
|
* @param ThreadId
|
|
* @param ProcessDebuggingDetail
|
|
* @return PUSERMODE_DEBUGGING_THREAD_DETAILS
|
|
*/
|
|
PUSERMODE_DEBUGGING_THREAD_DETAILS
|
|
ThreadHolderFindOrCreateThreadDebuggingDetail(UINT32 ThreadId, PUSERMODE_DEBUGGING_PROCESS_DETAILS ProcessDebuggingDetail)
|
|
{
|
|
PLIST_ENTRY TempList = 0;
|
|
|
|
TempList = &ProcessDebuggingDetail->ThreadsListHead;
|
|
|
|
//
|
|
// Let's see if we can find the thread
|
|
//
|
|
while (&ProcessDebuggingDetail->ThreadsListHead != TempList->Flink)
|
|
{
|
|
TempList = TempList->Flink;
|
|
PUSERMODE_DEBUGGING_THREAD_HOLDER ThreadHolder =
|
|
CONTAINING_RECORD(TempList, USERMODE_DEBUGGING_THREAD_HOLDER, ThreadHolderList);
|
|
|
|
for (SIZE_T i = 0; i < MAX_THREADS_IN_A_PROCESS_HOLDER; i++)
|
|
{
|
|
if (ThreadHolder->Threads[i].ThreadId == ThreadId)
|
|
{
|
|
//
|
|
// We find a thread, let's return it's structure
|
|
//
|
|
return &ThreadHolder->Threads[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// *** We're here, the thread is not found, let's create an entry for it ***
|
|
//
|
|
|
|
//
|
|
// Two threads should not simultaneously reach here
|
|
//
|
|
SpinlockLock(&VmxRootThreadHoldingLock);
|
|
|
|
TempList = &ProcessDebuggingDetail->ThreadsListHead;
|
|
|
|
//
|
|
// Let's see if we can find the thread
|
|
//
|
|
while (&ProcessDebuggingDetail->ThreadsListHead != TempList->Flink)
|
|
{
|
|
TempList = TempList->Flink;
|
|
PUSERMODE_DEBUGGING_THREAD_HOLDER ThreadHolder =
|
|
CONTAINING_RECORD(TempList, USERMODE_DEBUGGING_THREAD_HOLDER, ThreadHolderList);
|
|
|
|
for (SIZE_T i = 0; i < MAX_THREADS_IN_A_PROCESS_HOLDER; i++)
|
|
{
|
|
if (ThreadHolder->Threads[i].ThreadId == NULL_ZERO)
|
|
{
|
|
//
|
|
// We find a null thread place, let's return it's structure
|
|
//
|
|
ThreadHolder->Threads[i].ThreadId = ThreadId;
|
|
|
|
SpinlockUnlock(&VmxRootThreadHoldingLock);
|
|
return &ThreadHolder->Threads[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// We didn't find an empty entry,
|
|
// let's use another structure and link it to the thread holder
|
|
//
|
|
PUSERMODE_DEBUGGING_THREAD_HOLDER NewThreadHolder = (USERMODE_DEBUGGING_THREAD_HOLDER *)
|
|
PoolManagerRequestPool(PROCESS_THREAD_HOLDER, TRUE, sizeof(USERMODE_DEBUGGING_THREAD_HOLDER));
|
|
|
|
if (NewThreadHolder == NULL)
|
|
{
|
|
LogError("Err, enable to find a place to save the threads data, "
|
|
"please use 'prealloc' command to allocate more pre-allocated "
|
|
"buffer for the thread holder");
|
|
|
|
SpinlockUnlock(&VmxRootThreadHoldingLock);
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Add the current thread as the first entry of the holder
|
|
//
|
|
NewThreadHolder->Threads[0].ThreadId = ThreadId;
|
|
|
|
//
|
|
// Link to the thread holding structure
|
|
//
|
|
InsertHeadList(&ProcessDebuggingDetail->ThreadsListHead, &(NewThreadHolder->ThreadHolderList));
|
|
|
|
//
|
|
// Other threads are now allowed to use the thread listing mechanism
|
|
//
|
|
SpinlockUnlock(&VmxRootThreadHoldingLock);
|
|
|
|
return &NewThreadHolder->Threads[0];
|
|
}
|
|
|
|
/**
|
|
* @brief Apply the action of the user debugger to a specific thread or
|
|
* all threads
|
|
*
|
|
* @param ProcessDebuggingDetails
|
|
* @param ActionRequest
|
|
*
|
|
* @return BOOLEAN Shows whether the command is applied or not
|
|
*/
|
|
BOOLEAN
|
|
ThreadHolderApplyActionToPausedThreads(PUSERMODE_DEBUGGING_PROCESS_DETAILS ProcessDebuggingDetails,
|
|
PDEBUGGER_UD_COMMAND_PACKET ActionRequest)
|
|
{
|
|
PUSERMODE_DEBUGGING_THREAD_DETAILS ThreadDebuggingDetails;
|
|
BOOLEAN CommandApplied = FALSE;
|
|
|
|
if (!ActionRequest->ApplyToAllPausedThreads)
|
|
{
|
|
//
|
|
// *** only the active thread ***
|
|
//
|
|
|
|
ThreadDebuggingDetails = ThreadHolderGetProcessThreadDetailsByProcessIdAndThreadId(ProcessDebuggingDetails->ProcessId,
|
|
ActionRequest->TargetThreadId);
|
|
|
|
//
|
|
// Apply the command
|
|
//
|
|
for (SIZE_T i = 0; i < MAX_USER_ACTIONS_FOR_THREADS; i++)
|
|
{
|
|
if (ThreadDebuggingDetails->UdAction[i].ActionType == DEBUGGER_UD_COMMAND_ACTION_TYPE_NONE)
|
|
{
|
|
//
|
|
// Set the action
|
|
//
|
|
ThreadDebuggingDetails->UdAction[i].OptionalParam1 = ActionRequest->UdAction.OptionalParam1;
|
|
ThreadDebuggingDetails->UdAction[i].OptionalParam2 = ActionRequest->UdAction.OptionalParam2;
|
|
ThreadDebuggingDetails->UdAction[i].OptionalParam3 = ActionRequest->UdAction.OptionalParam3;
|
|
ThreadDebuggingDetails->UdAction[i].OptionalParam4 = ActionRequest->UdAction.OptionalParam4;
|
|
|
|
//
|
|
// At last we set the action type to make it valid
|
|
//
|
|
ThreadDebuggingDetails->UdAction[i].ActionType = ActionRequest->UdAction.ActionType;
|
|
|
|
//
|
|
// Command is applied
|
|
//
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// *** apply to all paused threads ***
|
|
//
|
|
PLIST_ENTRY TempList = 0;
|
|
|
|
TempList = &ProcessDebuggingDetails->ThreadsListHead;
|
|
|
|
while (&ProcessDebuggingDetails->ThreadsListHead != TempList->Flink)
|
|
{
|
|
TempList = TempList->Flink;
|
|
PUSERMODE_DEBUGGING_THREAD_HOLDER ThreadHolder =
|
|
CONTAINING_RECORD(TempList, USERMODE_DEBUGGING_THREAD_HOLDER, ThreadHolderList);
|
|
|
|
for (SIZE_T i = 0; i < MAX_THREADS_IN_A_PROCESS_HOLDER; i++)
|
|
{
|
|
if (ThreadHolder->Threads[i].ThreadId != NULL_ZERO &&
|
|
ThreadHolder->Threads[i].IsPaused)
|
|
{
|
|
for (SIZE_T j = 0; j < MAX_USER_ACTIONS_FOR_THREADS; j++)
|
|
{
|
|
if (ThreadHolder->Threads[i].UdAction[j].ActionType == DEBUGGER_UD_COMMAND_ACTION_TYPE_NONE)
|
|
{
|
|
//
|
|
// Set the action
|
|
//
|
|
ThreadHolder->Threads[i].UdAction[j].OptionalParam1 = ActionRequest->UdAction.OptionalParam1;
|
|
ThreadHolder->Threads[i].UdAction[j].OptionalParam2 = ActionRequest->UdAction.OptionalParam2;
|
|
ThreadHolder->Threads[i].UdAction[j].OptionalParam3 = ActionRequest->UdAction.OptionalParam3;
|
|
ThreadHolder->Threads[i].UdAction[j].OptionalParam4 = ActionRequest->UdAction.OptionalParam4;
|
|
|
|
//
|
|
// At last we set the action type to make it valid
|
|
//
|
|
ThreadHolder->Threads[i].UdAction[j].ActionType = ActionRequest->UdAction.ActionType;
|
|
|
|
CommandApplied = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Return the result of applying the command
|
|
//
|
|
return CommandApplied;
|
|
}
|
|
|
|
/**
|
|
* @brief Free all of thread holder structures
|
|
*
|
|
* @param ProcessDebuggingDetail
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
ThreadHolderFreeHoldingStructures(PUSERMODE_DEBUGGING_PROCESS_DETAILS ProcessDebuggingDetail)
|
|
{
|
|
PLIST_ENTRY TempList = 0;
|
|
|
|
TempList = &ProcessDebuggingDetail->ThreadsListHead;
|
|
|
|
while (&ProcessDebuggingDetail->ThreadsListHead != TempList->Flink)
|
|
{
|
|
TempList = TempList->Flink;
|
|
PUSERMODE_DEBUGGING_THREAD_HOLDER ThreadHolder =
|
|
CONTAINING_RECORD(TempList, USERMODE_DEBUGGING_THREAD_HOLDER, ThreadHolderList);
|
|
|
|
//
|
|
// The thread is allocated from the pool management, so we'll
|
|
// free it from there
|
|
//
|
|
PoolManagerFreePool((UINT64)ThreadHolder);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Query count of active debugging threads and processes
|
|
*
|
|
* @return UINT32
|
|
*/
|
|
UINT32
|
|
ThreadHolderQueryCountOfActiveDebuggingThreadsAndProcesses()
|
|
{
|
|
PLIST_ENTRY TempList = 0;
|
|
PLIST_ENTRY TempList2 = 0;
|
|
UINT32 CountOfThreadsAndProcesses = 0;
|
|
|
|
TempList = &g_ProcessDebuggingDetailsListHead;
|
|
|
|
while (&g_ProcessDebuggingDetailsListHead != TempList->Flink)
|
|
{
|
|
TempList = TempList->Flink;
|
|
PUSERMODE_DEBUGGING_PROCESS_DETAILS ProcessDebuggingDetails =
|
|
CONTAINING_RECORD(TempList, USERMODE_DEBUGGING_PROCESS_DETAILS, AttachedProcessList);
|
|
|
|
//
|
|
// Each process is also counted (no matter if it has active paused thread or not)
|
|
//
|
|
CountOfThreadsAndProcesses++;
|
|
|
|
//
|
|
// Search through all the active threads of this process
|
|
//
|
|
TempList2 = &ProcessDebuggingDetails->ThreadsListHead;
|
|
|
|
while (&ProcessDebuggingDetails->ThreadsListHead != TempList2->Flink)
|
|
{
|
|
TempList2 = TempList2->Flink;
|
|
PUSERMODE_DEBUGGING_THREAD_HOLDER ThreadHolder =
|
|
CONTAINING_RECORD(TempList2, USERMODE_DEBUGGING_THREAD_HOLDER, ThreadHolderList);
|
|
|
|
for (SIZE_T i = 0; i < MAX_THREADS_IN_A_PROCESS_HOLDER; i++)
|
|
{
|
|
if (ThreadHolder->Threads[i].IsPaused)
|
|
{
|
|
//
|
|
// A paused thread should be counted
|
|
//
|
|
CountOfThreadsAndProcesses++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Return count of active threads and processes
|
|
//
|
|
return CountOfThreadsAndProcesses;
|
|
}
|
|
|
|
/**
|
|
* @brief Query details of active debugging threads and processes
|
|
*
|
|
* @param BufferToStoreDetails
|
|
* @param MaxCount
|
|
*
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
ThreadHolderQueryDetailsOfActiveDebuggingThreadsAndProcesses(
|
|
USERMODE_DEBUGGING_THREAD_OR_PROCESS_STATE_DETAILS * BufferToStoreDetails,
|
|
UINT32 MaxCount)
|
|
{
|
|
PLIST_ENTRY TempList = 0;
|
|
PLIST_ENTRY TempList2 = 0;
|
|
UINT32 CurrentIndex = 0;
|
|
|
|
if (MaxCount == 0)
|
|
{
|
|
//
|
|
// Invalid query, storage is empty
|
|
//
|
|
return;
|
|
}
|
|
|
|
TempList = &g_ProcessDebuggingDetailsListHead;
|
|
|
|
while (&g_ProcessDebuggingDetailsListHead != TempList->Flink)
|
|
{
|
|
TempList = TempList->Flink;
|
|
PUSERMODE_DEBUGGING_PROCESS_DETAILS ProcessDebuggingDetails =
|
|
CONTAINING_RECORD(TempList, USERMODE_DEBUGGING_PROCESS_DETAILS, AttachedProcessList);
|
|
|
|
//
|
|
// Each process is also save (no matter if it has active paused thread or not)
|
|
//
|
|
BufferToStoreDetails[CurrentIndex].IsProcess = TRUE;
|
|
BufferToStoreDetails[CurrentIndex].ProcessId = ProcessDebuggingDetails->ProcessId;
|
|
CurrentIndex++;
|
|
if (MaxCount == CurrentIndex)
|
|
{
|
|
//
|
|
// Storage is full
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Search through all the active threads of this process
|
|
//
|
|
TempList2 = &ProcessDebuggingDetails->ThreadsListHead;
|
|
|
|
while (&ProcessDebuggingDetails->ThreadsListHead != TempList2->Flink)
|
|
{
|
|
TempList2 = TempList2->Flink;
|
|
PUSERMODE_DEBUGGING_THREAD_HOLDER ThreadHolder =
|
|
CONTAINING_RECORD(TempList2, USERMODE_DEBUGGING_THREAD_HOLDER, ThreadHolderList);
|
|
|
|
for (SIZE_T i = 0; i < MAX_THREADS_IN_A_PROCESS_HOLDER; i++)
|
|
{
|
|
if (ThreadHolder->Threads[i].IsPaused)
|
|
{
|
|
//
|
|
// A paused thread should be saved
|
|
//
|
|
BufferToStoreDetails[CurrentIndex].IsProcess = FALSE;
|
|
BufferToStoreDetails[CurrentIndex].ProcessId = ProcessDebuggingDetails->ProcessId;
|
|
BufferToStoreDetails[CurrentIndex].ThreadId = ThreadHolder->Threads[i].ThreadId;
|
|
BufferToStoreDetails[CurrentIndex].NumberOfBlockedContextSwitches = ThreadHolder->Threads[i].NumberOfBlockedContextSwitches;
|
|
|
|
CurrentIndex++;
|
|
if (MaxCount == CurrentIndex)
|
|
{
|
|
//
|
|
// Storage is full
|
|
//
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|