HyperDbg Debugger
Loading...
Searching...
No Matches
BreakpointCommands.c File Reference

Routines for breakpoint commands. More...

#include "pch.h"

Functions

BOOLEAN BreakpointCheckAndPerformActionsOnTrapFlags (UINT32 ProcessId, UINT32 ThreadId, BOOLEAN *TrapSetByDebugger)
 Check and perform actions on RFLAGS.TF.
BOOLEAN BreakpointTriggerCallbacks (PROCESSOR_DEBUGGING_STATE *DbgState, UINT32 ProcessId, UINT32 ThreadId)
 Trigger callback for breakpoint hit.
BOOLEAN BreakpointRestoreTheTrapFlagOnceTriggered (UINT32 ProcessId, UINT32 ThreadId)
 This function makes sure to unset the RFLAGS.TF on next trigger of #DB on the target process/thread.
BOOLEAN BreakpointCheckAndHandleDebugBreakpoint (UINT32 CoreId)
 Check and handle debug breakpoint exceptions.
BOOLEAN BreakpointClear (PDEBUGGEE_BP_DESCRIPTOR BreakpointDescriptor)
 clears the 0xcc and removes the breakpoint @detail this function won't remove the descriptor from the list
VOID BreakpointClearAndDeallocateMemory (PDEBUGGEE_BP_DESCRIPTOR BreakpointDesc)
 Clears the breakpoint and remove the entry from the breakpoint list.
BOOLEAN BreakpointCheckAndHandleReApplyingBreakpoint (PROCESSOR_DEBUGGING_STATE *DbgState)
 Check and reapply breakpoint.
BOOLEAN BreakpointCheckAndHandleDebuggerDefinedBreakpoints (PROCESSOR_DEBUGGING_STATE *DbgState, UINT64 GuestRip, DEBUGGEE_PAUSING_REASON Reason, BOOLEAN ChangeMtfState)
 Check if the breakpoint vm-exit relates to 'bp' command or not.
BOOLEAN BreakpointHandleBreakpoints (UINT32 CoreId)
 Handle breakpoint vm-exits (#BP).
BOOLEAN BreakpointWrite (PDEBUGGEE_BP_DESCRIPTOR BreakpointDescriptor, BOOLEAN SwitchToTargetMemoryLayout)
 writes the 0xcc and applies the breakpoint @detail this function won't remove the descriptor from the list
VOID BreakpointRemoveAllBreakpoints ()
 Remove all the breakpoints if possible.
PDEBUGGEE_BP_DESCRIPTOR BreakpointGetEntryByBreakpointId (UINT64 BreakpointId)
 Find entry of breakpoint descriptor from list of breakpoints by breakpoint id.
PDEBUGGEE_BP_DESCRIPTOR BreakpointGetEntryByAddress (UINT64 Address)
 Find entry of breakpoint descriptor from list of breakpoints by address.
BOOLEAN BreakpointAddNew (PDEBUGGEE_BP_PACKET BpDescriptorArg, BOOLEAN SwitchToTargetMemoryLayout)
 Add new breakpoints.
VOID BreakpointListAllBreakpoint ()
 List all breakpoints.
BOOLEAN BreakpointListOrModify (PDEBUGGEE_BP_LIST_OR_MODIFY_PACKET ListOrModifyBreakpoints, BOOLEAN SwitchToTargetMemoryLayout)
 List of modify breakpoints.

Detailed Description

Routines for breakpoint commands.

Author
Sina Karvandi (sina@.nosp@m.hype.nosp@m.rdbg..nosp@m.org)
Version
0.1
Date
2021-03-12

Function Documentation

◆ BreakpointAddNew()

BOOLEAN BreakpointAddNew ( PDEBUGGEE_BP_PACKET BpDescriptorArg,
BOOLEAN SwitchToTargetMemoryLayout )

Add new breakpoints.

Parameters
BpDescriptor
SwitchToTargetMemoryLayout
Returns
BOOLEAN
951{
952 CR3_TYPE GuestCr3 = {0};
953 PDEBUGGEE_BP_DESCRIPTOR BreakpointDescriptor = NULL;
954 BOOLEAN IsAddress32Bit = FALSE;
955
956 //
957 // Find the current process cr3
958 //
959 if (SwitchToTargetMemoryLayout)
960 {
961 //
962 // Check if the process id is valid or not
963 //
964 if (BpDescriptorArg->Pid != DEBUGGEE_BP_APPLY_TO_ALL_PROCESSES &&
965 !CommonIsProcessExist(BpDescriptorArg->Pid))
966 {
967 //
968 // Process id is invalid (Set the error)
969 //
970 BpDescriptorArg->Result = DEBUGGER_ERROR_INVALID_PROCESS_ID;
971 return FALSE;
972 }
973
974 GuestCr3.Flags = LayoutGetCr3ByProcessId(BpDescriptorArg->Pid).Flags;
975 }
976 else
977 {
979 }
980
981 //
982 // *** Validate arguments ***
983 //
984
985 //
986 // Check if the core number is not invalid
987 //
988 if (BpDescriptorArg->Core != DEBUGGEE_BP_APPLY_TO_ALL_CORES &&
989 !CommonValidateCoreNumber(BpDescriptorArg->Core))
990 {
991 //
992 // Core is invalid (Set the error)
993 //
994 BpDescriptorArg->Result = DEBUGGER_ERROR_INVALID_CORE_ID;
995 return FALSE;
996 }
997
998 //
999 // Check if breakpoint already exists on list or not
1000 //
1001 if (BreakpointGetEntryByAddress(BpDescriptorArg->Address) != NULL)
1002 {
1003 //
1004 // Address is already on the list (Set the error)
1005 //
1007 return FALSE;
1008 }
1009
1010 //
1011 // Check if address is safe (only one byte for 0xcc)
1012 //
1013 if (SwitchToTargetMemoryLayout)
1014 {
1015 if (!CheckAccessValidityAndSafetyByProcessId(BpDescriptorArg->Address, sizeof(BYTE), BpDescriptorArg->Pid))
1016 {
1018 return FALSE;
1019 }
1020 }
1021 else
1022 {
1023 if (!CheckAccessValidityAndSafety(BpDescriptorArg->Address, sizeof(BYTE)))
1024 {
1026 return FALSE;
1027 }
1028 }
1029
1030 //
1031 // On the debugger mode, we won't check for process id and thread id, if these arguments are invalid
1032 // then the HyperDbg simply ignores the breakpoints but it makes the computer slow
1033 // it just won't be triggered
1034 //
1035
1036 //
1037 // When we reach here means that the arguments are valid and address is
1038 // safe to access (put 0xcc)
1039 //
1040
1041 //
1042 // Get the pre-allocated buffer
1043 //
1044 BreakpointDescriptor = (DEBUGGEE_BP_DESCRIPTOR *)
1046
1047 if (BreakpointDescriptor == NULL)
1048 {
1049 //
1050 // No pool ! Probably the user set more than MAXIMUM_BREAKPOINTS_WITHOUT_CONTINUE
1051 // pools without IOCTL (continue)
1052 //
1054 return FALSE;
1055 }
1056
1057 //
1058 // Copy details of breakpoint to the descriptor structure
1059 //
1061 BreakpointDescriptor->BreakpointId = g_MaximumBreakpointId;
1062 BreakpointDescriptor->Address = BpDescriptorArg->Address;
1063 BreakpointDescriptor->PhysAddress = VirtualAddressToPhysicalAddressByProcessCr3((PVOID)BpDescriptorArg->Address,
1064 GuestCr3);
1065 BreakpointDescriptor->Core = BpDescriptorArg->Core;
1066 BreakpointDescriptor->Pid = BpDescriptorArg->Pid;
1067 BreakpointDescriptor->Tid = BpDescriptorArg->Tid;
1068 BreakpointDescriptor->RemoveAfterHit = BpDescriptorArg->RemoveAfterHit;
1069 BreakpointDescriptor->CheckForCallbacks = BpDescriptorArg->CheckForCallbacks;
1070
1071 //
1072 // Check whether address is 32-bit or 64-bit
1073 //
1074 if (BpDescriptorArg->Address & 0xff00000000000000)
1075 {
1076 //
1077 // This is a kernel-base address and as the kernel is 64-bit, we assume it's a 64-bit address
1078 //
1079 IsAddress32Bit = FALSE;
1080 }
1081 else
1082 {
1083 //
1084 // The address is not a kernel address, thus, we check whether the debuggee is running on user-mode
1085 // or not
1086 //
1087 if (SwitchToTargetMemoryLayout)
1088 {
1089 UserAccessIsWow64Process((HANDLE)BpDescriptorArg->Pid, &IsAddress32Bit);
1090 }
1091 else
1092 {
1093 IsAddress32Bit = KdIsGuestOnUsermode32Bit();
1094 }
1095 }
1096
1097 //
1098 // Use length disassembler engine to get the instruction length
1099 //
1100 if (SwitchToTargetMemoryLayout)
1101 {
1103 (PVOID)BpDescriptorArg->Address,
1104 IsAddress32Bit,
1105 BpDescriptorArg->Pid);
1106 }
1107 else
1108 {
1110 (PVOID)BpDescriptorArg->Address,
1111 IsAddress32Bit);
1112 }
1113
1114 //
1115 // Breakpoints are enabled by default
1116 //
1117 BreakpointDescriptor->Enabled = TRUE;
1118
1119 //
1120 // Now we should add the breakpoint to the list of breakpoints (LIST_ENTRY)
1121 //
1122 InsertHeadList(&g_BreakpointsListHead, &(BreakpointDescriptor->BreakpointsList));
1123
1124 //
1125 // Apply the breakpoint
1126 //
1127 BreakpointWrite(BreakpointDescriptor, SwitchToTargetMemoryLayout);
1128
1129 //
1130 // Show that operation was successful
1131 //
1132 BpDescriptorArg->Result = DEBUGGER_OPERATION_WAS_SUCCESSFUL;
1133
1134 return TRUE;
1135}
BOOLEAN BreakpointWrite(PDEBUGGEE_BP_DESCRIPTOR BreakpointDescriptor, BOOLEAN SwitchToTargetMemoryLayout)
writes the 0xcc and applies the breakpoint @detail this function won't remove the descriptor from the...
Definition BreakpointCommands.c:780
PDEBUGGEE_BP_DESCRIPTOR BreakpointGetEntryByAddress(UINT64 Address)
Find entry of breakpoint descriptor from list of breakpoints by address.
Definition BreakpointCommands.c:919
BOOLEAN KdIsGuestOnUsermode32Bit()
determines if the guest was in 32-bit user-mode or 64-bit (long mode)
Definition Kd.c:3220
UINT64 PoolManagerRequestPool(POOL_ALLOCATION_INTENTION Intention, BOOLEAN RequestNewPool, UINT32 Size)
This function should be called from vmx-root in order to get a pool from the list.
Definition PoolManager.c:230
BOOLEAN UserAccessIsWow64Process(HANDLE ProcessId, PBOOLEAN Is32Bit)
Detects whether process is 32-bit or 64-bit.
Definition UserAccess.c:753
unsigned short UINT16
Definition BasicTypes.h:53
UCHAR BOOLEAN
Definition BasicTypes.h:35
void * PVOID
Definition BasicTypes.h:56
unsigned char BYTE
Definition BasicTypes.h:40
#define TRUE
Definition BasicTypes.h:114
#define FALSE
Definition BasicTypes.h:113
struct _CR3_TYPE CR3_TYPE
CR3 Structure.
#define DEBUGGEE_BP_APPLY_TO_ALL_PROCESSES
The constant to apply to all processes for bp command.
Definition Constants.h:781
#define DEBUGGEE_BP_APPLY_TO_ALL_CORES
The constant to apply to all cores for bp command.
Definition Constants.h:775
@ BREAKPOINT_DEFINITION_STRUCTURE
Definition DataTypes.h:78
#define DEBUGGER_ERROR_MAXIMUM_BREAKPOINT_WITHOUT_CONTINUE
error, maximum pools were used without continuing debuggee
Definition ErrorCodes.h:184
#define DEBUGGER_ERROR_BREAKPOINT_ALREADY_EXISTS_ON_THE_ADDRESS
error, breakpoint already exists on the target address
Definition ErrorCodes.h:190
#define DEBUGGER_ERROR_INVALID_CORE_ID
error, the core id is invalid
Definition ErrorCodes.h:69
#define DEBUGGER_ERROR_EDIT_MEMORY_STATUS_INVALID_ADDRESS_BASED_ON_CURRENT_PROCESS
error, an invalid address is specified based on current cr3 in !e* or e* commands
Definition ErrorCodes.h:106
#define DEBUGGER_ERROR_INVALID_PROCESS_ID
error, the process id is invalid
Definition ErrorCodes.h:220
#define DEBUGGER_OPERATION_WAS_SUCCESSFUL
General value to indicate that the operation or request was successful.
Definition ErrorCodes.h:23
IMPORT_EXPORT_VMM BOOLEAN CheckAccessValidityAndSafetyByProcessId(UINT64 TargetAddress, UINT32 Size, UINT32 ProcessId)
Check the safety to access the memory by process ID.
Definition AddressCheck.c:332
IMPORT_EXPORT_VMM BOOLEAN CheckAccessValidityAndSafety(UINT64 TargetAddress, UINT32 Size)
Check the safety to access the memory.
Definition AddressCheck.c:318
IMPORT_EXPORT_VMM UINT64 VirtualAddressToPhysicalAddressByProcessCr3(_In_ PVOID VirtualAddress, _In_ CR3_TYPE TargetCr3)
IMPORT_EXPORT_VMM UINT32 DisassemblerLengthDisassembleEngineInVmxRootOnTargetProcess(PVOID Address, BOOLEAN Is32Bit)
Disassembler length disassembler engine.
Definition Disassembler.c:297
IMPORT_EXPORT_VMM UINT32 DisassemblerLengthDisassembleEngineByProcessId(PVOID Address, BOOLEAN Is32Bit, UINT32 ProcessId)
Disassembler length disassembler engine.
Definition Disassembler.c:329
IMPORT_EXPORT_VMM CR3_TYPE LayoutGetCurrentProcessCr3()
Get cr3 of the target running process.
Definition Layout.c:55
IMPORT_EXPORT_VMM CR3_TYPE LayoutGetCr3ByProcessId(UINT32 ProcessId)
Converts pid to kernel cr3.
Definition Layout.c:24
LIST_ENTRY g_BreakpointsListHead
List header of breakpoints for debugger-mode.
Definition Global.h:139
UINT64 g_MaximumBreakpointId
Seed for setting id of breakpoints.
Definition Global.h:145
_Use_decl_annotations_ BOOLEAN CommonValidateCoreNumber(UINT32 CoreNumber)
Validate core number.
Definition Common.c:256
BOOLEAN CommonIsProcessExist(UINT32 ProcId)
Checks whether the process with ProcId exists or not.
Definition Common.c:24
struct _DEBUGGEE_BP_DESCRIPTOR DEBUGGEE_BP_DESCRIPTOR
The structure of storing breakpoints.
struct _DEBUGGEE_BP_DESCRIPTOR * PDEBUGGEE_BP_DESCRIPTOR
NULL()
Definition test-case-generator.py:530
UINT64 Flags
Definition BasicTypes.h:239
UINT64 BreakpointId
Definition State.h:73
BOOLEAN RemoveAfterHit
Definition State.h:84
BOOLEAN CheckForCallbacks
Definition State.h:85
UINT16 InstructionLength
Definition State.h:81
UINT64 Address
Definition State.h:76
LIST_ENTRY BreakpointsList
Definition State.h:74
BOOLEAN Enabled
Definition State.h:75
UINT64 PhysAddress
Definition State.h:77
UINT32 Pid
Definition State.h:78
UINT32 Tid
Definition State.h:79
UINT32 Core
Definition State.h:80
UINT32 Tid
Definition RequestStructures.h:1519
UINT32 Result
Definition RequestStructures.h:1523
BOOLEAN RemoveAfterHit
Definition RequestStructures.h:1521
UINT32 Core
Definition RequestStructures.h:1520
BOOLEAN CheckForCallbacks
Definition RequestStructures.h:1522
UINT64 Address
Definition RequestStructures.h:1517
UINT32 Pid
Definition RequestStructures.h:1518

◆ BreakpointCheckAndHandleDebugBreakpoint()

BOOLEAN BreakpointCheckAndHandleDebugBreakpoint ( UINT32 CoreId)

Check and handle debug breakpoint exceptions.

Parameters
CoreId
Returns
BOOLEAN
240{
241 BOOLEAN TrapSetByDebugger;
242 PROCESSOR_DEBUGGING_STATE * DbgState = &g_DbgState[CoreId];
243 BOOLEAN HandledByDebuggerRoutines = TRUE;
244
245 //
246 // *** Check whether anything should be changed with trap-flags
247 // and also it indicates whether the debugger itself set this trap
248 // flag or it's not supposed to be set by the debugger ***
249 //
251 HANDLE_TO_UINT32(PsGetCurrentThreadId()),
252 &TrapSetByDebugger))
253 {
255 {
256 //
257 // This check was to show whether it is because of thread change detection or not
258 //
259
260 // This way of handling has a problem, if the user set to change
261 // the thread and instead of using 'g', it pressed the 'p' to
262 // set or a trap happens somewhere then will be ignored
263 // it because we don't know the origin of this debug breakpoint
264 // and it only happens on '.thread2' command, the correct way
265 // to handle it is to find the exact hw debug register that caused
266 // this vm-exit, but it's a really rare case, so we left it without
267 // handling this case
268 //
269 ThreadHandleThreadChange(DbgState);
270 }
271 else if (g_UserDebuggerState == TRUE &&
273 {
274 //
275 // Handle for user-mode attaching mechanism
276 //
278 }
279 else if (g_KernelDebuggerState == TRUE)
280 {
281 //
282 // Here we added the handler for the kernel because we want
283 // stepping routines to work, even if the debugger masks the
284 // traps by using 'test trap off', so stepping still works
285 //
286
287 //
288 // Handle debug events (breakpoint, traps, hardware debug register when kernel
289 // debugger is attached)
290 //
291 KdHandleDebugEventsWhenKernelDebuggerIsAttached(DbgState, TrapSetByDebugger);
292 }
293 else if (g_UserDebuggerState == TRUE &&
294 UdHandleDebugEventsWhenUserDebuggerIsAttached(DbgState, TrapSetByDebugger))
295 {
296 //
297 // if the above function returns true, no need for further action
298 // it's handled in the user debugger
299 //
300 }
301 else
302 {
303 //
304 // Here it means that the trap is supposed to be handled by
305 // HyperDbg but, we couldn't find any routines that gonna
306 // handle it (it's probably an error)
307 //
308 HandledByDebuggerRoutines = FALSE;
309 LogError("Err, trap is supposed to be handled by the debugger, but none of routines handled it");
310 }
311 }
312 else
313 {
314 //
315 // *** it's not supposed to be handled by the debugger routines, the guest
316 // or the target debuggee throws a debug break (#DB) ***
317 //
318
319 //
320 // It means that it's not handled by the debugger routines
321 // By default HyperDbg intercepts all #DBs and break the debugger if
322 // it's attached to the debugger, otherwise injects to the guest VM
323 //
325 {
326 //
327 // The user explicitly told the debugger not to intercept any
328 // traps (e.g., by using 'test trap off')
329 //
330 HandledByDebuggerRoutines = FALSE;
331 }
332 else if (g_KernelDebuggerState == TRUE)
333 {
334 //
335 // Handle debug events (breakpoint, traps, hardware debug register when kernel
336 // debugger is attached)
337 //
338 KdHandleDebugEventsWhenKernelDebuggerIsAttached(DbgState, TrapSetByDebugger);
339 }
340 else if (g_UserDebuggerState == TRUE &&
341 UdHandleDebugEventsWhenUserDebuggerIsAttached(DbgState, TrapSetByDebugger))
342 {
343 //
344 // if the above function returns true, no need for further action
345 // it's handled in the user debugger
346 //
347 }
348 else
349 {
350 //
351 // Inject to back to the guest as it's not either handled by the kernel debugger
352 // routines or the user debugger
353 //
354 HandledByDebuggerRoutines = FALSE;
355 }
356 }
357
358 return HandledByDebuggerRoutines;
359}
VOID AttachingHandleEntrypointInterception(PROCESSOR_DEBUGGING_STATE *DbgState)
Handle the interception of finding the entrypoint on attaching to user-mode process.
Definition Attaching.c:441
BOOLEAN BreakpointCheckAndPerformActionsOnTrapFlags(UINT32 ProcessId, UINT32 ThreadId, BOOLEAN *TrapSetByDebugger)
Check and perform actions on RFLAGS.TF.
Definition BreakpointCommands.c:23
VOID KdHandleDebugEventsWhenKernelDebuggerIsAttached(PROCESSOR_DEBUGGING_STATE *DbgState, BOOLEAN TrapSetByDebugger)
Handles debug events when kernel-debugger is attached.
Definition Kd.c:487
#define HANDLE_TO_UINT32(_var)
Definition MetaMacros.h:39
BOOLEAN ThreadHandleThreadChange(PROCESSOR_DEBUGGING_STATE *DbgState)
handle thread changes
Definition Thread.c:22
BOOLEAN UdHandleDebugEventsWhenUserDebuggerIsAttached(PROCESSOR_DEBUGGING_STATE *DbgState, BOOLEAN TrapSetByDebugger)
Handles debug events when user-debugger is attached.
Definition Ud.c:267
#define LogError(format,...)
Log in the case of error.
Definition HyperDbgHyperLogIntrinsics.h:113
BOOLEAN g_IsWaitingForReturnAndRunFromPageFault
Whether the thread attaching mechanism is waiting for a page-fault finish or not.
Definition Global.h:194
BOOLEAN g_InterceptDebugBreaks
shows whether the debugger should intercept breakpoints (DB) or not
Definition Global.h:169
PROCESSOR_DEBUGGING_STATE * g_DbgState
Save the state and variables related to debugging on each to logical core.
Definition Global.h:17
BOOLEAN g_UserDebuggerState
shows whether the user debugger is enabled or disabled
Definition Global.h:157
BOOLEAN g_KernelDebuggerState
shows whether the kernel debugger is enabled or disabled
Definition Global.h:151
BOOLEAN g_IsWaitingForUserModeProcessEntryToBeCalled
Whether the thread attaching mechanism is waiting for DB or not.
Definition Global.h:206
struct _PROCESSOR_DEBUGGING_STATE PROCESSOR_DEBUGGING_STATE
Saves the debugger state.
BOOLEAN DebugRegisterInterceptionState
Definition State.h:56
DEBUGGEE_PROCESS_OR_THREAD_TRACING_DETAILS ThreadOrProcessTracingDetails
Definition State.h:179

◆ BreakpointCheckAndHandleDebuggerDefinedBreakpoints()

BOOLEAN BreakpointCheckAndHandleDebuggerDefinedBreakpoints ( PROCESSOR_DEBUGGING_STATE * DbgState,
UINT64 GuestRip,
DEBUGGEE_PAUSING_REASON Reason,
BOOLEAN ChangeMtfState )

Check if the breakpoint vm-exit relates to 'bp' command or not.

Parameters
DbgStateThe state of the debugger on the current core
GuestRip
Reason
ChangeMtfState
Returns
BOOLEAN
482{
483 CR3_TYPE GuestCr3 = {0};
484 BOOLEAN IsHandledByBpRoutines = FALSE;
485 PLIST_ENTRY TempList = 0;
486 UINT64 GuestRipPhysical = (UINT64)NULL;
487 DEBUGGER_TRIGGERED_EVENT_DETAILS TargetContext = {0};
488 BOOLEAN AvoidUnsetMtf = FALSE;
489 BOOLEAN IgnoreUserHandling = FALSE;
490
491 //
492 // ***** Check breakpoint for 'bp' command *****
493 //
494
495 //
496 // Find the current process cr3
497 //
499
500 //
501 // Convert breakpoint to physical address
502 //
503 GuestRipPhysical = VirtualAddressToPhysicalAddressByProcessCr3((PVOID)GuestRip, GuestCr3);
504
505 //
506 // Iterate through the list of breakpoints
507 //
508 TempList = &g_BreakpointsListHead;
509
510 while (&g_BreakpointsListHead != TempList->Flink)
511 {
512 TempList = TempList->Flink;
513 PDEBUGGEE_BP_DESCRIPTOR CurrentBreakpointDesc = CONTAINING_RECORD(TempList, DEBUGGEE_BP_DESCRIPTOR, BreakpointsList);
514
515 if (CurrentBreakpointDesc->PhysAddress == GuestRipPhysical)
516 {
517 //
518 // It's a breakpoint by 'bp' command
519 //
520 IsHandledByBpRoutines = TRUE;
521
522 //
523 // First, we remove the breakpoint
524 //
526 (UINT64)&CurrentBreakpointDesc->PreviousByte,
527 sizeof(BYTE));
528
529 //
530 // Now, halt the debuggee
531 //
532 TargetContext.Context = (PVOID)VmFuncGetLastVmexitRip(DbgState->CoreId);
533
534 //
535 // In breakpoints tag is breakpoint id, not event tag
536 //
538 {
539 TargetContext.Tag = CurrentBreakpointDesc->BreakpointId;
540 }
541
542 //
543 // Hint the debuggee about the length
544 //
545 DbgState->InstructionLengthHint = CurrentBreakpointDesc->InstructionLength;
546
547 //
548 // Check constraints
549 //
550 if ((CurrentBreakpointDesc->Pid == DEBUGGEE_BP_APPLY_TO_ALL_PROCESSES || CurrentBreakpointDesc->Pid == HANDLE_TO_UINT32(PsGetCurrentProcessId())) &&
551 (CurrentBreakpointDesc->Tid == DEBUGGEE_BP_APPLY_TO_ALL_THREADS || CurrentBreakpointDesc->Tid == HANDLE_TO_UINT32(PsGetCurrentThreadId())) &&
552 (CurrentBreakpointDesc->Core == DEBUGGEE_BP_APPLY_TO_ALL_CORES || CurrentBreakpointDesc->Core == DbgState->CoreId))
553 {
554 //
555 // Check if breakpoint should be removed after this hit or not
556 //
557 if (CurrentBreakpointDesc->RemoveAfterHit)
558 {
559 //
560 // One hit, we have to remove it
561 //
562 BreakpointClearAndDeallocateMemory(CurrentBreakpointDesc);
563 }
564
565 //
566 // Check if it needs to check for callbacks or not
567 //
568 if (CurrentBreakpointDesc->CheckForCallbacks)
569 {
570 //
571 // check callbacks
572 //
573 IgnoreUserHandling = BreakpointTriggerCallbacks(DbgState, HANDLE_TO_UINT32(PsGetCurrentProcessId()), HANDLE_TO_UINT32(PsGetCurrentThreadId()));
574 }
575
576 //
577 // Check if we need to handle the breakpoint by user or just ignore handling it
578 //
580 {
581 //
582 // *** It's not safe to access CurrentBreakpointDesc anymore as the
583 // breakpoint might be removed ***
584 //
586 {
588 Reason,
589 &TargetContext);
590 }
591 else if (g_UserDebuggerState)
592 {
593 UdHandleInstantBreak(DbgState, Reason, NULL);
594 }
595 else
596 {
597 LogInfo("Err, no debugger is attached to handle the breakpoint");
598 }
599 }
600 }
601
602 //
603 // Reset hint to instruction length
604 //
605 DbgState->InstructionLengthHint = 0;
606
607 //
608 // Check if we should re-apply the breakpoint after this instruction
609 // or not (in other words, is breakpoint still valid)
610 //
611 if (!CurrentBreakpointDesc->AvoidReApplyBreakpoint)
612 {
613 //
614 // We should re-apply the breakpoint on next mtf
615 //
616 DbgState->SoftwareBreakpointState = CurrentBreakpointDesc;
617
618 //
619 // As we want to continue debuggee, the MTF might arrive when the
620 // host finish executing it's time slice; thus, a clock interrupt
621 // or an IPI might be arrived and the next instruction is not what
622 // we expect. The following codes are added because we realized if the execution takes long then
623 // the execution might be switched to another routines, thus, MTF might conclude on
624 // another routine and we might (and will) trigger the same instruction soon
625 //
627
628 //
629 // Avoid unsetting MTF
630 //
631 AvoidUnsetMtf = TRUE;
632 }
633
634 //
635 // Do not increment rip
636 //
638
639 //
640 // No need to iterate anymore
641 //
642 break;
643 }
644 }
645
646 if (IsHandledByBpRoutines && ChangeMtfState)
647 {
648 VmFuncChangeMtfUnsettingState(DbgState->CoreId, AvoidUnsetMtf);
649 }
650
651 return IsHandledByBpRoutines;
652}
VOID BreakpointClearAndDeallocateMemory(PDEBUGGEE_BP_DESCRIPTOR BreakpointDesc)
Clears the breakpoint and remove the entry from the breakpoint list.
Definition BreakpointCommands.c:414
BOOLEAN BreakpointTriggerCallbacks(PROCESSOR_DEBUGGING_STATE *DbgState, UINT32 ProcessId, UINT32 ThreadId)
Trigger callback for breakpoint hit.
Definition BreakpointCommands.c:148
_Use_decl_annotations_ VOID KdHandleBreakpointAndDebugBreakpoints(PROCESSOR_DEBUGGING_STATE *DbgState, DEBUGGEE_PAUSING_REASON Reason, PDEBUGGER_TRIGGERED_EVENT_DETAILS EventDetails)
Handle DBs and BPs for kernel debugger.
Definition Kd.c:1291
BOOLEAN UdHandleInstantBreak(PROCESSOR_DEBUGGING_STATE *DbgState, DEBUGGEE_PAUSING_REASON Reason, PUSERMODE_DEBUGGING_PROCESS_DETAILS ProcessDebuggingDetail)
Handle cases where we instant break is needed on the user debugger.
Definition Ud.c:122
@ DEBUGGEE_PAUSING_REASON_DEBUGGEE_SOFTWARE_BREAKPOINT_HIT
Definition Connection.h:29
#define DEBUGGEE_BP_APPLY_TO_ALL_THREADS
The constant to apply to all threads for bp command.
Definition Constants.h:787
struct _DEBUGGER_TRIGGERED_EVENT_DETAILS DEBUGGER_TRIGGERED_EVENT_DETAILS
The structure of detail of a triggered event in HyperDbg.
#define LogInfo(format,...)
Define log variables.
Definition HyperDbgHyperLogIntrinsics.h:71
IMPORT_EXPORT_VMM VOID VmFuncSuppressRipIncrement(UINT32 CoreId)
Suppress the incrementation of RIP.
Definition Export.c:34
IMPORT_EXPORT_VMM VOID VmFuncEnableMtfAndChangeExternalInterruptState(UINT32 CoreId)
Enables MTF and adjust external interrupt state.
Definition Export.c:1073
IMPORT_EXPORT_VMM VOID VmFuncChangeMtfUnsettingState(UINT32 CoreId, BOOLEAN Set)
Suppress unsetting MTF.
Definition Export.c:47
IMPORT_EXPORT_VMM BOOLEAN MemoryMapperWriteMemorySafeByPhysicalAddress(_Inout_ UINT64 DestinationPa, _In_ UINT64 Source, _In_ SIZE_T SizeToWrite)
IMPORT_EXPORT_VMM UINT64 VmFuncGetLastVmexitRip(UINT32 CoreId)
get the last vm-exit RIP
Definition Export.c:363
BOOLEAN g_InterceptBreakpoints
shows whether the debugger should intercept breakpoints (BP) or not
Definition Global.h:163
BOOLEAN g_InterceptBreakpointsAndEventsForCommandsInRemoteComputer
To avoid getting stuck from getting hit from the breakpoints while executing the commands in the remo...
Definition Global.h:214
#define CONTAINING_RECORD(address, type, field)
Definition nt-list.h:36
BYTE PreviousByte
Definition State.h:82
BOOLEAN AvoidReApplyBreakpoint
Definition State.h:83
UINT64 Tag
Definition DataTypes.h:226
PVOID Context
Definition DataTypes.h:227
UINT32 CoreId
Definition State.h:168
UINT16 InstructionLengthHint
Definition State.h:182
PDEBUGGEE_BP_DESCRIPTOR SoftwareBreakpointState
Definition State.h:177

◆ BreakpointCheckAndHandleReApplyingBreakpoint()

BOOLEAN BreakpointCheckAndHandleReApplyingBreakpoint ( PROCESSOR_DEBUGGING_STATE * DbgState)

Check and reapply breakpoint.

Parameters
DbgStateThe state of the debugger on the current core
Returns
BOOLEAN
441{
442 BOOLEAN Result = FALSE;
443
444 if (DbgState->SoftwareBreakpointState != NULL)
445 {
446 BYTE BreakpointByte = 0xcc;
447
448 //
449 // MTF is handled
450 //
451 Result = TRUE;
452
453 //
454 // Restore previous breakpoint byte
455 //
458 (UINT64)&BreakpointByte,
459 sizeof(BYTE));
460
461 DbgState->SoftwareBreakpointState = NULL;
462 }
463
464 return Result;
465}

◆ BreakpointCheckAndPerformActionsOnTrapFlags()

BOOLEAN BreakpointCheckAndPerformActionsOnTrapFlags ( UINT32 ProcessId,
UINT32 ThreadId,
BOOLEAN * TrapSetByDebugger )

Check and perform actions on RFLAGS.TF.

Parameters
ProcessId
ThreadId
TrapSetByDebugger
Returns
BOOLEAN Shows whether the #DB should be handled by the debugger or re-injected
24{
25 UINT32 Index;
26 DEBUGGER_PROCESS_THREAD_INFORMATION ProcThrdInfo = {0};
27 BOOLEAN Result;
28 BOOLEAN ResultToReturn;
29 RFLAGS Rflags = {0};
30
31 //
32 // Read the RFLAGS
33 //
34 Rflags.AsUInt = VmFuncGetRflags();
35
36 //
37 // Form the process id and thread id into a 64-bit value
38 //
39 ProcThrdInfo.Fields.ProcessId = ProcessId;
40 ProcThrdInfo.Fields.ThreadId = ThreadId;
41
42 //
43 // Make sure, nobody is in the middle of modifying the list
44 //
46
47 //
48 // *** Search the list of processes/threads for the current process's trap flag state ***
49 //
50 Result = BinarySearchPerformSearchItem((UINT64 *)&g_TrapFlagState.ThreadInformation[0],
51 g_TrapFlagState.NumberOfItems,
52 &Index,
53 ProcThrdInfo.AsUInt);
54
55 //
56 // Indicate whether the trap flag is set by the debugger or not
57 //
58 *TrapSetByDebugger = Result;
59
60 //
61 // We check the trap flag after the results because we might set the trap flag
62 // for the thread but the thread might run 'popfq' removing our trap flag
63 // so, we both check whether thread is expected to have trap flag, if not
64 // we check whether the trap flag is available or not
65 //
66 if (!Result && !Rflags.TrapFlag)
67 {
68 //
69 // It's not related to a TRAP FLAG, and we didn't previously set trap flag for this thread
70 // So, probably other events like setting hardware debug breakpoints caused this #DB
71 // which means that it should be handled by the debugger
72 //
73 ResultToReturn = TRUE;
74 goto Return;
75 }
76 else if (!Result && Rflags.TrapFlag)
77 {
78 //
79 // As it's not set by the debugger (not found in our list), it means the program or
80 // a debugger already set the trap flag, we'll return FALSE
81 //
82 // LogInfo("Caution: The process (pid:%x, tid:%x, name:%s) is utilizing a trap flag, "
83 // "which was not previously adjusted by HyperDbg. This occurrence could indicate "
84 // "the employment of an anti-debugging technique by the process or the involvement "
85 // "of another debugger. By default, HyperDbg automatically manages these #DB events "
86 // "and halt the debugger; however, if you wish to redirect them to the debugger, "
87 // "you can utilize 'test trap off'. Alternatively, you can use the transparent-mode "
88 // "to mitigate these situations",
89 // PsGetCurrentProcessId(),
90 // PsGetCurrentThreadId(),
91 // CommonGetProcessNameFromProcessControlBlock(PsGetCurrentProcess()));
92
93 //
94 // Returning false means that it should be re-injected into the debuggee
95 //
96 ResultToReturn = FALSE;
97 goto Return;
98 }
99 else
100 {
101 //
102 // *** being here means the thread is found in the list of threads that we set TRAP FLAG on it ***
103 //
104
105 //
106 // Uset or set the TRAP flag
107 //
109
110 //
111 // Remove the thread/process from the list
112 // We're sure the Result is TRUE
113 //
114 InsertionSortDeleteItem((UINT64 *)&g_TrapFlagState.ThreadInformation[0],
115 &g_TrapFlagState.NumberOfItems,
116 Index);
117
118 //
119 // Handled #DB by debugger
120 //
121 ResultToReturn = TRUE;
122 goto Return;
123 }
124
125Return:
126
127 //
128 // Unlock the list modification lock
129 //
131
132 //
133 // By default, #DBs are managed by HyperDbg
134 //
135 return ResultToReturn;
136}
BOOLEAN BinarySearchPerformSearchItem(UINT64 ArrayPtr[], UINT32 NumberOfItems, UINT32 *ResultIndex, UINT64 Key)
A utility function to perform the binary search.
Definition BinarySearch.c:46
volatile LONG BreakpointCommandTrapListLock
The lock for modifying list of process/thread for unsetting TRAP FLAG.
Definition BreakpointCommands.h:22
BOOLEAN InsertionSortDeleteItem(UINT64 ArrayPtr[], UINT32 *NumberOfItems, UINT32 Index)
Function to implement insertion sort.
Definition InsertionSort.c:69
VOID SpinlockLock(volatile LONG *Lock)
Tries to get the lock and won't return until successfully get the lock.
Definition Spinlock.c:53
VOID SpinlockUnlock(volatile LONG *Lock)
Release the lock.
Definition Spinlock.c:162
unsigned int UINT32
Definition BasicTypes.h:54
IMPORT_EXPORT_VMM VOID VmFuncSetRflagTrapFlag(BOOLEAN Set)
Set Rflag's trap flag.
Definition Export.c:123
IMPORT_EXPORT_VMM UINT64 VmFuncGetRflags()
Read guest's RFLAGS.
Definition Export.c:397
DEBUGGER_TRAP_FLAG_STATE g_TrapFlagState
State of the trap-flag.
Definition Global.h:77
struct _DEBUGGER_PROCESS_THREAD_INFORMATION DEBUGGER_PROCESS_THREAD_INFORMATION
The thread/process information.
UINT64 AsUInt
Definition State.h:108
UINT32 ProcessId
Definition State.h:112
struct _DEBUGGER_PROCESS_THREAD_INFORMATION::@377140057364001237056132370063071376367357142252::@172143030234360142230226246044006264162165314002 Fields
UINT32 ThreadId
Definition State.h:113

◆ BreakpointClear()

BOOLEAN BreakpointClear ( PDEBUGGEE_BP_DESCRIPTOR BreakpointDescriptor)

clears the 0xcc and removes the breakpoint @detail this function won't remove the descriptor from the list

Parameters
BreakpointDescriptor
Returns
BOOLEAN
370{
371 BYTE TargetMem = NULL_ZERO;
372
373 //
374 // Check if address is safe (only one byte for 0xcc)
375 //
376 if (!CheckAccessValidityAndSafety(BreakpointDescriptor->Address, sizeof(BYTE)))
377 {
378 //
379 // Double check if we can access it by physical address
380 //
382 (UINT64)&TargetMem,
383 sizeof(BYTE));
384
385 if (TargetMem != 0xcc)
386 {
387 return FALSE;
388 }
389 }
390
391 //
392 // Apply the previous byte
393 //
395 (UINT64)&BreakpointDescriptor->PreviousByte,
396 sizeof(BYTE));
397
398 //
399 // Set breakpoint to disabled
400 //
401 BreakpointDescriptor->Enabled = FALSE;
402 BreakpointDescriptor->AvoidReApplyBreakpoint = TRUE;
403
404 return TRUE;
405}
#define NULL_ZERO
Definition BasicTypes.h:110
IMPORT_EXPORT_VMM BOOLEAN MemoryMapperReadMemorySafeByPhysicalAddress(_In_ UINT64 PaAddressToRead, _Inout_ UINT64 BufferToSaveMemory, _In_ SIZE_T SizeToRead)

◆ BreakpointClearAndDeallocateMemory()

VOID BreakpointClearAndDeallocateMemory ( PDEBUGGEE_BP_DESCRIPTOR BreakpointDesc)

Clears the breakpoint and remove the entry from the breakpoint list.

Parameters

return VOID

415{
416 //
417 // Clear the breakpoint
418 //
419 BreakpointClear(BreakpointDesc);
420
421 //
422 // Remove breakpoint from the list of breakpoints
423 //
424 RemoveEntryList(&BreakpointDesc->BreakpointsList);
425
426 //
427 // Uninitialize the breakpoint descriptor (safely)
428 //
429 PoolManagerFreePool((UINT64)BreakpointDesc);
430}
BOOLEAN BreakpointClear(PDEBUGGEE_BP_DESCRIPTOR BreakpointDescriptor)
clears the 0xcc and removes the breakpoint @detail this function won't remove the descriptor from the...
Definition BreakpointCommands.c:369
BOOLEAN PoolManagerFreePool(UINT64 AddressToFree)
This function set a pool flag to be freed, and it will be freed on the next IOCTL when it's safe to r...
Definition PoolManager.c:154

◆ BreakpointGetEntryByAddress()

PDEBUGGEE_BP_DESCRIPTOR BreakpointGetEntryByAddress ( UINT64 Address)

Find entry of breakpoint descriptor from list of breakpoints by address.

Parameters
Address
Returns
PDEBUGGEE_BP_DESCRIPTOR
920{
921 PLIST_ENTRY TempList = 0;
922
923 TempList = &g_BreakpointsListHead;
924
925 while (&g_BreakpointsListHead != TempList->Flink)
926 {
927 TempList = TempList->Flink;
928 PDEBUGGEE_BP_DESCRIPTOR CurrentBreakpointDesc = CONTAINING_RECORD(TempList, DEBUGGEE_BP_DESCRIPTOR, BreakpointsList);
929
930 if (CurrentBreakpointDesc->Address == Address)
931 {
932 return CurrentBreakpointDesc;
933 }
934 }
935
936 //
937 // We didn't find anything, so return null
938 //
939 return NULL;
940}

◆ BreakpointGetEntryByBreakpointId()

PDEBUGGEE_BP_DESCRIPTOR BreakpointGetEntryByBreakpointId ( UINT64 BreakpointId)

Find entry of breakpoint descriptor from list of breakpoints by breakpoint id.

Parameters
BreakpointId
Returns
PDEBUGGEE_BP_DESCRIPTOR
889{
890 PLIST_ENTRY TempList = 0;
891
892 TempList = &g_BreakpointsListHead;
893
894 while (&g_BreakpointsListHead != TempList->Flink)
895 {
896 TempList = TempList->Flink;
897 PDEBUGGEE_BP_DESCRIPTOR CurrentBreakpointDesc = CONTAINING_RECORD(TempList, DEBUGGEE_BP_DESCRIPTOR, BreakpointsList);
898
899 if (CurrentBreakpointDesc->BreakpointId == BreakpointId)
900 {
901 return CurrentBreakpointDesc;
902 }
903 }
904
905 //
906 // We didn't find anything, so return null
907 //
908 return NULL;
909}

◆ BreakpointHandleBreakpoints()

BOOLEAN BreakpointHandleBreakpoints ( UINT32 CoreId)

Handle breakpoint vm-exits (#BP).

Parameters
CoreId
Returns
BOOLEAN
663{
664 DEBUGGER_TRIGGERED_EVENT_DETAILS TargetContext = {0};
665 UINT64 GuestRip = 0;
666 PROCESSOR_DEBUGGING_STATE * DbgState = &g_DbgState[CoreId];
667
668 GuestRip = VmFuncGetRip();
669
670 //
671 // A breakpoint triggered and two things might be happened,
672 // first, a breakpoint is triggered randomly in the computer and
673 // we shouldn't do anything on it (won't change the instruction)
674 // second, the breakpoint is because of the 'bp' command, we should
675 // replace it with exact byte
676 //
677
678 //
679 // Check if the breakpoint is handled by the debugger routines
680 //
682 GuestRip,
684 FALSE))
685 {
686 //
687 // The breakpoint is handled by the debugger routines
688 // so, we don't need to do anything else
689 //
690 return TRUE;
691 }
692
693 //
694 // re-inject #BP back to the guest if not handled by the hidden breakpoint
695 //
697 {
698 //
699 // *** Kernel debugger is attached, let's halt everything ***
700 //
701
702 //
703 // To avoid the computer crash situation from the HyperDbg's breakpoint hitting while the interception is on
704 // we should always call BreakpointCheckAndHandleDebuggerDefinedBreakpoints first to handle the breakpoint
705 //
706
708 {
709 //
710 // re-inject back to the guest as not handled if the interception is on and the breakpoint is not from the Hyperdbg's breakpoints
711 //
712 return FALSE;
713 }
714
715 //
716 // It's a random breakpoint byte
717 //
718 TargetContext.Context = (PVOID)GuestRip;
721 &TargetContext);
722
723 //
724 // Increment rip
725 //
727
728 //
729 // By default, we handle the random breakpoints if the kernel debugger is attached
730 //
731 return TRUE;
732 }
733 else if (g_UserDebuggerState)
734 {
735 //
736 // *** User debugger is attached, let's halt the process ***
737 //
738
739 //
740 // Check if it's a random breakpoint byte
741 //
742 if (UdHandleInstantBreak(DbgState,
744 NULL))
745 {
746 //
747 // if the above function returns true, it's handled in the user debugger
748 //
749
750 //
751 // Increment rip
752 //
754
755 return TRUE;
756 }
757
758 //
759 // By default, we won't handle the random (unrelated) breakpoints in the user debugger
760 //
761 return FALSE;
762 }
763
764 //
765 // *** re-inject back to the guest as not handled here ***
766 //
767 return FALSE;
768}
BOOLEAN BreakpointCheckAndHandleDebuggerDefinedBreakpoints(PROCESSOR_DEBUGGING_STATE *DbgState, UINT64 GuestRip, DEBUGGEE_PAUSING_REASON Reason, BOOLEAN ChangeMtfState)
Check if the breakpoint vm-exit relates to 'bp' command or not.
Definition BreakpointCommands.c:478
IMPORT_EXPORT_VMM UINT64 VmFuncGetRip()
Read guest's RIP.
Definition Export.c:420
IMPORT_EXPORT_VMM VOID VmFuncPerformRipIncrement(UINT32 CoreId)
Perform the incrementation of RIP.
Definition Export.c:22

◆ BreakpointListAllBreakpoint()

VOID BreakpointListAllBreakpoint ( )

List all breakpoints.

Returns
VOID
1144{
1145 BOOLEAN IsListEmpty = TRUE;
1146 PLIST_ENTRY TempList = 0;
1147
1148 TempList = &g_BreakpointsListHead;
1149
1150 while (&g_BreakpointsListHead != TempList->Blink)
1151 {
1152 TempList = TempList->Blink;
1153 PDEBUGGEE_BP_DESCRIPTOR CurrentBreakpointDesc = CONTAINING_RECORD(TempList, DEBUGGEE_BP_DESCRIPTOR, BreakpointsList);
1154
1155 if (IsListEmpty)
1156 {
1157 Log("Id Address Status\n");
1158 Log("-- --------------- --------");
1159
1160 IsListEmpty = FALSE;
1161 }
1162
1163 Log("\n%02x %016llx %s", CurrentBreakpointDesc->BreakpointId, CurrentBreakpointDesc->Address, CurrentBreakpointDesc->Enabled ? "enabled" : "disabled");
1164
1165 if (CurrentBreakpointDesc->Core != DEBUGGEE_BP_APPLY_TO_ALL_CORES)
1166 {
1167 Log(" core = %x ", CurrentBreakpointDesc->Core);
1168 }
1169 if (CurrentBreakpointDesc->Pid != DEBUGGEE_BP_APPLY_TO_ALL_PROCESSES)
1170 {
1171 Log(" pid = %x ", CurrentBreakpointDesc->Pid);
1172 }
1173 if (CurrentBreakpointDesc->Tid != DEBUGGEE_BP_APPLY_TO_ALL_THREADS)
1174 {
1175 Log(" tid = %x ", CurrentBreakpointDesc->Tid);
1176 }
1177 }
1178
1179 //
1180 // Check if the list is empty or not
1181 //
1182 if (IsListEmpty)
1183 {
1184 Log("Breakpoints list is empty");
1185 }
1186}
#define Log(format,...)
Log without any prefix.
Definition HyperDbgHyperLogIntrinsics.h:129

◆ BreakpointListOrModify()

BOOLEAN BreakpointListOrModify ( PDEBUGGEE_BP_LIST_OR_MODIFY_PACKET ListOrModifyBreakpoints,
BOOLEAN SwitchToTargetMemoryLayout )

List of modify breakpoints.

Parameters
ListOrModifyBreakpoints
SwitchToTargetMemoryLayout
Returns
BOOLEAN
1197{
1198 PDEBUGGEE_BP_DESCRIPTOR BreakpointDescriptor = NULL;
1199
1201 {
1203 }
1204 else if (ListOrModifyBreakpoints->Request == DEBUGGEE_BREAKPOINT_MODIFICATION_REQUEST_ENABLE)
1205 {
1206 BreakpointDescriptor = BreakpointGetEntryByBreakpointId(ListOrModifyBreakpoints->BreakpointId);
1207
1208 if (BreakpointDescriptor == NULL)
1209 {
1210 //
1211 // Breakpoint id is invalid
1212 //
1213 ListOrModifyBreakpoints->Result = DEBUGGER_ERROR_BREAKPOINT_ID_NOT_FOUND;
1214 return FALSE;
1215 }
1216
1217 //
1218 // Check to make sure that breakpoint is not already enabled
1219 //
1220 if (BreakpointDescriptor->Enabled)
1221 {
1222 ListOrModifyBreakpoints->Result = DEBUGGER_ERROR_BREAKPOINT_ALREADY_ENABLED;
1223 return FALSE;
1224 }
1225
1226 //
1227 // Set the breakpoint (without removing from list)
1228 //
1229 BreakpointWrite(BreakpointDescriptor, SwitchToTargetMemoryLayout);
1230 }
1231 else if (ListOrModifyBreakpoints->Request == DEBUGGEE_BREAKPOINT_MODIFICATION_REQUEST_DISABLE)
1232 {
1233 BreakpointDescriptor = BreakpointGetEntryByBreakpointId(ListOrModifyBreakpoints->BreakpointId);
1234
1235 if (BreakpointDescriptor == NULL)
1236 {
1237 //
1238 // Breakpoint id is invalid
1239 //
1240 ListOrModifyBreakpoints->Result = DEBUGGER_ERROR_BREAKPOINT_ID_NOT_FOUND;
1241 return FALSE;
1242 }
1243
1244 //
1245 // Check to make sure that breakpoint is not already disabled
1246 //
1247 if (!BreakpointDescriptor->Enabled)
1248 {
1249 ListOrModifyBreakpoints->Result = DEBUGGER_ERROR_BREAKPOINT_ALREADY_DISABLED;
1250 return FALSE;
1251 }
1252
1253 //
1254 // Unset the breakpoint (without removing from list)
1255 //
1256 BreakpointClear(BreakpointDescriptor);
1257 }
1258 else if (ListOrModifyBreakpoints->Request == DEBUGGEE_BREAKPOINT_MODIFICATION_REQUEST_CLEAR)
1259 {
1260 BreakpointDescriptor = BreakpointGetEntryByBreakpointId(ListOrModifyBreakpoints->BreakpointId);
1261
1262 if (BreakpointDescriptor == NULL)
1263 {
1264 //
1265 // Breakpoint id is invalid
1266 //
1267 ListOrModifyBreakpoints->Result = DEBUGGER_ERROR_BREAKPOINT_ID_NOT_FOUND;
1268 return FALSE;
1269 }
1270
1271 //
1272 // Clear and deallocate the breakpoint
1273 //
1274 BreakpointClearAndDeallocateMemory(BreakpointDescriptor);
1275 }
1276
1277 //
1278 // Operation was successful
1279 //
1280 ListOrModifyBreakpoints->Result = DEBUGGER_OPERATION_WAS_SUCCESSFUL;
1281
1282 return TRUE;
1283}
PDEBUGGEE_BP_DESCRIPTOR BreakpointGetEntryByBreakpointId(UINT64 BreakpointId)
Find entry of breakpoint descriptor from list of breakpoints by breakpoint id.
Definition BreakpointCommands.c:888
VOID BreakpointListAllBreakpoint()
List all breakpoints.
Definition BreakpointCommands.c:1143
#define DEBUGGER_ERROR_BREAKPOINT_ID_NOT_FOUND
error, breakpoint id not found
Definition ErrorCodes.h:196
#define DEBUGGER_ERROR_BREAKPOINT_ALREADY_DISABLED
error, breakpoint already disabled
Definition ErrorCodes.h:202
#define DEBUGGER_ERROR_BREAKPOINT_ALREADY_ENABLED
error, breakpoint already enabled
Definition ErrorCodes.h:208
@ DEBUGGEE_BREAKPOINT_MODIFICATION_REQUEST_DISABLE
Definition RequestStructures.h:1543
@ DEBUGGEE_BREAKPOINT_MODIFICATION_REQUEST_LIST_BREAKPOINTS
Definition RequestStructures.h:1541
@ DEBUGGEE_BREAKPOINT_MODIFICATION_REQUEST_ENABLE
Definition RequestStructures.h:1542
@ DEBUGGEE_BREAKPOINT_MODIFICATION_REQUEST_CLEAR
Definition RequestStructures.h:1544
UINT64 BreakpointId
Definition RequestStructures.h:1554
UINT32 Result
Definition RequestStructures.h:1556
DEBUGGEE_BREAKPOINT_MODIFICATION_REQUEST Request
Definition RequestStructures.h:1555

◆ BreakpointRemoveAllBreakpoints()

VOID BreakpointRemoveAllBreakpoints ( )

Remove all the breakpoints if possible.

Returns
VOID
860{
861 PLIST_ENTRY TempList = 0;
862
863 //
864 // Iterate through the list of breakpoints
865 //
866 TempList = &g_BreakpointsListHead;
867
868 while (&g_BreakpointsListHead != TempList->Flink)
869 {
870 TempList = TempList->Flink;
871 PDEBUGGEE_BP_DESCRIPTOR CurrentBreakpointDesc = CONTAINING_RECORD(TempList, DEBUGGEE_BP_DESCRIPTOR, BreakpointsList);
872
873 //
874 // Clear and deallocate the breakpoint
875 //
876 BreakpointClearAndDeallocateMemory(CurrentBreakpointDesc);
877 }
878}

◆ BreakpointRestoreTheTrapFlagOnceTriggered()

BOOLEAN BreakpointRestoreTheTrapFlagOnceTriggered ( UINT32 ProcessId,
UINT32 ThreadId )

This function makes sure to unset the RFLAGS.TF on next trigger of #DB on the target process/thread.

Parameters
ProcessId
ThreadId
Returns
BOOLEAN
175{
176 UINT32 Index;
177 BOOLEAN Result;
178 BOOLEAN SuccessfullyStored;
179 DEBUGGER_PROCESS_THREAD_INFORMATION ProcThrdInfo = {0};
180
181 //
182 // Form the process id and thread id into a 64-bit value
183 //
184 ProcThrdInfo.Fields.ProcessId = ProcessId;
185 ProcThrdInfo.Fields.ThreadId = ThreadId;
186
187 //
188 // Make sure, nobody is in the middle of modifying the list
189 //
191
192 //
193 // *** Search the list of processes/threads for the current process's trap flag state ***
194 //
195 Result = BinarySearchPerformSearchItem((UINT64 *)&g_TrapFlagState.ThreadInformation[0],
196 g_TrapFlagState.NumberOfItems,
197 &Index,
198 ProcThrdInfo.AsUInt);
199
200 if (Result)
201 {
202 //
203 // It means that we already find this entry in the stored list
204 // so, just imply that the addition was successful (no need for extra addition)
205 //
206 SuccessfullyStored = TRUE;
207 goto Return;
208 }
209 else
210 {
211 //
212 // Insert the thread into the list as the item is not already present
213 //
214 SuccessfullyStored = InsertionSortInsertItem((UINT64 *)&g_TrapFlagState.ThreadInformation[0],
215 &g_TrapFlagState.NumberOfItems,
217 &Index, // not used
218 ProcThrdInfo.AsUInt);
219 goto Return;
220 }
221
222Return:
223 //
224 // Unlock the list modification lock
225 //
227
228 return SuccessfullyStored;
229}
BOOLEAN InsertionSortInsertItem(UINT64 ArrayPtr[], UINT32 *NumberOfItems, UINT32 MaxNumOfItems, UINT32 *Index, UINT64 Key)
Function to implement insertion sort.
Definition InsertionSort.c:26
#define MAXIMUM_NUMBER_OF_THREAD_INFORMATION_FOR_TRAPS
maximum number of thread/process ids to be allocated for a simultaneous debugging
Definition Constants.h:409

◆ BreakpointTriggerCallbacks()

BOOLEAN BreakpointTriggerCallbacks ( PROCESSOR_DEBUGGING_STATE * DbgState,
UINT32 ProcessId,
UINT32 ThreadId )

Trigger callback for breakpoint hit.

Parameters
DbgStateThe state of the debugger on the current core
ProcessId
ThreadId
Returns
BOOLEAN If true, it won't halt the debugger, but if false will halt the debugger
149{
150 UNREFERENCED_PARAMETER(DbgState);
151 UNREFERENCED_PARAMETER(ProcessId);
152 UNREFERENCED_PARAMETER(ThreadId);
153
154 //
155 // Add the process/thread to the watching list
156 //
157 // LogInfo("Adding to watch list: Process Id: %x, Thread Id: %x", ProcessId, ThreadId);
158
159 //
160 // By default return FALSE to set handling the breakpoint to the user to the debugger
161 //
162 return FALSE;
163}

◆ BreakpointWrite()

BOOLEAN BreakpointWrite ( PDEBUGGEE_BP_DESCRIPTOR BreakpointDescriptor,
BOOLEAN SwitchToTargetMemoryLayout )

writes the 0xcc and applies the breakpoint @detail this function won't remove the descriptor from the list

Parameters
BreakpointDescriptor
SwitchToTargetMemoryLayoutIf TRUE, it will switch to the target memory layout
Returns
BOOLEAN
781{
782 BYTE PreviousByte = NULL_ZERO;
783 BYTE BreakpointByte = 0xcc; // int 3
784
785 //
786 // Check if address is safe (only one byte for 0xcc)
787 //
788
789 if (SwitchToTargetMemoryLayout)
790 {
791 if (!CheckAccessValidityAndSafetyByProcessId(BreakpointDescriptor->Address, sizeof(BYTE), BreakpointDescriptor->Pid))
792 {
793 return FALSE;
794 }
795 }
796 else
797 {
798 if (!CheckAccessValidityAndSafety(BreakpointDescriptor->Address, sizeof(BYTE)))
799 {
800 return FALSE;
801 }
802 }
803
804 //
805 // Read and save previous byte and save it to the descriptor
806 //
807 if (SwitchToTargetMemoryLayout)
808 {
810 BreakpointDescriptor->Address,
811 &PreviousByte,
812 sizeof(BYTE),
813 BreakpointDescriptor->Pid);
814 }
815 else
816 {
818 BreakpointDescriptor->Address,
819 &PreviousByte,
820 sizeof(BYTE));
821 }
822
823 //
824 // Store the previous byte
825 //
826 BreakpointDescriptor->PreviousByte = PreviousByte;
827
828 //
829 // Set breakpoint to enabled
830 //
831 BreakpointDescriptor->Enabled = TRUE;
832 BreakpointDescriptor->AvoidReApplyBreakpoint = FALSE;
833
834 //
835 // Apply the breakpoint
836 //
837 if (SwitchToTargetMemoryLayout)
838 {
840 (PVOID)&BreakpointByte,
841 sizeof(BYTE));
842 }
843 else
844 {
846 (UINT64)&BreakpointByte,
847 sizeof(BYTE));
848 }
849
850 return TRUE;
851}
IMPORT_EXPORT_VMM BOOLEAN MemoryMapperReadMemoryUnsafe(_In_ UINT64 VaAddressToRead, _Inout_ PVOID BufferToSaveMemory, _In_ SIZE_T SizeToRead, _In_ UINT32 TargetProcessId)
IMPORT_EXPORT_VMM BOOLEAN MemoryMapperWriteMemorySafeFromVmxNonRootyPhysicalAddress(_In_ UINT64 DestinationPa, _In_ PVOID Source, _In_ SIZE_T SizeToWrite)
IMPORT_EXPORT_VMM BOOLEAN MemoryMapperReadMemorySafeOnTargetProcess(_In_ UINT64 VaAddressToRead, _Inout_ PVOID BufferToSaveMemory, _In_ SIZE_T SizeToRead)