diff --git a/CHANGELOG.md b/CHANGELOG.md index bba99790..71b3a84b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.11.0.0] - 2024-XX-XX +New release of the HyperDbg Debugger. + +### Added +- Added the local APIC command (xAPIC and x2APIC modes) ([link](https://docs.hyperdbg.org/commands/extension-commands/apic)) + +### Changed + ## [0.10.2.0] - 2024-10-11 New release of the HyperDbg Debugger. diff --git a/hyperdbg/hyperhv/code/devices/Apic.c b/hyperdbg/hyperhv/code/devices/Apic.c index 1711213b..9a2d4410 100644 --- a/hyperdbg/hyperhv/code/devices/Apic.c +++ b/hyperdbg/hyperhv/code/devices/Apic.c @@ -1,8 +1,11 @@ /** - * @file Apic.h + * @file Apic.c * @author Sina Karvandi (sina@hyperdbg.org) * @brief Routines for Advanced Programmable Interrupt Controller (APIC) - * @details The code is derived from (https://www.cpl0.com/blog/?p=46) + * @details The code is derived from (https://www.cpl0.com/blog/?p=46) and the code + * for showing the APIC details in the XAPIC is derived from bitdefender/napoca project + * which is enhanced to support X2APIC mode in HyperDbg + * * @version 0.1 * @date 2020-12-31 * @@ -11,6 +14,183 @@ */ #include "pch.h" +/** + * @brief Perfom read I/O APIC + * + * @param IoApicBaseVa + * @param Reg + * + * @return UINT64 + */ +UINT64 +IoApicRead(volatile IO_APIC_ENT * IoApicBaseVa, UINT32 Reg) +{ + UINT32 High = 0, Low; + + IoApicBaseVa->Reg = Reg; + Low = IoApicBaseVa->Data; + + if (Reg >= IOAPIC_REDTBL(0) && Reg < IOAPIC_REDTBL(IOAPIC_REDTBL_MAX)) + { + // ASSERT(Reg % 2 == 0); + Reg++; + IoApicBaseVa->Reg = Reg; + High = IoApicBaseVa->Data; + return IOAPIC_APPEND_QWORD(High, Low); + } + else + { + return Low; + } +} + +/** + * @brief Perfom write to I/O APIC + * + * @param IoApicBaseVa + * @param Reg + * @param Data + * + * @return VOID + */ +VOID +IoApicWrite(volatile IO_APIC_ENT * IoApicBaseVa, UINT32 Reg, UINT64 Data) +{ + IoApicBaseVa->Reg = Reg; + IoApicBaseVa->Data = IOAPIC_LOW_DWORD(Data); + + if (Reg >= IOAPIC_REDTBL(0) && Reg < IOAPIC_REDTBL(IOAPIC_REDTBL_MAX)) + { + // ASSERT(Reg % 2 == 0); + Reg++; + IoApicBaseVa->Reg = Reg; + IoApicBaseVa->Data = IOAPIC_HIGH_DWORD(Data); + } +} + +/** + * @brief Dump redirections + * + * @param Desc + * @param CommandReg + * @param DestSelf + * @param Lh + * @param Ll + * + * @return ULONG + */ +ULONG +ApicDumpRedir(PUCHAR Desc, + BOOLEAN CommandReg, + BOOLEAN DestSelf, + ULONGLONG Lh, + ULONGLONG Ll) +{ + static PUCHAR DelMode[] = { + (PUCHAR) "FixedDel", + (PUCHAR) "LowestDl", + (PUCHAR) "res010 ", + (PUCHAR) "remoterd", + (PUCHAR) "NMI ", + (PUCHAR) "RESET ", + (PUCHAR) "res110 ", + (PUCHAR) "ExtINTA "}; + + static PUCHAR DesShDesc[] = {(PUCHAR) "", + (PUCHAR) " Dest=Self", + (PUCHAR) " Dest=ALL", + (PUCHAR) " Dest=Othrs"}; + + ULONG Del, Dest, Delstat, Rirr, Trig, Masked, Destsh; + + Del = (Ll >> 8) & 0x7; + Dest = (Ll >> 11) & 0x1; + Delstat = (Ll >> 12) & 0x1; + Rirr = (Ll >> 14) & 0x1; + Trig = (Ll >> 15) & 0x1; + Masked = (Ll >> 16) & 0x1; + Destsh = (Ll >> 18) & 0x3; + + if (CommandReg) + { + // + // command reg's don't have a mask + // + Masked = 0; + } + + Log("%s: %016llx Vec:%02X %s ", + Desc, + Ll, + Ll & 0xff, + DelMode[Del]); + + if (DestSelf) + { + Log("%s", DesShDesc[1]); + } + else if (CommandReg && Destsh) + { + Log("%s", DesShDesc[Destsh]); + } + else + { + if (Dest) + { + Log("Lg:%08x", Lh); + } + else + { + Log("PhysDest:%02X", (Lh >> 56) & 0xFF); + } + } + + Log("%s %s %s %s\n", + Delstat ? "-Pend" : " ", + Trig ? "level" : "edge ", + Rirr ? "rirr" : " ", + Masked ? "masked" : " "); + + return 0; +} + +/** + * @brief Dump I/O APIC + * + * @return VOID + */ +VOID +ApicDumpIoApic() +{ + UINT32 Index, Max; + UCHAR Desc[40]; + UINT64 ll, lh; + + UINT64 ApicBasePa = IO_APIC_DEFAULT_BASE_ADDR; + + ll = IoApicRead(g_IoApicBase, IO_VERS_REGISTER), + + Max = (ll >> 16) & 0xff; + + Log("IoApic @ %08x ID:%x (%x) Arb:%x\n", + ApicBasePa, + IoApicRead(g_IoApicBase, IO_ID_REGISTER) >> 24, + ll & 0xFF, + IoApicRead(g_IoApicBase, IO_ARB_ID_REGISTER)); + + // + // Dump inti table + // + Max *= 2; + for (Index = 0; Index <= Max; Index += 2) + { + ll = IoApicRead(g_IoApicBase, IO_REDIR_BASE + Index + 0); + lh = IoApicRead(g_IoApicBase, IO_REDIR_BASE + Index + 1); + sprintf((CHAR *)Desc, "Inti%02X.", Index / 2); + ApicDumpRedir(Desc, FALSE, FALSE, lh, ll); + } +} + /** * @brief Trigger NMI on XAPIC * @param Low @@ -38,6 +218,130 @@ X2ApicIcrWrite(UINT32 Low, UINT32 High) __writemsr(X2_MSR_BASE + TO_X2(ICROffset), ((UINT64)High << 32) | Low); } +/** + * @brief Read x2APIC mode + * @param Offset + * + * @return UINT64 + */ +UINT64 +X2ApicRead(UINT32 Offset) +{ + return __readmsr(X2_MSR_BASE + TO_X2(Offset)); +} + +/** + * @brief Store the local APIC in XAPIC mode + * + * @return BOOLEAN + */ +BOOLEAN +ApicStoretLocalApicInXApicMode(PLAPIC_PAGE LApicBuffer) +{ + volatile LAPIC_PAGE * LocalApicVa = g_ApicBase; + + // + // Check if the base virtual address of local APIC is valid or not + // + if (!g_ApicBase) + { + return FALSE; + } + + // + // Store fields + // + LApicBuffer->Id = LocalApicVa->Id; + LApicBuffer->Version = LocalApicVa->Version; + LApicBuffer->SpuriousInterruptVector = LocalApicVa->SpuriousInterruptVector; + LApicBuffer->TPR = LocalApicVa->TPR; + LApicBuffer->ProcessorPriority = LocalApicVa->ProcessorPriority; + LApicBuffer->LogicalDestination = LocalApicVa->LogicalDestination; + LApicBuffer->ErrorStatus = LocalApicVa->ErrorStatus; + LApicBuffer->LvtLINT0 = LocalApicVa->LvtLINT0; + LApicBuffer->LvtLINT1 = LocalApicVa->LvtLINT1; + LApicBuffer->LvtCmci = LocalApicVa->LvtCmci; + LApicBuffer->LvtPerfMonCounters = LocalApicVa->LvtPerfMonCounters; + LApicBuffer->LvtTimer = LocalApicVa->LvtTimer; + LApicBuffer->LvtThermalSensor = LocalApicVa->LvtThermalSensor; + LApicBuffer->LvtError = LocalApicVa->LvtError; + LApicBuffer->InitialCount = LocalApicVa->InitialCount; + LApicBuffer->CurrentCount = LocalApicVa->CurrentCount; + LApicBuffer->DivideConfiguration = LocalApicVa->DivideConfiguration; + + // + // Save the ISR, TMR and IRR + // + for (UINT32 i = 0; i < 8; i++) + { + LApicBuffer->ISR[i * 4] = LocalApicVa->ISR[i * 4]; + } + + for (UINT32 i = 0; i < 8; i++) + { + LApicBuffer->TMR[i * 4] = LocalApicVa->TMR[i * 4]; + } + + for (UINT32 i = 0; i < 8; i++) + { + LApicBuffer->IRR[i * 4] = LocalApicVa->IRR[i * 4]; + } + + return TRUE; +} + +/** + * @brief Store the local APIC in X2APIC mode + * + * @return BOOLEAN + */ +BOOLEAN +ApicStoreLocalApicInX2ApicMode(PLAPIC_PAGE LApicBuffer) +{ + ApicDumpIoApic(); + + // + // Store fields + // + LApicBuffer->Id = (UINT32)X2ApicRead(APIC_ID); + LApicBuffer->Version = (UINT32)X2ApicRead(APIC_VERSION); + LApicBuffer->SpuriousInterruptVector = (UINT32)X2ApicRead(APIC_SPURIOUS_INTERRUPT_VECTOR); + LApicBuffer->TPR = (UINT32)X2ApicRead(APIC_TASK_PRIORITY); + LApicBuffer->ProcessorPriority = (UINT32)X2ApicRead(APIC_PROCESSOR_PRIORITY); + LApicBuffer->LogicalDestination = (UINT32)X2ApicRead(APIC_LOGICAL_DESTINATION); + LApicBuffer->ErrorStatus = (UINT32)X2ApicRead(APIC_ERROR_STATUS); + LApicBuffer->LvtLINT0 = (UINT32)X2ApicRead(APIC_LVT_LINT0); + LApicBuffer->LvtLINT1 = (UINT32)X2ApicRead(APIC_LVT_LINT1); + LApicBuffer->LvtCmci = (UINT32)X2ApicRead(APIC_LVT_CORRECTED_MACHINE_CHECK_INTERRUPT); + LApicBuffer->LvtPerfMonCounters = (UINT32)X2ApicRead(APIC_LVT_PERFORMANCE_MONITORING_COUNTERS); + LApicBuffer->LvtTimer = (UINT32)X2ApicRead(APIC_LVT_TIMER); + LApicBuffer->LvtThermalSensor = (UINT32)X2ApicRead(APIC_LVT_THERMAL_SENSOR); + LApicBuffer->LvtError = (UINT32)X2ApicRead(APIC_LVT_ERROR); + LApicBuffer->InitialCount = (UINT32)X2ApicRead(APIC_INITIAL_COUNT); + LApicBuffer->CurrentCount = (UINT32)X2ApicRead(APIC_CURRENT_COUNT); + LApicBuffer->DivideConfiguration = (UINT32)X2ApicRead(APIC_DIVIDE_CONFIGURATION); + + // + // Save the ISR, TMR and IRR + // + for (UINT32 i = 0; i < 8; i++) + { + LApicBuffer->ISR[i * 4] = (UINT32)X2ApicRead(APIC_IN_SERVICE_BITS_31_0 + (0x10 * i)); + } + + for (UINT32 i = 0; i < 8; i++) + { + LApicBuffer->TMR[i * 4] = (UINT32)X2ApicRead(APIC_TRIGGER_MODE_BITS_31_0 + (0x10 * i)); + } + + for (UINT32 i = 0; i < 8; i++) + { + LApicBuffer->IRR[i * 4] = (UINT32)X2ApicRead(APIC_INTERRUPT_REQUEST_BITS_31_0 + (0x10 * i)); + } + + return TRUE; +} + /** * @brief Trigger NMI on X2APIC or APIC based on Current system * @@ -56,6 +360,28 @@ ApicTriggerGenericNmi() } } +/** + * @brief Stire the details of APIC in xAPIC and x2APIC mode + * @param LApicBuffer + * @param IsUsingX2APIC + * + * @return BOOLEAN + */ +BOOLEAN +ApicStoreLocalApicFields(PLAPIC_PAGE LApicBuffer, PBOOLEAN IsUsingX2APIC) +{ + if (g_CompatibilityCheck.IsX2Apic) + { + *IsUsingX2APIC = TRUE; + return ApicStoreLocalApicInX2ApicMode(LApicBuffer); + } + else + { + *IsUsingX2APIC = FALSE; + return ApicStoretLocalApicInXApicMode(LApicBuffer); + } +} + /** * @brief Initialize APIC * @@ -66,14 +392,41 @@ ApicInitialize() { UINT64 ApicBaseMSR; PHYSICAL_ADDRESS PaApicBase; + PHYSICAL_ADDRESS PaIoApicBase; + + ApicBaseMSR = __readmsr(IA32_APIC_BASE); - ApicBaseMSR = __readmsr(0x1B); if (!(ApicBaseMSR & (1 << 11))) + { return FALSE; + } + + // + // Map I/O APIC default base address + // + // The exact APIC base address should be read from MADT table (ACPI) + // However, we don't have an ACPI parser right now, but the address + // is proved to stay at this (default) physical address since Intel + // recommends OS/BIOS to not relocate it, but it could be relocated + // however, this address is valid for almost all of the systems + // + PaIoApicBase.QuadPart = IO_APIC_DEFAULT_BASE_ADDR & 0xFFFFFF000; + g_IoApicBase = MmMapIoSpace(PaIoApicBase, 0x1000, MmNonCached); + + if (!g_IoApicBase) + { + // + // Not gonna fail the initialization since the IOAPIC might be relocated by + // either OS/BIOS + // + + // return FALSE; + } if (ApicBaseMSR & (1 << 10)) { g_CompatibilityCheck.IsX2Apic = TRUE; + return FALSE; } else @@ -82,10 +435,13 @@ ApicInitialize() g_ApicBase = MmMapIoSpace(PaApicBase, 0x1000, MmNonCached); if (!g_ApicBase) + { return FALSE; + } g_CompatibilityCheck.IsX2Apic = FALSE; } + return TRUE; } @@ -98,10 +454,20 @@ VOID ApicUninitialize() { // - // Unmap I/O Base + // Unmap Local APIC base // if (g_ApicBase) + { MmUnmapIoSpace(g_ApicBase, 0x1000); + } + + // + // Unmap I/O APIC base + // + if (g_IoApicBase) + { + MmUnmapIoSpace(g_IoApicBase, 0x1000); + } } /** diff --git a/hyperdbg/hyperhv/code/interface/Export.c b/hyperdbg/hyperhv/code/interface/Export.c index 3c2132af..bee44b89 100644 --- a/hyperdbg/hyperhv/code/interface/Export.c +++ b/hyperdbg/hyperhv/code/interface/Export.c @@ -813,3 +813,16 @@ VmFuncEnableAndCheckForPreviousExternalInterrupts(UINT32 CoreId) { HvEnableAndCheckForPreviousExternalInterrupts(&g_GuestState[CoreId]); } + +/** + * @brief Store the details Local APIC in xapic or x2apic modes + * @param LocalApicBuffer + * @param IsUsingX2APIC + * + * @return VOID + */ +BOOLEAN +VmFuncApicStoreLocalApicFields(PLAPIC_PAGE LocalApicBuffer, PBOOLEAN IsUsingX2APIC) +{ + return ApicStoreLocalApicFields(LocalApicBuffer, IsUsingX2APIC); +} diff --git a/hyperdbg/hyperhv/header/devices/Apic.h b/hyperdbg/hyperhv/header/devices/Apic.h index 341d2b96..4a69b51d 100644 --- a/hyperdbg/hyperhv/header/devices/Apic.h +++ b/hyperdbg/hyperhv/header/devices/Apic.h @@ -26,7 +26,7 @@ #define APIC_LVR 0x30 #define APIC_LVR_MASK 0xFF00FF -#define GET_APIC_VERSION(x) ((x)&0xFFu) +#define GET_APIC_VERSION(x) ((x) & 0xFFu) #define GET_APIC_MAXLVT(x) (((x) >> 16) & 0xFFu) #define APIC_INTEGRATED(x) (1) @@ -143,6 +143,64 @@ #define APIC_BASE_MSR 0x800 +////////////////////////////////////////////////// +// I/O APIC // +////////////////////////////////////////////////// + +typedef struct _IO_APIC_ENT +{ + UINT32 Reg; + UINT32 Pad[3]; + UINT32 Data; + +} IO_APIC_ENT, *PIO_APIC_ENT; + +#define IO_APIC_DEFAULT_BASE_ADDR 0xFEC00000 // Default physical address of IO APIC + +#define IOAPIC_APPEND_QWORD(hi, lo) (((UINT64)(hi) << 32) | (UINT64)(lo)) +#define IOAPIC_LOW_DWORD(x) ((UINT32)(x)) +#define IOAPIC_HIGH_DWORD(x) ((UINT32)((x) >> 32)) + +#define IOAPIC_REDTBL(x) (0x10 + (x) * 2) +#define IOAPIC_REDTBL_MAX (24) + +#define LU_SIZE 0x400 + +#define LU_ID_REGISTER 0x00000020 +#define LU_VERS_REGISTER 0x00000030 +#define LU_TPR 0x00000080 +#define LU_APR 0x00000090 +#define LU_PPR 0x000000A0 +#define LU_EOI 0x000000B0 +#define LU_REMOTE_REGISTER 0x000000C0 + +#define LU_DEST 0x000000D0 +#define LU_DEST_FORMAT 0x000000E0 + +#define LU_SPURIOUS_VECTOR 0x000000F0 +#define LU_FAULT_VECTOR 0x00000370 + +#define LU_ISR_0 0x00000100 +#define LU_TMR_0 0x00000180 +#define LU_IRR_0 0x00000200 +#define LU_ERROR_STATUS 0x00000280 +#define LU_INT_CMD_LOW 0x00000300 +#define LU_INT_CMD_HIGH 0x00000310 +#define LU_TIMER_VECTOR 0x00000320 +#define LU_INT_VECTOR_0 0x00000350 +#define LU_INT_VECTOR_1 0x00000360 +#define LU_INITIAL_COUNT 0x00000380 +#define LU_CURRENT_COUNT 0x00000390 +#define LU_DIVIDER_CONFIG 0x000003E0 + +#define IO_REGISTER_SELECT 0x00000000 +#define IO_REGISTER_WINDOW 0x00000010 + +#define IO_ID_REGISTER 0x00000000 +#define IO_VERS_REGISTER 0x00000001 +#define IO_ARB_ID_REGISTER 0x00000002 +#define IO_REDIR_BASE 0x00000010 + ////////////////////////////////////////////////// // Functions // ////////////////////////////////////////////////// @@ -153,6 +211,9 @@ ApicInitialize(); VOID ApicUninitialize(); +BOOLEAN +ApicStoreLocalApicFields(PLAPIC_PAGE LApicBuffer, PBOOLEAN IsUsingX2APIC); + VOID ApicSelfIpi(UINT32 Vector); diff --git a/hyperdbg/hyperhv/header/globals/GlobalVariables.h b/hyperdbg/hyperhv/header/globals/GlobalVariables.h index 85c720fd..8f525866 100644 --- a/hyperdbg/hyperhv/header/globals/GlobalVariables.h +++ b/hyperdbg/hyperhv/header/globals/GlobalVariables.h @@ -75,11 +75,17 @@ BOOLEAN g_IsEptHook2sDetourListInitialized; BOOLEAN g_TransparentMode; /** - * @brief APIC Base + * @brief Local APIC Base * */ VOID * g_ApicBase; +/** + * @brief I/O APIC Base + * + */ +VOID * g_IoApicBase; + /** * @brief check for broadcasting NMI mechanism support and its * initialization diff --git a/hyperdbg/hyperkd/code/debugger/commands/ExtensionCommands.c b/hyperdbg/hyperkd/code/debugger/commands/ExtensionCommands.c index 48527e36..30362b6f 100644 --- a/hyperdbg/hyperkd/code/debugger/commands/ExtensionCommands.c +++ b/hyperdbg/hyperkd/code/debugger/commands/ExtensionCommands.c @@ -12,6 +12,50 @@ */ #include "pch.h" +/** + * @brief Perform actions regarding APIC + * + * @param ApicRequest + * + * @return UINT32 Size to send to the debuggee + */ +UINT32 +ExtensionCommandPerformActionsForApicRequests(PDEBUGGER_APIC_REQUEST ApicRequest) +{ + BOOLEAN IsUsingX2APIC = FALSE; + PLAPIC_PAGE BufferToStoreLApic = (LAPIC_PAGE *)(((CHAR *)ApicRequest) + sizeof(DEBUGGER_APIC_REQUEST)); + + if (ApicRequest->ApicType == DEBUGGER_APIC_REQUEST_TYPE_READ_LOCAL_APIC) + { + if (VmFuncApicStoreLocalApicFields(BufferToStoreLApic, &IsUsingX2APIC)) + { + // + // The status was okay + // + ApicRequest->KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL; + ApicRequest->IsUsingX2APIC = IsUsingX2APIC; + + return sizeof(DEBUGGER_APIC_REQUEST) + sizeof(LAPIC_PAGE); + } + else + { + // + // There was an error performing the action + // + ApicRequest->KernelStatus = DEBUGGER_ERROR_APIC_ACTIONS_ERROR; + return sizeof(DEBUGGER_APIC_REQUEST); + } + } + else + { + // + // Invalid request + // + ApicRequest->KernelStatus = DEBUGGER_ERROR_APIC_ACTIONS_ERROR; + return sizeof(DEBUGGER_APIC_REQUEST); + } +} + /** * @brief routines for !va2pa and !pa2va commands * diff --git a/hyperdbg/hyperkd/code/debugger/kernel-level/Kd.c b/hyperdbg/hyperkd/code/debugger/kernel-level/Kd.c index c52ac38d..0e18e0b5 100644 --- a/hyperdbg/hyperkd/code/debugger/kernel-level/Kd.c +++ b/hyperdbg/hyperkd/code/debugger/kernel-level/Kd.c @@ -2308,6 +2308,7 @@ KdDispatchAndPerformCommandsFromDebugger(PROCESSOR_DEBUGGING_STATE * DbgState) PDEBUGGER_SEARCH_MEMORY SearchQueryPacket; PDEBUGGEE_BP_PACKET BpPacket; PDEBUGGER_READ_PAGE_TABLE_ENTRIES_DETAILS PtePacket; + PDEBUGGER_APIC_REQUEST ApicPacket; PDEBUGGER_PAGE_IN_REQUEST PageinPacket; PDEBUGGER_VA2PA_AND_PA2VA_COMMANDS Va2paPa2vaPacket; PDEBUGGEE_BP_LIST_OR_MODIFY_PACKET BpListOrModifyPacket; @@ -2995,6 +2996,25 @@ KdDispatchAndPerformCommandsFromDebugger(PROCESSOR_DEBUGGING_STATE * DbgState) break; + case DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_PERFORM_ACTIONS_ON_APIC: + + ApicPacket = (DEBUGGER_APIC_REQUEST *)(((CHAR *)TheActualPacket) + sizeof(DEBUGGER_REMOTE_PACKET)); + + // + // Call APIC handler (size to send is computed by this function) + // + SizeToSend = ExtensionCommandPerformActionsForApicRequests(ApicPacket); + + // + // Send the result of the APIC requests back to the debuggee + // + KdResponsePacketToDebugger(DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGEE_TO_DEBUGGER, + DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_DEBUGGEE_RESULT_OF_APIC_REQUESTS, + (CHAR *)ApicPacket, + SizeToSend); + + break; + case DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_INJECT_PAGE_FAULT: PageinPacket = (DEBUGGER_PAGE_IN_REQUEST *)(((CHAR *)TheActualPacket) + sizeof(DEBUGGER_REMOTE_PACKET)); diff --git a/hyperdbg/hyperkd/code/driver/Ioctl.c b/hyperdbg/hyperkd/code/driver/Ioctl.c index 95b612b8..d317ca9b 100644 --- a/hyperdbg/hyperkd/code/driver/Ioctl.c +++ b/hyperdbg/hyperkd/code/driver/Ioctl.c @@ -39,6 +39,7 @@ DrvDispatchIoControl(PDEVICE_OBJECT DeviceObject, PIRP Irp) PDEBUGGER_FLUSH_LOGGING_BUFFERS DebuggerFlushBuffersRequest; PDEBUGGER_PREALLOC_COMMAND DebuggerReservePreallocPoolRequest; PDEBUGGER_PREACTIVATE_COMMAND DebuggerPreactivationRequest; + PDEBUGGER_APIC_REQUEST DebuggerApicRequest; PDEBUGGER_UD_COMMAND_PACKET DebuggerUdCommandRequest; PUSERMODE_LOADED_MODULE_DETAILS DebuggerUsermodeModulesRequest; PDEBUGGER_QUERY_ACTIVE_PROCESSES_OR_THREADS DebuggerUsermodeProcessOrThreadQueryRequest; @@ -202,6 +203,7 @@ DrvDispatchIoControl(PDEVICE_OBJECT DeviceObject, PIRP Irp) break; case IOCTL_DEBUGGER_READ_OR_WRITE_MSR: + // // First validate the parameters. // @@ -1106,6 +1108,46 @@ DrvDispatchIoControl(PDEVICE_OBJECT DeviceObject, PIRP Irp) break; + case IOCTL_PERFROM_ACTIONS_ON_APIC: + + // + // First validate the parameters. + // + if (IrpStack->Parameters.DeviceIoControl.InputBufferLength < SIZEOF_DEBUGGER_APIC_REQUEST || Irp->AssociatedIrp.SystemBuffer == NULL) + { + Status = STATUS_INVALID_PARAMETER; + LogError("Err, invalid parameter to IOCTL dispatcher"); + break; + } + + InBuffLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength; + OutBuffLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength; + + if (!InBuffLength || !OutBuffLength) + { + Status = STATUS_INVALID_PARAMETER; + break; + } + + // + // Both usermode and to send to usermode and the coming buffer are + // at the same place + // + DebuggerApicRequest = (PDEBUGGER_APIC_REQUEST)Irp->AssociatedIrp.SystemBuffer; + + // + // Perform the actions relating to the APIC request + // + Irp->IoStatus.Information = ExtensionCommandPerformActionsForApicRequests(DebuggerApicRequest); + Status = STATUS_SUCCESS; + + // + // Avoid zeroing it + // + DoNotChangeInformation = TRUE; + + break; + case IOCTL_SEND_USER_DEBUGGER_COMMANDS: // diff --git a/hyperdbg/hyperkd/header/debugger/commands/ExtensionCommands.h b/hyperdbg/hyperkd/header/debugger/commands/ExtensionCommands.h index 5abb5fff..1755246a 100644 --- a/hyperdbg/hyperkd/header/debugger/commands/ExtensionCommands.h +++ b/hyperdbg/hyperkd/header/debugger/commands/ExtensionCommands.h @@ -18,6 +18,9 @@ BOOLEAN ExtensionCommandPte(PDEBUGGER_READ_PAGE_TABLE_ENTRIES_DETAILS PteDetails, BOOLEAN IsOperatingInVmxRoot); +UINT32 +ExtensionCommandPerformActionsForApicRequests(PDEBUGGER_APIC_REQUEST ApicRequest); + VOID ExtensionCommandVa2paAndPa2va(PDEBUGGER_VA2PA_AND_PA2VA_COMMANDS AddressDetails, BOOLEAN OperateOnVmxRoot); diff --git a/hyperdbg/include/SDK/headers/Connection.h b/hyperdbg/include/SDK/headers/Connection.h index 3541c519..9432dd2a 100644 --- a/hyperdbg/include/SDK/headers/Connection.h +++ b/hyperdbg/include/SDK/headers/Connection.h @@ -97,6 +97,7 @@ typedef enum _DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_INJECT_PAGE_FAULT, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_WRITE_REGISTER, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_QUERY_PCITREE, + DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_PERFORM_ACTIONS_ON_APIC, // // Debuggee to debugger @@ -129,8 +130,9 @@ typedef enum _DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_DEBUGGEE_RESULT_OF_PTE, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_DEBUGGEE_RESULT_OF_VA2PA_AND_PA2VA, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_DEBUGGEE_RESULT_OF_BRINGING_PAGES_IN, - DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_DEBUGGEE_RESULT_OF_WRITE_REGISTER, + DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_DEBUGGEE_RESULT_OF_WRITE_REGISTERz DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_DEBUGGEE_RESULT_OF_PCITREE, + DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_DEBUGGEE_RESULT_OF_APIC_REQUESTS, // // hardware debuggee to debugger diff --git a/hyperdbg/include/SDK/headers/Constants.h b/hyperdbg/include/SDK/headers/Constants.h index b6f52da7..9c0de0ae 100644 --- a/hyperdbg/include/SDK/headers/Constants.h +++ b/hyperdbg/include/SDK/headers/Constants.h @@ -17,8 +17,8 @@ ////////////////////////////////////////////////// #define VERSION_MAJOR 0 -#define VERSION_MINOR 10 -#define VERSION_PATCH 2 +#define VERSION_MINOR 11 +#define VERSION_PATCH 0 // // Example of __DATE__ string: "Jul 27 2012" diff --git a/hyperdbg/include/SDK/headers/ErrorCodes.h b/hyperdbg/include/SDK/headers/ErrorCodes.h index 76e411c2..7bc6f683 100644 --- a/hyperdbg/include/SDK/headers/ErrorCodes.h +++ b/hyperdbg/include/SDK/headers/ErrorCodes.h @@ -539,6 +539,12 @@ */ #define DEBUGGER_ERROR_INVALID_PHYSICAL_ADDRESS 0xc0000052 +/** + * @brief error, could not perform APIC actions + * + */ +#define DEBUGGER_ERROR_APIC_ACTIONS_ERROR 0xc0000053 + // // WHEN YOU ADD ANYTHING TO THIS LIST OF ERRORS, THEN // MAKE SURE TO ADD AN ERROR MESSAGE TO ShowErrorMessage(UINT32 Error) diff --git a/hyperdbg/include/SDK/headers/Ioctls.h b/hyperdbg/include/SDK/headers/Ioctls.h index c0013939..f3ad82c6 100644 --- a/hyperdbg/include/SDK/headers/Ioctls.h +++ b/hyperdbg/include/SDK/headers/Ioctls.h @@ -294,4 +294,11 @@ * */ #define IOCTL_PCIE_ENDPOINT_ENUM \ - CTL_CODE(FILE_DEVICE_UNKNOWN, 0x821, METHOD_BUFFERED, FILE_ANY_ACCESS) \ No newline at end of file + CTL_CODE(FILE_DEVICE_UNKNOWN, 0x821, METHOD_BUFFERED, FILE_ANY_ACCESS) + +/** + * @brief ioctl, to perform actions related to APIC + * + */ +#define IOCTL_PERFROM_ACTIONS_ON_APIC \ + CTL_CODE(FILE_DEVICE_UNKNOWN, 0x822, METHOD_BUFFERED, FILE_ANY_ACCESS) diff --git a/hyperdbg/include/SDK/headers/RequestStructures.h b/hyperdbg/include/SDK/headers/RequestStructures.h index 83f1b182..d98fcc1a 100644 --- a/hyperdbg/include/SDK/headers/RequestStructures.h +++ b/hyperdbg/include/SDK/headers/RequestStructures.h @@ -1023,6 +1023,139 @@ typedef struct _DEBUGGEE_STEP_PACKET */ #define DEBUGGER_REMOTE_TRACKING_DEFAULT_COUNT_OF_STEPPING 0xffffffff +/* ============================================================================================== + +/** + * @brief Perform actions related to APIC + * + */ +typedef enum _DEBUGGER_APIC_REQUEST_TYPE +{ + DEBUGGER_APIC_REQUEST_TYPE_READ_LOCAL_APIC, + +} DEBUGGER_APIC_REQUEST_TYPE; + +/** + * @brief The structure of actions for APIC + * + */ +typedef struct _DEBUGGER_APIC_REQUEST +{ + DEBUGGER_APIC_REQUEST_TYPE ApicType; + BOOLEAN IsUsingX2APIC; + UINT32 KernelStatus; + +} DEBUGGER_APIC_REQUEST, *PDEBUGGER_APIC_REQUEST; + +/** + * @brief Debugger size of DEBUGGER_APIC_REQUEST + * + */ +#define SIZEOF_DEBUGGER_APIC_REQUEST \ + sizeof(DEBUGGER_APIC_REQUEST) + +/** + * @brief LAPIC structure size + */ +#define LAPIC_SIZE 0x400 + +#define LAPIC_LVT_FLAG_ENTRY_MASKED (1UL << 16) +#define LAPIC_LVT_DELIVERY_MODE_EXT_INT (7UL << 8) +#define LAPIC_SVR_FLAG_SW_ENABLE (1UL << 8) + +/** + * @brief LAPIC structure and offsets + */ +typedef struct _LAPIC_PAGE +{ + UINT8 Reserved000[0x10]; + UINT8 Reserved010[0x10]; + + UINT32 Id; // offset 0x020 + UINT8 Reserved024[0x0C]; + + UINT32 Version; // offset 0x030 + UINT8 Reserved034[0x0C]; + + UINT8 Reserved040[0x40]; + + UINT32 TPR; // offset 0x080 + UINT8 Reserved084[0x0C]; + + UINT32 ArbitrationPriority; // offset 0x090 + UINT8 Reserved094[0x0C]; + + UINT32 ProcessorPriority; // offset 0x0A0 + UINT8 Reserved0A4[0x0C]; + + UINT32 EOI; // offset 0x0B0 + UINT8 Reserved0B4[0x0C]; + + UINT32 RemoteRead; // offset 0x0C0 + UINT8 Reserved0C4[0x0C]; + + UINT32 LogicalDestination; // offset 0x0D0 + UINT8 Reserved0D4[0x0C]; + + UINT32 DestinationFormat; // offset 0x0E0 + UINT8 Reserved0E4[0x0C]; + + UINT32 SpuriousInterruptVector; // offset 0x0F0 + UINT8 Reserved0F4[0x0C]; + + UINT32 ISR[32]; // offset 0x100 + + UINT32 TMR[32]; // offset 0x180 + + UINT32 IRR[32]; // offset 0x200 + + UINT32 ErrorStatus; // offset 0x280 + UINT8 Reserved284[0x0C]; + + UINT8 Reserved290[0x60]; + + UINT32 LvtCmci; // offset 0x2F0 + UINT8 Reserved2F4[0x0C]; + + UINT32 IcrLow; // offset 0x300 + UINT8 Reserved304[0x0C]; + + UINT32 IcrHigh; // offset 0x310 + UINT8 Reserved314[0x0C]; + + UINT32 LvtTimer; // offset 0x320 + UINT8 Reserved324[0x0C]; + + UINT32 LvtThermalSensor; // offset 0x330 + UINT8 Reserved334[0x0C]; + + UINT32 LvtPerfMonCounters; // offset 0x340 + UINT8 Reserved344[0x0C]; + + UINT32 LvtLINT0; // offset 0x350 + UINT8 Reserved354[0x0C]; + + UINT32 LvtLINT1; // offset 0x360 + UINT8 Reserved364[0x0C]; + + UINT32 LvtError; // offset 0x370 + UINT8 Reserved374[0x0C]; + + UINT32 InitialCount; // offset 0x380 + UINT8 Reserved384[0x0C]; + + UINT32 CurrentCount; // offset 0x390 + UINT8 Reserved394[0x0C]; + + UINT8 Reserved3A0[0x40]; // offset 0x3A0 + + UINT32 DivideConfiguration; // offset 0x3E0 + UINT8 Reserved3E4[0x0C]; + + UINT32 SelfIpi; // offset 0x3F0 + UINT8 Reserved3F4[0x0C]; // valid only for X2APIC +} LAPIC_PAGE, *PLAPIC_PAGE; + /* ============================================================================================== */ diff --git a/hyperdbg/include/SDK/imports/kernel/HyperDbgVmmImports.h b/hyperdbg/include/SDK/imports/kernel/HyperDbgVmmImports.h index d57b927c..165bf2ef 100644 --- a/hyperdbg/include/SDK/imports/kernel/HyperDbgVmmImports.h +++ b/hyperdbg/include/SDK/imports/kernel/HyperDbgVmmImports.h @@ -215,6 +215,9 @@ VmFuncVmxCompatibleWcsncmp(const wchar_t * Address1, const wchar_t * Address2, S IMPORT_EXPORT_VMM INT32 VmFuncVmxCompatibleMemcmp(const CHAR * Address1, const CHAR * Address2, size_t Count); +IMPORT_EXPORT_VMM BOOLEAN +VmFuncApicStoreLocalApicFields(PLAPIC_PAGE LocalApicBuffer, PBOOLEAN IsUsingX2APIC); + ////////////////////////////////////////////////// // Configuration Functions // ////////////////////////////////////////////////// diff --git a/hyperdbg/include/SDK/imports/user/HyperDbgLibImports.h b/hyperdbg/include/SDK/imports/user/HyperDbgLibImports.h index d5206724..936e6885 100644 --- a/hyperdbg/include/SDK/imports/user/HyperDbgLibImports.h +++ b/hyperdbg/include/SDK/imports/user/HyperDbgLibImports.h @@ -232,6 +232,13 @@ hyperdbg_u_start_process(const WCHAR * path); IMPORT_EXPORT_LIBHYPERDBG BOOLEAN hyperdbg_u_start_process_with_args(const WCHAR * path, const WCHAR * arguments); +// +// APIC related command +// Exported functionality of the '!apic' command +// +IMPORT_EXPORT_LIBHYPERDBG BOOLEAN +hyperdbg_u_command_get_local_apic(PLAPIC_PAGE local_apic, BOOLEAN * is_using_x2apic); + // // Assembler // Exported functionality of the 'a' command diff --git a/hyperdbg/libhyperdbg/code/debugger/commands/extension-commands/apic.cpp b/hyperdbg/libhyperdbg/code/debugger/commands/extension-commands/apic.cpp new file mode 100644 index 00000000..1418e20c --- /dev/null +++ b/hyperdbg/libhyperdbg/code/debugger/commands/extension-commands/apic.cpp @@ -0,0 +1,282 @@ +/** + * @file apic.cpp + * @author Sina Karvandi (sina@hyperdbg.org) + * @brief !apic command + * @details + * @version 0.11 + * @date 2024-11-08 + * + * @copyright This project is released under the GNU Public License v3. + * + */ +#include "pch.h" + +// +// Global Variables +// +extern BOOLEAN g_IsSerialConnectedToRemoteDebuggee; + +/** + * @brief help of the !apic command + * + * @return VOID + */ +VOID +CommandApicHelp() +{ + ShowMessages("!apic : shows the details of Local APIC in both xAPIC and x2APIC modes.\n\n"); + + ShowMessages("syntax : \t!apic\n"); + + ShowMessages("\n"); + ShowMessages("\t\te.g : !apic\n"); +} + +/** + * @brief Send APIC requests + * + * @param ApicType + * @param ApicBuffer + * @param ExpectedRequestSize + * @param IsUsingX2APIC + * + * @return VOID + */ +BOOLEAN +CommandApicSendRequest(DEBUGGER_APIC_REQUEST_TYPE ApicType, + PVOID ApicBuffer, + UINT32 ExpectedRequestSize, + PBOOLEAN IsUsingX2APIC) +{ + BOOL Status; + ULONG ReturnedLength; + PDEBUGGER_APIC_REQUEST ApicRequest; + UINT32 RequestSize = 0; + + RequestSize = SIZEOF_DEBUGGER_APIC_REQUEST + ExpectedRequestSize; + + // + // Allocate buffer to fill the request + // + ApicRequest = (PDEBUGGER_APIC_REQUEST)malloc(RequestSize); + + if (ApicRequest == NULL) + { + // + // Unable to allocate buffer + // + return FALSE; + } + + RtlZeroMemory(ApicRequest, RequestSize); + + // + // Set the APIC type to local apic + // Note that the APIC mode (xAPIC and x2APIC) is determined in the debugger + // + ApicRequest->ApicType = ApicType; + + if (g_IsSerialConnectedToRemoteDebuggee) + { + // + // Send the request over serial kernel debugger + // + if (!KdSendApicActionPacketsToDebuggee(ApicRequest, RequestSize)) + { + return FALSE; + } + else + { + *IsUsingX2APIC = ApicRequest->IsUsingX2APIC; + RtlCopyMemory(ApicBuffer, (PVOID)(((CHAR *)ApicRequest) + sizeof(DEBUGGER_APIC_REQUEST)), ExpectedRequestSize); + + return TRUE; + } + } + else + { + AssertShowMessageReturnStmt(g_DeviceHandle, ASSERT_MESSAGE_DRIVER_NOT_LOADED, AssertReturnFalse); + + // + // Send IOCTL + // + Status = DeviceIoControl( + g_DeviceHandle, // Handle to device + IOCTL_PERFROM_ACTIONS_ON_APIC, // IO Control Code (IOCTL) + ApicRequest, // Input Buffer to driver. + SIZEOF_DEBUGGER_APIC_REQUEST, // Input buffer length + ApicRequest, // Output Buffer from driver. + RequestSize, // Length of output + // buffer in bytes. + &ReturnedLength, // Bytes placed in buffer. + NULL // synchronous call + ); + + if (!Status) + { + ShowMessages("ioctl failed with code 0x%x\n", GetLastError()); + return FALSE; + } + + if (ApicRequest->KernelStatus == DEBUGGER_OPERATION_WAS_SUCCESSFUL) + { + // + // Fill the request buffer + // + *IsUsingX2APIC = ApicRequest->IsUsingX2APIC; + RtlCopyMemory(ApicBuffer, (PVOID)(((CHAR *)ApicRequest) + sizeof(DEBUGGER_APIC_REQUEST)), ExpectedRequestSize); + + return TRUE; + } + else + { + // + // An err occurred, no results + // + ShowErrorMessage(ApicRequest->KernelStatus); + return FALSE; + } + } +} + +/** + * @brief Request to get Local APIC + * + * @param LocalApic + * @param IsUsingX2APIC + * + * @return BOOLEAN + */ +BOOLEAN +HyperDbgGetLocalApic(PLAPIC_PAGE LocalApic, PBOOLEAN IsUsingX2APIC) +{ + return CommandApicSendRequest(DEBUGGER_APIC_REQUEST_TYPE_READ_LOCAL_APIC, + LocalApic, + sizeof(LAPIC_PAGE), + IsUsingX2APIC); +} + +/** + * @brief !apic command handler + * + * @param CommandTokens + * @param Command + * + * @return VOID + */ +VOID +CommandApic(vector CommandTokens, string Command) +{ + BOOLEAN IsUsingX2APIC = FALSE; + UINT8 i = 0, j = 0; + UINT32 k = 0; + UINT32 Reg = 0; + LAPIC_PAGE LocalApic = {0}; + + if (CommandTokens.size() != 1) + { + ShowMessages("incorrect use of the '%s'\n\n", + GetCaseSensitiveStringFromCommandToken(CommandTokens.at(0)).c_str()); + + CommandApicHelp(); + return; + } + + // + // Get the local APIC results + // + if (HyperDbgGetLocalApic(&LocalApic, &IsUsingX2APIC) == FALSE) + { + return; + } + + // + // Show different fields of the Local APIC + // + ShowMessages("*** (%s Mode) PHYSICAL LAPIC ID = %u, Ver = 0x%x, MaxLvtEntry = %d, DirectedEOI = P%d/E%d, (SW: '%s')\n" + " -> TPR = 0x%08x, PPR = 0x%08x\n" + " -> LDR = 0x%08x, SVR = 0x%08x, Err = 0x%08x\n" + " -> LVT_INT0 = 0x%08x, LVT_INT1 = 0x%08x\n" + " -> LVT_CMCI = 0x%08x, LVT_PMCR = 0x%08x\n" + " -> LVT_TMR = 0x%08x, LVT_TSR = 0x%08x\n" + " -> LVT_ERR = 0x%08x\n" + " -> InitialCount = 0x%08x, CurrentCount = 0x%08x, DivideConfig = 0x%08x\n", + IsUsingX2APIC ? "X2APIC" : "XAPIC", + LocalApic.Id >> 24, + LocalApic.Version, + (LocalApic.Version & 0xFF0000) >> 16, + (LocalApic.Version >> 24) & 1, + (LocalApic.SpuriousInterruptVector >> 12) & 1, + (LocalApic.SpuriousInterruptVector & LAPIC_SVR_FLAG_SW_ENABLE) != 0 ? "Enabled" : "Disabled", + LocalApic.TPR, + LocalApic.ProcessorPriority, + LocalApic.LogicalDestination, + LocalApic.SpuriousInterruptVector, + LocalApic.ErrorStatus, + LocalApic.LvtLINT0, + LocalApic.LvtLINT1, + LocalApic.LvtCmci, + LocalApic.LvtPerfMonCounters, + LocalApic.LvtTimer, + LocalApic.LvtThermalSensor, + LocalApic.LvtError, + LocalApic.InitialCount, + LocalApic.CurrentCount, + LocalApic.DivideConfiguration); + + // + // Print the ISR, TMR and IRR + // + ShowMessages("ISR : "); + + for (i = 0; i < 8; i++) + { + k = 1; + Reg = (UINT32)LocalApic.ISR[i * 4]; + for (j = 0; j < 32; j++) + { + if (0 != (Reg & k)) + { + ShowMessages("0x%02hhx ", (UINT8)(i * 32 + j)); + } + k = k << 1; + } + } + ShowMessages("\n"); + + ShowMessages("TMR : "); + + for (i = 0; i < 8; i++) + { + k = 1; + Reg = (UINT32)LocalApic.TMR[i * 4]; + for (j = 0; j < 32; j++) + { + if (Reg & k) + { + ShowMessages("0x%02hhx ", (UINT8)(i * 32 + j)); + } + k = k << 1; + } + } + + ShowMessages("\n"); + + ShowMessages("IRR : "); + + for (i = 0; i < 8; i++) + { + k = 1; + Reg = (UINT32)LocalApic.IRR[i * 4]; + for (j = 0; j < 32; j++) + { + if (Reg & k) + { + ShowMessages("0x%02hhx ", (UINT8)(i * 32 + j)); + } + k = k << 1; + } + } + + ShowMessages("\n"); +} diff --git a/hyperdbg/libhyperdbg/code/debugger/core/debugger.cpp b/hyperdbg/libhyperdbg/code/debugger/core/debugger.cpp index cb0de455..f8238167 100644 --- a/hyperdbg/libhyperdbg/code/debugger/core/debugger.cpp +++ b/hyperdbg/libhyperdbg/code/debugger/core/debugger.cpp @@ -532,6 +532,11 @@ ShowErrorMessage(UINT32 Error) Error); break; + case DEBUGGER_ERROR_APIC_ACTIONS_ERROR: + ShowMessages("err, could not perform APIC actions (%x)\n", + Error); + break; + default: ShowMessages("err, error not found (%x)\n", Error); diff --git a/hyperdbg/libhyperdbg/code/debugger/core/interpreter.cpp b/hyperdbg/libhyperdbg/code/debugger/core/interpreter.cpp index 1b9ee9b2..a1d3c669 100644 --- a/hyperdbg/libhyperdbg/code/debugger/core/interpreter.cpp +++ b/hyperdbg/libhyperdbg/code/debugger/core/interpreter.cpp @@ -1445,6 +1445,10 @@ InitializeCommandsDictionary() g_CommandsList["~"] = {&CommandCore, &CommandCoreHelp, DEBUGGER_COMMAND_CORE_ATTRIBUTES}; g_CommandsList["core"] = {&CommandCore, &CommandCoreHelp, DEBUGGER_COMMAND_CORE_ATTRIBUTES}; + g_CommandsList["!apic"] = {&CommandApic, &CommandApicHelp, DEBUGGER_COMMAND_APIC_ATTRIBUTES}; + g_CommandsList["!lapic"] = {&CommandApic, &CommandApicHelp, DEBUGGER_COMMAND_APIC_ATTRIBUTES}; + g_CommandsList["!localapic"] = {&CommandApic, &CommandApicHelp, DEBUGGER_COMMAND_APIC_ATTRIBUTES}; + g_CommandsList["!monitor"] = {&CommandMonitor, &CommandMonitorHelp, DEBUGGER_COMMAND_MONITOR_ATTRIBUTES}; g_CommandsList["!vmcall"] = {&CommandVmcall, &CommandVmcallHelp, DEBUGGER_COMMAND_VMCALL_ATTRIBUTES}; diff --git a/hyperdbg/libhyperdbg/code/debugger/kernel-level/kd.cpp b/hyperdbg/libhyperdbg/code/debugger/kernel-level/kd.cpp index 3c2b138b..092a318d 100644 --- a/hyperdbg/libhyperdbg/code/debugger/kernel-level/kd.cpp +++ b/hyperdbg/libhyperdbg/code/debugger/kernel-level/kd.cpp @@ -984,6 +984,42 @@ KdSendVa2paAndPa2vaPacketToDebuggee(PDEBUGGER_VA2PA_AND_PA2VA_COMMANDS Va2paAndP return TRUE; } +/** + * @brief Send requests for APIC packet to the debuggee + * @param ApicPage + * @param ExpectedRequestSize + * + * @return BOOLEAN + */ +BOOLEAN +KdSendApicActionPacketsToDebuggee(PDEBUGGER_APIC_REQUEST ApicRequest, UINT32 ExpectedRequestSize) +{ + // + // Set the request data + // + DbgWaitSetRequestData(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_APIC_ACTIONS, ApicRequest, ExpectedRequestSize); + + // + // Send the APIC request packets + // + if (!KdCommandPacketAndBufferToDebuggee( + DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGER_TO_DEBUGGEE_EXECUTE_ON_VMX_ROOT, + DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_PERFORM_ACTIONS_ON_APIC, + (CHAR *)ApicRequest, + sizeof(DEBUGGER_APIC_REQUEST) // only sending the request header + )) + { + return FALSE; + } + + // + // Wait until the result of actions to APIC is received + // + DbgWaitForKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_APIC_ACTIONS); + + return TRUE; +} + /** * @brief Sends a breakpoint set or 'bp' command packet to the debuggee * @param BpPacket diff --git a/hyperdbg/libhyperdbg/code/debugger/kernel-level/kernel-listening.cpp b/hyperdbg/libhyperdbg/code/debugger/kernel-level/kernel-listening.cpp index 70597ee6..b7c8ae16 100644 --- a/hyperdbg/libhyperdbg/code/debugger/kernel-level/kernel-listening.cpp +++ b/hyperdbg/libhyperdbg/code/debugger/kernel-level/kernel-listening.cpp @@ -63,6 +63,7 @@ ListeningSerialPortInDebugger() PDEBUGGER_DEBUGGER_TEST_QUERY_BUFFER TestQueryPacket; PDEBUGGEE_REGISTER_READ_DESCRIPTION ReadRegisterPacket; PDEBUGGEE_REGISTER_WRITE_DESCRIPTION WriteRegisterPacket; + PDEBUGGER_APIC_REQUEST ApicRequestPacket; PDEBUGGER_READ_MEMORY ReadMemoryPacket; PDEBUGGER_EDIT_MEMORY EditMemoryPacket; PDEBUGGEE_BP_PACKET BpPacket; @@ -832,6 +833,27 @@ StartAgain: break; + case DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_DEBUGGEE_RESULT_OF_APIC_REQUESTS: + + ApicRequestPacket = (DEBUGGER_APIC_REQUEST *)(((CHAR *)TheActualPacket) + sizeof(DEBUGGER_REMOTE_PACKET)); + + // + // Get the address and size of the caller + // + DbgWaitGetRequestData(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_APIC_ACTIONS, &CallerAddress, &CallerSize); + + // + // Copy the memory buffer for the caller + // + memcpy(CallerAddress, ApicRequestPacket, CallerSize); + + // + // Signal the event relating to receiving result of performing actions into APIC + // + DbgReceivedKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_APIC_ACTIONS); + + break; + case DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_DEBUGGEE_RESULT_OF_READING_MEMORY: ReadMemoryPacket = (DEBUGGER_READ_MEMORY *)(((CHAR *)TheActualPacket) + sizeof(DEBUGGER_REMOTE_PACKET)); diff --git a/hyperdbg/libhyperdbg/code/export/export.cpp b/hyperdbg/libhyperdbg/code/export/export.cpp index 9c8590bb..1e76792c 100644 --- a/hyperdbg/libhyperdbg/code/export/export.cpp +++ b/hyperdbg/libhyperdbg/code/export/export.cpp @@ -684,6 +684,22 @@ hyperdbg_u_stepping_step_over_for_gu(BOOLEAN last_instruction) return SteppingStepOverForGu(last_instruction); } +/** + * @brief Get Local APIC + * @details The system automatically detects whether to read it + * in the xAPIC or x2APIC mode + * + * @param local_apic + * @param is_using_x2apic + * + * @return BOOLEAN + */ +BOOLEAN +hyperdbg_u_command_get_local_apic(PLAPIC_PAGE local_apic, BOOLEAN * is_using_x2apic) +{ + return HyperDbgGetLocalApic(local_apic, is_using_x2apic); +} + /** * @brief Run hwdbg script * diff --git a/hyperdbg/libhyperdbg/header/commands.h b/hyperdbg/libhyperdbg/header/commands.h index d159439d..6b29a2e3 100644 --- a/hyperdbg/libhyperdbg/header/commands.h +++ b/hyperdbg/libhyperdbg/header/commands.h @@ -322,6 +322,8 @@ typedef std::map CommandType; #define DEBUGGER_COMMAND_PTE_ATTRIBUTES DEBUGGER_COMMAND_ATTRIBUTE_LOCAL_COMMAND_IN_DEBUGGER_MODE +#define DEBUGGER_COMMAND_APIC_ATTRIBUTES DEBUGGER_COMMAND_ATTRIBUTE_LOCAL_COMMAND_IN_DEBUGGER_MODE + #define DEBUGGER_COMMAND_CORE_ATTRIBUTES \ DEBUGGER_COMMAND_ATTRIBUTE_LOCAL_COMMAND_IN_DEBUGGER_MODE @@ -700,6 +702,9 @@ CommandPe(vector CommandTokens, string Command); VOID CommandRev(vector CommandTokens, string Command); +VOID +CommandApic(vector CommandTokens, string Command); + VOID CommandTrack(vector CommandTokens, string Command); diff --git a/hyperdbg/libhyperdbg/header/debugger.h b/hyperdbg/libhyperdbg/header/debugger.h index 3e2f4251..bd596ee2 100644 --- a/hyperdbg/libhyperdbg/header/debugger.h +++ b/hyperdbg/libhyperdbg/header/debugger.h @@ -57,6 +57,7 @@ #define DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_PAGE_IN_STATE 0x19 #define DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_WRITE_REGISTER 0x1a #define DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_PCITREE_RESULT 0x1b +#define DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_APIC_ACTIONS 0x1c ////////////////////////////////////////////////// // Event Details // @@ -278,3 +279,6 @@ HyperDbgDebugCurrentDeviceUsingComPort(const CHAR * PortName, DWORD Baudrate); BOOLEAN HyperDbgDebugCloseRemoteDebugger(); + +BOOLEAN +HyperDbgGetLocalApic(PLAPIC_PAGE LocalApic, PBOOLEAN IsUsingX2APIC); diff --git a/hyperdbg/libhyperdbg/header/help.h b/hyperdbg/libhyperdbg/header/help.h index c9a14d68..ad32fe24 100644 --- a/hyperdbg/libhyperdbg/header/help.h +++ b/hyperdbg/libhyperdbg/header/help.h @@ -213,6 +213,9 @@ CommandPHelp(); VOID CommandCoreHelp(); +VOID +CommandApicHelp(); + VOID CommandProcessHelp(); diff --git a/hyperdbg/libhyperdbg/header/kd.h b/hyperdbg/libhyperdbg/header/kd.h index 03f67178..293f2324 100644 --- a/hyperdbg/libhyperdbg/header/kd.h +++ b/hyperdbg/libhyperdbg/header/kd.h @@ -198,6 +198,9 @@ KdSendBpPacketToDebuggee(PDEBUGGEE_BP_PACKET BpPacket); BOOLEAN KdSendVa2paAndPa2vaPacketToDebuggee(PDEBUGGER_VA2PA_AND_PA2VA_COMMANDS Va2paAndPa2vaPacket); +BOOLEAN +KdSendApicActionPacketsToDebuggee(PDEBUGGER_APIC_REQUEST ApicRequest, UINT32 ExpectedRequestSize); + BOOLEAN KdSendPtePacketToDebuggee(PDEBUGGER_READ_PAGE_TABLE_ENTRIES_DETAILS PtePacket); diff --git a/hyperdbg/libhyperdbg/libhyperdbg.vcxproj b/hyperdbg/libhyperdbg/libhyperdbg.vcxproj index 6a083a46..ed77089d 100644 --- a/hyperdbg/libhyperdbg/libhyperdbg.vcxproj +++ b/hyperdbg/libhyperdbg/libhyperdbg.vcxproj @@ -168,6 +168,7 @@ + diff --git a/hyperdbg/libhyperdbg/libhyperdbg.vcxproj.filters b/hyperdbg/libhyperdbg/libhyperdbg.vcxproj.filters index b5f1df1d..ee646d83 100644 --- a/hyperdbg/libhyperdbg/libhyperdbg.vcxproj.filters +++ b/hyperdbg/libhyperdbg/libhyperdbg.vcxproj.filters @@ -566,6 +566,7 @@ code\debugger\commands\hwdbg-commands + code\debugger\commands\extension-commands