mirror of
https://github.com/HyperDbg/HyperDbg.git
synced 2026-07-10 01:29:59 +00:00
Fix adding missing IOCTL for Intel PT
This commit is contained in:
parent
ade6877a7d
commit
df12e9fd79
6 changed files with 152 additions and 67 deletions
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
//
|
||||
|
|
|
|||
|
|
@ -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 <wchar.h>
|
||||
# include <wchar.h>
|
||||
|
||||
// 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
|
||||
|
|
|
|||
|
|
@ -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__)
|
||||
|
|
|
|||
|
|
@ -82,11 +82,6 @@ CommandCore(vector<CommandToken> 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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue