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

Implementation of Debugger Commands. More...

#include "pch.h"

Functions

BOOLEAN DebuggerCommandReadMemory (PDEBUGGER_READ_MEMORY ReadMemRequest, PVOID UserBuffer, PSIZE_T ReturnSize)
 Read memory for different commands.
 
BOOLEAN DebuggerCommandReadMemoryVmxRoot (PDEBUGGER_READ_MEMORY ReadMemRequest, UCHAR *UserBuffer, UINT32 *ReturnSize)
 Read memory for different commands from vmxroot mode.
 
NTSTATUS DebuggerReadOrWriteMsr (PDEBUGGER_READ_AND_WRITE_ON_MSR ReadOrWriteMsrRequest, UINT64 *UserBuffer, PSIZE_T ReturnSize)
 Perform rdmsr, wrmsr commands.
 
NTSTATUS DebuggerCommandEditMemory (PDEBUGGER_EDIT_MEMORY EditMemRequest)
 Edit physical and virtual memory.
 
BOOLEAN DebuggerCommandEditMemoryVmxRoot (PDEBUGGER_EDIT_MEMORY EditMemRequest)
 Edit physical and virtual memory on vmxroot mode.
 
BOOLEAN PerformSearchAddress (UINT64 *AddressToSaveResults, PDEBUGGER_SEARCH_MEMORY SearchMemRequest, UINT64 StartAddress, UINT64 EndAddress, BOOLEAN IsDebuggeePaused, PUINT32 CountOfMatchedCases)
 Search on virtual memory (not work on physical memory)
 
BOOLEAN SearchAddressWrapper (PUINT64 AddressToSaveResults, PDEBUGGER_SEARCH_MEMORY SearchMemRequest, UINT64 StartAddress, UINT64 EndAddress, BOOLEAN IsDebuggeePaused, PUINT32 CountOfMatchedCases)
 The wrapper to check for validity of addresses and call the search routines for both physical and virtual memory.
 
NTSTATUS DebuggerCommandSearchMemory (PDEBUGGER_SEARCH_MEMORY SearchMemRequest)
 Start searching memory.
 
NTSTATUS DebuggerCommandFlush (PDEBUGGER_FLUSH_LOGGING_BUFFERS DebuggerFlushBuffersRequest)
 Perform the flush requests to vmx-root and vmx non-root buffers.
 
NTSTATUS DebuggerCommandSignalExecutionState (PDEBUGGER_SEND_COMMAND_EXECUTION_FINISHED_SIGNAL DebuggerFinishedExecutionRequest)
 Perform the command finished signal.
 
NTSTATUS DebuggerCommandSendMessage (PDEBUGGER_SEND_USERMODE_MESSAGES_TO_DEBUGGER DebuggerSendUsermodeMessageRequest)
 Send the user-mode buffer to debugger.
 
NTSTATUS DebuggerCommandSendGeneralBufferToDebugger (PDEBUGGEE_SEND_GENERAL_PACKET_FROM_DEBUGGEE_TO_DEBUGGER DebuggeeBufferRequest)
 Send general buffers from the debuggee to the debugger.
 
NTSTATUS DebuggerCommandReservePreallocatedPools (PDEBUGGER_PREALLOC_COMMAND PreallocRequest)
 Reserve and allocate pre-allocated buffers.
 
NTSTATUS DebuggerCommandPreactivateFunctionality (PDEBUGGER_PREACTIVATE_COMMAND PreactivateRequest)
 Preactivate a special functionality.
 
BOOLEAN DebuggerCommandBringPagein (PDEBUGGER_PAGE_IN_REQUEST PageinRequest)
 routines for the .pagein command
 

Detailed Description

Implementation of Debugger Commands.

Author
Sina Karvandi (sina@.nosp@m.hype.nosp@m.rdbg..nosp@m.org)
Alee Amini (alee@.nosp@m.hype.nosp@m.rdbg..nosp@m.org)
Version
0.1
Date
2020-04-23

Function Documentation

◆ DebuggerCommandBringPagein()

BOOLEAN DebuggerCommandBringPagein ( PDEBUGGER_PAGE_IN_REQUEST PageinRequest)

routines for the .pagein command

Parameters
PageinRequest
Returns
BOOLEAN
1476{
1477 //
1478 // *** Perform the injection here ***
1479 //
1480 LogInfo("Page-request is received!");
1481
1482 //
1483 // Adjust the flags for showing the successful #PF injection
1484 //
1486
1487 return TRUE;
1488}
#define TRUE
Definition BasicTypes.h:55
#define DEBUGGER_OPERATION_WAS_SUCCESSFUL
General value to indicate that the operation or request was successful.
Definition ErrorCodes.h:23
#define LogInfo(format,...)
Define log variables.
Definition HyperDbgHyperLogIntrinsics.h:71
UINT32 KernelStatus
Definition RequestStructures.h:78

◆ DebuggerCommandEditMemory()

NTSTATUS DebuggerCommandEditMemory ( PDEBUGGER_EDIT_MEMORY EditMemRequest)

Edit physical and virtual memory.

Parameters
EditMemRequestedit memory request
Returns
NTSTATUS
442{
443 UINT32 LengthOfEachChunk = 0;
444 PVOID DestinationAddress = 0;
445 PVOID SourceAddress = 0;
446
447 //
448 // set chunk size in each modification
449 //
450 if (EditMemRequest->ByteSize == EDIT_BYTE)
451 {
452 LengthOfEachChunk = 1;
453 }
454 else if (EditMemRequest->ByteSize == EDIT_DWORD)
455 {
456 LengthOfEachChunk = 4;
457 }
458 else if (EditMemRequest->ByteSize == EDIT_QWORD)
459 {
460 LengthOfEachChunk = 8;
461 }
462 else
463 {
464 //
465 // Invalid parameter
466 //
468 return STATUS_UNSUCCESSFUL;
469 }
470
471 //
472 // Check if address is valid or not valid (virtual address)
473 //
474 if (EditMemRequest->MemoryType == EDIT_VIRTUAL_MEMORY)
475 {
476 if (EditMemRequest->ProcessId == HANDLE_TO_UINT32(PsGetCurrentProcessId()) && VirtualAddressToPhysicalAddress((PVOID)EditMemRequest->Address) == 0)
477 {
478 //
479 // It's an invalid address in current process
480 //
482 return STATUS_UNSUCCESSFUL;
483 }
484 else if (VirtualAddressToPhysicalAddressByProcessId((PVOID)EditMemRequest->Address, EditMemRequest->ProcessId) == 0)
485 {
486 //
487 // It's an invalid address in another process
488 //
490 return STATUS_UNSUCCESSFUL;
491 }
492
493 //
494 // Edit the memory
495 //
496 for (size_t i = 0; i < EditMemRequest->CountOf64Chunks; i++)
497 {
498 DestinationAddress = (PVOID)((UINT64)EditMemRequest->Address + (i * LengthOfEachChunk));
499 SourceAddress = (PVOID)((UINT64)EditMemRequest + SIZEOF_DEBUGGER_EDIT_MEMORY + (i * sizeof(UINT64)));
500
501 //
502 // Instead of directly accessing the memory we use the MemoryMapperWriteMemorySafe
503 // It is because the target page might be read-only so we can make it writable
504 //
505 // RtlCopyBytes(DestinationAddress, SourceAddress, LengthOfEachChunk);
506 MemoryMapperWriteMemoryUnsafe((UINT64)DestinationAddress, SourceAddress, LengthOfEachChunk, EditMemRequest->ProcessId);
507 }
508 }
509 else if (EditMemRequest->MemoryType == EDIT_PHYSICAL_MEMORY)
510 {
511 //
512 // Check whether the physical addres
513 //
514 if (!CheckAddressPhysical(EditMemRequest->Address))
515 {
516 EditMemRequest->Result = DEBUGGER_ERROR_INVALID_ADDRESS;
517 return STATUS_UNSUCCESSFUL;
518 }
519
520 //
521 // Edit the physical memory
522 //
523 for (size_t i = 0; i < EditMemRequest->CountOf64Chunks; i++)
524 {
525 DestinationAddress = (PVOID)((UINT64)EditMemRequest->Address + (i * LengthOfEachChunk));
526 SourceAddress = (PVOID)((UINT64)EditMemRequest + SIZEOF_DEBUGGER_EDIT_MEMORY + (i * sizeof(UINT64)));
527
528 MemoryMapperWriteMemorySafeByPhysicalAddress((UINT64)DestinationAddress, (UINT64)SourceAddress, LengthOfEachChunk);
529 }
530 }
531 else
532 {
533 //
534 // Invalid parameter
535 //
537 return STATUS_UNSUCCESSFUL;
538 }
539
540 //
541 // Set the resutls
542 //
544
545 return STATUS_SUCCESS;
546}
BOOLEAN CheckAddressPhysical(UINT64 PAddr)
Checks if the physical address is correct or not based on physical address width.
Definition AddressCheck.c:120
unsigned __int64 UINT64
Definition BasicTypes.h:21
unsigned int UINT32
Definition BasicTypes.h:48
_Use_decl_annotations_ UINT64 VirtualAddressToPhysicalAddressByProcessId(PVOID VirtualAddress, UINT32 ProcessId)
Converts Virtual Address to Physical Address based on a specific process id's kernel cr3.
Definition Conversion.c:171
_Use_decl_annotations_ UINT64 VirtualAddressToPhysicalAddress(_In_ PVOID VirtualAddress)
Converts Virtual Address to Physical Address.
Definition Conversion.c:154
#define DEBUGGER_ERROR_EDIT_MEMORY_STATUS_INVALID_ADDRESS_BASED_ON_OTHER_PROCESS
error, an invalid address is specified based on anotehr process's cr3 in !e* or e* commands
Definition ErrorCodes.h:114
#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_ADDRESS
error, invalid address specified for debugger
Definition ErrorCodes.h:63
#define DEBUGGER_ERROR_EDIT_MEMORY_STATUS_INVALID_PARAMETER
error, invalid parameters in !e* e* commands
Definition ErrorCodes.h:99
_Use_decl_annotations_ BOOLEAN MemoryMapperWriteMemoryUnsafe(UINT64 Destination, PVOID Source, SIZE_T SizeToWrite, UINT32 TargetProcessId)
Write memory safely by mapping the buffer (It's a wrapper)
Definition MemoryMapper.c:1411
_Use_decl_annotations_ BOOLEAN MemoryMapperWriteMemorySafeByPhysicalAddress(UINT64 DestinationPa, UINT64 Source, SIZE_T SizeToWrite)
Write memory safely by mapping the buffer.
Definition MemoryMapper.c:1432
#define HANDLE_TO_UINT32(_var)
Definition MetaMacros.h:39
@ EDIT_PHYSICAL_MEMORY
Definition RequestStructures.h:463
@ EDIT_VIRTUAL_MEMORY
Definition RequestStructures.h:462
@ EDIT_QWORD
Definition RequestStructures.h:474
@ EDIT_DWORD
Definition RequestStructures.h:473
@ EDIT_BYTE
Definition RequestStructures.h:472
#define SIZEOF_DEBUGGER_EDIT_MEMORY
Definition RequestStructures.h:454
#define STATUS_UNSUCCESSFUL
Definition Windows.h:172
UINT32 Result
Definition RequestStructures.h:483
UINT64 Address
Definition RequestStructures.h:484
DEBUGGER_EDIT_MEMORY_TYPE MemoryType
Definition RequestStructures.h:486
UINT32 CountOf64Chunks
Definition RequestStructures.h:488
UINT32 ProcessId
Definition RequestStructures.h:485
DEBUGGER_EDIT_MEMORY_BYTE_SIZE ByteSize
Definition RequestStructures.h:487

◆ DebuggerCommandEditMemoryVmxRoot()

BOOLEAN DebuggerCommandEditMemoryVmxRoot ( PDEBUGGER_EDIT_MEMORY EditMemRequest)

Edit physical and virtual memory on vmxroot mode.

Parameters
EditMemRequestedit memory request
Returns
NTSTATUS
556{
557 UINT32 LengthOfEachChunk = 0;
558 PVOID DestinationAddress = 0;
559 PVOID SourceAddress = 0;
560
561 //
562 // THIS FUNCTION IS SAFE TO BE CALLED FROM VMX-ROOT
563 //
564
565 //
566 // set chunk size in each modification
567 //
568 if (EditMemRequest->ByteSize == EDIT_BYTE)
569 {
570 LengthOfEachChunk = 1;
571 }
572 else if (EditMemRequest->ByteSize == EDIT_DWORD)
573 {
574 LengthOfEachChunk = 4;
575 }
576 else if (EditMemRequest->ByteSize == EDIT_QWORD)
577 {
578 LengthOfEachChunk = 8;
579 }
580 else
581 {
582 //
583 // Invalid parameter
584 //
586 return FALSE;
587 }
588
589 if (EditMemRequest->MemoryType == EDIT_VIRTUAL_MEMORY)
590 {
591 //
592 // Check whether the virtual memory is available in the current
593 // memory layout and also is present in the RAM
594 //
595 if (!CheckAccessValidityAndSafety(EditMemRequest->Address,
596 EditMemRequest->ByteSize * EditMemRequest->CountOf64Chunks))
597 {
598 EditMemRequest->Result = DEBUGGER_ERROR_INVALID_ADDRESS;
599 return FALSE;
600 }
601
602 //
603 // Edit the memory
604 //
605 for (size_t i = 0; i < EditMemRequest->CountOf64Chunks; i++)
606 {
607 DestinationAddress = (PVOID)((UINT64)EditMemRequest->Address + (i * LengthOfEachChunk));
608 SourceAddress = (PVOID)((UINT64)EditMemRequest + SIZEOF_DEBUGGER_EDIT_MEMORY + (i * sizeof(UINT64)));
609
610 //
611 // Instead of directly accessing the memory we use the MemoryMapperWriteMemorySafeOnTargetProcess
612 // It is because the target page might be read-only so we can make it writable
613 //
614
615 // RtlCopyBytes(DestinationAddress, SourceAddress, LengthOfEachChunk);
616 MemoryMapperWriteMemorySafeOnTargetProcess((UINT64)DestinationAddress, SourceAddress, LengthOfEachChunk);
617 }
618 }
619 else if (EditMemRequest->MemoryType == EDIT_PHYSICAL_MEMORY)
620 {
621 //
622 // Check whether the physical addres
623 //
624 if (!CheckAddressPhysical(EditMemRequest->Address))
625 {
626 EditMemRequest->Result = DEBUGGER_ERROR_INVALID_ADDRESS;
627 return FALSE;
628 }
629
630 //
631 // Edit the physical memory
632 //
633 for (size_t i = 0; i < EditMemRequest->CountOf64Chunks; i++)
634 {
635 DestinationAddress = (PVOID)((UINT64)EditMemRequest->Address + (i * LengthOfEachChunk));
636 SourceAddress = (PVOID)((UINT64)EditMemRequest + SIZEOF_DEBUGGER_EDIT_MEMORY + (i * sizeof(UINT64)));
637
638 MemoryMapperWriteMemorySafeByPhysicalAddress((UINT64)DestinationAddress, (UINT64)SourceAddress, LengthOfEachChunk);
639 }
640 }
641 else
642 {
643 //
644 // Invalid parameter
645 //
647 return FALSE;
648 }
649
650 //
651 // Set the resutls
652 //
654 return TRUE;
655}
BOOLEAN CheckAccessValidityAndSafety(UINT64 TargetAddress, UINT32 Size)
Check the safety to access the memory.
Definition AddressCheck.c:156
#define FALSE
Definition BasicTypes.h:54
_Use_decl_annotations_ BOOLEAN MemoryMapperWriteMemorySafeOnTargetProcess(UINT64 Destination, PVOID Source, SIZE_T Size)
Write memory safely by mapping the buffer on the target process memory (It's a wrapper)
Definition MemoryMapper.c:1165

◆ DebuggerCommandFlush()

NTSTATUS DebuggerCommandFlush ( PDEBUGGER_FLUSH_LOGGING_BUFFERS DebuggerFlushBuffersRequest)

Perform the flush requests to vmx-root and vmx non-root buffers.

Parameters
DebuggerFlushBuffersRequestRequest to flush the buffers
Returns
NTSTATUS
1236{
1237 //
1238 // We try to flush buffers for both vmx-root and regular kernel buffer
1239 //
1240 DebuggerFlushBuffersRequest->CountOfMessagesThatSetAsReadFromVmxRoot = LogMarkAllAsRead(TRUE);
1242 DebuggerFlushBuffersRequest->KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL;
1243
1244 return STATUS_SUCCESS;
1245}
UINT32 LogMarkAllAsRead(BOOLEAN IsVmxRoot)
Mark all buffers as read.
Definition Logging.c:558
UINT32 CountOfMessagesThatSetAsReadFromVmxRoot
Definition RequestStructures.h:296
UINT32 CountOfMessagesThatSetAsReadFromVmxNonRoot
Definition RequestStructures.h:297
UINT32 KernelStatus
Definition RequestStructures.h:295

◆ DebuggerCommandPreactivateFunctionality()

NTSTATUS DebuggerCommandPreactivateFunctionality ( PDEBUGGER_PREACTIVATE_COMMAND PreactivateRequest)

Preactivate a special functionality.

Parameters
PreactivateRequestRequest details of preactivation
Returns
NTSTATUS
1444{
1445 switch (PreactivateRequest->Type)
1446 {
1448
1449 //
1450 // Request for allocating the mode mechanism
1451 //
1453
1454 break;
1455
1456 default:
1457
1459 return STATUS_UNSUCCESSFUL;
1460 }
1461
1462 PreactivateRequest->KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL;
1463
1464 return STATUS_SUCCESS;
1465}
BOOLEAN ConfigureInitializeExecTrapOnAllProcessors()
routines for initializing user-mode, kernel-mode exec trap
Definition Configuration.c:37
#define DEBUGGER_ERROR_COULD_NOT_FIND_PREACTIVATION_TYPE
error, could not find the type of preactivation
Definition ErrorCodes.h:507
@ DEBUGGER_PREACTIVATE_COMMAND_TYPE_MODE
Definition RequestStructures.h:190
UINT32 KernelStatus
Definition RequestStructures.h:204
DEBUGGER_PREACTIVATE_COMMAND_TYPE Type
Definition RequestStructures.h:203

◆ DebuggerCommandReadMemory()

BOOLEAN DebuggerCommandReadMemory ( PDEBUGGER_READ_MEMORY ReadMemRequest,
PVOID UserBuffer,
PSIZE_T ReturnSize )

Read memory for different commands.

Parameters
ReadMemRequestrequest structure for reading memory
UserBufferuser buffer to copy the memory
ReturnSizesize that should be returned to user mode buffers
Returns
BOOLEAN
26{
27 UINT32 Pid;
28 UINT32 Size;
31 BOOLEAN Is32BitProcess = FALSE;
32
33 //
34 // Adjust the parameters
35 //
36 Pid = ReadMemRequest->Pid;
37 Size = ReadMemRequest->Size;
38 Address = ReadMemRequest->Address;
39 MemType = ReadMemRequest->MemoryType;
40
41 if (Size && Address != (UINT64)NULL)
42 {
44 (PVOID)Address,
45 MemType,
46 (PVOID)UserBuffer,
47 Size,
48 ReturnSize))
49 {
50 //
51 // Reading memory was successful
52 //
53
54 //
55 // *** Now, we check whether this a disassembly request for a virtual address
56 // or not, if so, we'll detect whether the target process is 32-bit or 64-bit ***
57 //
58
59 //
60 // Check if the address is on a 32-bit mode process or not (just in case of disassembling)
61 //
62 if (ReadMemRequest->MemoryType == DEBUGGER_READ_VIRTUAL_ADDRESS && ReadMemRequest->GetAddressMode)
63 {
64 //
65 // Check if the address is in the canonical range for kernel space
66 //
67 if (ReadMemRequest->Address >= 0xFFFF800000000000 && ReadMemRequest->Address <= 0xFFFFFFFFFFFFFFFF)
68 {
69 //
70 // The address is in the range of canonical kernel space, so it's 64-bit process
71 //
73 }
74 else
75 {
76 //
77 // The address is in the user-mode and the memory type is a virtual address
78 // for disassembly, so we have to query whether the target process is a
79 // 32-bit process or a 64-bit process
80 //
81 if (UserAccessIsWow64Process((HANDLE)ReadMemRequest->Pid, &Is32BitProcess))
82 {
83 if (Is32BitProcess)
84 {
86 }
87 else
88 {
90 }
91 }
92 else
93 {
94 //
95 // We couldn't determine the type of process, let's assume that it's a
96 // 64-bit process by default
97 //
99 }
100 }
101 }
102
103 //
104 // Anyway, the read was successful
105 //
107 return TRUE;
108 }
109 else
110 {
111 //
112 // Reading memory was not successful
113 //
115 return FALSE;
116 }
117 }
118 else
119 {
120 //
121 // Parameters are invalid
122 //
124 return FALSE;
125 }
126}
UCHAR BOOLEAN
Definition BasicTypes.h:39
#define DEBUGGER_ERROR_READING_MEMORY_INVALID_PARAMETER
error, for reading from memory in case of invalid parameters
Definition ErrorCodes.h:405
UINT64 Address
Definition HyperDbgScriptImports.h:67
BOOLEAN MemoryManagerReadProcessMemoryNormal(HANDLE PID, PVOID Address, DEBUGGER_READ_MEMORY_TYPE MemType, PVOID UserBuffer, SIZE_T Size, PSIZE_T ReturnSize)
Read process memory.
Definition MemoryManager.c:29
enum _DEBUGGER_READ_MEMORY_TYPE DEBUGGER_READ_MEMORY_TYPE
different type of addresses
@ DEBUGGER_READ_ADDRESS_MODE_32_BIT
Definition RequestStructures.h:239
@ DEBUGGER_READ_ADDRESS_MODE_64_BIT
Definition RequestStructures.h:240
@ DEBUGGER_READ_VIRTUAL_ADDRESS
Definition RequestStructures.h:230
BOOLEAN UserAccessIsWow64Process(HANDLE ProcessId, PBOOLEAN Is32Bit)
Detects whether process is 32-bit or 64-bit.
Definition UserAccess.c:753
UINT32 KernelStatus
Definition RequestStructures.h:275
UINT32 Size
Definition RequestStructures.h:269
UINT32 Pid
Definition RequestStructures.h:267
DEBUGGER_READ_MEMORY_ADDRESS_MODE AddressMode
Definition RequestStructures.h:271
BOOLEAN GetAddressMode
Definition RequestStructures.h:270
DEBUGGER_READ_MEMORY_TYPE MemoryType
Definition RequestStructures.h:272
UINT64 Address
Definition RequestStructures.h:268

◆ DebuggerCommandReadMemoryVmxRoot()

BOOLEAN DebuggerCommandReadMemoryVmxRoot ( PDEBUGGER_READ_MEMORY ReadMemRequest,
UCHAR * UserBuffer,
UINT32 * ReturnSize )

Read memory for different commands from vmxroot mode.

Parameters
ReadMemRequestrequest structure for reading memory
UserBufferuser buffer to copy the memory
ReturnSizesize that should be returned to user mode buffers
Returns
BOOLEAN
138{
139 UINT32 Pid;
140 UINT32 Size;
142 UINT64 OffsetInUserBuffer;
144 BOOLEAN Is32BitProcess = FALSE;
145 PLIST_ENTRY TempList = 0;
146
147 Pid = ReadMemRequest->Pid;
148 Size = ReadMemRequest->Size;
149 Address = ReadMemRequest->Address;
150 MemType = ReadMemRequest->MemoryType;
151
152 //
153 // read memory safe
154 //
155 if (MemType == DEBUGGER_READ_PHYSICAL_ADDRESS)
156 {
157 //
158 // Check whether the physical memory is valid or not
159 //
161 {
163 return FALSE;
164 }
165
167 }
168 else if (MemType == DEBUGGER_READ_VIRTUAL_ADDRESS)
169 {
170 //
171 // Check whether the virtual memory is available in the current
172 // memory layout and also is present in the RAM
173 //
175 {
177 return FALSE;
178 }
179
180 //
181 // Read memory safely
182 //
184
185 //
186 // Check if the target memory is filled with breakpoint of the 'bp' commands
187 // if the memory is changed due to this command, then we'll changes it to
188 // the previous byte
189 //
190
191 //
192 // Iterate through the breakpoint list
193 //
194 TempList = &g_BreakpointsListHead;
195
196 while (&g_BreakpointsListHead != TempList->Flink)
197 {
198 TempList = TempList->Flink;
199 PDEBUGGEE_BP_DESCRIPTOR CurrentBreakpointDesc = CONTAINING_RECORD(TempList, DEBUGGEE_BP_DESCRIPTOR, BreakpointsList);
200
201 if (CurrentBreakpointDesc->Address >= Address && CurrentBreakpointDesc->Address <= Address + Size)
202 {
203 //
204 // The address is found, we have to swap the byte if the target
205 // byte is 0xcc
206 //
207
208 //
209 // Find the address location at user buffer
210 //
211 OffsetInUserBuffer = CurrentBreakpointDesc->Address - Address;
212
213 if (UserBuffer[OffsetInUserBuffer] == 0xcc)
214 {
215 UserBuffer[OffsetInUserBuffer] = CurrentBreakpointDesc->PreviousByte;
216 }
217 }
218 }
219 }
220 else
221 {
223 return FALSE;
224 }
225
226 //
227 // Check if the address is on a 32-bit mode process or not (just in case of disassembling)
228 //
229 if (ReadMemRequest->MemoryType == DEBUGGER_READ_VIRTUAL_ADDRESS && ReadMemRequest->GetAddressMode)
230 {
231 //
232 // Check if the address is in the canonical range for kernel space
233 //
234 if (ReadMemRequest->Address >= 0xFFFF800000000000 && ReadMemRequest->Address <= 0xFFFFFFFFFFFFFFFF)
235 {
236 //
237 // The address is in the range of canonical kernel space, so it's 64-bit process
238 //
240 }
241 else
242 {
243 //
244 // The address is in the user-mode and the memory type is a virtual address
245 // for disassembly, so we have to query whether the target process is a
246 // 32-bit process or a 64-bit process
247 //
248 if (UserAccessIsWow64ProcessByEprocess(PsGetCurrentProcess(), &Is32BitProcess))
249 {
250 if (Is32BitProcess)
251 {
253 }
254 else
255 {
257 }
258 }
259 else
260 {
261 //
262 // We couldn't determine the type of process, let's assume that it's a
263 // 64-bit process by default
264 //
266 }
267 }
268 }
269
270 //
271 // Set the final status of memory read as it was successful
272 //
274 *ReturnSize = Size;
275
276 return TRUE;
277}
#define DEBUGGER_ERROR_MEMORY_TYPE_INVALID
error, memory type is invalid
Definition ErrorCodes.h:214
#define DEBUGGER_ERROR_INVALID_PHYSICAL_ADDRESS
error, invalid physical address
Definition ErrorCodes.h:540
_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
_Use_decl_annotations_ BOOLEAN MemoryMapperReadMemorySafeByPhysicalAddress(UINT64 PaAddressToRead, UINT64 BufferToSaveMemory, SIZE_T SizeToRead)
Read memory safely by mapping the buffer by physical address (It's a wrapper)
Definition MemoryMapper.c:1077
@ DEBUGGER_READ_PHYSICAL_ADDRESS
Definition RequestStructures.h:229
BOOLEAN UserAccessIsWow64ProcessByEprocess(PEPROCESS SourceProcess, PBOOLEAN Is32Bit)
Detects whether process is 32-bit or 64-bit by using EPROCESS pointer.
Definition UserAccess.c:711
LIST_ENTRY g_BreakpointsListHead
List header of breakpoints for debugger-mode.
Definition Global.h:91
The structure of storing breakpoints.
Definition State.h:72
BYTE PreviousByte
Definition State.h:82
UINT64 Address
Definition State.h:76

◆ DebuggerCommandReservePreallocatedPools()

NTSTATUS DebuggerCommandReservePreallocatedPools ( PDEBUGGER_PREALLOC_COMMAND PreallocRequest)

Reserve and allocate pre-allocated buffers.

Parameters
PreallocRequestRequest details of needed buffers to be reserved
Returns
NTSTATUS
1320{
1321 switch (PreallocRequest->Type)
1322 {
1324
1325 //
1326 // Request pages to be allocated for thread interception mechanism
1327 //
1329 PreallocRequest->Count,
1331
1332 break;
1333
1335
1336 //
1337 // Perform the allocations for the '!monitor' command
1338 //
1340
1341 break;
1342
1344
1345 //
1346 // Perform the allocations for the '!epthook' command
1347 //
1349
1350 break;
1351
1353
1354 //
1355 // All the prealloc requests of regular EPT hooks are needed for the '!epthook2'
1356 //
1358
1359 break;
1360
1362
1363 //
1364 // Request pages to be allocated for regular instant events
1365 //
1367 PreallocRequest->Count,
1369
1370 //
1371 // Request pages to be allocated for regular instant events's actions
1372 //
1374 PreallocRequest->Count,
1376
1377 break;
1378
1380
1381 //
1382 // Request pages to be allocated for big instant events
1383 //
1385 PreallocRequest->Count,
1387
1388 //
1389 // Request pages to be allocated for big instant events's actions
1390 //
1392 PreallocRequest->Count,
1394
1395 break;
1396
1398
1399 //
1400 // Request pages to be allocated for regular safe buffer ($buffer) for events
1401 //
1403 PreallocRequest->Count,
1405
1406 break;
1407
1409
1410 //
1411 // Request pages to be allocated for big safe buffer ($buffer) for events
1412 //
1414 PreallocRequest->Count,
1416
1417 break;
1418
1419 default:
1420
1422 return STATUS_UNSUCCESSFUL;
1423 }
1424
1425 //
1426 // Invalidate and perform the allocations as we're in PASSIVE_LEVEL
1427 //
1429
1431
1432 return STATUS_SUCCESS;
1433}
VOID ConfigureEptHookAllocateExtraHookingPagesForMemoryMonitorsAndExecEptHooks(UINT32 Count)
Allocate (reserve) extra pages for storing details of page hooks for memory monitor and regular hidde...
Definition Configuration.c:227
VOID ConfigureEptHookReservePreallocatedPoolsForEptHooks(UINT32 Count)
Allocate (reserve) pages for storing EPT hooks page hooks.
Definition Configuration.c:239
#define BIG_INSTANT_EVENT_ACTION_BUFFER
Pre-allocated size for a big action + custom code or script buffer.
Definition Constants.h:300
#define REGULAR_INSTANT_EVENT_REQUESTED_SAFE_BUFFER
Pre-allocated size for a regular requested safe buffer.
Definition Constants.h:306
#define REGULAR_INSTANT_EVENT_ACTION_BUFFER
Pre-allocated size for a regular action + custom code or script buffer.
Definition Constants.h:294
#define REGULAR_INSTANT_EVENT_CONDITIONAL_BUFFER
Pre-allocated size for a regular event + conditions buffer.
Definition Constants.h:282
#define BIG_INSTANT_EVENT_CONDITIONAL_BUFFER
Pre-allocated size for a big event + conditions buffer.
Definition Constants.h:288
#define BIG_INSTANT_EVENT_REQUESTED_SAFE_BUFFER
Pre-allocated size for a big requested safe buffer.
Definition Constants.h:312
@ PROCESS_THREAD_HOLDER
Definition DataTypes.h:46
@ INSTANT_REGULAR_SAFE_BUFFER_FOR_EVENTS
Definition DataTypes.h:59
@ INSTANT_BIG_SAFE_BUFFER_FOR_EVENTS
Definition DataTypes.h:60
@ INSTANT_BIG_EVENT_BUFFER
Definition DataTypes.h:52
@ INSTANT_BIG_EVENT_ACTION_BUFFER
Definition DataTypes.h:54
@ INSTANT_REGULAR_EVENT_ACTION_BUFFER
Definition DataTypes.h:53
@ INSTANT_REGULAR_EVENT_BUFFER
Definition DataTypes.h:51
#define DEBUGGER_ERROR_COULD_NOT_FIND_ALLOCATION_TYPE
error, could not find the type of allocation
Definition ErrorCodes.h:282
BOOLEAN PoolManagerCheckAndPerformAllocationAndDeallocation()
This function performs allocations from VMX non-root based on g_RequestNewAllocation.
Definition PoolManager.c:302
BOOLEAN PoolManagerRequestAllocation(SIZE_T Size, UINT32 Count, POOL_ALLOCATION_INTENTION Intention)
Request to allocate new buffers.
Definition PoolManager.c:415
@ DEBUGGER_PREALLOC_COMMAND_TYPE_MONITOR
Definition RequestStructures.h:156
@ DEBUGGER_PREALLOC_COMMAND_TYPE_EPTHOOK2
Definition RequestStructures.h:158
@ DEBUGGER_PREALLOC_COMMAND_TYPE_BIG_EVENT
Definition RequestStructures.h:160
@ DEBUGGER_PREALLOC_COMMAND_TYPE_REGULAR_EVENT
Definition RequestStructures.h:159
@ DEBUGGER_PREALLOC_COMMAND_TYPE_THREAD_INTERCEPTION
Definition RequestStructures.h:155
@ DEBUGGER_PREALLOC_COMMAND_TYPE_BIG_SAFE_BUFFER
Definition RequestStructures.h:162
@ DEBUGGER_PREALLOC_COMMAND_TYPE_REGULAR_SAFE_BUFFER
Definition RequestStructures.h:161
@ DEBUGGER_PREALLOC_COMMAND_TYPE_EPTHOOK
Definition RequestStructures.h:157
DEBUGGER_PREALLOC_COMMAND_TYPE Type
Definition RequestStructures.h:175
UINT32 KernelStatus
Definition RequestStructures.h:177
UINT32 Count
Definition RequestStructures.h:176
The holder for detail of each thread in process.
Definition ThreadHolder.h:46

◆ DebuggerCommandSearchMemory()

NTSTATUS DebuggerCommandSearchMemory ( PDEBUGGER_SEARCH_MEMORY SearchMemRequest)

Start searching memory.

Parameters
SearchMemRequestRequest to search memory
Returns
NTSTATUS
1135{
1136 PUINT64 SearchResultsStorage = NULL;
1137 PUINT64 UsermodeBuffer = NULL;
1138 UINT64 AddressFrom = 0;
1139 UINT64 AddressTo = 0;
1140 UINT64 CurrentValue = 0;
1141 UINT32 ResultsIndex = 0;
1142 UINT32 CountOfResults = 0;
1143
1144 //
1145 // Check if process id is valid or not
1146 //
1147 if (SearchMemRequest->ProcessId != HANDLE_TO_UINT32(PsGetCurrentProcessId()) && !CommonIsProcessExist(SearchMemRequest->ProcessId))
1148 {
1149 return STATUS_INVALID_PARAMETER;
1150 }
1151
1152 //
1153 // User-mode buffer is same as SearchMemRequest
1154 //
1155 UsermodeBuffer = (UINT64 *)SearchMemRequest;
1156
1157 //
1158 // We store the user-mode data in a separate variable because
1159 // we will use them later when we Zeroed the SearchMemRequest
1160 //
1161 AddressFrom = SearchMemRequest->Address;
1162 AddressTo = SearchMemRequest->Address + SearchMemRequest->Length;
1163
1164 //
1165 // We support up to MaximumSearchResults search results
1166 //
1167 SearchResultsStorage = PlatformMemAllocateZeroedNonPagedPool(MaximumSearchResults * sizeof(UINT64));
1168
1169 if (SearchResultsStorage == NULL)
1170 {
1171 //
1172 // Not enough memory
1173 //
1174 return STATUS_INSUFFICIENT_RESOURCES;
1175 }
1176
1177 //
1178 // Call the wrapper
1179 //
1180 SearchAddressWrapper(SearchResultsStorage, SearchMemRequest, AddressFrom, AddressTo, FALSE, &CountOfResults);
1181
1182 //
1183 // In this point, we to store the results (if any) to the user-mode
1184 // buffer SearchMemRequest itself is the user-mode buffer and we also
1185 // checked from the previous function that the output buffer is at
1186 // least SearchMemRequest bigger or equal to MaximumSearchResults * sizeof(UINT64)
1187 // so we need to clear everything here, and also we should keep in mind that
1188 // SearchMemRequest is no longer valid
1189 //
1190 RtlZeroMemory(SearchMemRequest, MaximumSearchResults * sizeof(UINT64));
1191
1192 //
1193 // It's time to move the results from our temporary buffer to the user-mode
1194 // buffer, also there is something that we should check and that's the fact
1195 // that we used aligned page addresses so the results should be checked to
1196 // see whether the results are between the user's entered addresses or not
1197 //
1198 for (size_t i = 0; i < MaximumSearchResults; i++)
1199 {
1200 CurrentValue = SearchResultsStorage[i];
1201
1202 if (CurrentValue == (UINT64)NULL)
1203 {
1204 //
1205 // Nothing left to move
1206 //
1207 break;
1208 }
1209
1210 if (CurrentValue >= AddressFrom && CurrentValue <= AddressTo)
1211 {
1212 //
1213 // Move the variable
1214 //
1215 UsermodeBuffer[ResultsIndex] = CurrentValue;
1216 ResultsIndex++;
1217 }
1218 }
1219
1220 //
1221 // Free the results pool
1222 //
1223 PlatformMemFreePool(SearchResultsStorage);
1224
1225 return STATUS_SUCCESS;
1226}
unsigned __int64 * PUINT64
Definition BasicTypes.h:21
#define MaximumSearchResults
maximum results that will be returned by !s* s* command
Definition Constants.h:514
BOOLEAN SearchAddressWrapper(PUINT64 AddressToSaveResults, PDEBUGGER_SEARCH_MEMORY SearchMemRequest, UINT64 StartAddress, UINT64 EndAddress, BOOLEAN IsDebuggeePaused, PUINT32 CountOfMatchedCases)
The wrapper to check for validity of addresses and call the search routines for both physical and vir...
Definition DebuggerCommands.c:962
VOID PlatformMemFreePool(PVOID BufferAddress)
Free (dellocate) a non-paged buffer.
Definition Mem.c:86
PVOID PlatformMemAllocateZeroedNonPagedPool(SIZE_T NumberOfBytes)
Allocate a non-paged buffer (zeroed)
Definition Mem.c:69
BOOLEAN CommonIsProcessExist(UINT32 ProcId)
Checks whether the process with ProcId exists or not.
Definition Common.c:24
NULL()
Definition test-case-generator.py:530
UINT64 Length
Definition RequestStructures.h:529
UINT32 ProcessId
Definition RequestStructures.h:530
UINT64 Address
Definition RequestStructures.h:528

◆ DebuggerCommandSendGeneralBufferToDebugger()

NTSTATUS DebuggerCommandSendGeneralBufferToDebugger ( PDEBUGGEE_SEND_GENERAL_PACKET_FROM_DEBUGGEE_TO_DEBUGGER DebuggeeBufferRequest)

Send general buffers from the debuggee to the debugger.

Parameters
DebuggeeBufferRequestRequest to buffer that will be sent to the debugger
Returns
NTSTATUS
1297{
1298 //
1299 // It's better to send the signal from vmx-root mode to avoid deadlock
1300 //
1302 (UINT64)DebuggeeBufferRequest,
1303 0,
1304 0);
1305
1306 DebuggeeBufferRequest->KernelResult = DEBUGGER_OPERATION_WAS_SUCCESSFUL;
1307
1308 return STATUS_SUCCESS;
1309}
#define DEBUGGER_VMCALL_SEND_GENERAL_BUFFER_TO_DEBUGGER
VMCALL to send general buffers from debuggee user-mode to the debugger.
Definition DebuggerVmcalls.h:49
NTSTATUS VmFuncVmxVmcall(unsigned long long VmcallNumber, unsigned long long OptionalParam1, unsigned long long OptionalParam2, unsigned long long OptionalParam3)
Export for running VMX VMCALLs.
Definition Export.c:683
UINT32 KernelResult
Definition RequestStructures.h:388

◆ DebuggerCommandSendMessage()

NTSTATUS DebuggerCommandSendMessage ( PDEBUGGER_SEND_USERMODE_MESSAGES_TO_DEBUGGER DebuggerSendUsermodeMessageRequest)

Send the user-mode buffer to debugger.

Parameters
DebuggerSendUsermodeMessageRequestRequest to send message to debugger
Returns
NTSTATUS
1275{
1276 //
1277 // It's better to send the signal from vmx-root mode to avoid deadlock
1278 //
1280 (UINT64)DebuggerSendUsermodeMessageRequest + (SIZEOF_DEBUGGER_SEND_USERMODE_MESSAGES_TO_DEBUGGER),
1281 DebuggerSendUsermodeMessageRequest->Length,
1282 0);
1283
1284 DebuggerSendUsermodeMessageRequest->KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL;
1285
1286 return STATUS_SUCCESS;
1287}
#define DEBUGGER_VMCALL_SEND_MESSAGES_TO_DEBUGGER
VMCALL to send messages to the debugger.
Definition DebuggerVmcalls.h:42
#define SIZEOF_DEBUGGER_SEND_USERMODE_MESSAGES_TO_DEBUGGER
Definition RequestStructures.h:400
UINT32 KernelStatus
Definition RequestStructures.h:409
UINT32 Length
Definition RequestStructures.h:410

◆ DebuggerCommandSignalExecutionState()

NTSTATUS DebuggerCommandSignalExecutionState ( PDEBUGGER_SEND_COMMAND_EXECUTION_FINISHED_SIGNAL DebuggerFinishedExecutionRequest)

Perform the command finished signal.

Parameters
DebuggerFinishedExecutionRequestRequest to signal debuggee about execution state
Returns
NTSTATUS
1256{
1257 //
1258 // It's better to send the signal from vmx-root mode
1259 //
1261
1262 DebuggerFinishedExecutionRequest->KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL;
1263
1264 return STATUS_SUCCESS;
1265}
#define DEBUGGER_VMCALL_SIGNAL_DEBUGGER_EXECUTION_FINISHED
VMCALL to signal debugger that debuggee finished execution of the command.
Definition DebuggerVmcalls.h:36
UINT32 KernelStatus
Definition RequestStructures.h:368

◆ DebuggerReadOrWriteMsr()

NTSTATUS DebuggerReadOrWriteMsr ( PDEBUGGER_READ_AND_WRITE_ON_MSR ReadOrWriteMsrRequest,
UINT64 * UserBuffer,
PSIZE_T ReturnSize )

Perform rdmsr, wrmsr commands.

Parameters
ReadOrWriteMsrRequestMsr read/write request
UserBufferuser buffer to save the results
ReturnSizereturn size to user-mode buffers
Returns
NTSTATUS
289{
290 NTSTATUS Status;
291 ULONG ProcessorsCount;
292
293 ProcessorsCount = KeQueryActiveProcessorCount(0);
294
295 //
296 // We don't check whether the MSR is in valid range of hardware or not
297 // because the user might send a non-valid MSR which means sth to the
298 // Windows or VMM, e.g the range specified for VMMs in Hyper-v
299 //
300
301 if (ReadOrWriteMsrRequest->ActionType == DEBUGGER_MSR_WRITE)
302 {
303 //
304 // Set Msr to be applied on the target cores
305 //
307 {
308 //
309 // Means that we should apply it on all cores
310 //
311 for (size_t i = 0; i < ProcessorsCount; i++)
312 {
313 g_DbgState[i].MsrState.Msr = ReadOrWriteMsrRequest->Msr;
314 g_DbgState[i].MsrState.Value = ReadOrWriteMsrRequest->Value;
315 }
316 //
317 // Broadcast to all cores to change their Msrs
318 //
319 KeGenericCallDpc(DpcRoutineWriteMsrToAllCores, 0x0);
320 }
321 else
322 {
323 //
324 // We have to change a single core's msr
325 //
326
327 //
328 // Check if the core number is not invalid
329 //
330 if (ReadOrWriteMsrRequest->CoreNumber >= ProcessorsCount)
331 {
332 return STATUS_INVALID_PARAMETER;
333 }
334 //
335 // Otherwise it's valid
336 //
337 g_DbgState[ReadOrWriteMsrRequest->CoreNumber].MsrState.Msr = ReadOrWriteMsrRequest->Msr;
338 g_DbgState[ReadOrWriteMsrRequest->CoreNumber].MsrState.Value = ReadOrWriteMsrRequest->Value;
339
340 //
341 // Execute it on a single core
342 //
343 Status = DpcRoutineRunTaskOnSingleCore(ReadOrWriteMsrRequest->CoreNumber, (PVOID)DpcRoutinePerformWriteMsr, NULL);
344
345 *ReturnSize = 0;
346 return Status;
347 }
348
349 //
350 // It's an wrmsr, nothing to return
351 //
352 *ReturnSize = 0;
353 return STATUS_SUCCESS;
354 }
355 else if (ReadOrWriteMsrRequest->ActionType == DEBUGGER_MSR_READ)
356 {
357 //
358 // Set Msr to be applied on the target cores
359 //
361 {
362 //
363 // Means that we should apply it on all cores
364 //
365 for (size_t i = 0; i < ProcessorsCount; i++)
366 {
367 g_DbgState[i].MsrState.Msr = ReadOrWriteMsrRequest->Msr;
368 }
369
370 //
371 // Broadcast to all cores to read their Msrs
372 //
373 KeGenericCallDpc(DpcRoutineReadMsrToAllCores, 0x0);
374
375 //
376 // When we reach here, all processors read their shits
377 // so we have to fill that fucking buffer for user mode
378 //
379 for (size_t i = 0; i < ProcessorsCount; i++)
380 {
381 UserBuffer[i] = g_DbgState[i].MsrState.Value;
382 }
383
384 //
385 // It's an rdmsr we have to return a value for all cores
386 //
387
388 *ReturnSize = sizeof(UINT64) * ProcessorsCount;
389 return STATUS_SUCCESS;
390 }
391 else
392 {
393 //
394 // Apply to one core
395 //
396
397 //
398 // Check if the core number is not invalid
399 //
400 if (ReadOrWriteMsrRequest->CoreNumber >= ProcessorsCount)
401 {
402 *ReturnSize = 0;
403 return STATUS_INVALID_PARAMETER;
404 }
405 //
406 // Otherwise it's valid
407 //
408 g_DbgState[ReadOrWriteMsrRequest->CoreNumber].MsrState.Msr = ReadOrWriteMsrRequest->Msr;
409
410 //
411 // Execute it on a single core
412 //
413 Status = DpcRoutineRunTaskOnSingleCore(ReadOrWriteMsrRequest->CoreNumber, (PVOID)DpcRoutinePerformReadMsr, NULL);
414
415 if (Status != STATUS_SUCCESS)
416 {
417 *ReturnSize = 0;
418 return Status;
419 }
420 //
421 // Restore the result to the usermode
422 //
423 UserBuffer[0] = g_DbgState[ReadOrWriteMsrRequest->CoreNumber].MsrState.Value;
424
425 *ReturnSize = sizeof(UINT64);
426 return STATUS_SUCCESS;
427 }
428 }
429
430 *ReturnSize = 0;
431 return STATUS_UNSUCCESSFUL;
432}
unsigned long ULONG
Definition BasicTypes.h:37
#define DEBUGGER_READ_AND_WRITE_ON_MSR_APPLY_ALL_CORES
Read and write MSRs to all cores.
Definition Constants.h:599
@ DEBUGGER_MSR_READ
Definition RequestStructures.h:431
@ DEBUGGER_MSR_WRITE
Definition RequestStructures.h:432
NTSTATUS DpcRoutineRunTaskOnSingleCore(UINT32 CoreNumber, PVOID Routine, PVOID DeferredContext)
This function synchronize the function execution for a single core You should only used it for one co...
Definition DpcRoutines.c:35
VOID DpcRoutinePerformWriteMsr(KDPC *Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2)
Broadcast msr write.
Definition DpcRoutines.c:128
VOID DpcRoutinePerformReadMsr(KDPC *Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2)
Broadcast msr read.
Definition DpcRoutines.c:160
VOID DpcRoutineWriteMsrToAllCores(KDPC *Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2)
Broadcast Msr Write.
Definition DpcRoutines.c:192
VOID DpcRoutineReadMsrToAllCores(KDPC *Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2)
Broadcast Msr read.
Definition DpcRoutines.c:226
PROCESSOR_DEBUGGING_STATE * g_DbgState
Save the state and variables related to debugging on each to logical core.
Definition Global.h:17
UINT32 CoreNumber
Definition RequestStructures.h:442
DEBUGGER_MSR_ACTION_TYPE ActionType
Definition RequestStructures.h:446
UINT64 Msr
Definition RequestStructures.h:441
UINT64 Value
Definition RequestStructures.h:447
UINT64 Msr
Definition State.h:24
UINT64 Value
Definition State.h:25
PROCESSOR_DEBUGGING_MSR_READ_OR_WRITE MsrState
Definition State.h:172

◆ PerformSearchAddress()

BOOLEAN PerformSearchAddress ( UINT64 * AddressToSaveResults,
PDEBUGGER_SEARCH_MEMORY SearchMemRequest,
UINT64 StartAddress,
UINT64 EndAddress,
BOOLEAN IsDebuggeePaused,
PUINT32 CountOfMatchedCases )

Search on virtual memory (not work on physical memory)

This function can be called from vmx-root mode Do NOT directly call this function as the virtual addresses should be valid on the target process memory layout instead call : SearchAddressWrapper the address between StartAddress and EndAddress should be contiguous

Parameters
AddressToSaveResultsAddress to save the search results
SearchMemRequestrequest structure of searching memory
StartAddressvalid start address based on target process
EndAddressvalid end address based on target process
IsDebuggeePausedSet to true when the search is performed in the debugger mode
CountOfMatchedCasesNumber of matched cases
Returns
BOOLEAN Whether the search was successful or not
682{
683 UINT32 CountOfOccurance = 0;
684 UINT64 Cmp64 = 0;
685 UINT32 IndexToArrayOfResults = 0;
686 UINT32 LengthOfEachChunk = 0;
687 PVOID TempSourceAddress = 0;
688 PVOID SourceAddress = 0;
689 BOOLEAN StillMatch = FALSE;
690 UINT64 TempValue = (UINT64)NULL;
691 CR3_TYPE CurrentProcessCr3 = {0};
692
693 //
694 // set chunk size in each modification
695 //
696 if (SearchMemRequest->ByteSize == SEARCH_BYTE)
697 {
698 LengthOfEachChunk = 1;
699 }
700 else if (SearchMemRequest->ByteSize == SEARCH_DWORD)
701 {
702 LengthOfEachChunk = 4;
703 }
704 else if (SearchMemRequest->ByteSize == SEARCH_QWORD)
705 {
706 LengthOfEachChunk = 8;
707 }
708 else
709 {
710 //
711 // Invalid parameter
712 //
713 return FALSE;
714 }
715
716 //
717 // Check if address is virtual address or physical address
718 //
719 if (SearchMemRequest->MemoryType == SEARCH_VIRTUAL_MEMORY ||
721 {
722 //
723 // Search the memory
724 //
725
726 //
727 // Change the memory layout (cr3), if the user specified a
728 // special process
729 //
730 if (IsDebuggeePaused)
731 {
732 //
733 // Switch to target process memory layout
734 //
736 }
737 else
738 {
739 if (SearchMemRequest->ProcessId != HANDLE_TO_UINT32(PsGetCurrentProcessId()))
740 {
741 CurrentProcessCr3 = SwitchToProcessMemoryLayout(SearchMemRequest->ProcessId);
742 }
743 }
744
745 //
746 // Here we iterate through the buffer we received from
747 // user-mode
748 //
749 SourceAddress = (PVOID)((UINT64)SearchMemRequest + SIZEOF_DEBUGGER_SEARCH_MEMORY);
750
751 for (size_t BaseIterator = (size_t)StartAddress; BaseIterator < ((UINT64)EndAddress); BaseIterator += LengthOfEachChunk)
752 {
753 //
754 // *** Search the memory ***
755 //
756
757 //
758 // Copy 64bit, 32bit or one byte value into Cmp64 buffer and then compare it
759 // Check if we should access the memory directly, or through safe memory
760 // routine from vmx-root
761 //
762 if (IsDebuggeePaused)
763 {
764 MemoryMapperReadMemorySafe((UINT64)BaseIterator, &Cmp64, LengthOfEachChunk);
765 }
766 else
767 {
768 RtlCopyMemory(&Cmp64, (PVOID)BaseIterator, LengthOfEachChunk);
769 }
770
771 //
772 // Get the searching bytes
773 //
774 TempValue = *(UINT64 *)SourceAddress;
775
776 //
777 // Check whether the byte matches the source or not
778 //
779 if (Cmp64 == TempValue)
780 {
781 //
782 // Indicate that it matches until now
783 //
784 StillMatch = TRUE;
785
786 //
787 // Try to check each element (we don't start from the very first element as
788 // it checked before )
789 //
790 for (size_t i = LengthOfEachChunk; i < SearchMemRequest->CountOf64Chunks; i++)
791 {
792 //
793 // I know, we have a double check here ;)
794 //
795 TempSourceAddress = (PVOID)((UINT64)SearchMemRequest + SIZEOF_DEBUGGER_SEARCH_MEMORY + (i * sizeof(UINT64)));
796
797 //
798 // Add i to BaseIterator and recompute the Cmp64
799 // Check if we should access the memory directly, or through safe memory
800 // routine from vmx-root
801 //
802 if (IsDebuggeePaused)
803 {
804 MemoryMapperReadMemorySafe((UINT64)(BaseIterator + (LengthOfEachChunk * i)), &Cmp64, LengthOfEachChunk);
805 }
806 else
807 {
808 RtlCopyMemory(&Cmp64, (PVOID)(BaseIterator + (LengthOfEachChunk * i)), LengthOfEachChunk);
809 }
810
811 //
812 // Check if we should access the memory directly,
813 // or through safe memory routine from vmx-root
814 //
815 if (IsDebuggeePaused)
816 {
817 MemoryMapperReadMemorySafe((UINT64)TempSourceAddress, &TempValue, sizeof(UINT64));
818 }
819 else
820 {
821 TempValue = *(UINT64 *)TempSourceAddress;
822 }
823
824 if (!(Cmp64 == TempValue))
825 {
826 //
827 // One thing didn't match so this is not the pattern
828 //
829 StillMatch = FALSE;
830
831 //
832 // Break from the loop
833 //
834 break;
835 }
836 }
837
838 //
839 // Check if we find the pattern or not
840 //
841 if (StillMatch)
842 {
843 //
844 // We found the a matching address, let's save the
845 // address for future use
846 //
847 CountOfOccurance++;
848
849 if (IsDebuggeePaused)
850 {
851 if (SearchMemRequest->MemoryType == SEARCH_PHYSICAL_FROM_VIRTUAL_MEMORY)
852 {
853 //
854 // It's a physical memory
855 //
856 Log("%llx\n", VirtualAddressToPhysicalAddress((PVOID)BaseIterator));
857 }
858 else
859 {
860 //
861 // It's a virtual memory
862 //
863 Log("%llx\n", BaseIterator);
864 }
865 }
866 else
867 {
868 if (SearchMemRequest->MemoryType == SEARCH_PHYSICAL_FROM_VIRTUAL_MEMORY)
869 {
870 //
871 // It's a physical memory
872 //
873 AddressToSaveResults[IndexToArrayOfResults] = VirtualAddressToPhysicalAddress((PVOID)BaseIterator);
874 }
875 else
876 {
877 //
878 // It's a virtual memory
879 //
880 AddressToSaveResults[IndexToArrayOfResults] = BaseIterator;
881 }
882 }
883
884 //
885 // Increase the array pointer if it doesn't exceed the limitation
886 //
887 if (MaximumSearchResults > IndexToArrayOfResults)
888 {
889 IndexToArrayOfResults++;
890 }
891 else
892 {
893 //
894 // The result buffer is full!
895 //
896 *CountOfMatchedCases = CountOfOccurance;
897 return TRUE;
898 }
899 }
900 }
901 else
902 {
903 //
904 // Not found in the place
905 //
906 continue;
907 }
908 }
909
910 //
911 // Restore the previous memory layout (cr3), if the user specified a
912 // special process
913 //
914 if (IsDebuggeePaused || SearchMemRequest->ProcessId != HANDLE_TO_UINT32(PsGetCurrentProcessId()))
915 {
916 SwitchToPreviousProcess(CurrentProcessCr3);
917 }
918 }
919 else if (SearchMemRequest->MemoryType == SEARCH_PHYSICAL_MEMORY)
920 {
921 //
922 // That's an error, the physical memory is handled like virtual memory and
923 // thus we should never reach here
924 //
925 LogError("Err, searching physical memory is not allowed without virtual address");
926
927 return FALSE;
928 }
929 else
930 {
931 //
932 // Invalid parameter
933 //
934 return FALSE;
935 }
936
937 //
938 // As we're here the search is finished without error
939 //
940 *CountOfMatchedCases = CountOfOccurance;
941 return TRUE;
942}
#define Log(format,...)
Log without any prefix.
Definition HyperDbgHyperLogIntrinsics.h:129
#define LogError(format,...)
Log in the case of error.
Definition HyperDbgHyperLogIntrinsics.h:113
CR3_TYPE LayoutGetCurrentProcessCr3()
Get cr3 of the target running process.
Definition Layout.c:55
_Use_decl_annotations_ BOOLEAN MemoryMapperReadMemorySafe(UINT64 VaAddressToRead, PVOID BufferToSaveMemory, SIZE_T SizeToRead)
Read memory safely by mapping the buffer (It's a wrapper)
Definition MemoryMapper.c:1101
@ SEARCH_QWORD
Definition RequestStructures.h:518
@ SEARCH_BYTE
Definition RequestStructures.h:516
@ SEARCH_DWORD
Definition RequestStructures.h:517
@ SEARCH_PHYSICAL_FROM_VIRTUAL_MEMORY
Definition RequestStructures.h:506
@ SEARCH_PHYSICAL_MEMORY
Definition RequestStructures.h:504
@ SEARCH_VIRTUAL_MEMORY
Definition RequestStructures.h:505
#define SIZEOF_DEBUGGER_SEARCH_MEMORY
Definition RequestStructures.h:496
_Use_decl_annotations_ VOID SwitchToPreviousProcess(CR3_TYPE PreviousProcess)
Switch to previous process's cr3.
Definition SwitchLayout.c:125
_Use_decl_annotations_ CR3_TYPE SwitchToProcessMemoryLayoutByCr3(CR3_TYPE TargetCr3)
Switch to another process's cr3.
Definition SwitchLayout.c:99
_Use_decl_annotations_ CR3_TYPE SwitchToProcessMemoryLayout(UINT32 ProcessId)
Switch to another process's cr3.
Definition SwitchLayout.c:25
CR3 Structure.
Definition BasicTypes.h:130
UINT32 CountOf64Chunks
Definition RequestStructures.h:533
DEBUGGER_SEARCH_MEMORY_BYTE_SIZE ByteSize
Definition RequestStructures.h:532
DEBUGGER_SEARCH_MEMORY_TYPE MemoryType
Definition RequestStructures.h:531

◆ SearchAddressWrapper()

BOOLEAN SearchAddressWrapper ( PUINT64 AddressToSaveResults,
PDEBUGGER_SEARCH_MEMORY SearchMemRequest,
UINT64 StartAddress,
UINT64 EndAddress,
BOOLEAN IsDebuggeePaused,
PUINT32 CountOfMatchedCases )

The wrapper to check for validity of addresses and call the search routines for both physical and virtual memory.

This function can be called from vmx-root mode The address between start address and end address will be checked to make a contiguous address

Parameters
AddressToSaveResultsAddress to save the search results
SearchMemRequestrequest structure of searching memory
StartAddressstart address of searching based on target process
EndAddressstart address of searching based on target process
IsDebuggeePausedSet to true when the search is performed in the debugger mode
CountOfMatchedCasesNumber of matched cases
Returns
BOOLEAN Whether there was any error or not
968{
969 CR3_TYPE CurrentProcessCr3;
970 UINT64 BaseAddress = 0;
971 UINT64 RealPhysicalAddress = 0;
972 UINT64 TempValue = (UINT64)NULL;
973 UINT64 TempStartAddress = (UINT64)NULL;
974 BOOLEAN DoesBaseAddrSaved = FALSE;
975 BOOLEAN SearchResult = FALSE;
976
977 //
978 // Reset the count of matched cases
979 //
980 *CountOfMatchedCases = 0;
981
982 if (SearchMemRequest->MemoryType == SEARCH_VIRTUAL_MEMORY)
983 {
984 //
985 // It's a virtual address search
986 //
987
988 //
989 // Align the page and search with alignment
990 //
991 TempStartAddress = StartAddress;
992 StartAddress = (UINT64)PAGE_ALIGN(StartAddress);
993
994 if (IsDebuggeePaused)
995 {
996 //
997 // Switch to new process's memory layout
998 //
1000 }
1001 else
1002 {
1003 //
1004 // Switch to new process's memory layout
1005 //
1006 CurrentProcessCr3 = SwitchToProcessMemoryLayout(SearchMemRequest->ProcessId);
1007 }
1008
1009 //
1010 // We will try to find a contigues address
1011 //
1012 while (StartAddress < EndAddress)
1013 {
1014 //
1015 // Check if address is valid or not
1016 // Generally, we can use VirtualAddressToPhysicalAddressByProcessId
1017 // but let's not change the cr3 multiple times
1018 //
1019 TempValue = VirtualAddressToPhysicalAddress((PVOID)StartAddress);
1020
1021 if (TempValue != 0)
1022 {
1023 //
1024 // Address is valid, let's add a page size to it
1025 // nothing to do
1026 //
1027 if (!DoesBaseAddrSaved)
1028 {
1029 BaseAddress = TempStartAddress;
1030 DoesBaseAddrSaved = TRUE;
1031 }
1032 }
1033 else
1034 {
1035 //
1036 // Address is not valid anymore
1037 //
1038 break;
1039 }
1040
1041 //
1042 // Make the start address ready for next address
1043 //
1044 StartAddress += PAGE_SIZE;
1045 }
1046
1047 //
1048 // Restore the original process
1049 //
1050 SwitchToPreviousProcess(CurrentProcessCr3);
1051
1052 //
1053 // All of the address chunk was valid
1054 //
1055 if (DoesBaseAddrSaved && StartAddress > BaseAddress)
1056 {
1057 SearchResult = PerformSearchAddress(AddressToSaveResults,
1058 SearchMemRequest,
1059 BaseAddress,
1060 EndAddress,
1061 IsDebuggeePaused,
1062 CountOfMatchedCases);
1063 }
1064 else
1065 {
1066 //
1067 // There was an error, address was probably not contiguous
1068 //
1069 return FALSE;
1070 }
1071 }
1072 else if (SearchMemRequest->MemoryType == SEARCH_PHYSICAL_MEMORY)
1073 {
1074 //
1075 // when we reached here, we know that it's a valid physical memory,
1076 // so we change the structure and pass it as a virtual address to
1077 // the search function
1078 //
1079 RealPhysicalAddress = SearchMemRequest->Address;
1080
1081 //
1082 // Change the start address
1083 //
1084 if (IsDebuggeePaused)
1085 {
1086 SearchMemRequest->Address = PhysicalAddressToVirtualAddressOnTargetProcess((PVOID)StartAddress);
1087 EndAddress = PhysicalAddressToVirtualAddressOnTargetProcess((PVOID)EndAddress);
1088 }
1089 else if (SearchMemRequest->ProcessId == HANDLE_TO_UINT32(PsGetCurrentProcessId()))
1090 {
1091 SearchMemRequest->Address = PhysicalAddressToVirtualAddress(StartAddress);
1092 EndAddress = PhysicalAddressToVirtualAddress(EndAddress);
1093 }
1094 else
1095 {
1096 SearchMemRequest->Address = PhysicalAddressToVirtualAddressByProcessId((PVOID)StartAddress,
1097 SearchMemRequest->ProcessId);
1098 EndAddress = PhysicalAddressToVirtualAddressByProcessId((PVOID)EndAddress,
1099 SearchMemRequest->ProcessId);
1100 }
1101
1102 //
1103 // Change the type of memory
1104 //
1106
1107 //
1108 // Call the wrapper
1109 //
1110 SearchResult = PerformSearchAddress(AddressToSaveResults,
1111 SearchMemRequest,
1112 SearchMemRequest->Address,
1113 EndAddress,
1114 IsDebuggeePaused,
1115 CountOfMatchedCases);
1116
1117 //
1118 // Restore the previous state
1119 //
1120 SearchMemRequest->MemoryType = SEARCH_PHYSICAL_MEMORY;
1121 SearchMemRequest->Address = RealPhysicalAddress;
1122 }
1123
1124 return SearchResult;
1125}
_Use_decl_annotations_ UINT64 PhysicalAddressToVirtualAddressOnTargetProcess(PVOID PhysicalAddress)
Converts Physical Address to Virtual Address based on current process's kernel cr3.
Definition Conversion.c:137
_Use_decl_annotations_ UINT64 PhysicalAddressToVirtualAddressByProcessId(PVOID PhysicalAddress, UINT32 ProcessId)
Converts Physical Address to Virtual Address based on a specific process id.
Definition Conversion.c:42
_Use_decl_annotations_ UINT64 PhysicalAddressToVirtualAddress(UINT64 PhysicalAddress)
Converts Physical Address to Virtual Address.
Definition Conversion.c:22
BOOLEAN PerformSearchAddress(UINT64 *AddressToSaveResults, PDEBUGGER_SEARCH_MEMORY SearchMemRequest, UINT64 StartAddress, UINT64 EndAddress, BOOLEAN IsDebuggeePaused, PUINT32 CountOfMatchedCases)
Search on virtual memory (not work on physical memory)
Definition DebuggerCommands.c:676
#define PAGE_SIZE
Size of each page (4096 bytes)
Definition common.h:69
#define PAGE_ALIGN(Va)
Aligning a page.
Definition common.h:75