HyperDbg/hyperdbg/libhyperdbg/code/debugger/commands/meta-commands/thread.cpp
2024-07-31 14:08:14 +09:00

306 lines
11 KiB
C++

/**
* @file thread.cpp
* @author Sina Karvandi (sina@hyperdbg.org)
* @brief show and change threads
* @details
* @version 0.1
* @date 2021-11-23
*
* @copyright This project is released under the GNU Public License v3.
*
*/
#include "pch.h"
//
// Global Variables
//
extern BOOLEAN g_IsSerialConnectedToRemoteDebuggee;
/**
* @brief help of the .thread command
*
* @return VOID
*/
VOID
CommandThreadHelp()
{
ShowMessages(".thread, .thread2 : shows and changes the threads. "
"This command needs public symbols for 'ntoskrnl.exe' if "
"you want to see the threads list. Please visit the "
"documentation to know about the difference between '.thread' "
"and '.thread2'.\n\n");
ShowMessages("syntax : \t.thread\n");
ShowMessages("syntax : \t.thread [list] [process Eprocess (hex)]\n");
ShowMessages("syntax : \t.thread [tid ThreadId (hex)]\n");
ShowMessages("syntax : \t.thread [thread Ethread (hex)]\n");
ShowMessages("syntax : \t.thread2 [tid ThreadId (hex)]\n");
ShowMessages("syntax : \t.thread2 [thread Ethread (hex)]\n");
ShowMessages("\n");
ShowMessages("\t\te.g : .thread\n");
ShowMessages("\t\te.g : .thread tid 48a4\n");
ShowMessages("\t\te.g : .thread2 tid 48a4\n");
ShowMessages("\t\te.g : .thread thread ffff948c`c8970200\n");
ShowMessages("\t\te.g : .thread list\n");
ShowMessages("\t\te.g : .thread list process ffff948c`a1279880\n");
}
BOOLEAN
CommandThreadListThreads(UINT64 Eprocess)
{
UINT32 ThreadListHeadOffset = 0; // nt!_EPROCESS.ThreadListHead
UINT32 ThreadListEntryOffset = 0; // nt!_ETHREAD.ThreadListEntry
UINT32 CidOffset = 0; // nt!_ETHREAD.Cid
UINT32 OffsetOfActiveProcessLinks = 0; // nt!_EPROCESS.ActiveProcessLinks
UINT64 AddressOfActiveProcessHead = 0; // nt!PsActiveProcessHead
DEBUGGEE_THREAD_LIST_NEEDED_DETAILS ThreadListNeededItems = {0};
//
// Query for nt!_EPROCESS.ThreadListHead, nt!_ETHREAD.ThreadListEntry,
// from the top of nt!_EPROCESS, and nt!_ETHREAD address and check if
// we find them or not, otherwise, it means that the PDB for ntoskrnl.exe
// is not available
//
if (ScriptEngineGetFieldOffsetWrapper((CHAR *)"nt!_EPROCESS", (CHAR *)"ThreadListHead", &ThreadListHeadOffset) &&
ScriptEngineGetFieldOffsetWrapper((CHAR *)"nt!_ETHREAD", (CHAR *)"ThreadListEntry", &ThreadListEntryOffset) &&
ScriptEngineGetFieldOffsetWrapper((CHAR *)"nt!_ETHREAD", (CHAR *)"Cid", &CidOffset) &&
ScriptEngineGetFieldOffsetWrapper((CHAR *)"nt!_EPROCESS", (CHAR *)"ActiveProcessLinks", &OffsetOfActiveProcessLinks) &&
SymbolConvertNameOrExprToAddress("nt!PsActiveProcessHead", &AddressOfActiveProcessHead))
{
ThreadListNeededItems.ThreadListHeadOffset = ThreadListHeadOffset;
ThreadListNeededItems.ThreadListEntryOffset = ThreadListEntryOffset;
ThreadListNeededItems.CidOffset = CidOffset;
ThreadListNeededItems.ActiveProcessLinksOffset = OffsetOfActiveProcessLinks;
ThreadListNeededItems.PsActiveProcessHead = AddressOfActiveProcessHead;
ThreadListNeededItems.Process = Eprocess;
//
// Check if it's connected to a remote debuggee or not
//
if (!g_IsSerialConnectedToRemoteDebuggee)
{
//
// Get the thread details in VMI mode
//
ObjectShowProcessesOrThreadList(FALSE,
NULL,
NULL,
&ThreadListNeededItems);
}
else
{
//
// Send the packet to list threads
//
KdSendSwitchThreadPacketToDebuggee(DEBUGGEE_DETAILS_AND_SWITCH_THREAD_GET_THREAD_LIST,
NULL,
NULL,
FALSE,
&ThreadListNeededItems);
}
return TRUE;
}
else
{
return FALSE;
}
}
/**
* @brief .thread command handler
*
* @param CommandTokens
* @param Command
*
* @return VOID
*/
VOID
CommandThread(vector<CommandToken> CommandTokens, string Command)
{
UINT32 TargetThreadId = 0;
UINT64 TargetThread = 0;
UINT64 TargetProcess = 0;
BOOLEAN CheckByClkIntr = FALSE;
if (CommandTokens.size() >= 5)
{
ShowMessages("incorrect use of the '%s'\n\n",
GetCaseSensitiveStringFromCommandToken(CommandTokens.at(0)).c_str());
CommandThreadHelp();
return;
}
if (CommandTokens.size() == 1)
{
//
// Check if it's connected to a remote debuggee or not
//
if (!g_IsSerialConnectedToRemoteDebuggee)
{
ObjectShowProcessesOrThreadDetails(FALSE);
}
else
{
//
// Send the packet to get current thread
//
KdSendSwitchThreadPacketToDebuggee(DEBUGGEE_DETAILS_AND_SWITCH_THREAD_GET_THREAD_DETAILS,
NULL,
NULL,
FALSE,
NULL);
}
}
else if (CommandTokens.size() == 2)
{
if (CompareLowerCaseStrings(CommandTokens.at(1), "list"))
{
//
// Sending null as the nt!_EPROCESS indicates that the target process is
// the current process (Current nt!_EPROCESS)
//
if (!CommandThreadListThreads(NULL))
{
ShowMessages("err, the need offset to iterate over threads not found, "
"make sure to load ntoskrnl.exe's PDB file. use '.help .sym' for "
"more information\n");
return;
}
}
else
{
ShowMessages(
"err, unknown parameter at '%s'\n\n",
GetCaseSensitiveStringFromCommandToken(CommandTokens.at(1)).c_str());
CommandThreadHelp();
return;
}
}
else if (CommandTokens.size() == 3)
{
//
// Check if it's connected to a remote debuggee or not
//
if (!g_IsSerialConnectedToRemoteDebuggee)
{
ShowMessages("err, you're not connected to any debuggee in Debugger Mode, "
"you can use the '.attach', or the '.detach' commands if you're "
"operating in VMI Mode\n");
return;
}
if (CompareLowerCaseStrings(CommandTokens.at(1), "tid"))
{
if (!ConvertTokenToUInt32(CommandTokens.at(2), &TargetThreadId))
{
ShowMessages(
"please specify a correct hex value for the thread id that you "
"want to operate on it\n\n");
CommandThreadHelp();
return;
}
}
else if (CompareLowerCaseStrings(CommandTokens.at(1), "thread"))
{
if (!SymbolConvertNameOrExprToAddress(GetCaseSensitiveStringFromCommandToken(CommandTokens.at(2)), &TargetThread))
{
ShowMessages(
"please specify a correct hex value for the thread (nt!_ETHREAD) that you "
"want to operate on it\n\n");
CommandThreadHelp();
return;
}
}
else if (CompareLowerCaseStrings(CommandTokens.at(1), "list") && CompareLowerCaseStrings(CommandTokens.at(2), "process"))
{
ShowMessages(
"please specify a hex value for the process\n\n");
CommandThreadHelp();
return;
}
else
{
ShowMessages(
"err, unknown parameter at '%s'\n\n",
GetCaseSensitiveStringFromCommandToken(CommandTokens.at(2)).c_str());
CommandThreadHelp();
return;
}
if (CompareLowerCaseStrings(CommandTokens.at(0), ".thread2"))
{
//
// Check by changes to gs:[188]
//
CheckByClkIntr = FALSE;
}
else
{
//
// Check on clock interrupt changes
//
CheckByClkIntr = TRUE;
}
//
// Send the packet to change the thread
//
KdSendSwitchThreadPacketToDebuggee(DEBUGGEE_DETAILS_AND_SWITCH_THREAD_PERFORM_SWITCH,
TargetThreadId,
TargetThread,
CheckByClkIntr,
NULL);
}
else if (CommandTokens.size() == 4)
{
if (CompareLowerCaseStrings(CommandTokens.at(1), "list"))
{
if (CompareLowerCaseStrings(CommandTokens.at(2), "process"))
{
if (!SymbolConvertNameOrExprToAddress(GetCaseSensitiveStringFromCommandToken(CommandTokens.at(3)), &TargetProcess))
{
ShowMessages(
"please specify a correct hex value for the process (nt!_EPROCESS) that you "
"want to see its threads\n\n");
CommandThreadHelp();
return;
}
//
// List the target process's threads
//
if (!CommandThreadListThreads(TargetProcess))
{
ShowMessages("err, the need offset to iterate over threads not found, "
"make sure to load ntoskrnl.exe's PDB file. use '.help .sym' for "
"more information\n");
return;
}
}
else
{
ShowMessages(
"err, unknown parameter at '%s'\n\n",
GetCaseSensitiveStringFromCommandToken(CommandTokens.at(2)).c_str());
CommandThreadHelp();
return;
}
}
else
{
ShowMessages(
"err, unknown parameter at '%s'\n\n",
GetCaseSensitiveStringFromCommandToken(CommandTokens.at(1)).c_str());
CommandThreadHelp();
return;
}
}
else
{
ShowMessages("invalid parameter\n\n");
CommandThreadHelp();
return;
}
}