/** * @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_IsKdModuleLoaded; 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)) { free(ApicRequest); return FALSE; } else { *IsUsingX2APIC = ApicRequest->IsUsingX2APIC; RtlCopyMemory(ApicBuffer, (PVOID)(((CHAR *)ApicRequest) + sizeof(DEBUGGER_APIC_REQUEST)), ExpectedRequestSize); free(ApicRequest); return TRUE; } } else { AssertShowMessageReturnStmt(g_IsKdModuleLoaded, g_DeviceHandle, ASSERT_MESSAGE_KD_NOT_LOADED, ASSERT_MESSAGE_DRIVER_NOT_LOADED, AssertReturnFalse); // // Send IOCTL // Status = DeviceIoControl( g_DeviceHandle, // Handle to device IOCTL_PERFORM_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()); free(ApicRequest); return FALSE; } if (ReturnedLength != RequestSize && ReturnedLength != SIZEOF_DEBUGGER_APIC_REQUEST) { // // An err occurred // ShowMessages("err, apic request failed\n"); free(ApicRequest); 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); free(ApicRequest); return TRUE; } else { // // An err occurred, no results // ShowErrorMessage(ApicRequest->KernelStatus); free(ApicRequest); 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"); }