HyperDbg Debugger
Loading...
Searching...
No Matches
Ud.h File Reference

Header for routines related to user mode debugging. More...

Go to the source code of this file.

Functions

BOOLEAN UdInitializeUserDebugger ()
 initialize user debugger
 
VOID UdUninitializeUserDebugger ()
 uninitialize user debugger
 
BOOLEAN UdCheckAndHandleBreakpointsAndDebugBreaks (PROCESSOR_DEBUGGING_STATE *DbgState, DEBUGGEE_PAUSING_REASON Reason, PDEBUGGER_TRIGGERED_EVENT_DETAILS EventDetails)
 Handle #DBs and #BPs for kernel debugger.
 
BOOLEAN UdDispatchUsermodeCommands (PDEBUGGER_UD_COMMAND_PACKET ActionRequest)
 Dispatch the user-mode commands.
 
BOOLEAN UdCheckForCommand ()
 Check for the user-mode commands.
 

Detailed Description

Header for routines related to user mode debugging.

Author
Sina Karvandi (sina@.nosp@m.hype.nosp@m.rdbg..nosp@m.org)
Version
0.1
Date
2022-01-06

Function Documentation

◆ UdCheckAndHandleBreakpointsAndDebugBreaks()

BOOLEAN UdCheckAndHandleBreakpointsAndDebugBreaks ( PROCESSOR_DEBUGGING_STATE * DbgState,
DEBUGGEE_PAUSING_REASON Reason,
PDEBUGGER_TRIGGERED_EVENT_DETAILS EventDetails )

Handle #DBs and #BPs for kernel debugger.

This function can be used in vmx-root

Parameters
DbgStateThe state of the debugger on the current core
Reason
EventDetails
Returns
BOOLEAN
446{
447 DEBUGGEE_UD_PAUSED_PACKET PausePacket;
448 ULONG ExitInstructionLength = 0;
449 UINT32 SizeOfSafeBufferToRead = 0;
450 RFLAGS Rflags = {0};
451 PUSERMODE_DEBUGGING_PROCESS_DETAILS ProcessDebuggingDetails = NULL;
452 PUSERMODE_DEBUGGING_THREAD_DETAILS ThreadDebuggingDetails = NULL;
453 UINT64 LastVmexitRip = VmFuncGetLastVmexitRip(DbgState->CoreId);
454
455 //
456 // Breaking only supported in vmx-root mode, and if user-debugger is
457 // loaded
458 //
460 {
461 return FALSE;
462 }
463
464 //
465 // Check entry of paused thread
466 //
467 ProcessDebuggingDetails = AttachingFindProcessDebuggingDetailsByProcessId(HANDLE_TO_UINT32(PsGetCurrentProcessId()));
468
469 if (!ProcessDebuggingDetails)
470 {
471 //
472 // Token not found!
473 //
474 return FALSE;
475 }
476
477 //
478 // Find the thread entry and if not found, create one for it
479 //
480 ThreadDebuggingDetails = ThreadHolderFindOrCreateThreadDebuggingDetail(HANDLE_TO_UINT32(PsGetCurrentThreadId()), ProcessDebuggingDetails);
481
482 if (!ThreadDebuggingDetails)
483 {
484 //
485 // Sth went wrong!
486 //
487 return FALSE;
488 }
489
490 //
491 // Set it as active thread debugging
492 //
493 ProcessDebuggingDetails->ActiveThreadId = ThreadDebuggingDetails->ThreadId;
494
495 //
496 // Perform the pre-pausing tasks
497 //
498 UdPrePausingReasons(DbgState, ThreadDebuggingDetails, Reason, EventDetails);
499
500 //
501 // *** Fill the pausing structure ***
502 //
503
504 RtlZeroMemory(&PausePacket, sizeof(DEBUGGEE_UD_PAUSED_PACKET));
505
506 //
507 // Set the pausing reason
508 //
509 PausePacket.PausingReason = Reason;
510
511 //
512 // Set process debugging information
513 //
514 PausePacket.ProcessId = HANDLE_TO_UINT32(PsGetCurrentProcessId());
515 PausePacket.ThreadId = HANDLE_TO_UINT32(PsGetCurrentThreadId());
516 PausePacket.ProcessDebuggingToken = ProcessDebuggingDetails->Token;
517
518 //
519 // Set the RIP and mode of execution
520 //
521 PausePacket.Rip = LastVmexitRip;
522 PausePacket.Is32Bit = KdIsGuestOnUsermode32Bit();
523
524 //
525 // Set rflags for finding the results of conditional jumps
526 //
527 Rflags.AsUInt = VmFuncGetRflags();
528 PausePacket.Rflags = Rflags.AsUInt;
529
530 //
531 // Set the event tag (if it's an event)
532 //
533 if (EventDetails != NULL)
534 {
535 PausePacket.EventTag = EventDetails->Tag;
536 PausePacket.EventCallingStage = EventDetails->Stage;
537 }
538
539 //
540 // Read the instruction len
541 //
542 if (DbgState->InstructionLengthHint != 0)
543 {
544 ExitInstructionLength = DbgState->InstructionLengthHint;
545 }
546 else
547 {
548 //
549 // Reading instruction length (VMCS_VMEXIT_INSTRUCTION_LENGTH) proved to
550 // provide wrong results, so we won't use it
551 //
552
553 //
554 // Compute the amount of buffer we can read without problem
555 //
556 SizeOfSafeBufferToRead = (UINT32)(LastVmexitRip & 0xfff);
557 SizeOfSafeBufferToRead += MAXIMUM_INSTR_SIZE;
558
559 if (SizeOfSafeBufferToRead >= PAGE_SIZE)
560 {
561 SizeOfSafeBufferToRead = SizeOfSafeBufferToRead - PAGE_SIZE;
562 SizeOfSafeBufferToRead = MAXIMUM_INSTR_SIZE - SizeOfSafeBufferToRead;
563 }
564 else
565 {
566 SizeOfSafeBufferToRead = MAXIMUM_INSTR_SIZE;
567 }
568
569 //
570 // Set the length to notify debuggee
571 //
572 ExitInstructionLength = SizeOfSafeBufferToRead;
573 }
574
575 //
576 // Set the reading length of bytes (for instruction disassembling)
577 //
578 PausePacket.ReadInstructionLen = (UINT16)ExitInstructionLength;
579
580 //
581 // Find the current instruction
582 //
584 &PausePacket.InstructionBytesOnRip,
585 ExitInstructionLength);
586
587 //
588 // Copy registers to the pause packet
589 //
590 RtlCopyMemory(&PausePacket.GuestRegs, DbgState->Regs, sizeof(GUEST_REGS));
591
592 //
593 // Send the pause packet, along with RIP and an indication
594 // to pause to the user debugger
595 //
597 &PausePacket,
599 TRUE);
600
601 //
602 // Halt the thread on nop sleds
603 //
604 UdSpinThreadOnNop(ThreadDebuggingDetails, ProcessDebuggingDetails);
605
606 //
607 // Everything was okay
608 //
609 return TRUE;
610}
PUSERMODE_DEBUGGING_PROCESS_DETAILS AttachingFindProcessDebuggingDetailsByProcessId(UINT32 ProcessId)
Find user-mode debugging details for threads by process Id.
Definition Attaching.c:187
unsigned short UINT16
Definition BasicTypes.h:47
#define TRUE
Definition BasicTypes.h:55
#define FALSE
Definition BasicTypes.h:54
unsigned __int64 UINT64
Definition BasicTypes.h:21
unsigned int UINT32
Definition BasicTypes.h:48
unsigned long ULONG
Definition BasicTypes.h:37
BOOLEAN LogCallbackSendBuffer(_In_ UINT32 OperationCode, _In_reads_bytes_(BufferLength) PVOID Buffer, _In_ UINT32 BufferLength, _In_ BOOLEAN Priority)
routines callback for sending buffer
Definition Callback.c:123
#define OPERATION_NOTIFICATION_FROM_USER_DEBUGGER_PAUSE
Definition Constants.h:387
#define MAXIMUM_INSTR_SIZE
maximum instruction size in Intel
Definition Constants.h:468
UINT64 VmFuncGetRflags()
Read guest's RFLAGS.
Definition Export.c:352
BOOLEAN VmFuncVmxGetCurrentExecutionMode()
Get the current VMX operation state.
Definition Export.c:552
UINT64 VmFuncGetLastVmexitRip(UINT32 CoreId)
get the last vm-exit RIP
Definition Export.c:318
BOOLEAN KdIsGuestOnUsermode32Bit()
determines if the guest was in 32-bit user-mode or 64-bit (long mode)
Definition Kd.c:3107
_Use_decl_annotations_ BOOLEAN MemoryMapperReadMemorySafeOnTargetProcess(UINT64 VaAddressToRead, PVOID BufferToSaveMemory, SIZE_T SizeToRead)
Read memory safely by mapping the buffer on the target process memory (It's a wrapper)
Definition MemoryMapper.c:1120
#define HANDLE_TO_UINT32(_var)
Definition MetaMacros.h:39
PUSERMODE_DEBUGGING_THREAD_DETAILS ThreadHolderFindOrCreateThreadDebuggingDetail(UINT32 ThreadId, PUSERMODE_DEBUGGING_PROCESS_DETAILS ProcessDebuggingDetail)
Find or create user-mode debugging details for threads.
Definition ThreadHolder.c:257
VOID UdSpinThreadOnNop(PUSERMODE_DEBUGGING_THREAD_DETAILS ThreadDebuggingDetails, PUSERMODE_DEBUGGING_PROCESS_DETAILS ProcessDebuggingDetails)
Spin on nop sled in user-mode to halt the debuggee.
Definition Ud.c:379
VOID UdPrePausingReasons(PROCESSOR_DEBUGGING_STATE *DbgState, PUSERMODE_DEBUGGING_THREAD_DETAILS ThreadDebuggingDetails, DEBUGGEE_PAUSING_REASON Reason, PDEBUGGER_TRIGGERED_EVENT_DETAILS EventDetails)
Handle special reasons pre-pausings.
Definition Ud.c:409
BOOLEAN g_UserDebuggerState
shows whether the user debugger is enabled or disabled
Definition Global.h:109
#define PAGE_SIZE
Size of each page (4096 bytes)
Definition common.h:69
NULL()
Definition test-case-generator.py:530
The structure of pausing packet in uHyperDbg.
Definition DataTypes.h:229
GUEST_REGS GuestRegs
Definition DataTypes.h:241
DEBUGGEE_PAUSING_REASON PausingReason
Definition DataTypes.h:233
UINT16 ReadInstructionLen
Definition DataTypes.h:240
UINT64 Rip
Definition DataTypes.h:230
VMM_CALLBACK_EVENT_CALLING_STAGE_TYPE EventCallingStage
Definition DataTypes.h:238
BOOLEAN Is32Bit
Definition DataTypes.h:232
UINT64 ProcessDebuggingToken
Definition DataTypes.h:231
UINT64 EventTag
Definition DataTypes.h:237
UINT64 Rflags
Definition DataTypes.h:236
UINT32 ThreadId
Definition DataTypes.h:235
UINT32 ProcessId
Definition DataTypes.h:234
BYTE InstructionBytesOnRip[MAXIMUM_INSTR_SIZE]
Definition DataTypes.h:239
UINT64 Tag
Definition DataTypes.h:193
VMM_CALLBACK_EVENT_CALLING_STAGE_TYPE Stage
Definition DataTypes.h:195
GUEST_REGS * Regs
Definition State.h:168
UINT32 CoreId
Definition State.h:169
UINT16 InstructionLengthHint
Definition State.h:182
Description of each active thread in user-mode attaching mechanism.
Definition Attaching.h:49
UINT64 Token
Definition Attaching.h:50
UINT32 ActiveThreadId
Definition Attaching.h:53
Details of each thread in process.
Definition ThreadHolder.h:33
UINT32 ThreadId
Definition ThreadHolder.h:34
Definition BasicTypes.h:70

◆ UdCheckForCommand()

BOOLEAN UdCheckForCommand ( )

Check for the user-mode commands.

Returns
BOOLEAN
258{
259 PUSERMODE_DEBUGGING_THREAD_DETAILS ThreadDebuggingDetails;
260
261 //
262 // Check if user-debugger is initialized or not
263 //
265 {
266 return FALSE;
267 }
268
269 ThreadDebuggingDetails = ThreadHolderGetProcessThreadDetailsByProcessIdAndThreadId(HANDLE_TO_UINT32(PsGetCurrentProcessId()),
270 HANDLE_TO_UINT32(PsGetCurrentThreadId()));
271
272 if (!ThreadDebuggingDetails)
273 {
274 return FALSE;
275 }
276
277 //
278 // If we reached here, the current thread is in debugger attached mechanism
279 // now we check whether it's a regular CPUID or a debugger paused thread CPUID
280 //
281 if (!ThreadDebuggingDetails->IsPaused)
282 {
283 return FALSE;
284 }
285
286 //
287 // Here, we're sure that this thread is looking for command, let
288 // see if we find anything
289 //
290 for (size_t i = 0; i < MAX_USER_ACTIONS_FOR_THREADS; i++)
291 {
292 if (ThreadDebuggingDetails->UdAction[i].ActionType != DEBUGGER_UD_COMMAND_ACTION_TYPE_NONE)
293 {
294 //
295 // Perform the command
296 //
297 UdPerformCommand(ThreadDebuggingDetails,
298 ThreadDebuggingDetails->UdAction[i].ActionType,
299 ThreadDebuggingDetails->UdAction[i].OptionalParam1,
300 ThreadDebuggingDetails->UdAction[i].OptionalParam2,
301 ThreadDebuggingDetails->UdAction[i].OptionalParam3,
302 ThreadDebuggingDetails->UdAction[i].OptionalParam4);
303
304 //
305 // Remove the command
306 //
307 ThreadDebuggingDetails->UdAction[i].OptionalParam1 = (UINT64)NULL;
308 ThreadDebuggingDetails->UdAction[i].OptionalParam2 = (UINT64)NULL;
309 ThreadDebuggingDetails->UdAction[i].OptionalParam3 = (UINT64)NULL;
310 ThreadDebuggingDetails->UdAction[i].OptionalParam4 = (UINT64)NULL;
311
312 //
313 // At last disable it
314 //
315 ThreadDebuggingDetails->UdAction[i].ActionType = DEBUGGER_UD_COMMAND_ACTION_TYPE_NONE;
316
317 //
318 // only one command at a time
319 //
320 break;
321 }
322 }
323
324 //
325 // Won't change the registers for cpuid
326 //
327 return TRUE;
328}
#define MAX_USER_ACTIONS_FOR_THREADS
Maximum actions in paused threads storage.
Definition Attaching.h:22
@ DEBUGGER_UD_COMMAND_ACTION_TYPE_NONE
Definition RequestStructures.h:867
PUSERMODE_DEBUGGING_THREAD_DETAILS ThreadHolderGetProcessThreadDetailsByProcessIdAndThreadId(UINT32 ProcessId, UINT32 ThreadId)
Find the active threads of the process from process id.
Definition ThreadHolder.c:109
BOOLEAN UdPerformCommand(PUSERMODE_DEBUGGING_THREAD_DETAILS ThreadDebuggingDetails, DEBUGGER_UD_COMMAND_ACTION_TYPE UserAction, UINT64 OptionalParam1, UINT64 OptionalParam2, UINT64 OptionalParam3, UINT64 OptionalParam4)
Perform the user-mode commands.
Definition Ud.c:205
DEBUGGER_UD_COMMAND_ACTION_TYPE ActionType
Definition RequestStructures.h:880
UINT64 OptionalParam1
Definition RequestStructures.h:881
UINT64 OptionalParam3
Definition RequestStructures.h:883
UINT64 OptionalParam4
Definition RequestStructures.h:884
UINT64 OptionalParam2
Definition RequestStructures.h:882
DEBUGGER_UD_COMMAND_ACTION UdAction[MAX_USER_ACTIONS_FOR_THREADS]
Definition ThreadHolder.h:37
BOOLEAN IsPaused
Definition ThreadHolder.h:36

◆ UdDispatchUsermodeCommands()

BOOLEAN UdDispatchUsermodeCommands ( PDEBUGGER_UD_COMMAND_PACKET ActionRequest)

Dispatch the user-mode commands.

Parameters
ActionRequest
Returns
BOOLEAN
338{
339 PUSERMODE_DEBUGGING_PROCESS_DETAILS ProcessDebuggingDetails;
340
341 //
342 // Find the thread debugging detail of the thread
343 //
344 ProcessDebuggingDetails = AttachingFindProcessDebuggingDetailsByToken(ActionRequest->ProcessDebuggingDetailToken);
345
346 if (!ProcessDebuggingDetails)
347 {
348 //
349 // Token not found!
350 //
351 return FALSE;
352 }
353
354 //
355 // Based on the documentation, HyperDbg stops intercepting threads
356 // when the debugger sent the first command, but if user presses
357 // CTRL+C again, all the threads (or new threads) that will enter
358 // the user-mode will be intercepted
359 //
360 if (ProcessDebuggingDetails->IsOnThreadInterceptingPhase)
361 {
362 AttachingConfigureInterceptingThreads(ProcessDebuggingDetails->Token, FALSE);
363 }
364
365 //
366 // Apply the command to all threads or just one thread
367 //
368 return ThreadHolderApplyActionToPausedThreads(ProcessDebuggingDetails, ActionRequest);
369}
BOOLEAN AttachingConfigureInterceptingThreads(UINT64 ProcessDebuggingToken, BOOLEAN Enable)
Enable or disable the thread intercepting phase.
Definition Attaching.c:695
PUSERMODE_DEBUGGING_PROCESS_DETAILS AttachingFindProcessDebuggingDetailsByToken(UINT64 Token)
Find user-mode debugging details for threads by token.
Definition Attaching.c:164
BOOLEAN ThreadHolderApplyActionToPausedThreads(PUSERMODE_DEBUGGING_PROCESS_DETAILS ProcessDebuggingDetails, PDEBUGGER_UD_COMMAND_PACKET ActionRequest)
Apply the action of the user debugger to a specific thread or all threads.
Definition ThreadHolder.c:364
UINT64 ProcessDebuggingDetailToken
Definition RequestStructures.h:895
BOOLEAN IsOnThreadInterceptingPhase
Definition Attaching.h:64

◆ UdInitializeUserDebugger()

BOOLEAN UdInitializeUserDebugger ( )

initialize user debugger

this function should be called on vmx non-root

Returns
BOOLEAN

initialize user debugger

Returns
VOID
22{
23 //
24 // Check if it's already initialized or not, we'll ignore it if it's
25 // previously initialized
26 //
28 {
29 return TRUE;
30 }
31
32 //
33 // Check if we have functions we need for attaching mechanism
34 //
36 {
37 LogError("Err, unable to find needed functions for user-debugger");
38 // return FALSE;
39 }
40
41 //
42 // Start the seed of user-mode debugging thread
43 //
45
46 //
47 // Initialize the thread debugging details list
48 //
50
51 //
52 // Enable vm-exit on Hardware debug exceptions and breakpoints
53 // so, intercept #DBs and #BP by changing exception bitmap (one core)
54 //
56
57 //
58 // Request to allocate buffers for thread holder of threads
59 //
61
62 //
63 // Indicate that the user debugger is active
64 //
66
67 return TRUE;
68}
VOID BroadcastEnableDbAndBpExitingAllCores()
routines to set vm-exit on all #DBs and #BP on all cores
Definition Broadcast.c:35
#define DebuggerThreadDebuggingTagStartSeed
The seeds that user-mode thread detail token start with it.
Definition Constants.h:229
#define LogError(format,...)
Log in the case of error.
Definition HyperDbgHyperLogIntrinsics.h:113
VOID ThreadHolderAllocateThreadHoldingBuffers()
Pre allocate buffer for thread holder.
Definition ThreadHolder.c:21
ZwQueryInformationProcess g_ZwQueryInformationProcess
Address of ZwQueryInformationProcess.
Definition UserAccess.h:187
PsGetProcessPeb g_PsGetProcessPeb
Address of PsGetProcessPeb.
Definition UserAccess.h:193
PsGetProcessWow64Process g_PsGetProcessWow64Process
Address of PsGetProcessWow64Process.
Definition UserAccess.h:199
FORCEINLINE VOID InitializeListHead(_Out_ PLIST_ENTRY ListHead)
Definition Windows.h:41
LIST_ENTRY g_ProcessDebuggingDetailsListHead
List header of thread debugging details.
Definition Global.h:152
UINT64 g_SeedOfUserDebuggingDetails
Seed for tokens of unique details buffer for threads.
Definition Global.h:139

◆ UdUninitializeUserDebugger()

VOID UdUninitializeUserDebugger ( )

uninitialize user debugger

this function should be called on vmx non-root

Returns
VOID

uninitialize user debugger

Returns
VOID
78{
80 {
81 //
82 // Indicate that the user debugger is not active
83 //
85
86 //
87 // Free and deallocate all the buffers (pools) relating to
88 // thread debugging details
89 //
91 }
92}
VOID AttachingRemoveAndFreeAllProcessDebuggingDetails()
Remove and deallocate all thread debuggig details.
Definition Attaching.c:229