diff --git a/hyperdbg/hyperkd/code/driver/Ioctl.c b/hyperdbg/hyperkd/code/driver/Ioctl.c index 5ae146e7..d3e22af3 100644 --- a/hyperdbg/hyperkd/code/driver/Ioctl.c +++ b/hyperdbg/hyperkd/code/driver/Ioctl.c @@ -134,6 +134,74 @@ IoctlCheckIoctlAllowed(ULONG Ioctl) } } +/** + * @brief Resolve a process id to the CR3 the Intel PT engine should match. + * + * @details Intel PT's CR3 filter compares the live CR3, which differs between + * user and kernel mode when KVA shadowing (KPTI) is enabled: + * - kernel-mode runs under _KPROCESS.DirectoryTableBase + * - user-mode runs under _KPROCESS.UserDirectoryTableBase (shadow) + * So pick the kernel CR3 for kernel-only traces, otherwise the user + * (shadow) CR3 — falling back to the kernel CR3 when KVA shadowing is + * off (UserDirectoryTableBase has a zero page base in that case, i.e. + * user-mode also runs under the kernel CR3). + * + * @param ProcessId Target process id + * @param TraceUser Whether CPL>0 will be traced + * @param TraceKernel Whether CPL==0 will be traced + * + * @return UINT64 CR3 page base (low 12 bits cleared), or 0 if the pid is gone + */ +static UINT64 +DrvResolvePtTargetCr3(UINT32 ProcessId, BOOLEAN TraceUser, BOOLEAN TraceKernel) +{ + // + // _KPROCESS.UserDirectoryTableBase offset (x64 Windows 10 1803+ / 11). + // Only this one constant is build-specific; adjust it if the user CR3 + // ever reads wrong on a newer kernel. + // + const ULONG UserDirTableBaseOffset = 0x388; + + PEPROCESS TargetProcess; + UINT64 KernelCr3; + UINT64 UserCr3; + UINT64 Chosen; + + if (PsLookupProcessByProcessId((HANDLE)(ULONG_PTR)ProcessId, &TargetProcess) != STATUS_SUCCESS) + { + return 0; + } + + KernelCr3 = (UINT64)((NT_KPROCESS *)TargetProcess)->DirectoryTableBase; + UserCr3 = *(UINT64 *)((UCHAR *)TargetProcess + UserDirTableBaseOffset); + + ObDereferenceObject(TargetProcess); + + if (TraceKernel && !TraceUser) + { + // + // Kernel-only trace — match the kernel CR3 + // + Chosen = KernelCr3; + } + else if ((UserCr3 & ~0xFFFULL) != 0) + { + // + // KVA shadowing on — user mode runs under the shadow CR3 + // + Chosen = UserCr3; + } + else + { + // + // KVA shadowing off — user mode runs under the kernel CR3 + // + Chosen = KernelCr3; + } + + return Chosen & ~0xFFFULL; +} + /** * @brief IOCTL Dispatcher for Basic IOCTLs (initialization and event registration) * @@ -1265,27 +1333,6 @@ DrvDispatchVmmIoControl(PIRP Irp, PIO_STACK_LOCATION IrpStack, BOOLEAN * DoNotCh // DrvAdjustStatusAndSetOutputSize(SIZEOF_DEBUGGER_QUERY_ACTIVE_PROCESSES_OR_THREADS, DoNotChangeInformation, Irp, &Status); - // - // If the caller asked to filter by a process id (and didn't - // already provide an explicit CR3), resolve the PID to the CR3 - // the PT engine should match here — hyperkd owns the NT_KPROCESS - // layout, whereas the hypertrace engine only consumes a CR3. The - // kernel/user CR3 is chosen based on the requested trace mode so - // it works whether or not KVA shadowing (KPTI) is enabled. - // - if (HyperTracePtOperationRequest->TargetProcessId != 0 && - HyperTracePtOperationRequest->TargetCr3 == 0) - { - HyperTracePtOperationRequest->TargetCr3 = - DrvResolvePtTargetCr3(HyperTracePtOperationRequest->TargetProcessId, - (BOOLEAN)(HyperTracePtOperationRequest->TraceUser != 0), - (BOOLEAN)(HyperTracePtOperationRequest->TraceKernel != 0)); - } - - // - // Perform the HyperTrace PT operation - // - HyperTracePtPerformOperation(HyperTracePtOperationRequest); break; case IOCTL_GET_LIST_OF_THREADS_AND_PROCESSES: @@ -1521,6 +1568,7 @@ DrvDispatchHyperTraceIoControl(PIRP Irp, PIO_STACK_LOCATION IrpStack, BOOLEAN * PHYPERTRACE_LBR_OPERATION_PACKETS HyperTraceLbrOperationRequest; PHYPERTRACE_LBR_DUMP_PACKETS HyperTraceLbrdumpRequest; PHYPERTRACE_PT_OPERATION_PACKETS HyperTracePtOperationRequest; + PHYPERTRACE_PT_MMAP_PACKETS HyperTracePtMmapRequest; ULONG InBuffLength; ULONG OutBuffLength; NTSTATUS Status = STATUS_SUCCESS; @@ -1614,6 +1662,23 @@ DrvDispatchHyperTraceIoControl(PIRP Irp, PIO_STACK_LOCATION IrpStack, BOOLEAN * break; } + // + // If the caller asked to filter by a process id (and didn't + // already provide an explicit CR3), resolve the PID to the CR3 + // the PT engine should match here — hyperkd owns the NT_KPROCESS + // layout, whereas the hypertrace engine only consumes a CR3. The + // kernel/user CR3 is chosen based on the requested trace mode so + // it works whether or not KVA shadowing (KPTI) is enabled. + // + if (HyperTracePtOperationRequest->TargetProcessId != 0 && + HyperTracePtOperationRequest->TargetCr3 == 0) + { + HyperTracePtOperationRequest->TargetCr3 = + DrvResolvePtTargetCr3(HyperTracePtOperationRequest->TargetProcessId, + (BOOLEAN)(HyperTracePtOperationRequest->TraceUser != 0), + (BOOLEAN)(HyperTracePtOperationRequest->TraceKernel != 0)); + } + // // Perform the HyperTrace PT operation // @@ -1622,7 +1687,35 @@ DrvDispatchHyperTraceIoControl(PIRP Irp, PIO_STACK_LOCATION IrpStack, BOOLEAN * // // Adjust the status and output size // - DrvAdjustStatusAndSetOutputSize(SIZEOF_HYPERTRACE_PT_OPERATION_PACKETS, DoNotChangeInformation, Irp, &Status); + DrvAdjustStatusAndSetOutputSize(SIZEOF_HYPERTRACE_LBR_DUMP_PACKETS, DoNotChangeInformation, Irp, &Status); + + break; + + case IOCTL_PERFORM_HYPERTRACE_PT_MMAP: + + // + // Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP + // + if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_HYPERTRACE_PT_MMAP_PACKETS, + (PVOID *)&HyperTracePtMmapRequest, + Irp, + IrpStack, + &InBuffLength, + &OutBuffLength)) + { + Status = STATUS_INVALID_PARAMETER; + break; + } + + // + // Map the per-CPU PT output buffers into the calling user process + // + HyperTracePtMmap(HyperTracePtMmapRequest); + + // + // Adjust the status and output size + // + DrvAdjustStatusAndSetOutputSize(SIZEOF_HYPERTRACE_PT_MMAP_PACKETS, DoNotChangeInformation, Irp, &Status); break; diff --git a/hyperdbg/hypertrace/header/pch.h b/hyperdbg/hypertrace/header/pch.h index a6f7b465..4e591600 100644 --- a/hyperdbg/hypertrace/header/pch.h +++ b/hyperdbg/hypertrace/header/pch.h @@ -67,12 +67,6 @@ #include "platform/kernel/header/PlatformIo.h" #include "platform/kernel/header/PlatformEvent.h" -// -// DPC and broadcasting function headers -// -#include "broadcast/DpcRoutines.h" -#include "broadcast/Broadcast.h" - // // Unload function (to be called when the driver is unloaded) // @@ -113,6 +107,12 @@ #include "pt/Pt.h" #include "api/PtApi.h" +// +// DPC and broadcasting function headers +// +#include "broadcast/DpcRoutines.h" +#include "broadcast/Broadcast.h" + // // Export functions // diff --git a/hyperdbg/include/platform/general/header/Environment.h b/hyperdbg/include/platform/general/header/Environment.h index 652f8e3b..caaa22e7 100644 --- a/hyperdbg/include/platform/general/header/Environment.h +++ b/hyperdbg/include/platform/general/header/Environment.h @@ -30,51 +30,49 @@ # error "This code cannot compile on non-Windows, non-Linux, and non-BSD platforms" #endif - - #ifdef HYPERDBG_ENV_LINUX // SAL annotations -# define _In_ -# define _Out_ -# define _Inout_ -# define _In_opt_ -# define _Out_opt_ -# define _In_z_ -# define _Outptr_ -# define _In_reads_bytes_(x) -# define _Out_writes_bytes_(x) -# define _Inout_updates_bytes_all_(x) +# define _In_ +# define _Out_ +# define _Inout_ +# define _In_opt_ +# define _Out_opt_ +# define _In_z_ +# define _Outptr_ +# define _In_reads_bytes_(x) +# define _Out_writes_bytes_(x) +# define _Inout_updates_bytes_all_(x) // wchar_t is a C++ built-in but needs this header in C -# include +# include // Windows string/char types -typedef char TCHAR; -typedef char * LPTSTR; -typedef const char * LPCTSTR; -typedef const char * LPCSTR; -typedef char * LPSTR; -typedef const char * PCSTR; -typedef char * PSTR; -typedef wchar_t * PWCHAR; +typedef char TCHAR; +typedef char * LPTSTR; +typedef const char * LPCTSTR; +typedef const char * LPCSTR; +typedef char * LPSTR; +typedef const char * PCSTR; +typedef char * PSTR; +typedef short * PWCHAR; // Windows socket type (Linux sockets are plain int) -typedef int SOCKET; -# define INVALID_SOCKET ((SOCKET)(-1)) -# define SOCKET_ERROR (-1) +typedef int SOCKET; +# define INVALID_SOCKET ((SOCKET)(-1)) +# define SOCKET_ERROR (-1) // Windows calling convention (no-op on Linux) -# define WINAPI +# define WINAPI // Windows module handle (equivalent to dlopen's void * on Linux) typedef void * HMODULE; // Misc Windows macros -# define UNREFERENCED_PARAMETER(P) ((void)(P)) +# define UNREFERENCED_PARAMETER(P) ((void)(P)) // Win32 wait/event constants (used by the cross-platform sync wrappers) -# define INFINITE 0xFFFFFFFF -# define WAIT_OBJECT_0 0x00000000 +# define INFINITE 0xFFFFFFFF +# define WAIT_OBJECT_0 0x00000000 #endif // HYPERDBG_ENV_LINUX diff --git a/hyperdbg/include/platform/user/code/platform-lib-calls.c b/hyperdbg/include/platform/user/code/platform-lib-calls.c index d3ebbcae..c52759ec 100644 --- a/hyperdbg/include/platform/user/code/platform-lib-calls.c +++ b/hyperdbg/include/platform/user/code/platform-lib-calls.c @@ -218,13 +218,12 @@ PlatformGetCurrentProcessName(VOID) // // Return the basename (strip the directory part) // + char * LastSeparator = strrchr(ProcessNameBuf, '\\'); + if (LastSeparator) { - char * LastSeparator = strrchr(ProcessNameBuf, '\\'); - if (LastSeparator) - { - return LastSeparator + 1; - } + return LastSeparator + 1; } + return ProcessNameBuf; #elif defined(__linux__) diff --git a/hyperdbg/libhyperdbg/code/debugger/commands/debugging-commands/core.cpp b/hyperdbg/libhyperdbg/code/debugger/commands/debugging-commands/core.cpp index de8cd321..2a1852db 100644 --- a/hyperdbg/libhyperdbg/code/debugger/commands/debugging-commands/core.cpp +++ b/hyperdbg/libhyperdbg/code/debugger/commands/debugging-commands/core.cpp @@ -82,11 +82,6 @@ CommandCore(vector CommandTokens, string Command) // // Send the changing core packet // -#ifdef _WIN32 KdSendSwitchCorePacketToDebuggee(TargetCore); -#else - // TODO: kernel debugger communication is not yet implemented on Linux - ShowMessages("err, switching cores is not supported on Linux yet\n\n"); -#endif } } diff --git a/hyperdbg/libhyperdbg/code/debugger/commands/extension-commands/pt.cpp b/hyperdbg/libhyperdbg/code/debugger/commands/extension-commands/pt.cpp index 79f4fc6f..e97e4a35 100644 --- a/hyperdbg/libhyperdbg/code/debugger/commands/extension-commands/pt.cpp +++ b/hyperdbg/libhyperdbg/code/debugger/commands/extension-commands/pt.cpp @@ -163,7 +163,7 @@ HyperDbgPtMmapSendRequest(HYPERTRACE_PT_MMAP_PACKETS * MmapRequest) return FALSE; } - AssertShowMessageReturnStmt(g_DeviceHandle, ASSERT_MESSAGE_DRIVER_NOT_LOADED, AssertReturnFalse); + AssertShowMessageReturnStmt(g_IsHyperTraceModuleLoaded, g_DeviceHandle, ASSERT_MESSAGE_HYPERTRACE_NOT_LOADED, ASSERT_MESSAGE_DRIVER_NOT_LOADED, AssertReturnFalse); Status = DeviceIoControl( g_DeviceHandle, // Handle to device