/** * @file kd.cpp * @author Sina Karvandi (sina@hyperdbg.org) * @brief routines to kernel debugging * @details * @version 0.1 * @date 2020-12-22 * * @copyright This project is released under the GNU Public License v3. * */ #include "pch.h" // // Global Variables // extern HANDLE g_SerialListeningThreadHandle; extern HANDLE g_SerialRemoteComPortHandle; extern HANDLE g_DebuggeeStopCommandEventHandle; extern DEBUGGER_SYNCRONIZATION_EVENTS_STATE g_KernelSyncronizationObjectsHandleTable[DEBUGGER_MAXIMUM_SYNCRONIZATION_KERNEL_DEBUGGER_OBJECTS]; extern BYTE g_CurrentRunningInstruction[MAXIMUM_INSTR_SIZE]; extern BOOLEAN g_IsConnectedToHyperDbgLocally; #ifdef _WIN32 extern OVERLAPPED g_OverlappedIoStructureForReadDebugger; extern OVERLAPPED g_OverlappedIoStructureForWriteDebugger; extern OVERLAPPED g_OverlappedIoStructureForReadDebuggee; #endif // _WIN32 extern DEBUGGER_EVENT_AND_ACTION_RESULT g_DebuggeeResultOfRegisteringEvent; extern DEBUGGER_EVENT_AND_ACTION_RESULT g_DebuggeeResultOfAddingActionsToEvent; extern BOOLEAN g_IsSerialConnectedToRemoteDebuggee; extern BOOLEAN g_IsSerialConnectedToRemoteDebugger; extern BOOLEAN g_IsDebuggerConntectedToNamedPipe; extern BOOLEAN g_IsDebuggeeRunning; extern BOOLEAN g_IsKdModuleLoaded; extern BOOLEAN g_IsVmmModuleLoaded; extern BOOLEAN g_SerialConnectionAlreadyClosed; extern BOOLEAN g_IgnoreNewLoggingMessages; extern BOOLEAN g_SharedEventStatus; extern BOOLEAN g_IsRunningInstruction32Bit; extern BOOLEAN g_IgnorePauseRequests; extern BOOLEAN g_IsDebuggeeInHandshakingPhase; extern BOOLEAN g_ShouldPreviousCommandBeContinued; extern BYTE g_EndOfBufferCheckSerial[4]; extern ULONG g_CurrentRemoteCore; /** * @brief compares the buffer with a string * * @param CurrentLoopIndex Number of previously read bytes * @param Buffer * @return BOOLEAN */ BOOLEAN KdCheckForTheEndOfTheBuffer(PUINT32 CurrentLoopIndex, BYTE * Buffer) { UINT32 ActualBufferLength; ActualBufferLength = *CurrentLoopIndex; // // End of buffer is 4 character long // if (*CurrentLoopIndex <= 3) { return FALSE; } if (Buffer[ActualBufferLength] == SERIAL_END_OF_BUFFER_CHAR_4 && Buffer[ActualBufferLength - 1] == SERIAL_END_OF_BUFFER_CHAR_3 && Buffer[ActualBufferLength - 2] == SERIAL_END_OF_BUFFER_CHAR_2 && Buffer[ActualBufferLength - 3] == SERIAL_END_OF_BUFFER_CHAR_1) { // // Clear the end character // Buffer[ActualBufferLength - 3] = NULL; Buffer[ActualBufferLength - 2] = NULL; Buffer[ActualBufferLength - 1] = NULL; Buffer[ActualBufferLength] = NULL; // // Set the new length // *CurrentLoopIndex = ActualBufferLength - 3; return TRUE; } return FALSE; } /** * @brief compares the buffer with a string * * @param Buffer * @param CompareBuffer * @return BOOLEAN */ BOOLEAN KdCompareBufferWithString(CHAR * Buffer, const CHAR * CompareBuffer) { INT Result; Result = strcmp(Buffer, CompareBuffer); if (Result == 0) return TRUE; else return FALSE; } /** * @brief calculate the checksum of received buffer from debugger * * @param Buffer * @param LengthReceived * @return BYTE */ BYTE KdComputeDataChecksum(PVOID Buffer, UINT32 Length) { BYTE CalculatedCheckSum = 0; BYTE Temp = 0; while (Length--) { Temp = *(BYTE *)Buffer; CalculatedCheckSum = CalculatedCheckSum + Temp; Buffer = (PVOID)((UINT64)Buffer + 1); } return CalculatedCheckSum; } /** * @brief Interpret the packets from debuggee in the case of paused * * @return VOID */ VOID KdInterpretPausedDebuggee() { // // Wait for handshake to complete or in other words // get the receive packet // DbgWaitForKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_PAUSED_DEBUGGEE_DETAILS); } /** * @brief Sends a continue or 'g' command packet to the debuggee * * @return BOOLEAN */ BOOLEAN KdSendContinuePacketToDebuggee() { // // No core // g_CurrentRemoteCore = DEBUGGER_DEBUGGEE_IS_RUNNING_NO_CORE; // // Send 'g' as continue packet // if (!KdCommandPacketToDebuggee( DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGER_TO_DEBUGGEE_EXECUTE_ON_VMX_ROOT, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_MODE_CONTINUE)) { return FALSE; } return TRUE; } /** * @brief Sends a change core or '~ x' command packet to the debuggee * * @return BOOLEAN */ BOOLEAN KdSendSwitchCorePacketToDebuggee(UINT32 NewCore) { DEBUGGEE_CHANGE_CORE_PACKET CoreChangePacket = {0}; CoreChangePacket.NewCore = NewCore; if (CoreChangePacket.NewCore == g_CurrentRemoteCore) { // // We show an error message here when there is no core change (because the // target core and current operating core is the same) // ShowMessages("the current operating core is %x (not changed)\n", CoreChangePacket.NewCore); return FALSE; } // // Send '~' as switch packet // if (!KdCommandPacketAndBufferToDebuggee( DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGER_TO_DEBUGGEE_EXECUTE_ON_VMX_ROOT, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_MODE_CHANGE_CORE, (CHAR *)&CoreChangePacket, sizeof(DEBUGGEE_CHANGE_CORE_PACKET))) { return FALSE; } // // Wait until the result of core change received // DbgWaitForKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_CORE_SWITCHING_RESULT); return TRUE; } /** * @brief Sends a short-circuiting event request to debuggee * @param IsEnabled * * @return BOOLEAN */ BOOLEAN KdSendShortCircuitingEventToDebuggee(BOOLEAN IsEnabled) { DEBUGGER_SHORT_CIRCUITING_EVENT ShortCircuitEventPacket = {0}; // // Fill the structure of the packet // ShortCircuitEventPacket.IsShortCircuiting = IsEnabled; // // Send modify and query event packet // if (!KdCommandPacketAndBufferToDebuggee( DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGER_TO_DEBUGGEE_EXECUTE_ON_VMX_ROOT, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_SET_SHORT_CIRCUITING_STATE, (CHAR *)&ShortCircuitEventPacket, sizeof(DEBUGGER_SHORT_CIRCUITING_EVENT))) { return FALSE; } // // Wait until the result of setting short-circuiting event state is received // DbgWaitForKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_SHORT_CIRCUITING_EVENT_STATE); return TRUE; } /** * @brief Sends a query or request to enable/disable/clear for event * @details if IsQueryState is TRUE then TypeOfAction is ignored * @param Tag * @param TypeOfAction * @param IsEnabled If it's a query state then this argument can be used * * @return BOOLEAN */ BOOLEAN KdSendEventQueryAndModifyPacketToDebuggee( UINT64 Tag, DEBUGGER_MODIFY_EVENTS_TYPE TypeOfAction, BOOLEAN * IsEnabled) { DEBUGGER_MODIFY_EVENTS ModifyAndQueryEventPacket = {0}; g_SharedEventStatus = FALSE; // // Fill the structure of packet // ModifyAndQueryEventPacket.Tag = Tag; ModifyAndQueryEventPacket.TypeOfAction = TypeOfAction; // // Send modify and query event packet // if (!KdCommandPacketAndBufferToDebuggee( DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGER_TO_DEBUGGEE_EXECUTE_ON_VMX_ROOT, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_QUERY_AND_MODIFY_EVENT, (CHAR *)&ModifyAndQueryEventPacket, sizeof(DEBUGGER_MODIFY_EVENTS))) { return FALSE; } // // Wait until the result of query and modify event is received // DbgWaitForKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_MODIFY_AND_QUERY_EVENT); if (TypeOfAction == DEBUGGER_MODIFY_EVENTS_QUERY_STATE) { // // We should read the results to set IsEnabled variable // *IsEnabled = g_SharedEventStatus; } return TRUE; } /** * @brief Send a flush request to the debuggee * * @return BOOLEAN */ BOOLEAN KdSendFlushPacketToDebuggee() { DEBUGGER_FLUSH_LOGGING_BUFFERS FlushPacket = {0}; // // Send 'flush' command as flush packet // if (!KdCommandPacketAndBufferToDebuggee( DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGER_TO_DEBUGGEE_EXECUTE_ON_VMX_ROOT, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_MODE_FLUSH_BUFFERS, (CHAR *)&FlushPacket, sizeof(DEBUGGER_FLUSH_LOGGING_BUFFERS))) { return FALSE; } // // Wait until the result of flushing received // DbgWaitForKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_FLUSH_RESULT); return TRUE; } /** * @brief Send a callstack request to the debuggee * @param BaseAddress * @param Size * @param DisplayMethod * @param Is32Bit * * @return BOOLEAN */ BOOLEAN KdSendCallStackPacketToDebuggee(UINT64 BaseAddress, UINT32 Size, DEBUGGER_CALLSTACK_DISPLAY_METHOD DisplayMethod, BOOLEAN Is32Bit) { UINT32 FrameCount; UINT32 CallstackRequestSize = 0; PDEBUGGER_CALLSTACK_REQUEST CallstackPacket = NULL; if (Size == 0) { return FALSE; } if (Is32Bit) { FrameCount = Size / sizeof(UINT32); } else { FrameCount = Size / sizeof(UINT64); } CallstackRequestSize = sizeof(DEBUGGER_CALLSTACK_REQUEST) + (sizeof(DEBUGGER_SINGLE_CALLSTACK_FRAME) * FrameCount); // // Allocate buffer for request // CallstackPacket = (PDEBUGGER_CALLSTACK_REQUEST)malloc(CallstackRequestSize); if (CallstackPacket == NULL) { return FALSE; } PlatformZeroMemory(CallstackPacket, CallstackRequestSize); // // Set the details // CallstackPacket->BaseAddress = BaseAddress; CallstackPacket->Is32Bit = Is32Bit; CallstackPacket->Size = Size; CallstackPacket->BufferSize = CallstackRequestSize; CallstackPacket->FrameCount = FrameCount; CallstackPacket->DisplayMethod = DisplayMethod; // // Send 'k' command as callstack request packet // if (!KdCommandPacketAndBufferToDebuggee( DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGER_TO_DEBUGGEE_EXECUTE_ON_VMX_ROOT, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_MODE_CALLSTACK, (CHAR *)CallstackPacket, CallstackRequestSize)) { free(CallstackPacket); return FALSE; } // // Wait until the result of callstack is received // DbgWaitForKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_CALLSTACK_RESULT); free(CallstackPacket); return TRUE; } /** * @brief Send a test query request to the debuggee * * @param Type * * @return BOOLEAN */ BOOLEAN KdSendTestQueryPacketToDebuggee(DEBUGGER_TEST_QUERY_STATE Type) { DEBUGGER_DEBUGGER_TEST_QUERY_BUFFER TestQueryPacket = {}; TestQueryPacket.RequestType = Type; // // Send 'test query' command as query packet // if (!KdCommandPacketAndBufferToDebuggee( DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGER_TO_DEBUGGEE_EXECUTE_ON_VMX_ROOT, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_MODE_TEST_QUERY, (CHAR *)&TestQueryPacket, sizeof(DEBUGGER_DEBUGGER_TEST_QUERY_BUFFER))) { return FALSE; } // // Wait until the result of test query is received // DbgWaitForKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_TEST_QUERY); return TRUE; } /** * @brief Send a test query request to the debuggee with the specified context * * @param Type * @param Context * * @return BOOLEAN */ BOOLEAN KdSendTestQueryPacketWithContextToDebuggee(DEBUGGER_TEST_QUERY_STATE Type, UINT64 Context) { DEBUGGER_DEBUGGER_TEST_QUERY_BUFFER TestQueryPacket = {}; TestQueryPacket.RequestType = Type; TestQueryPacket.Context = Context; // // Send 'test query' command as query packet // if (!KdCommandPacketAndBufferToDebuggee( DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGER_TO_DEBUGGEE_EXECUTE_ON_VMX_ROOT, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_MODE_TEST_QUERY, (CHAR *)&TestQueryPacket, sizeof(DEBUGGER_DEBUGGER_TEST_QUERY_BUFFER))) { return FALSE; } // // Wait until the result of test query is received // DbgWaitForKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_TEST_QUERY); return TRUE; } /** * @brief Send symbol reload packet to the debuggee * * @return BOOLEAN */ BOOLEAN KdSendSymbolReloadPacketToDebuggee(UINT32 ProcessId) { DEBUGGEE_SYMBOL_REQUEST_PACKET SymbolRequest = {0}; SymbolRequest.ProcessId = ProcessId; // // Send '.sym reload' as symbol reload packet // if (!KdCommandPacketAndBufferToDebuggee( DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGER_TO_DEBUGGEE_EXECUTE_ON_VMX_ROOT, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_SYMBOL_RELOAD, (CHAR *)&SymbolRequest, sizeof(DEBUGGEE_SYMBOL_REQUEST_PACKET))) { return FALSE; } // // Wait until all of the symbol packets are received // DbgWaitForKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_SYMBOL_RELOAD); return TRUE; } /** * @brief Send a read register packet to the debuggee * @param RegDes * @param RegBuffSize * * @return BOOLEAN */ BOOLEAN KdSendReadRegisterPacketToDebuggee(PDEBUGGEE_REGISTER_READ_DESCRIPTION RegDes, UINT32 RegBuffSize) { // // Set the request data // DbgWaitSetKernelRequestData(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_READ_REGISTERS, RegDes, RegBuffSize); // // Send the 'r' command as read register packet // if (!KdCommandPacketAndBufferToDebuggee( DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGER_TO_DEBUGGEE_EXECUTE_ON_VMX_ROOT, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_READ_REGISTERS, (CHAR *)RegDes, sizeof(DEBUGGEE_REGISTER_READ_DESCRIPTION) // only the header is enough, no need to send the entire buffer )) { return FALSE; } // // Wait until the result of read registers received // DbgWaitForKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_READ_REGISTERS); return TRUE; } /** * @brief Send a write register packet to the debuggee * @param RegDes * * @return BOOLEAN */ BOOLEAN KdSendWriteRegisterPacketToDebuggee(PDEBUGGEE_REGISTER_WRITE_DESCRIPTION RegDes) { // // Set the request data // DbgWaitSetKernelRequestData(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_WRITE_REGISTER, RegDes, sizeof(DEBUGGEE_REGISTER_WRITE_DESCRIPTION)); // // Send write register packet // if (!KdCommandPacketAndBufferToDebuggee( DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGER_TO_DEBUGGEE_EXECUTE_ON_VMX_ROOT, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_WRITE_REGISTER, (CHAR *)RegDes, sizeof(DEBUGGEE_REGISTER_WRITE_DESCRIPTION))) { return FALSE; } // // Wait until the result of write register received // DbgWaitForKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_WRITE_REGISTER); return TRUE; } /** * @brief Send a Read memory packet to the debuggee * @param ReadMem * @param Size * * @return BOOLEAN */ BOOLEAN KdSendReadMemoryPacketToDebuggee(PDEBUGGER_READ_MEMORY ReadMem, UINT32 RequestSize) { // // Set the request data // DbgWaitSetKernelRequestData(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_READ_MEMORY, ReadMem, RequestSize); // // Send u-d command as read memory packet // if (!KdCommandPacketAndBufferToDebuggee( DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGER_TO_DEBUGGEE_EXECUTE_ON_VMX_ROOT, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_READ_MEMORY, (CHAR *)ReadMem, sizeof(DEBUGGER_READ_MEMORY) // only the header is enough, no need to send the entire buffer )) { return FALSE; } // // Wait until the result of read registers received // DbgWaitForKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_READ_MEMORY); return TRUE; } /** * @brief Send an Edit memory packet to the debuggee * @param EditMem * @param Size * * @return BOOLEAN */ BOOLEAN KdSendEditMemoryPacketToDebuggee(PDEBUGGER_EDIT_MEMORY EditMem, UINT32 Size) { // // Set the request data // DbgWaitSetKernelRequestData(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_EDIT_MEMORY, EditMem, sizeof(DEBUGGER_EDIT_MEMORY)); // // Send d command as read memory packet // if (!KdCommandPacketAndBufferToDebuggee( DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGER_TO_DEBUGGEE_EXECUTE_ON_VMX_ROOT, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_EDIT_MEMORY, (CHAR *)EditMem, Size)) { return FALSE; } // // Wait until the result of read registers received // DbgWaitForKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_EDIT_MEMORY); return TRUE; } /** * @brief Send a register event request to the debuggee * @details as this command uses one global variable to transfer the buffers * so should not be called simultaneously * @param Event * @param EventBufferLength * * @return PDEBUGGER_EVENT_AND_ACTION_RESULT */ PDEBUGGER_EVENT_AND_ACTION_RESULT KdSendRegisterEventPacketToDebuggee(PDEBUGGER_GENERAL_EVENT_DETAIL Event, UINT32 EventBufferLength) { PDEBUGGEE_EVENT_AND_ACTION_HEADER_FOR_REMOTE_PACKET Header; UINT32 Len; Len = EventBufferLength + sizeof(DEBUGGEE_EVENT_AND_ACTION_HEADER_FOR_REMOTE_PACKET); Header = (PDEBUGGEE_EVENT_AND_ACTION_HEADER_FOR_REMOTE_PACKET)malloc(Len); if (Header == NULL) { return NULL; } PlatformZeroMemory(Header, Len); // // Set length in header // Header->Length = EventBufferLength; // // Move buffer // memcpy((PVOID)((UINT64)Header + sizeof(DEBUGGEE_EVENT_AND_ACTION_HEADER_FOR_REMOTE_PACKET)), (PVOID)Event, EventBufferLength); PlatformZeroMemory(&g_DebuggeeResultOfRegisteringEvent, sizeof(DEBUGGER_EVENT_AND_ACTION_RESULT)); // // Send register event packet // if (!KdCommandPacketAndBufferToDebuggee( DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGER_TO_DEBUGGEE_EXECUTE_ON_VMX_ROOT, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_REGISTER_EVENT, (CHAR *)Header, Len)) { free(Header); return NULL; } // // Wait until the result of registering received // DbgWaitForKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_REGISTER_EVENT); free(Header); return &g_DebuggeeResultOfRegisteringEvent; } /** * @brief Send an add action to event request to the debuggee * @details as this command uses one global variable to transfer the buffers * so should not be called simultaneously * @param GeneralAction * @param GeneralActionLength * * @return PDEBUGGER_EVENT_AND_ACTION_RESULT */ PDEBUGGER_EVENT_AND_ACTION_RESULT KdSendAddActionToEventPacketToDebuggee(PDEBUGGER_GENERAL_ACTION GeneralAction, UINT32 GeneralActionLength) { PDEBUGGEE_EVENT_AND_ACTION_HEADER_FOR_REMOTE_PACKET Header; UINT32 Len; Len = GeneralActionLength + sizeof(DEBUGGEE_EVENT_AND_ACTION_HEADER_FOR_REMOTE_PACKET); Header = (PDEBUGGEE_EVENT_AND_ACTION_HEADER_FOR_REMOTE_PACKET)malloc(Len); if (Header == NULL) { return NULL; } PlatformZeroMemory(Header, Len); // // Set length in header // Header->Length = GeneralActionLength; // // Move buffer // memcpy((PVOID)((UINT64)Header + sizeof(DEBUGGEE_EVENT_AND_ACTION_HEADER_FOR_REMOTE_PACKET)), (PVOID)GeneralAction, GeneralActionLength); PlatformZeroMemory(&g_DebuggeeResultOfAddingActionsToEvent, sizeof(DEBUGGER_EVENT_AND_ACTION_RESULT)); // // Send add action to event packet // if (!KdCommandPacketAndBufferToDebuggee( DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGER_TO_DEBUGGEE_EXECUTE_ON_VMX_ROOT, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_ADD_ACTION_TO_EVENT, (CHAR *)Header, Len)) { free(Header); return NULL; } // // Wait until the result of adding action to event received // DbgWaitForKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_ADD_ACTION_TO_EVENT); free(Header); return &g_DebuggeeResultOfAddingActionsToEvent; } /** * @brief Sends a change process or show process details packet to the debuggee * @param ActionType * @param NewPid * @param NewProcess * @param SetChangeByClockInterrupt * @param SymDetailsForProcessList * * @return BOOLEAN */ BOOLEAN KdSendSwitchProcessPacketToDebuggee(DEBUGGEE_DETAILS_AND_SWITCH_PROCESS_TYPE ActionType, UINT32 NewPid, UINT64 NewProcess, BOOLEAN SetChangeByClockInterrupt, PDEBUGGEE_PROCESS_LIST_NEEDED_DETAILS SymDetailsForProcessList) { DEBUGGEE_DETAILS_AND_SWITCH_PROCESS_PACKET ProcessChangePacket = {}; ProcessChangePacket.ActionType = ActionType; ProcessChangePacket.ProcessId = NewPid; ProcessChangePacket.Process = NewProcess; ProcessChangePacket.IsSwitchByClkIntr = SetChangeByClockInterrupt; // // Check if the command really needs these information or not // it's because some of the command don't need symbol offset information // if (SymDetailsForProcessList != NULL) { memcpy(&ProcessChangePacket.ProcessListSymDetails, SymDetailsForProcessList, sizeof(DEBUGGEE_PROCESS_LIST_NEEDED_DETAILS)); } // // Send '.process' as switch packet // if (!KdCommandPacketAndBufferToDebuggee( DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGER_TO_DEBUGGEE_EXECUTE_ON_VMX_ROOT, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_MODE_CHANGE_PROCESS, (CHAR *)&ProcessChangePacket, sizeof(DEBUGGEE_DETAILS_AND_SWITCH_PROCESS_PACKET))) { return FALSE; } // // Wait until the result of process change received // DbgWaitForKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_PROCESS_SWITCHING_RESULT); return TRUE; } /** * @brief Sends a change thread or show threads detail packet to the debuggee * @param ActionType * @param NewTid * @param NewThread * @param CheckByClockInterrupt * @param SymDetailsForThreadList * * @return BOOLEAN */ BOOLEAN KdSendSwitchThreadPacketToDebuggee(DEBUGGEE_DETAILS_AND_SWITCH_THREAD_TYPE ActionType, UINT32 NewTid, UINT64 NewThread, BOOLEAN CheckByClockInterrupt, PDEBUGGEE_THREAD_LIST_NEEDED_DETAILS SymDetailsForThreadList) { DEBUGGEE_DETAILS_AND_SWITCH_THREAD_PACKET ThreadChangePacket = {}; ThreadChangePacket.ActionType = ActionType; ThreadChangePacket.ThreadId = NewTid; ThreadChangePacket.Thread = NewThread; ThreadChangePacket.CheckByClockInterrupt = CheckByClockInterrupt; // // Check if the command really needs these information or not // it's because some of the command don't need symbol offset information // if (SymDetailsForThreadList != NULL) { memcpy(&ThreadChangePacket.ThreadListSymDetails, SymDetailsForThreadList, sizeof(DEBUGGEE_THREAD_LIST_NEEDED_DETAILS)); } // // Send '.thread' as switch packet // if (!KdCommandPacketAndBufferToDebuggee( DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGER_TO_DEBUGGEE_EXECUTE_ON_VMX_ROOT, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_MODE_CHANGE_THREAD, (CHAR *)&ThreadChangePacket, sizeof(DEBUGGEE_DETAILS_AND_SWITCH_THREAD_PACKET))) { return FALSE; } // // Wait until the result of thread change received // DbgWaitForKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_THREAD_SWITCHING_RESULT); return TRUE; } /** * @brief Sends a PTE or '!pte' command packet to the debuggee * @param PtePacket * * @return BOOLEAN */ BOOLEAN KdSendPtePacketToDebuggee(PDEBUGGER_READ_PAGE_TABLE_ENTRIES_DETAILS PtePacket) { // // Send the '!pte' packet // if (!KdCommandPacketAndBufferToDebuggee( DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGER_TO_DEBUGGEE_EXECUTE_ON_VMX_ROOT, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_SYMBOL_QUERY_PTE, (CHAR *)PtePacket, sizeof(DEBUGGER_READ_PAGE_TABLE_ENTRIES_DETAILS))) { return FALSE; } // // Wait until the result of PTE packet is received // DbgWaitForKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_PTE_RESULT); return TRUE; } /** * @brief Sends a page-in or '.pagein' command packet to the debuggee * @param PageinPacket * * @return BOOLEAN */ BOOLEAN KdSendPageinPacketToDebuggee(PDEBUGGER_PAGE_IN_REQUEST PageinPacket) { // // Send the '.pagein' packet // if (!KdCommandPacketAndBufferToDebuggee( DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGER_TO_DEBUGGEE_EXECUTE_ON_VMX_ROOT, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_INJECT_PAGE_FAULT, (CHAR *)PageinPacket, sizeof(DEBUGGER_PAGE_IN_REQUEST))) { return FALSE; } // // Wait until the result of page-in packet is received // DbgWaitForKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_PAGE_IN_STATE); return TRUE; } /** * @brief Sends VA2PA and PA2VA packest, or '!va2pa' and '!pa2va' commands packet to the debuggee * @param Va2paAndPa2vaPacket * * @return BOOLEAN */ BOOLEAN KdSendVa2paAndPa2vaPacketToDebuggee(PDEBUGGER_VA2PA_AND_PA2VA_COMMANDS Va2paAndPa2vaPacket) { // // Send '!va2pa' or '!pa2va' as a query packet // if (!KdCommandPacketAndBufferToDebuggee( DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGER_TO_DEBUGGEE_EXECUTE_ON_VMX_ROOT, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_QUERY_PA2VA_AND_VA2PA, (CHAR *)Va2paAndPa2vaPacket, sizeof(DEBUGGER_VA2PA_AND_PA2VA_COMMANDS))) { return FALSE; } // // Wait until the result of VA2PA or PA2VA packet is received // DbgWaitForKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_VA2PA_AND_PA2VA_RESULT); 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 // DbgWaitSetKernelRequestData(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 Send requests for SMI operation packet to the debuggee * * @param SmiOperationRequest * * @return BOOLEAN */ BOOLEAN KdSendSmiPacketsToDebuggee(PSMI_OPERATION_PACKETS SmiOperationRequest, UINT32 ExpectedRequestSize) { // // Set the request data // DbgWaitSetKernelRequestData(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_SMI_OPERATION_RESULT, SmiOperationRequest, ExpectedRequestSize); // // Send the SMI request packets // if (!KdCommandPacketAndBufferToDebuggee( DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGER_TO_DEBUGGEE_EXECUTE_ON_VMX_ROOT, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_PERFORM_SMI_OPERATION, (CHAR *)SmiOperationRequest, SIZEOF_SMI_OPERATION_PACKETS)) { return FALSE; } // // Wait until the result of actions to SMI is received // DbgWaitForKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_SMI_OPERATION_RESULT); return TRUE; } /** * @brief Send requests for HyperTrace LBR dump packet to the debuggee * * @param HyperTraceLbrdumpRequest * * @return BOOLEAN */ BOOLEAN KdSendHyperTraceLbrdumpPacketsToDebuggee(PHYPERTRACE_LBR_DUMP_PACKETS HyperTraceLbrdumpRequest, UINT32 ExpectedRequestSize) { // // Set the request data // DbgWaitSetKernelRequestData(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_HYPERTRACE_LBR_DUMP_RESULT, HyperTraceLbrdumpRequest, ExpectedRequestSize); // // Send the LBR request packets // if (!KdCommandPacketAndBufferToDebuggee( DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGER_TO_DEBUGGEE_EXECUTE_ON_VMX_ROOT, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_PERFORM_HYPERTRACE_LBR_DUMP, (CHAR *)HyperTraceLbrdumpRequest, SIZEOF_HYPERTRACE_LBR_DUMP_PACKETS)) { return FALSE; } // // Wait until the result of actions to HyperTrace LBR is received // DbgWaitForKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_HYPERTRACE_LBR_DUMP_RESULT); return TRUE; } /** * @brief Send requests for HyperTrace PT operation packet to the debuggee * * @param HyperTracePtOperationRequest * * @return BOOLEAN */ BOOLEAN KdSendHyperTracePtPacketsToDebuggee(PHYPERTRACE_PT_OPERATION_PACKETS HyperTracePtOperationRequest, UINT32 ExpectedRequestSize) { // // Set the request data // DbgWaitSetKernelRequestData(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_HYPERTRACE_PT_OPERATION_RESULT, HyperTracePtOperationRequest, ExpectedRequestSize); // // Send the PT request packets // if (!KdCommandPacketAndBufferToDebuggee( DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGER_TO_DEBUGGEE_EXECUTE_ON_VMX_ROOT, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_PERFORM_HYPERTRACE_PT_OPERATION, (CHAR *)HyperTracePtOperationRequest, SIZEOF_HYPERTRACE_PT_OPERATION_PACKETS)) { return FALSE; } // // Wait until the result of actions to HyperTrace PT is received // DbgWaitForKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_HYPERTRACE_PT_OPERATION_RESULT); return TRUE; } /** * @brief Send requests for IDT packet to the debuggee * @param IdtRequest * * @return BOOLEAN */ BOOLEAN KdSendQueryIdtPacketsToDebuggee(PINTERRUPT_DESCRIPTOR_TABLE_ENTRIES_PACKETS IdtRequest) { // // Set the request data // DbgWaitSetKernelRequestData(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_IDT_ENTRIES, IdtRequest, sizeof(INTERRUPT_DESCRIPTOR_TABLE_ENTRIES_PACKETS)); // // Send the IDT request packets // if (!KdCommandPacketToDebuggee( DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGER_TO_DEBUGGEE_EXECUTE_ON_VMX_ROOT, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_READ_IDT_ENTRIES)) { return FALSE; } // // Wait until the result of actions to IDT is received // DbgWaitForKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_IDT_ENTRIES); return TRUE; } /** * @brief Sends a breakpoint set or 'bp' command packet to the debuggee * @param BpPacket * * @return BOOLEAN */ BOOLEAN KdSendBpPacketToDebuggee(PDEBUGGEE_BP_PACKET BpPacket) { // // Send 'bp' as a breakpoint packet // if (!KdCommandPacketAndBufferToDebuggee( DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGER_TO_DEBUGGEE_EXECUTE_ON_VMX_ROOT, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_BP, (CHAR *)BpPacket, sizeof(DEBUGGEE_BP_PACKET))) { return FALSE; } // // Wait until the result of putting breakpoint is received // DbgWaitForKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_BP); return TRUE; } /** * @brief Sends a breakpoint list or modification packet to the debuggee * @param ListOrModifyPacket * * @return BOOLEAN */ BOOLEAN KdSendListOrModifyPacketToDebuggee( PDEBUGGEE_BP_LIST_OR_MODIFY_PACKET ListOrModifyPacket) { // // Send list or modify breakpoint packet // if (!KdCommandPacketAndBufferToDebuggee( DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGER_TO_DEBUGGEE_EXECUTE_ON_VMX_ROOT, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_LIST_OR_MODIFY_BREAKPOINTS, (CHAR *)ListOrModifyPacket, sizeof(DEBUGGEE_BP_LIST_OR_MODIFY_PACKET))) { return FALSE; } // // Wait until the result of listing or modifying breakpoints is received // DbgWaitForKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_LIST_OR_MODIFY_BREAKPOINTS); return TRUE; } /** * @brief Sends a script packet to the debuggee * @param BufferAddress * @param BufferLength * @param Pointer * @param IsFormat * * @return BOOLEAN */ BOOLEAN KdSendScriptPacketToDebuggee(UINT64 BufferAddress, UINT32 BufferLength, UINT32 Pointer, BOOLEAN IsFormat) { PDEBUGGEE_SCRIPT_PACKET ScriptPacket; UINT32 SizeOfStruct = 0; SizeOfStruct = sizeof(DEBUGGEE_SCRIPT_PACKET) + BufferLength; ScriptPacket = (DEBUGGEE_SCRIPT_PACKET *)malloc(SizeOfStruct); PlatformZeroMemory(ScriptPacket, SizeOfStruct); // // Fill the script packet buffer // ScriptPacket->ScriptBufferSize = BufferLength; ScriptPacket->ScriptBufferPointer = Pointer; ScriptPacket->IsFormat = IsFormat; // // Move the buffer at the bottom of the script packet // memcpy((PVOID)((UINT64)ScriptPacket + sizeof(DEBUGGEE_SCRIPT_PACKET)), (PVOID)BufferAddress, BufferLength); // // Send script packet // if (!KdCommandPacketAndBufferToDebuggee( DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGER_TO_DEBUGGEE_EXECUTE_ON_VMX_ROOT, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_RUN_SCRIPT, (CHAR *)ScriptPacket, SizeOfStruct)) { free(ScriptPacket); return FALSE; } if (IsFormat) { // // Wait for formats results too // DbgWaitForKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_SCRIPT_FORMATS_RESULT); } // // Wait until the result of script engine received // DbgWaitForKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_SCRIPT_RUNNING_RESULT); free(ScriptPacket); return TRUE; } /** * @brief Sends user input packet to the debuggee * @param Sendbuf * @param Len * @param IgnoreBreakingAgain * * @return BOOLEAN */ BOOLEAN KdSendUserInputPacketToDebuggee(const CHAR * Sendbuf, INT Len, BOOLEAN IgnoreBreakingAgain) { PDEBUGGEE_USER_INPUT_PACKET UserInputPacket; UINT32 SizeOfStruct = 0; SizeOfStruct = sizeof(DEBUGGEE_USER_INPUT_PACKET) + Len; UserInputPacket = (DEBUGGEE_USER_INPUT_PACKET *)malloc(SizeOfStruct); PlatformZeroMemory(UserInputPacket, SizeOfStruct); // // Fill the script packet buffer descriptors // UserInputPacket->CommandLen = Len; UserInputPacket->IgnoreFinishedSignal = IgnoreBreakingAgain; // // Move the user input buffer at the bottom of the structure packet // memcpy((PVOID)((UINT64)UserInputPacket + sizeof(DEBUGGEE_USER_INPUT_PACKET)), (PVOID)Sendbuf, Len); // // Send user-input packet // if (!KdCommandPacketAndBufferToDebuggee( DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGER_TO_DEBUGGEE_EXECUTE_ON_VMX_ROOT, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_USER_INPUT_BUFFER, (CHAR *)UserInputPacket, SizeOfStruct)) { free(UserInputPacket); return FALSE; } // // Wait until the result of user-input received // if (!IgnoreBreakingAgain) { DbgWaitForKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_DEBUGGEE_FINISHED_COMMAND_EXECUTION); } free(UserInputPacket); return TRUE; } /** * @brief Sends search query request packet to the debuggee * @param SearchRequestBuffer * @param SearchRequestBufferSize * * @return BOOLEAN */ BOOLEAN KdSendSearchRequestPacketToDebuggee(UINT64 * SearchRequestBuffer, UINT32 SearchRequestBufferSize) { // // Send search request packet // if (!KdCommandPacketAndBufferToDebuggee( DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGER_TO_DEBUGGEE_EXECUTE_ON_VMX_ROOT, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_SEARCH_QUERY, (CHAR *)SearchRequestBuffer, SearchRequestBufferSize)) { return FALSE; } // // Wait until the result of search request received // DbgWaitForKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_SEARCH_QUERY_RESULT); return TRUE; } /** * @brief Sends p (step out) and t (step in) packet to the debuggee * * @return BOOLEAN */ BOOLEAN KdSendStepPacketToDebuggee(DEBUGGER_REMOTE_STEPPING_REQUEST StepRequestType) { DEBUGGEE_STEP_PACKET StepPacket = {}; UINT32 CallInstructionSize; // // Set the type of step packet // StepPacket.StepType = StepRequestType; // // Check if it's a step-over // if (StepRequestType == DEBUGGER_REMOTE_STEPPING_REQUEST_STEP_OVER || StepRequestType == DEBUGGER_REMOTE_STEPPING_REQUEST_STEP_OVER_FOR_GU) { // // It's not needed to check for DEBUGGER_REMOTE_STEPPING_REQUEST_STEP_OVER_FOR_GU_LAST_INSTRUCTION // as the last instruction is a 'RET' not a 'CALL' // // // We should check whether the current instruction is a 'call' // instruction or not, if yes we have to compute the length of call // if (HyperDbgCheckWhetherTheCurrentInstructionIsCall( g_CurrentRunningInstruction, MAXIMUM_INSTR_SIZE, g_IsRunningInstruction32Bit ? FALSE : TRUE, // equals to !g_IsRunningInstruction32Bit &CallInstructionSize)) { // // It's a call in step-over // StepPacket.IsCurrentInstructionACall = TRUE; StepPacket.CallLength = CallInstructionSize; } } // // Set the debuggee is running after this command // if (StepRequestType == DEBUGGER_REMOTE_STEPPING_REQUEST_STEP_OVER || StepRequestType == DEBUGGER_REMOTE_STEPPING_REQUEST_STEP_OVER_FOR_GU || StepRequestType == DEBUGGER_REMOTE_STEPPING_REQUEST_STEP_IN) { // // The debuggee is also running after this type of command // This is because this way the debuggee is running after the step-over or step-in // so, if the program either terminates or couldn't run the next instruction, the // user could pause the debuggee again // g_IsDebuggeeRunning = TRUE; } // // Send step packet to the serial // if (!KdCommandPacketAndBufferToDebuggee( DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGER_TO_DEBUGGEE_EXECUTE_ON_VMX_ROOT, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_MODE_STEP, (CHAR *)&StepPacket, sizeof(DEBUGGEE_STEP_PACKET))) { return FALSE; } // // Wait until the result of user-input received // DbgWaitForKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_IS_DEBUGGER_RUNNING); return TRUE; } /** * @brief Sends a PAUSE packet to the debuggee * * @return BOOLEAN */ BOOLEAN KdSendPausePacketToDebuggee() { // // Send the pause packet to debuggee // if (!KdCommandPacketToDebuggee( DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGER_TO_DEBUGGEE_EXECUTE_ON_USER_MODE, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_USER_MODE_PAUSE)) { return FALSE; } // // Handle the paused state (show rip, instructions, etc.) // KdInterpretPausedDebuggee(); return TRUE; } /** * @brief Get Windows name, version and build to send to debugger * * @param BufferToSave * * @return BOOLEAN */ BOOLEAN KdGetWindowVersion(CHAR * BufferToSave) { #ifdef _WIN32 HKeyHolder currentVersion; DWORD valueType; CHAR bufferResult[MAXIMUM_CHARACTER_FOR_OS_NAME] = {0}; BYTE bufferProductName[MAXIMUM_CHARACTER_FOR_OS_NAME] = {0}; BYTE bufferCurrentBuild[MAXIMUM_CHARACTER_FOR_OS_NAME] = {0}; BYTE bufferDisplayVersion[MAXIMUM_CHARACTER_FOR_OS_NAME] = {0}; DWORD bufferSize = MAXIMUM_CHARACTER_FOR_OS_NAME; if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, LR"(SOFTWARE\Microsoft\Windows NT\CurrentVersion)", 0, KEY_QUERY_VALUE, ¤tVersion) != ERROR_SUCCESS) { // return FALSE; } if (RegQueryValueExA(currentVersion, "ProductName", nullptr, &valueType, bufferProductName, &bufferSize) != ERROR_SUCCESS) { // return FALSE; } if (valueType != REG_SZ) { // return FALSE; } bufferSize = MAXIMUM_CHARACTER_FOR_OS_NAME; if (RegQueryValueExA(currentVersion, "DisplayVersion", nullptr, &valueType, bufferDisplayVersion, &bufferSize) != ERROR_SUCCESS) { // return FALSE; } if (valueType != REG_SZ) { // return FALSE; } bufferSize = MAXIMUM_CHARACTER_FOR_OS_NAME; if (RegQueryValueExA(currentVersion, "CurrentBuild", nullptr, &valueType, bufferCurrentBuild, &bufferSize) != ERROR_SUCCESS) { // return FALSE; } if (valueType != REG_SZ) { // return FALSE; } sprintf_s(bufferResult, "%s %s %s (OS Build %s)", bufferProductName, IsWindowsServer() ? "- Server" : "- Client", bufferDisplayVersion, bufferCurrentBuild); memcpy(BufferToSave, bufferResult, MAXIMUM_CHARACTER_FOR_OS_NAME); return TRUE; #else // // TODO(Linux): the OS name/version is read from the Windows registry // (SOFTWARE\Microsoft\Windows NT\CurrentVersion), which has no Linux // analog. The caller treats a FALSE result as non-fatal and leaves the // (already zeroed) buffer empty. // UNREFERENCED_PARAMETER(BufferToSave); return FALSE; #endif // _WIN32 } /** * @brief Receive packet from the debuggee * * @param BufferToSave * @param LengthReceived * * @return BOOLEAN */ BOOLEAN KdReceivePacketFromDebuggee(CHAR * BufferToSave, UINT32 * LengthReceived) { CHAR ReadData = NULL; /* temperory Character */ DWORD NoBytesRead = 0; /* Bytes read by ReadFile() */ UINT32 Loop = 0; // // Read data and store in a buffer // do { #ifdef _WIN32 // // It's in the debugger // // // Try to read one byte in overlapped I/O (in debugger) // if (!ReadFile(g_SerialRemoteComPortHandle, &ReadData, sizeof(ReadData), NULL, &g_OverlappedIoStructureForReadDebugger)) { DWORD e = GetLastError(); if (e != ERROR_IO_PENDING) { return FALSE; } } // // Wait till one packet becomes available // WaitForSingleObject(g_OverlappedIoStructureForReadDebugger.hEvent, INFINITE); // // Get the result // GetOverlappedResult(g_SerialRemoteComPortHandle, &g_OverlappedIoStructureForReadDebugger, &NoBytesRead, FALSE); // // Reset event for next try // ResetEvent(g_OverlappedIoStructureForReadDebugger.hEvent); #else // // Linux: read one byte through the cross-platform serial transport // if (!PlatformSerialReadByte(g_SerialRemoteComPortHandle, &ReadData, &NoBytesRead, PLATFORM_SERIAL_IO_DEBUGGER)) { return FALSE; } #endif // // We already now that the maximum packet size is MaxSerialPacketSize // Check to make sure that we don't pass the boundaries // if (!(MaxSerialPacketSize > Loop)) { // // Invalid buffer // ShowMessages("err, a buffer received in which exceeds the " "buffer limitation\n"); return FALSE; } BufferToSave[Loop] = ReadData; if (KdCheckForTheEndOfTheBuffer(&Loop, (BYTE *)BufferToSave)) { break; } Loop++; } while (NoBytesRead > 0); // // Set the length // *LengthReceived = Loop; return TRUE; } /** * @brief Receive packet from the debugger * * @param BufferToSave * @param LengthReceived * * @return BOOLEAN */ BOOLEAN KdReceivePacketFromDebugger(CHAR * BufferToSave, UINT32 * LengthReceived) { CHAR ReadData = NULL; /* temperory Character */ DWORD NoBytesRead = 0; /* Bytes read by ReadFile() */ UINT32 Loop = 0; #ifdef _WIN32 // // Set the timeout in milliseconds (e.g., 5000 ms = 5 seconds) // DWORD ReadTimeout = 5000; // // Set the read timeout using SetCommTimeouts // COMMTIMEOUTS Timeouts; GetCommTimeouts(g_SerialRemoteComPortHandle, &Timeouts); Timeouts.ReadIntervalTimeout = MAXDWORD; Timeouts.ReadTotalTimeoutConstant = ReadTimeout; Timeouts.ReadTotalTimeoutMultiplier = 0; Timeouts.WriteTotalTimeoutConstant = 0; Timeouts.WriteTotalTimeoutMultiplier = 0; SetCommTimeouts(g_SerialRemoteComPortHandle, &Timeouts); #endif // // Read data and store in a buffer // do { #ifdef _WIN32 // // It's in the debuggee // // // Try to read one byte in overlapped I/O (in debugger) // if (!ReadFile(g_SerialRemoteComPortHandle, &ReadData, sizeof(ReadData), NULL, &g_OverlappedIoStructureForReadDebuggee)) { DWORD e = GetLastError(); if (e != ERROR_IO_PENDING) { return FALSE; } } // // Wait till one packet becomes available // WaitForSingleObject(g_OverlappedIoStructureForReadDebuggee.hEvent, INFINITE); // // Get the result // GetOverlappedResult(g_SerialRemoteComPortHandle, &g_OverlappedIoStructureForReadDebuggee, &NoBytesRead, FALSE); // // Reset event for next try // ResetEvent(g_OverlappedIoStructureForReadDebuggee.hEvent); #else // // Linux: read one byte through the cross-platform serial transport // (the 5s read timeout is applied inside the platform layer) // if (!PlatformSerialReadByte(g_SerialRemoteComPortHandle, &ReadData, &NoBytesRead, PLATFORM_SERIAL_IO_DEBUGGEE)) { return FALSE; } #endif // // We already now that the maximum packet size is MaxSerialPacketSize // Check to make sure that we don't pass the boundaries // if (!(MaxSerialPacketSize > Loop)) { // // Invalid buffer // ShowMessages("err, a buffer received in which exceeds the " "buffer limitation\n"); return FALSE; } BufferToSave[Loop] = ReadData; if (KdCheckForTheEndOfTheBuffer(&Loop, (BYTE *)BufferToSave)) { break; } Loop++; } while (NoBytesRead > 0); // // Set the length // *LengthReceived = Loop; return TRUE; } /** * @brief Sends a special packet to the debuggee * * @param Buffer * @param Length * @return BOOLEAN */ BOOLEAN KdSendPacketToDebuggee(const CHAR * Buffer, UINT32 Length, BOOLEAN SendEndOfBuffer) { BOOL Status; DWORD BytesWritten = 0; DWORD LastErrorCode = 0; // // Start getting debuggee messages again // g_IgnoreNewLoggingMessages = FALSE; // // Double check if buffer not pass the boundary // if (Length + SERIAL_END_OF_BUFFER_CHARS_COUNT > MaxSerialPacketSize) { ShowMessages("err, buffer is above the maximum buffer size that can be sent to debuggee (%d > %d), " "for more information, please visit https://docs.hyperdbg.org/tips-and-tricks/misc/customize-build/increase-communication-buffer-size\n", Length + SERIAL_END_OF_BUFFER_CHARS_COUNT, MaxSerialPacketSize); return FALSE; } // // Check if the remote code's handle found or not // if (g_SerialRemoteComPortHandle == NULL) { ShowMessages("err, handle to remote debuggee's com port is not found\n"); return FALSE; } #ifdef _WIN32 if (g_IsSerialConnectedToRemoteDebugger || g_IsDebuggeeInHandshakingPhase) { // // It's for a debuggee // Status = WriteFile(g_SerialRemoteComPortHandle, // Handle to the Serialport Buffer, // Data to be written to the port Length, // No of bytes to write into the port &BytesWritten, // No of bytes written to the port NULL); if (Status == FALSE) { ShowMessages("err, fail to write to com port or named pipe (error %x).\n", GetLastError()); return FALSE; } // // Check if message delivered successfully // if (BytesWritten != Length) { return FALSE; } } else { // // It's a debugger // if (WriteFile(g_SerialRemoteComPortHandle, Buffer, Length, NULL, &g_OverlappedIoStructureForWriteDebugger)) { // // Write Completed // goto Out; } LastErrorCode = GetLastError(); if (LastErrorCode != ERROR_IO_PENDING) { // // Error // // ShowMessages("err, on sending serial packets (%x)", LastErrorCode); return FALSE; } // // Wait until write completed // if (WaitForSingleObject(g_OverlappedIoStructureForWriteDebugger.hEvent, INFINITE) != WAIT_OBJECT_0) { // ShowMessages("err, on sending serial packets (signal error)"); return FALSE; } // // Reset event // ResetEvent(g_OverlappedIoStructureForWriteDebugger.hEvent); } #else // // Linux: write through the cross-platform serial transport. The debuggee / // handshaking path is synchronous; the debugger path is overlapped (handled // inside the platform layer). // { BOOLEAN Synchronous = (g_IsSerialConnectedToRemoteDebugger || g_IsDebuggeeInHandshakingPhase); if (!PlatformSerialWrite(g_SerialRemoteComPortHandle, Buffer, Length, Synchronous)) { return FALSE; } } #endif Out: if (SendEndOfBuffer) { // // Send End of Buffer Packet // if (!KdSendPacketToDebuggee((const CHAR *)g_EndOfBufferCheckSerial, sizeof(g_EndOfBufferCheckSerial), FALSE)) { return FALSE; } } // // All the bytes are sent // return TRUE; } /** * @brief Sends a HyperDbg packet to the debuggee * * @param RequestedAction * @return BOOLEAN */ BOOLEAN KdCommandPacketToDebuggee( DEBUGGER_REMOTE_PACKET_TYPE PacketType, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION RequestedAction) { DEBUGGER_REMOTE_PACKET Packet = {0}; // // There is no check for boundary here as it's fixed to // sizeof(DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION) + sizeof(DEBUGGER_REMOTE_PACKET) // // // Make the packet's structure // Packet.Indicator = INDICATOR_OF_HYPERDBG_PACKET; Packet.TypeOfThePacket = PacketType; // // Set the requested action // Packet.RequestedActionOfThePacket = RequestedAction; // // calculate checksum of the packet // Packet.Checksum = KdComputeDataChecksum((PVOID)((UINT64)&Packet + 1), sizeof(DEBUGGER_REMOTE_PACKET) - sizeof(BYTE)); if (!KdSendPacketToDebuggee((const CHAR *)&Packet, sizeof(DEBUGGER_REMOTE_PACKET), TRUE)) { return FALSE; } return TRUE; } /** * @brief Sends a HyperDbg packet + a buffer to the debuggee * * @param RequestedAction * @param Buffer * @param BufferLength * @return BOOLEAN */ BOOLEAN KdCommandPacketAndBufferToDebuggee( DEBUGGER_REMOTE_PACKET_TYPE PacketType, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION RequestedAction, CHAR * Buffer, UINT32 BufferLength) { DEBUGGER_REMOTE_PACKET Packet = {0}; // // Check if buffer not pass the boundary // if (sizeof(DEBUGGER_REMOTE_PACKET) + BufferLength + SERIAL_END_OF_BUFFER_CHARS_COUNT > MaxSerialPacketSize) { ShowMessages("err, buffer is above the maximum buffer size that can be sent to debuggee (%d > %d), " "for more information, please visit https://docs.hyperdbg.org/tips-and-tricks/misc/customize-build/increase-communication-buffer-size", sizeof(DEBUGGER_REMOTE_PACKET) + BufferLength + SERIAL_END_OF_BUFFER_CHARS_COUNT, MaxSerialPacketSize); return FALSE; } // // Make the packet's structure // Packet.Indicator = INDICATOR_OF_HYPERDBG_PACKET; Packet.TypeOfThePacket = PacketType; // // Set the requested action // Packet.RequestedActionOfThePacket = RequestedAction; // // calculate checksum of the packet // Packet.Checksum = KdComputeDataChecksum((PVOID)((UINT64)&Packet + 1), sizeof(DEBUGGER_REMOTE_PACKET) - sizeof(BYTE)); Packet.Checksum += KdComputeDataChecksum((PVOID)Buffer, BufferLength); // // Send the first buffer (without ending buffer indication) // if (!KdSendPacketToDebuggee((const CHAR *)&Packet, sizeof(DEBUGGER_REMOTE_PACKET), FALSE)) { return FALSE; } // // Send the second buffer (with ending buffer indication) // if (!KdSendPacketToDebuggee((const CHAR *)Buffer, BufferLength, TRUE)) { return FALSE; } return TRUE; } /** * @brief check if the debuggee needs to be paused * @param SignalRunningFlag * * @return VOID */ VOID KdBreakControlCheckAndPauseDebugger(BOOLEAN SignalRunningFlag) { // // Check if debuggee is running, otherwise the user // pressed CTRL+C multiple times // if (g_IsDebuggeeRunning) { // // Send the pause request to the remote computer // if (!KdSendPausePacketToDebuggee()) { ShowMessages("err, unable to pause the debuggee\n"); } // // Signal the event // if (SignalRunningFlag) { DbgReceivedKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_IS_DEBUGGER_RUNNING); } } } /** * @brief Set the status of the debuggee to wait for the pause * * @return VOID */ VOID KdSetStatusAndWaitForPause() { // // Set the debuggee to show that it's running // g_IsDebuggeeRunning = TRUE; // // Halt the UI // KdTheRemoteSystemIsRunning(); } /** * @brief check if the debuggee needs to be continued * * @return VOID */ VOID KdBreakControlCheckAndContinueDebugger() { // // Check if debuggee is paused or not // if (!g_IsDebuggeeRunning) { // // Send the continue request to the remote computer // if (KdSendContinuePacketToDebuggee()) { // // Set the debuggee to show that it's running // KdSetStatusAndWaitForPause(); } else { ShowMessages("err, unable to continue the debuggee\n"); } } } /** * @brief Respond to the debuggee with the version and build date of the debugger * * @return BOOLEAN */ BOOLEAN KdSendResponseOfThePingPacket() { // // For logging purposes // // ShowMessages("the ping request is received\n"); // // Send the handshake packet to debuggee // if (!KdCommandPacketAndBufferToDebuggee( DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGER_TO_DEBUGGEE_EXECUTE_ON_USER_MODE, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_USER_MODE_DEBUGGER_VERSION, (CHAR *)BuildSignature, sizeof(BuildSignature))) { ShowMessages("err, unable to send response to the ping packet\n"); return FALSE; } return TRUE; } /** * @brief wait for a event to be triggered and if the debuggee * is running it just halts the system * * @return VOID */ VOID KdTheRemoteSystemIsRunning() { // // Indicate that the debuggee is running // ShowMessages("debuggee is running...\n"); // // Wait until the users press CTRL+C // DbgWaitForKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_IS_DEBUGGER_RUNNING); } /** * @brief Prepare serial to connect to the remote server * @details wait to connect to debuggee (this is debugger) * * @param SerialHandle * @param IsNamedPipe * @param PauseAfterConnection * * @return BOOLEAN */ BOOLEAN KdPrepareSerialConnectionToRemoteSystem(HANDLE SerialHandle, BOOLEAN IsNamedPipe, BOOLEAN PauseAfterConnection) { #ifdef _WIN32 BOOL Status; /* Status */ DWORD EventMask = 0; /* Event mask to trigger */ #endif // _WIN32 // // Show an indication to connect the debugger // ShowMessages("waiting for debuggee to connect...\n"); if (!IsNamedPipe) { #ifdef _WIN32 // // Setting Receive Mask // Status = SetCommMask(SerialHandle, EV_RXCHAR); if (Status == FALSE) { // // Can be ignored // // ShowMessages("err, in setting CommMask\n"); // return FALSE; } // // Setting WaitComm() Event // Status = WaitCommEvent(SerialHandle, &EventMask, NULL); /* Wait for the character to be received */ if (Status == FALSE) { // // Can be ignored // // ShowMessages("err, in setting WaitCommEvent\n"); // return FALSE; } #else // // TODO(Linux): waiting for the first byte on the serial port is // Win32-only here (SetCommMask/WaitCommEvent); the Linux home for it is // platform-serial.c. Unreachable for now, as the Linux serial path is // refused in KdPrepareAndConnectDebugPort. // #endif // _WIN32 } // // Initialize the handle table // for (SIZE_T i = 0; i < DEBUGGER_MAXIMUM_SYNCRONIZATION_KERNEL_DEBUGGER_OBJECTS; i++) { g_KernelSyncronizationObjectsHandleTable[i].IsOnWaitingState = FALSE; g_KernelSyncronizationObjectsHandleTable[i].EventHandle = PlatformCreateEvent(FALSE, FALSE); } // // the debuggee is not already closed the connection // g_SerialConnectionAlreadyClosed = FALSE; // // Create the listening thread in debugger // g_SerialListeningThreadHandle = PlatformCreateThread(ListeningSerialPauseDebuggerThread, NULL); // // Wait for the 'Start' packet on the listener side // DbgWaitForKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_STARTED_PACKET_RECEIVED); // // Check to make sure the connection not close before starting a session // if (!g_SerialConnectionAlreadyClosed) { // // Ignore handling breaks // g_IgnorePauseRequests = TRUE; // // The next step is getting symbol details // ShowMessages("getting symbol details...\n"); // // Wait to receive symbol details // DbgWaitForKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_SYMBOL_RELOAD); // // Connected to the debuggee // g_IsSerialConnectedToRemoteDebuggee = TRUE; // // And debuggee is running // g_IsDebuggeeRunning = TRUE; // // Save the handler // g_SerialRemoteComPortHandle = SerialHandle; // // Is serial handle for a named pipe // g_IsDebuggerConntectedToNamedPipe = IsNamedPipe; // // Process CTRL+C breaks again // g_IgnorePauseRequests = FALSE; // // Now, the user can press ctrl+c to pause the debuggee // ShowMessages("press CTRL+C to pause the debuggee\n"); // // If the user wants to pause after connection // if (PauseAfterConnection) { // // Pause the target debuggee after connection // KdBreakControlCheckAndPauseDebugger(FALSE); } else { // // Wait for event on this thread // KdTheRemoteSystemIsRunning(); } } return TRUE; } /** * @brief Check and handshake to make sure if the remote debugger is listening * * @param ComPortHandle * * @return BOOLEAN */ BOOLEAN KdCheckIfDebuggerIsListening(HANDLE ComPortHandle) { CHAR BufferToReceive[MaxSerialPacketSize] = {0}; CHAR * ReceivedPingBuildVersionBuffer = NULL; PDEBUGGER_REMOTE_PACKET TheActualPacket = NULL; UINT32 LengthReceived = 0; BOOLEAN Result = FALSE; // // For logging purposes // // ShowMessages("the ping request is received\n"); StartAgain: // // Send the ping packet and request the version of the debugger // if (!KdCommandPacketToDebuggee( DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGEE_TO_DEBUGGER, DEBUGGER_REMOTE_PACKET_PING_AND_SEND_SUPPORTED_VERSION)) { } // // Wait for handshake to complete or in other words // get the receive packet // if (!KdReceivePacketFromDebugger(BufferToReceive, &LengthReceived)) { if (LengthReceived == 0 && BufferToReceive[0] == NULL) { // // The remote computer (debuggee) closed the connection // ShowMessages("err, the remote connection is closed\n"); return FALSE; } else { ShowMessages("err, invalid buffer received\n"); goto StartAgain; } } // // Check for invalid close packets // if (LengthReceived == 1 && BufferToReceive[0] == NULL) { ShowMessages("is the debugger listening? retry handshaking with the debugger... (timeout: 5 seconds)\n"); goto StartAgain; } // // Check the handshaking packet // TheActualPacket = (PDEBUGGER_REMOTE_PACKET)BufferToReceive; if (TheActualPacket->Indicator == INDICATOR_OF_HYPERDBG_PACKET) { // // Check checksum // if (KdComputeDataChecksum((PVOID)&TheActualPacket->Indicator, LengthReceived - sizeof(BYTE)) != TheActualPacket->Checksum) { ShowMessages("err, checksum is invalid\n"); goto StartAgain; } // // Check if the packet type is correct // if (TheActualPacket->TypeOfThePacket != DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGER_TO_DEBUGGEE_EXECUTE_ON_USER_MODE) { // // sth wrong happened, the packet is not belonging to use // nothing to do, just wait again // ShowMessages("err, unknown packet received from the debuggee\n"); goto StartAgain; } // // It's a HyperDbg packet // switch (TheActualPacket->RequestedActionOfThePacket) { case DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_USER_MODE_DEBUGGER_VERSION: ReceivedPingBuildVersionBuffer = (CHAR *)(((CHAR *)TheActualPacket) + sizeof(DEBUGGER_REMOTE_PACKET)); // ShowMessages("the answer to the PING request is received: %s\n", ReceivedPingBuildVersionBuffer); if (strcmp((const CHAR *)BuildSignature, ReceivedPingBuildVersionBuffer) == 0) { // // Build version matched // Result = TRUE; } else { // // Build version doesn't match // ShowMessages(ASSERT_MESSAGE_BUILD_SIGNATURE_DOESNT_MATCH); Result = FALSE; } break; default: Result = FALSE; ShowMessages("err, invalid packet is received. did you connect to an instance of HyperDbg?\n" "maybe an incorrect COM source is specified\n"); break; } } // // By default, we prevent the connection // return Result; } /** * @brief Prepare and initialize COM port * * @param PortName * @param Baudrate * @param Port * @param IsPreparing * @param IsNamedPipe * @param PauseAfterConnection * * @return BOOLEAN */ BOOLEAN KdPrepareAndConnectDebugPort(const CHAR * PortName, DWORD Baudrate, UINT32 Port, BOOLEAN IsPreparing, BOOLEAN IsNamedPipe, BOOLEAN PauseAfterConnection) { HANDLE Comm; /* Handle to the Serial port */ #ifdef _WIN32 BOOL Status; /* Status */ DCB SerialParams = {0}; /* Initializing DCB structure */ COMMTIMEOUTS Timeouts = {0}; /* Initializing timeouts structure */ CHAR PortNo[20] = {0}; /* contain friendly name */ #endif // _WIN32 BOOLEAN StatusIoctl; ULONG ReturnedLength; PDEBUGGER_PREPARE_DEBUGGEE DebuggeeRequest; // // Check if the debugger or debuggee is already active // if (IsConnectedToAnyInstanceOfDebuggerOrDebuggee()) { return FALSE; } if (IsPreparing && IsNamedPipe) { ShowMessages("err, cannot used named pipe for debuggee"); return FALSE; } if (!IsNamedPipe) { #ifdef _WIN32 // // It's a serial // // // Append name to make a Windows understandable format // sprintf_s(PortNo, 20, "\\\\.\\%s", PortName); // // Open the serial com port (if it's the debugger (not debuggee)) then // open with Overlapped I/O // if (IsPreparing) { // // It's debuggee (Non-overlapped I/O) // Comm = CreateFile(PortNo, // Friendly name GENERIC_READ | GENERIC_WRITE, // Read/Write Access 0, // No Sharing, ports can't be shared NULL, // No Security OPEN_EXISTING, // Open existing port only 0, // Non Overlapped I/O NULL); // Null for Comm Devices // // Create event for overlapped I/O (Read) // g_OverlappedIoStructureForReadDebuggee.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); } else { // // It's debugger (Overlapped I/O) // Comm = CreateFile(PortNo, // Friendly name GENERIC_READ | GENERIC_WRITE, // Read/Write Access 0, // No Sharing, ports can't be shared NULL, // No Security OPEN_EXISTING, // Open existing port only FILE_FLAG_OVERLAPPED, // Overlapped I/O NULL); // Null for Comm Devices // // Create event for overlapped I/O (Read) // g_OverlappedIoStructureForReadDebugger.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); // // Create event for overlapped I/O (Write) // g_OverlappedIoStructureForWriteDebugger.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); } if (Comm == INVALID_HANDLE_VALUE) { ShowMessages("err, port can't be opened\n"); return FALSE; } // // Purge the serial port // PurgeComm(Comm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT); // // Setting the Parameters for the SerialPort // SerialParams.DCBlength = sizeof(SerialParams); // // retrieves the current settings // Status = GetCommState(Comm, &SerialParams); if (Status == FALSE) { CloseHandle(Comm); ShowMessages("err, to Get the COM state\n"); return FALSE; } SerialParams.BaudRate = Baudrate; // BaudRate = 9600 (Based on user selection) SerialParams.ByteSize = 8; // ByteSize = 8 SerialParams.StopBits = ONESTOPBIT; // StopBits = 1 SerialParams.Parity = NOPARITY; // Parity = None Status = SetCommState(Comm, &SerialParams); if (Status == FALSE) { CloseHandle(Comm); ShowMessages("err, to Setting DCB Structure\n"); return FALSE; } // // Setting Timeouts (not use it anymore as we use special signature for // ending buffer) // (no need anymore as we use end buffer detection mechanism) // /* Timeouts.ReadIntervalTimeout = 50; Timeouts.ReadTotalTimeoutConstant = 50; Timeouts.ReadTotalTimeoutMultiplier = 10; Timeouts.WriteTotalTimeoutConstant = 50; Timeouts.WriteTotalTimeoutMultiplier = 10; if (SetCommTimeouts(Comm, &Timeouts) == FALSE) { ShowMessages("err, to Setting Time outs (%x).\n", GetLastError()); return FALSE; } */ #else // // TODO(Linux): opening and configuring the serial port is Win32-only // here (CreateFile/PurgeComm/GetCommState/SetCommState). The Linux // home for this is platform-serial.c, whose serial routines are still // stubs. Until they are implemented, refuse the serial path. // ShowMessages("err, serial connection is not supported on Linux yet\n"); return FALSE; #endif // _WIN32 } else { // // It's a namedpipe // Comm = NamedPipeClientCreatePipeOverlappedIo(PortName); if (!Comm) { // // Unable to create handle // ShowMessages("is the virtual machine running?\n"); return FALSE; } } if (IsPreparing) { // // It's a debuggee request // // // We entered the handshaking phase // g_IsDebuggeeInHandshakingPhase = TRUE; // // Set handle to serial device // g_SerialRemoteComPortHandle = Comm; // // Check if debuggee is listening before loading module // if (!KdCheckIfDebuggerIsListening(Comm)) { PlatformCloseHandle(Comm); g_SerialRemoteComPortHandle = NULL; g_IsDebuggeeInHandshakingPhase = FALSE; return FALSE; } else { // // Not in handshaking phase anymore (The handshaking phase was successful) // g_IsDebuggeeInHandshakingPhase = FALSE; } // // First, connect to local machine and we load the VMM module as it's a // module that is responsible for working on debugger // g_IsConnectedToHyperDbgLocally = TRUE; // // Load the VMM // if (HyperDbgInstallKdDriver() == 1 || HyperDbgLoadVmmModule() == 1) { PlatformCloseHandle(Comm); g_SerialRemoteComPortHandle = NULL; g_IsConnectedToHyperDbgLocally = FALSE; ShowMessages("failed to install or load the driver\n"); return FALSE; } // // Check if driver is loaded or not, in the case // of connecting to a remote machine as debuggee // if (!g_DeviceHandle) { PlatformCloseHandle(Comm); g_SerialRemoteComPortHandle = NULL; g_IsConnectedToHyperDbgLocally = FALSE; AssertShowMessageReturnStmt(g_IsKdModuleLoaded, g_DeviceHandle, ASSERT_MESSAGE_KD_NOT_LOADED, ASSERT_MESSAGE_DRIVER_NOT_LOADED, AssertReturnFalse); } // // Allocate buffer // DebuggeeRequest = (PDEBUGGER_PREPARE_DEBUGGEE)malloc(SIZEOF_DEBUGGER_PREPARE_DEBUGGEE); if (DebuggeeRequest == NULL) { PlatformCloseHandle(Comm); g_SerialRemoteComPortHandle = NULL; g_IsConnectedToHyperDbgLocally = FALSE; ShowMessages("err, unable to allocate memory for request packet"); return FALSE; } PlatformZeroMemory(DebuggeeRequest, SIZEOF_DEBUGGER_PREPARE_DEBUGGEE); // // Prepare the details structure // DebuggeeRequest->PortAddress = Port; DebuggeeRequest->Baudrate = Baudrate; // // Get base address of ntoskrnl // DebuggeeRequest->KernelBaseAddress = DebuggerGetNtoskrnlBase(); // // Set the debuggee name, version, and build number // if (!KdGetWindowVersion(DebuggeeRequest->OsName)) { // // It's not an error if it returned null (we could ignore it) // // return FALSE; } // // Send the request to the kernel // StatusIoctl = PlatformDeviceIoControl(g_DeviceHandle, // Handle to device IOCTL_PREPARE_DEBUGGEE, // IO Control Code (IOCTL) DebuggeeRequest, // Input Buffer to driver. SIZEOF_DEBUGGER_PREPARE_DEBUGGEE, // Input buffer // length DebuggeeRequest, // Output Buffer from driver. SIZEOF_DEBUGGER_PREPARE_DEBUGGEE, // Length of output // buffer in bytes. &ReturnedLength, // Bytes placed in buffer. NULL // synchronous call ); if (!StatusIoctl) { PlatformCloseHandle(Comm); g_SerialRemoteComPortHandle = NULL; g_IsConnectedToHyperDbgLocally = FALSE; ShowMessages("ioctl failed with code 0x%x\n", PlatformGetLastError()); // // Free the buffer // free(DebuggeeRequest); return FALSE; } if (DebuggeeRequest->Result == DEBUGGER_OPERATION_WAS_SUCCESSFUL) { // // Ignore handling CTRL+C breaks // g_IgnorePauseRequests = TRUE; // // initialize and load symbols (pdb) and send the details to the debugger // ShowMessages("synchronizing modules' symbol details\n"); // // Do not pause debugger after finish // KdReloadSymbolsInDebuggee(FALSE, PlatformGetCurrentProcessId()); } else { PlatformCloseHandle(Comm); g_SerialRemoteComPortHandle = NULL; g_IsConnectedToHyperDbgLocally = FALSE; ShowErrorMessage(DebuggeeRequest->Result); // // Free the buffer // free(DebuggeeRequest); return FALSE; } // // show the message that the operation was successful, // we show it here because if we set the next variables // to true, then it will be sent to the debugger instead // of showing the message in debuggee // ShowMessages("the operation was successful\n"); // // Serial connection is not already closed // g_SerialConnectionAlreadyClosed = FALSE; // // Indicate that we connected to the debugger // g_IsSerialConnectedToRemoteDebugger = TRUE; // // Free the buffer // free(DebuggeeRequest); // // Wait here so the user can't give new commands // Create an event (manually. no signal) // g_DebuggeeStopCommandEventHandle = PlatformCreateEvent(FALSE, FALSE); // // Create a thread to listen for pauses from the remote debugger // g_SerialListeningThreadHandle = PlatformCreateThread(ListeningSerialPauseDebuggeeThread, NULL); // // Test should be removed // // HyperDbgInterpreter("!syscall script { print(@rax); }"); // HyperDbgInterpreter("!epthook fffff801`639b1030 script { print(@rax); // }"); HyperDbgInterpreter("!msrwrite script { print(@rax); }"); // // // Now we should wait on this state until the user closes the connection to // debuggee from debugger // PlatformWaitForSingleObject(g_DebuggeeStopCommandEventHandle, INFINITE); // // Close the event's handle // PlatformCloseHandle(g_DebuggeeStopCommandEventHandle); g_DebuggeeStopCommandEventHandle = NULL; // // Handle CTRL+C breaks again // g_IgnorePauseRequests = FALSE; // // Finish it here // return TRUE; } else { // // Save the handler // g_SerialRemoteComPortHandle = Comm; // // If we are here, then it's a debugger (not debuggee) // let's prepare the debuggee // KdPrepareSerialConnectionToRemoteSystem(Comm, IsNamedPipe, PauseAfterConnection); } // // everything was done // return TRUE; } /** * @brief Send general buffer from debuggee to debugger * @param RequestedAction * @param Buffer * @param Length * @param PauseDebuggeeWhenSent * * @return BOOLEAN */ BOOLEAN KdSendGeneralBuffersFromDebuggeeToDebugger( DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION RequestedAction, PVOID Buffer, UINT32 BufferLength, BOOLEAN PauseDebuggeeWhenSent) { BOOL Status; ULONG ReturnedLength; PDEBUGGEE_SEND_GENERAL_PACKET_FROM_DEBUGGEE_TO_DEBUGGER GeneralPacketFromDebuggeeToDebuggerRequest; UINT32 Length; // // Compute the length of the packet (add to header ) // Length = sizeof(DEBUGGEE_SEND_GENERAL_PACKET_FROM_DEBUGGEE_TO_DEBUGGER) + BufferLength; // // Allocate the target buffer // GeneralPacketFromDebuggeeToDebuggerRequest = (PDEBUGGEE_SEND_GENERAL_PACKET_FROM_DEBUGGEE_TO_DEBUGGER)malloc(Length); if (GeneralPacketFromDebuggeeToDebuggerRequest == NULL) { // // err, allocating buffer // return FALSE; } PlatformZeroMemory(GeneralPacketFromDebuggeeToDebuggerRequest, Length); // // Fill the header structure // GeneralPacketFromDebuggeeToDebuggerRequest->RequestedAction = RequestedAction; GeneralPacketFromDebuggeeToDebuggerRequest->LengthOfBuffer = BufferLength; GeneralPacketFromDebuggeeToDebuggerRequest->PauseDebuggeeWhenSent = PauseDebuggeeWhenSent; // // Move the memory to the bottom of the structure // memcpy( (PVOID)((UINT64)GeneralPacketFromDebuggeeToDebuggerRequest + sizeof(DEBUGGEE_SEND_GENERAL_PACKET_FROM_DEBUGGEE_TO_DEBUGGER)), (PVOID)Buffer, BufferLength); // // Send Ioctl to the kernel // Status = PlatformDeviceIoControl( g_DeviceHandle, // Handle to device IOCTL_SEND_GENERAL_BUFFER_FROM_DEBUGGEE_TO_DEBUGGER, // IO Control Code (IOCTL) GeneralPacketFromDebuggeeToDebuggerRequest, // Input Buffer to driver. Length, // Input buffer // length GeneralPacketFromDebuggeeToDebuggerRequest, // Output Buffer from driver. SIZEOF_DEBUGGEE_SEND_GENERAL_PACKET_FROM_DEBUGGEE_TO_DEBUGGER, // Length // of // output // buffer // in // bytes. &ReturnedLength, // Bytes placed in buffer. NULL // synchronous call ); if (!Status) { ShowMessages("ioctl failed with code 0x%x\n", PlatformGetLastError()); free(GeneralPacketFromDebuggeeToDebuggerRequest); return FALSE; } if (GeneralPacketFromDebuggeeToDebuggerRequest->KernelResult != DEBUGGER_OPERATION_WAS_SUCCESSFUL) { ShowErrorMessage(GeneralPacketFromDebuggeeToDebuggerRequest->KernelResult); // // Free the buffer // free(GeneralPacketFromDebuggeeToDebuggerRequest); return FALSE; } free(GeneralPacketFromDebuggeeToDebuggerRequest); return TRUE; } /** * @brief Send the packets of reloading symbols to build a new * symbol table to the debugger and send the finished packet to * the debugger * @param PauseDebuggee * @param UserProcessId * * @return BOOLEAN */ BOOLEAN KdReloadSymbolsInDebuggee(BOOLEAN PauseDebuggee, UINT32 UserProcessId) { DEBUGGEE_SYMBOL_UPDATE_RESULT SymReload = {0}; // // In kernel debugger, if the process id is not specified // we choose the HyperDbg's process to load its modules // if (UserProcessId == NULL) { UserProcessId = PlatformGetCurrentProcessId(); } // // Request debuggee to send new symbol packets // SymbolPrepareDebuggerWithSymbolInfo(UserProcessId); // // Set the status // SymReload.KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL; // // Send the finished request packet // return KdSendGeneralBuffersFromDebuggeeToDebugger( DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_DEBUGGEE_RELOAD_SYMBOL_FINISHED, &SymReload, sizeof(DEBUGGEE_SYMBOL_UPDATE_RESULT), PauseDebuggee); } /** * @brief Send close packet to the debuggee and debugger * @details This function close the connection in both debuggee and debugger * both of the debuggee and debugger can use this function * * @return BOOLEAN */ BOOLEAN KdCloseConnection() { // // The process of closing connection already started // if (g_SerialConnectionAlreadyClosed) { return TRUE; } else { g_SerialConnectionAlreadyClosed = TRUE; } // // Unload the VMM driver if it's debuggee // if (g_IsSerialConnectedToRemoteDebugger) { if (g_IsConnectedToHyperDbgLocally && g_IsKdModuleLoaded) { // // The messages (and outputs) should no longer be passed // to the debugger, so we'll indicate that debugger is not // connected anymore // g_IsSerialConnectedToRemoteDebugger = FALSE; // // Unload VMM // HyperDbgUnloadVmm(); } } else if (g_IsSerialConnectedToRemoteDebuggee) { // // Send close & unload packet to debuggee (vmx-root) // if (KdCommandPacketToDebuggee( DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGER_TO_DEBUGGEE_EXECUTE_ON_VMX_ROOT, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_MODE_CLOSE_AND_UNLOAD_DEBUGGEE)) { // // It's a debugger, we should send the close packet to debuggee // ShowMessages("unloading debugger vmm module on debuggee..."); // // Send another packet so the user-mode is not waiting for new packet // KdCommandPacketToDebuggee( DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGER_TO_DEBUGGEE_EXECUTE_ON_USER_MODE, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_USER_MODE_DO_NOT_READ_ANY_PACKET); } } else { // // If we're here, probably the connection started but the debuggee is closed // without sending the start packet; thus, the debugger has no idea about // connection but we should uninitialize everything // ShowMessages("err, start packet not received but the target machine closed the " "connection\n"); // // Not waiting for start packet // DbgReceivedKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_STARTED_PACKET_RECEIVED); } // // Close handle and uninitialize everything // KdUninitializeConnection(); return TRUE; } /** * @brief Register an event in the debuggee * @param EventRegBuffer * @param Length * * @return BOOLEAN */ BOOLEAN KdRegisterEventInDebuggee(PDEBUGGER_GENERAL_EVENT_DETAIL EventRegBuffer, UINT32 Length) { BOOL Status; ULONG ReturnedLength; DEBUGGER_EVENT_AND_ACTION_RESULT ReturnedBuffer = {0}; AssertShowMessageReturnStmt(g_IsVmmModuleLoaded, g_DeviceHandle, ASSERT_MESSAGE_VMM_NOT_LOADED, ASSERT_MESSAGE_DRIVER_NOT_LOADED, AssertReturnFalse); // // Send IOCTL // Status = PlatformDeviceIoControl(g_DeviceHandle, // Handle to device IOCTL_DEBUGGER_REGISTER_EVENT, // IO Control Code (IOCTL) EventRegBuffer, Length // Input Buffer to driver. , // Input buffer length &ReturnedBuffer, // Output Buffer from driver. sizeof(DEBUGGER_EVENT_AND_ACTION_RESULT), // Length // of // output // buffer // in // bytes. &ReturnedLength, // Bytes placed in buffer. NULL // synchronous call ); if (!Status) { ShowMessages("ioctl failed with code 0x%x\n", PlatformGetLastError()); return FALSE; } // // Now that we registered the event (with or without error), // we should send the results back to the debugger // return KdSendGeneralBuffersFromDebuggeeToDebugger( DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_DEBUGGEE_RESULT_OF_REGISTERING_EVENT, &ReturnedBuffer, sizeof(DEBUGGER_EVENT_AND_ACTION_RESULT), TRUE); } /** * @brief Add action to an event in the debuggee * @param ActionAddingBuffer * @param Length * * @return BOOLEAN */ BOOLEAN KdAddActionToEventInDebuggee(PDEBUGGER_GENERAL_ACTION ActionAddingBuffer, UINT32 Length) { BOOL Status; ULONG ReturnedLength; DEBUGGER_EVENT_AND_ACTION_RESULT ReturnedBuffer = {0}; AssertShowMessageReturnStmt(g_IsVmmModuleLoaded, g_DeviceHandle, ASSERT_MESSAGE_VMM_NOT_LOADED, ASSERT_MESSAGE_DRIVER_NOT_LOADED, AssertReturnFalse); Status = PlatformDeviceIoControl(g_DeviceHandle, // Handle to device IOCTL_DEBUGGER_ADD_ACTION_TO_EVENT, // IO Control Code (IOCTL) ActionAddingBuffer, // Input Buffer to driver. Length, // Input buffer length &ReturnedBuffer, // Output Buffer from driver. sizeof(DEBUGGER_EVENT_AND_ACTION_RESULT), // Length // of // output // buffer // in // bytes. &ReturnedLength, // Bytes placed in buffer. NULL // synchronous call ); if (!Status) { ShowMessages("ioctl failed with code 0x%x\n", PlatformGetLastError()); return FALSE; } // // Now that we added the action to the event, we should send the // results to the debugger // return KdSendGeneralBuffersFromDebuggeeToDebugger( DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_DEBUGGEE_RESULT_OF_ADDING_ACTION_TO_EVENT, &ReturnedBuffer, sizeof(DEBUGGER_EVENT_AND_ACTION_RESULT), TRUE); } /** * @brief Modify the event ioctl in the debuggee * @param ModifyEvent * @param SendTheResultBackToDebugger * * @return BOOLEAN */ BOOLEAN KdSendModifyEventInDebuggee(PDEBUGGER_MODIFY_EVENTS ModifyEvent, BOOLEAN SendTheResultBackToDebugger) { BOOLEAN Status; ULONG ReturnedLength; // // This mechanism is only used for clear event, // it is because we apply enable/disable in kernel // directly // // // Check if debugger is loaded or not // AssertShowMessageReturnStmt(g_IsVmmModuleLoaded, g_DeviceHandle, ASSERT_MESSAGE_VMM_NOT_LOADED, ASSERT_MESSAGE_DRIVER_NOT_LOADED, AssertReturnFalse); // // Send the request to the kernel // Status = PlatformDeviceIoControl(g_DeviceHandle, // Handle to device IOCTL_DEBUGGER_MODIFY_EVENTS, // IO Control Code (IOCTL) ModifyEvent, // Input Buffer to driver. SIZEOF_DEBUGGER_MODIFY_EVENTS, // Input buffer length ModifyEvent, // Output Buffer from driver. SIZEOF_DEBUGGER_MODIFY_EVENTS, // Length of output // buffer in bytes. &ReturnedLength, // Bytes placed in buffer. NULL // synchronous call ); if (!Status) { ShowMessages("ioctl failed with code 0x%x\n", PlatformGetLastError()); return FALSE; } // // Send the buffer back to debugger // if (SendTheResultBackToDebugger) { return KdSendGeneralBuffersFromDebuggeeToDebugger( DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_DEBUGGEE_RESULT_OF_QUERY_AND_MODIFY_EVENT, ModifyEvent, sizeof(DEBUGGER_MODIFY_EVENTS), TRUE); } else { return TRUE; } } /** * @brief Handle user-input in debuggee * @param Descriptor * @return VOID */ VOID KdHandleUserInputInDebuggee(DEBUGGEE_USER_INPUT_PACKET * Descriptor) { BOOL Status; ULONG ReturnedLength; CHAR * Input; DEBUGGER_SEND_COMMAND_EXECUTION_FINISHED_SIGNAL FinishExecutionRequest = {0}; Input = (CHAR *)Descriptor + sizeof(DEBUGGEE_USER_INPUT_PACKET); // // Run the command // HyperDbgInterpreter(Input); // // Check if it needs to send a signal to indicate that the execution of // command finished // if (!Descriptor->IgnoreFinishedSignal) { // // By the way, we don't need to send an input buffer // to the kernel, but let's keep it like this, if we // want to pass some other arguments to the kernel in // the future // Status = PlatformDeviceIoControl( g_DeviceHandle, // Handle to device IOCTL_SEND_SIGNAL_EXECUTION_IN_DEBUGGEE_FINISHED, // IO Control Code (IOCTL) &FinishExecutionRequest, // Input Buffer to driver. SIZEOF_DEBUGGER_SEND_COMMAND_EXECUTION_FINISHED_SIGNAL, // Input buffer // length &FinishExecutionRequest, // Output Buffer from driver. SIZEOF_DEBUGGER_SEND_COMMAND_EXECUTION_FINISHED_SIGNAL, // Length of // output buffer // in bytes. &ReturnedLength, // Bytes placed in buffer. NULL // synchronous call ); if (!Status) { ShowMessages("ioctl failed with code 0x%x\n", PlatformGetLastError()); return; } } } /** * @brief Send result of user-mode ShowMessages to debuggee * @param Input * @param Length * @return VOID */ VOID KdSendUsermodePrints(CHAR * Input, UINT32 Length) { BOOL Status; ULONG ReturnedLength; PDEBUGGER_SEND_USERMODE_MESSAGES_TO_DEBUGGER UsermodeMessageRequest; UINT32 SizeToSend; SizeToSend = sizeof(DEBUGGER_SEND_USERMODE_MESSAGES_TO_DEBUGGER) + Length; UsermodeMessageRequest = (DEBUGGER_SEND_USERMODE_MESSAGES_TO_DEBUGGER *)malloc(SizeToSend); PlatformZeroMemory(UsermodeMessageRequest, SizeToSend); // // Set the length // UsermodeMessageRequest->Length = Length; // // Move the user message buffer at the bottom of the structure packet // memcpy((PVOID)((UINT64)UsermodeMessageRequest + sizeof(DEBUGGER_SEND_USERMODE_MESSAGES_TO_DEBUGGER)), (PVOID)Input, Length); Status = PlatformDeviceIoControl( g_DeviceHandle, // Handle to device IOCTL_SEND_USERMODE_MESSAGES_TO_DEBUGGER, // IO Control Code (IOCTL) UsermodeMessageRequest, // Input Buffer to driver. SizeToSend, // Input buffer // length UsermodeMessageRequest, // Output Buffer from driver. SizeToSend, // Length of // output buffer // in bytes. &ReturnedLength, // Bytes placed in buffer. NULL // synchronous call ); if (!Status) { ShowMessages("ioctl failed with code 0x%x\n", PlatformGetLastError()); free(UsermodeMessageRequest); return; } free(UsermodeMessageRequest); } /** * @brief Send each packet of debugging information (PDB) to the debugger * @param SymbolDetailPacket * @param CurrentSymbolInfoIndex * @param TotalSymbols * * @return VOID */ VOID KdSendSymbolDetailPacket(PMODULE_SYMBOL_DETAIL SymbolDetailPacket, UINT32 CurrentSymbolInfoIndex, UINT32 TotalSymbols) { BOOLEAN Result; PDEBUGGER_UPDATE_SYMBOL_TABLE UsermodeSymDetailRequest; UsermodeSymDetailRequest = (DEBUGGER_UPDATE_SYMBOL_TABLE *)malloc(sizeof(DEBUGGER_UPDATE_SYMBOL_TABLE)); PlatformZeroMemory(UsermodeSymDetailRequest, sizeof(DEBUGGER_UPDATE_SYMBOL_TABLE)); // // Set other parameters for the symbol details // UsermodeSymDetailRequest->CurrentSymbolIndex = CurrentSymbolInfoIndex; UsermodeSymDetailRequest->TotalSymbols = TotalSymbols; // // Move the user message buffer at the bottom of the structure packet // memcpy((PVOID)((UINT64)&UsermodeSymDetailRequest->SymbolDetailPacket), (PVOID)SymbolDetailPacket, sizeof(MODULE_SYMBOL_DETAIL)); // // Send the symbol update buffer to the debugger // Result = KdSendGeneralBuffersFromDebuggeeToDebugger( DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_DEBUGGEE_UPDATE_SYMBOL_INFO, UsermodeSymDetailRequest, sizeof(DEBUGGER_UPDATE_SYMBOL_TABLE), FALSE); if (!Result) { ShowMessages("err, sending symbol packets failed in debuggee"); free(UsermodeSymDetailRequest); return; } free(UsermodeSymDetailRequest); } /** * @brief Uninitialize everything in both debuggee and debugger * @details This function close the connection in both debuggee and debugger * both of the debuggee and debugger can use this function * * @return VOID */ VOID KdUninitializeConnection() { // // Close the handles of the listening threads // if (g_SerialListeningThreadHandle != NULL) { PlatformCloseHandle(g_SerialListeningThreadHandle); g_SerialListeningThreadHandle = NULL; } #ifdef _WIN32 // // The overlapped I/O events only exist on the Windows serial path (they are // created in KdPrepareAndConnectDebugPort), so they are only closed here. // if (g_OverlappedIoStructureForReadDebugger.hEvent != NULL) { CloseHandle(g_OverlappedIoStructureForReadDebugger.hEvent); } if (g_OverlappedIoStructureForReadDebuggee.hEvent != NULL) { CloseHandle(g_OverlappedIoStructureForReadDebuggee.hEvent); } if (g_OverlappedIoStructureForWriteDebugger.hEvent != NULL) { CloseHandle(g_OverlappedIoStructureForWriteDebugger.hEvent); } #endif // _WIN32 if (g_DebuggeeStopCommandEventHandle != NULL) { // // Signal the debuggee to get new commands // PlatformSetEvent(g_DebuggeeStopCommandEventHandle); } // // Unpause the debugger to get commands // DbgReceivedKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_IS_DEBUGGER_RUNNING); // // Close synchronization objects // for (SIZE_T i = 0; i < DEBUGGER_MAXIMUM_SYNCRONIZATION_KERNEL_DEBUGGER_OBJECTS; i++) { if (g_KernelSyncronizationObjectsHandleTable[i].EventHandle != NULL) { if (g_KernelSyncronizationObjectsHandleTable[i].IsOnWaitingState) { DbgReceivedKernelResponse(i); } PlatformCloseHandle(g_KernelSyncronizationObjectsHandleTable[i].EventHandle); g_KernelSyncronizationObjectsHandleTable[i].EventHandle = NULL; } } // // Unallocate symbol data // SymbolDeleteSymTable(); // // No current core // g_CurrentRemoteCore = DEBUGGER_DEBUGGEE_IS_RUNNING_NO_CORE; // // Not in handshaking phase // g_IsDebuggeeInHandshakingPhase = FALSE; // // If connected to debugger // g_IsSerialConnectedToRemoteDebugger = FALSE; // // No longer connected to the debuggee // g_IsSerialConnectedToRemoteDebuggee = FALSE; // // And debuggee is not running // g_IsDebuggeeRunning = FALSE; // // Not repeating the last command // g_ShouldPreviousCommandBeContinued = FALSE; // // Clear the handler // if (g_SerialRemoteComPortHandle != NULL) { PlatformCloseHandle(g_SerialRemoteComPortHandle); g_SerialRemoteComPortHandle = NULL; } // // Start getting debuggee messages on next try // g_IgnoreNewLoggingMessages = FALSE; // // Is serial handle for a named pipe // g_IsDebuggerConntectedToNamedPipe = FALSE; } /** * @brief Sends '!pcitree' command, including buffer, to the debuggee * @param PcitreePacket * * @return BOOLEAN */ BOOLEAN KdSendPcitreePacketToDebuggee(PDEBUGGEE_PCITREE_REQUEST_RESPONSE_PACKET PcitreePacket) { // // Send '!pcitree' packet // if (!KdCommandPacketAndBufferToDebuggee( DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGER_TO_DEBUGGEE_EXECUTE_ON_VMX_ROOT, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_QUERY_PCITREE, (CHAR *)PcitreePacket, sizeof(DEBUGGEE_PCITREE_REQUEST_RESPONSE_PACKET))) { return FALSE; } // // Wait until the result of Pcitree packet is received // DbgWaitForKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_PCITREE_RESULT); return TRUE; } /** * @brief Request PCI device info (CAM). Current consumers include '!pcicam'. * @param PciepinfoPacket * * @return BOOLEAN */ BOOLEAN KdSendPcidevinfoPacketToDebuggee(PDEBUGGEE_PCIDEVINFO_REQUEST_RESPONSE_PACKET PciepinfoPacket) { // // Send Pciepinfo packet // if (!KdCommandPacketAndBufferToDebuggee( DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGER_TO_DEBUGGEE_EXECUTE_ON_VMX_ROOT, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_QUERY_PCIDEVINFO, (CHAR *)PciepinfoPacket, sizeof(DEBUGGEE_PCIDEVINFO_REQUEST_RESPONSE_PACKET))) { return FALSE; } // // Wait until the result of Pcitree packet is received // DbgWaitForKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_PCIDEVINFO_RESULT); return TRUE; }