mirror of
https://github.com/HyperDbg/HyperDbg.git
synced 2026-07-15 12:09:34 +00:00
748 lines
22 KiB
C++
748 lines
22 KiB
C++
/**
|
|
* @file events.cpp
|
|
* @author Sina Karvandi (sina@hyperdbg.org)
|
|
* @brief events commands
|
|
* @details
|
|
* @version 0.1
|
|
* @date 2020-07-24
|
|
*
|
|
* @copyright This project is released under the GNU Public License v3.
|
|
*
|
|
*/
|
|
#include "pch.h"
|
|
|
|
//
|
|
// Global Variables
|
|
//
|
|
extern LIST_ENTRY g_EventTrace;
|
|
extern BOOLEAN g_EventTraceInitialized;
|
|
extern BOOLEAN g_BreakPrintingOutput;
|
|
extern BOOLEAN g_AutoFlush;
|
|
extern BOOLEAN g_IsVmmModuleLoaded;
|
|
extern BOOLEAN g_IsConnectedToRemoteDebuggee;
|
|
extern BOOLEAN g_IsSerialConnectedToRemoteDebuggee;
|
|
extern BOOLEAN g_IsSerialConnectedToRemoteDebugger;
|
|
extern UINT64 g_EventTag;
|
|
|
|
/**
|
|
* @brief help of the events command
|
|
*
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
CommandEventsHelp()
|
|
{
|
|
ShowMessages("events : shows active and disabled events\n");
|
|
|
|
ShowMessages("syntax : \tevents\n");
|
|
ShowMessages("syntax : \tevents [e|d|c all|EventNumber (hex)]\n");
|
|
ShowMessages("syntax : \tevents [sc State (on|off)]\n");
|
|
|
|
ShowMessages("e : enable\n");
|
|
ShowMessages("d : disable\n");
|
|
ShowMessages("c : clear\n");
|
|
|
|
ShowMessages("note : If you specify 'all' then e, d, or c will be applied to "
|
|
"all of the events.\n\n");
|
|
|
|
ShowMessages("\n");
|
|
ShowMessages("\te.g : events \n");
|
|
ShowMessages("\te.g : events e 12\n");
|
|
ShowMessages("\te.g : events d 10\n");
|
|
ShowMessages("\te.g : events c 10\n");
|
|
ShowMessages("\te.g : events c all\n");
|
|
ShowMessages("\te.g : events sc on\n");
|
|
ShowMessages("\te.g : events sc off\n");
|
|
}
|
|
|
|
/**
|
|
* @brief events command handler
|
|
*
|
|
* @param CommandTokens
|
|
* @param Command
|
|
*
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
CommandEvents(vector<CommandToken> CommandTokens, string Command)
|
|
{
|
|
DEBUGGER_MODIFY_EVENTS_TYPE RequestedAction;
|
|
UINT64 RequestedTag;
|
|
|
|
//
|
|
// Validate the parameters (size)
|
|
//
|
|
if (CommandTokens.size() != 1 && CommandTokens.size() != 3)
|
|
{
|
|
ShowMessages("incorrect use of the '%s'\n\n",
|
|
GetCaseSensitiveStringFromCommandToken(CommandTokens.at(0)).c_str());
|
|
CommandEventsHelp();
|
|
return;
|
|
}
|
|
|
|
if (CommandTokens.size() == 1)
|
|
{
|
|
if (!g_EventTraceInitialized)
|
|
{
|
|
ShowMessages("no active/disabled events \n");
|
|
return;
|
|
}
|
|
|
|
CommandEventsShowEvents();
|
|
|
|
//
|
|
// No need to continue any further
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Validate second argument as it's not just a simple
|
|
// events without any parameter
|
|
//
|
|
if (CompareLowerCaseStrings(CommandTokens.at(1), "e"))
|
|
{
|
|
RequestedAction = DEBUGGER_MODIFY_EVENTS_ENABLE;
|
|
}
|
|
else if (CompareLowerCaseStrings(CommandTokens.at(1), "d"))
|
|
{
|
|
RequestedAction = DEBUGGER_MODIFY_EVENTS_DISABLE;
|
|
}
|
|
else if (CompareLowerCaseStrings(CommandTokens.at(1), "c"))
|
|
{
|
|
RequestedAction = DEBUGGER_MODIFY_EVENTS_CLEAR;
|
|
}
|
|
else if (CompareLowerCaseStrings(CommandTokens.at(1), "sc"))
|
|
{
|
|
if (CompareLowerCaseStrings(CommandTokens.at(2), "on"))
|
|
{
|
|
KdSendShortCircuitingEventToDebuggee(TRUE);
|
|
}
|
|
else if (CompareLowerCaseStrings(CommandTokens.at(2), "off"))
|
|
{
|
|
KdSendShortCircuitingEventToDebuggee(FALSE);
|
|
}
|
|
else
|
|
{
|
|
ShowMessages(
|
|
"please specify a correct 'on' or 'off' state for the short-circuiting state\n\n");
|
|
CommandEventsHelp();
|
|
return;
|
|
}
|
|
|
|
//
|
|
// No need to further continue
|
|
//
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// unknown second command
|
|
//
|
|
ShowMessages("incorrect use of the '%s'\n\n",
|
|
GetCaseSensitiveStringFromCommandToken(CommandTokens.at(0)).c_str());
|
|
CommandEventsHelp();
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Validate third argument as it's not just a simple
|
|
// events without any parameter
|
|
//
|
|
if (CompareLowerCaseStrings(CommandTokens.at(2), "all"))
|
|
{
|
|
RequestedTag = DEBUGGER_MODIFY_EVENTS_APPLY_TO_ALL_TAG;
|
|
}
|
|
else if (!ConvertTokenToUInt64(CommandTokens.at(2), &RequestedTag))
|
|
{
|
|
ShowMessages(
|
|
"please specify a correct hex value for tag id (event number)\n\n");
|
|
CommandEventsHelp();
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Send the request to the kernel, we add it to a constant
|
|
// that's because we want start tags from that constant
|
|
//
|
|
if (RequestedTag != DEBUGGER_MODIFY_EVENTS_APPLY_TO_ALL_TAG)
|
|
{
|
|
RequestedTag = RequestedTag + DebuggerEventTagStartSeed;
|
|
}
|
|
|
|
//
|
|
// Perform event related tasks
|
|
//
|
|
CommandEventsModifyAndQueryEvents(RequestedTag, RequestedAction);
|
|
}
|
|
|
|
/**
|
|
* @brief Check the kernel whether the event is enabled or disabled
|
|
*
|
|
* @param Tag the tag of the target event
|
|
* @return BOOLEAN if the event was enabled and false if event was
|
|
* disabled
|
|
*/
|
|
BOOLEAN
|
|
CommandEventQueryEventState(UINT64 Tag)
|
|
{
|
|
BOOLEAN IsEnabled;
|
|
|
|
if (g_IsSerialConnectedToRemoteDebuggee)
|
|
{
|
|
//
|
|
// It's a remote debugger in Debugger Mode
|
|
//
|
|
if (KdSendEventQueryAndModifyPacketToDebuggee(
|
|
Tag,
|
|
DEBUGGER_MODIFY_EVENTS_QUERY_STATE,
|
|
&IsEnabled))
|
|
{
|
|
return IsEnabled;
|
|
}
|
|
else
|
|
{
|
|
ShowMessages("err, unable to get the state of the event\n");
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// It's a local debugging in VMI Mode
|
|
//
|
|
return CommandEventsModifyAndQueryEvents(
|
|
Tag,
|
|
DEBUGGER_MODIFY_EVENTS_QUERY_STATE);
|
|
}
|
|
//
|
|
// By default, disabled, even if there was an error
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* @brief print every active and disabled events
|
|
* @details this function will not show cleared events
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
CommandEventsShowEvents()
|
|
{
|
|
//
|
|
// It's an events without any argument so we have to show
|
|
// all the currently active events
|
|
//
|
|
PLIST_ENTRY TempList = 0;
|
|
BOOLEAN IsThereAnyEvents = FALSE;
|
|
|
|
TempList = &g_EventTrace;
|
|
while (&g_EventTrace != TempList->Blink)
|
|
{
|
|
TempList = TempList->Blink;
|
|
|
|
PDEBUGGER_GENERAL_EVENT_DETAIL CommandDetail = CONTAINING_RECORD(TempList, DEBUGGER_GENERAL_EVENT_DETAIL, CommandsEventList);
|
|
string CommandMessage((char *)CommandDetail->CommandStringBuffer);
|
|
|
|
//
|
|
// Do not show the \n(s)
|
|
//
|
|
ReplaceAll(CommandMessage, "\n", " ");
|
|
|
|
//
|
|
// Only show portion of message
|
|
//
|
|
if (CommandMessage.length() > 70)
|
|
{
|
|
CommandMessage = CommandMessage.substr(0, 70);
|
|
CommandMessage += "...";
|
|
}
|
|
|
|
ShowMessages("%x\t(%s)\t %s\n",
|
|
CommandDetail->Tag - DebuggerEventTagStartSeed,
|
|
// CommandDetail->IsEnabled ? "enabled" : "disabled",
|
|
CommandEventQueryEventState(CommandDetail->Tag)
|
|
? "enabled"
|
|
: "disabled", /* Query is live now */
|
|
CommandMessage.c_str());
|
|
|
|
if (!IsThereAnyEvents)
|
|
{
|
|
IsThereAnyEvents = TRUE;
|
|
}
|
|
}
|
|
|
|
if (!IsThereAnyEvents)
|
|
{
|
|
ShowMessages("no active/disabled events \n");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Disable a special event
|
|
*
|
|
* @param Tag the tag of the target event
|
|
* @return BOOLEAN if the operation was successful then it returns
|
|
* true otherwise it returns false
|
|
*/
|
|
BOOLEAN
|
|
CommandEventDisableEvent(UINT64 Tag)
|
|
{
|
|
PLIST_ENTRY TempList = 0;
|
|
BOOLEAN Result = FALSE;
|
|
|
|
TempList = &g_EventTrace;
|
|
while (&g_EventTrace != TempList->Blink)
|
|
{
|
|
TempList = TempList->Blink;
|
|
|
|
PDEBUGGER_GENERAL_EVENT_DETAIL CommandDetail = CONTAINING_RECORD(TempList, DEBUGGER_GENERAL_EVENT_DETAIL, CommandsEventList);
|
|
|
|
if (CommandDetail->Tag == Tag ||
|
|
Tag == DEBUGGER_MODIFY_EVENTS_APPLY_TO_ALL_TAG)
|
|
{
|
|
//
|
|
// Put it to FALSE, to indicate that it's not active
|
|
//
|
|
CommandDetail->IsEnabled = FALSE;
|
|
|
|
if (!Result)
|
|
{
|
|
Result = TRUE;
|
|
}
|
|
|
|
if (Tag != DEBUGGER_MODIFY_EVENTS_APPLY_TO_ALL_TAG)
|
|
{
|
|
//
|
|
// Only, one command exist with a tag, so we need to return as we
|
|
// find it
|
|
//
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Not found
|
|
//
|
|
return Result;
|
|
}
|
|
|
|
/**
|
|
* @brief enables a special event
|
|
*
|
|
* @param Tag the tag of the target event
|
|
* @return BOOLEAN if the operation was successful then it returns
|
|
* true otherwise it returns false
|
|
*/
|
|
BOOLEAN
|
|
CommandEventEnableEvent(UINT64 Tag)
|
|
{
|
|
PLIST_ENTRY TempList = 0;
|
|
BOOLEAN Result = FALSE;
|
|
|
|
TempList = &g_EventTrace;
|
|
while (&g_EventTrace != TempList->Blink)
|
|
{
|
|
TempList = TempList->Blink;
|
|
|
|
PDEBUGGER_GENERAL_EVENT_DETAIL CommandDetail = CONTAINING_RECORD(TempList, DEBUGGER_GENERAL_EVENT_DETAIL, CommandsEventList);
|
|
|
|
if (CommandDetail->Tag == Tag ||
|
|
Tag == DEBUGGER_MODIFY_EVENTS_APPLY_TO_ALL_TAG)
|
|
{
|
|
//
|
|
// Put it to TRUE, to indicate that it's active
|
|
//
|
|
CommandDetail->IsEnabled = TRUE;
|
|
|
|
if (!Result)
|
|
{
|
|
Result = TRUE;
|
|
}
|
|
|
|
if (Tag != DEBUGGER_MODIFY_EVENTS_APPLY_TO_ALL_TAG)
|
|
{
|
|
//
|
|
// Only, one command exist with a tag, so we need to return as we
|
|
// find it
|
|
//
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Not found
|
|
//
|
|
return Result;
|
|
}
|
|
|
|
/**
|
|
* @brief disable and remove a special event
|
|
*
|
|
* @param Tag the tag of the target event
|
|
* @return BOOLEAN if the operation was successful then it returns
|
|
* true otherwise it returns false
|
|
*/
|
|
BOOLEAN
|
|
CommandEventClearEvent(UINT64 Tag)
|
|
{
|
|
PLIST_ENTRY TempList = 0;
|
|
BOOLEAN Result = FALSE;
|
|
PDEBUGGER_GENERAL_EVENT_DETAIL TmpCommandDetail = NULL;
|
|
|
|
TempList = &g_EventTrace;
|
|
while (&g_EventTrace != TempList->Flink)
|
|
{
|
|
TempList = TempList->Flink;
|
|
|
|
PDEBUGGER_GENERAL_EVENT_DETAIL CommandDetail = CONTAINING_RECORD(TempList, DEBUGGER_GENERAL_EVENT_DETAIL, CommandsEventList);
|
|
|
|
if (CommandDetail->Tag == Tag || Tag == DEBUGGER_MODIFY_EVENTS_APPLY_TO_ALL_TAG)
|
|
{
|
|
//
|
|
// Free the buffer for string of command
|
|
//
|
|
free(CommandDetail->CommandStringBuffer);
|
|
|
|
if (!Result)
|
|
{
|
|
Result = TRUE;
|
|
//
|
|
// We'll save one element so we can traverse and deallocate
|
|
// all of the elements
|
|
//
|
|
TmpCommandDetail = CommandDetail;
|
|
}
|
|
|
|
if (Tag != DEBUGGER_MODIFY_EVENTS_APPLY_TO_ALL_TAG)
|
|
{
|
|
//
|
|
// Remove it from the list
|
|
//
|
|
RemoveEntryList(&CommandDetail->CommandsEventList);
|
|
|
|
//
|
|
// Free the event it self
|
|
//
|
|
free(CommandDetail);
|
|
|
|
//
|
|
// Only, one command exist with a tag, so we need to return as we
|
|
// find it
|
|
//
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Result && Tag == DEBUGGER_MODIFY_EVENTS_APPLY_TO_ALL_TAG)
|
|
{
|
|
//
|
|
// We have to deallocate all the elements (note that CommandDetail->CommandStringBuffer is
|
|
// already deallocated)
|
|
//
|
|
while ((UINT64)TmpCommandDetail != (UINT64)&g_EventTrace.Flink)
|
|
{
|
|
PVOID Temp = (PVOID)TmpCommandDetail;
|
|
TmpCommandDetail = (PDEBUGGER_GENERAL_EVENT_DETAIL)TmpCommandDetail->CommandsEventList.Flink;
|
|
|
|
free(Temp);
|
|
}
|
|
|
|
//
|
|
// Reinitialize list head
|
|
//
|
|
InitializeListHead(&g_EventTrace);
|
|
}
|
|
|
|
//
|
|
// Either not found or DEBUGGER_MODIFY_EVENTS_APPLY_TO_ALL_TAG is specified
|
|
//
|
|
return Result;
|
|
}
|
|
|
|
/**
|
|
* @brief Clears all the events and resets the tag
|
|
*
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
CommandEventsClearAllEventsAndResetTags()
|
|
{
|
|
//
|
|
// Check if events are initialized
|
|
//
|
|
if (g_EventTraceInitialized)
|
|
{
|
|
CommandEventClearEvent(DEBUGGER_MODIFY_EVENTS_APPLY_TO_ALL_TAG);
|
|
|
|
//
|
|
// Indicate that it's not initialized
|
|
//
|
|
g_EventTraceInitialized = FALSE;
|
|
|
|
//
|
|
// Reset tag numbering mechanism
|
|
//
|
|
g_EventTag = DebuggerEventTagStartSeed;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Handle events after modification
|
|
*
|
|
* @param Tag the tag of the target event
|
|
* @param ModifyEventRequest Results
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
CommandEventsHandleModifiedEvent(
|
|
UINT64 Tag,
|
|
PDEBUGGER_MODIFY_EVENTS ModifyEventRequest)
|
|
{
|
|
if (ModifyEventRequest->KernelStatus == DEBUGGER_OPERATION_WAS_SUCCESSFUL)
|
|
{
|
|
//
|
|
// Successful, nothing to show but we should also
|
|
// do the same (change) the user-mode structures
|
|
// that hold the event data
|
|
//
|
|
if (ModifyEventRequest->TypeOfAction == DEBUGGER_MODIFY_EVENTS_ENABLE)
|
|
{
|
|
if (!CommandEventEnableEvent(Tag))
|
|
{
|
|
ShowMessages("err, the event was successfully, "
|
|
"(enabled|disabled|cleared) but "
|
|
"can't apply it to the user-mode structures\n");
|
|
}
|
|
}
|
|
else if (ModifyEventRequest->TypeOfAction == DEBUGGER_MODIFY_EVENTS_DISABLE)
|
|
{
|
|
if (!CommandEventDisableEvent(Tag))
|
|
{
|
|
ShowMessages("err, the event was successfully, "
|
|
"(enabled|disabled|cleared) but "
|
|
"can't apply it to the user-mode structures\n");
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The action was applied successfully
|
|
//
|
|
if (g_BreakPrintingOutput)
|
|
{
|
|
//
|
|
// It is because we didn't query the target debuggee auto-flush
|
|
// variable
|
|
//
|
|
if (!g_IsConnectedToRemoteDebuggee &&
|
|
!g_IsSerialConnectedToRemoteDebuggee &&
|
|
!g_IsSerialConnectedToRemoteDebugger)
|
|
{
|
|
if (!g_AutoFlush)
|
|
{
|
|
ShowMessages(
|
|
"auto-flush mode is disabled, if there is still "
|
|
"messages or buffers in the kernel, you continue to see "
|
|
"the messages when you run 'g' until the kernel "
|
|
"buffers are empty. you can run 'settings autoflush "
|
|
"on' and after disabling and clearing events, "
|
|
"kernel buffers will be flushed automatically\n");
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We should flush buffers here
|
|
//
|
|
CommandFlushRequestFlush();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (ModifyEventRequest->TypeOfAction == DEBUGGER_MODIFY_EVENTS_CLEAR)
|
|
{
|
|
if (!CommandEventClearEvent(Tag))
|
|
{
|
|
ShowMessages("err, the event was successfully, "
|
|
"(enabled|disabled|cleared) but "
|
|
"can't apply it to the user-mode structures\n");
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If HyperDbg is operating at the Debugger Mode, we'll indicate that
|
|
// the event will be cleared after continuing the debuggee
|
|
//
|
|
if (g_IsSerialConnectedToRemoteDebuggee)
|
|
{
|
|
ShowMessages("%s successfully cleared, but please note in the Debugger Mode (current mode), HyperDbg "
|
|
"cannot clear events instantly. Instead, it first disables the events, and when "
|
|
"you continue the debuggee (e.g., by pressing the 'g' command), the event will be cleared. "
|
|
"Reapplying the same event without first continuing the debuggee may result in undefined behavior\n",
|
|
Tag == DEBUGGER_MODIFY_EVENTS_APPLY_TO_ALL_TAG ? "events are" : "the event is");
|
|
}
|
|
|
|
//
|
|
// The action was applied successfully
|
|
//
|
|
if (g_BreakPrintingOutput)
|
|
{
|
|
//
|
|
// It is because we didn't query the target debuggee auto-flush
|
|
// variable
|
|
//
|
|
if (!g_IsConnectedToRemoteDebuggee)
|
|
{
|
|
if (!g_AutoFlush)
|
|
{
|
|
ShowMessages(
|
|
"auto-flush mode is disabled, if there is still "
|
|
"messages or buffers in the kernel, you continue to see "
|
|
"the messages when you run 'g' until the kernel "
|
|
"buffers are empty. you can run 'settings autoflush "
|
|
"on' and after disabling and clearing events, "
|
|
"kernel buffers will be flushed automatically\n");
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We should flush buffers here
|
|
//
|
|
CommandFlushRequestFlush();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (ModifyEventRequest->TypeOfAction ==
|
|
DEBUGGER_MODIFY_EVENTS_QUERY_STATE)
|
|
{
|
|
//
|
|
// Nothing to show
|
|
//
|
|
}
|
|
else
|
|
{
|
|
ShowMessages(
|
|
"err, the event was successfully, (enabled|disabled|cleared) but "
|
|
"can't apply it to the user-mode structures\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Interpret error
|
|
//
|
|
ShowErrorMessage((UINT32)ModifyEventRequest->KernelStatus);
|
|
return;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief modify a special event (enable/disable/clear) and send the
|
|
* request directly to the kernel
|
|
* @details if you pass DEBUGGER_MODIFY_EVENTS_APPLY_TO_ALL_TAG as the
|
|
* tag then it will be applied to all the active/disabled events in the
|
|
* kernel
|
|
*
|
|
* @param Tag the tag of the target event
|
|
* @param TypeOfAction whether its a enable/disable/clear
|
|
* @return BOOLEAN Shows whether the event is enabled or disabled
|
|
*/
|
|
BOOLEAN
|
|
CommandEventsModifyAndQueryEvents(UINT64 Tag,
|
|
DEBUGGER_MODIFY_EVENTS_TYPE TypeOfAction)
|
|
{
|
|
BOOLEAN Status;
|
|
ULONG ReturnedLength;
|
|
DEBUGGER_MODIFY_EVENTS ModifyEventRequest = {0};
|
|
|
|
//
|
|
// Check if there is no event, then we shouldn't apply the
|
|
// enable, disable, or clear commands, this command also
|
|
// checks for DEBUGGER_MODIFY_EVENTS_APPLY_TO_ALL_TAG to
|
|
// see if at least one tag exists or not; however, it's not
|
|
// necessary as the kernel will check for the validity of
|
|
// tag too, but let's not send it to kernel as we can prevent
|
|
// invalid requests from user-mode too
|
|
//
|
|
if (!IsTagExist(Tag))
|
|
{
|
|
if (Tag == DEBUGGER_MODIFY_EVENTS_APPLY_TO_ALL_TAG)
|
|
{
|
|
ShowMessages("there is no event\n");
|
|
}
|
|
else
|
|
{
|
|
ShowMessages("err, tag id is invalid\n");
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
if (g_IsSerialConnectedToRemoteDebuggee)
|
|
{
|
|
//
|
|
// Remote debuggee Debugger Mode
|
|
//
|
|
KdSendEventQueryAndModifyPacketToDebuggee(Tag, TypeOfAction, NULL);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Local debugging VMI-Mode
|
|
//
|
|
|
|
//
|
|
// Check if the VMM module is loaded or not
|
|
//
|
|
AssertShowMessageReturnStmt(g_IsVmmModuleLoaded, g_DeviceHandle, ASSERT_MESSAGE_VMM_NOT_LOADED, ASSERT_MESSAGE_DRIVER_NOT_LOADED, AssertReturnFalse);
|
|
|
|
//
|
|
// Fill the structure to send it to the kernel
|
|
//
|
|
ModifyEventRequest.Tag = Tag;
|
|
ModifyEventRequest.TypeOfAction = TypeOfAction;
|
|
|
|
//
|
|
// Send the request to the kernel
|
|
//
|
|
Status =
|
|
DeviceIoControl(g_DeviceHandle, // Handle to device
|
|
IOCTL_DEBUGGER_MODIFY_EVENTS, // IO Control Code (IOCTL)
|
|
&ModifyEventRequest, // Input Buffer to driver.
|
|
SIZEOF_DEBUGGER_MODIFY_EVENTS, // Input buffer length
|
|
&ModifyEventRequest, // Output Buffer from driver.
|
|
SIZEOF_DEBUGGER_MODIFY_EVENTS, // Length of output
|
|
// buffer in bytes.
|
|
&ReturnedLength, // Bytes placed in buffer.
|
|
NULL // synchronous call
|
|
);
|
|
|
|
if (!Status)
|
|
{
|
|
ShowMessages("ioctl failed with code 0x%x\n", GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Perform further actions
|
|
//
|
|
CommandEventsHandleModifiedEvent(Tag, &ModifyEventRequest);
|
|
|
|
if (TypeOfAction == DEBUGGER_MODIFY_EVENTS_QUERY_STATE)
|
|
{
|
|
return ModifyEventRequest.IsEnabled;
|
|
}
|
|
}
|
|
|
|
//
|
|
// in all the cases except query state it shows whether the operation was
|
|
// successful or not
|
|
//
|
|
return TRUE;
|
|
}
|