HyperDbg/hyperdbg/libhyperdbg/code/app/packets.cpp
2026-06-05 19:21:41 +02:00

347 lines
10 KiB
C++

/**
* @file packets.cpp
* @author Sina Karvandi (sina@hyperdbg.org)
* @brief Functions for handling packets from the driver
* @details
* @version 0.19
* @date 2026-05-28
*
* @copyright This project is released under the GNU Public License v3.
*
*/
#include "pch.h"
using namespace std;
//
// Global Variables
//
extern HANDLE g_DeviceHandle;
extern HANDLE g_IsDriverLoadedSuccessfully;
extern BOOLEAN g_IsMessageLoggingWindowClosed;
extern BOOLEAN g_BreakPrintingOutput;
extern BOOLEAN g_OutputSourcesInitialized;
/**
* @brief Read kernel buffers using IRP Pending
*
* @param Device Driver handle
* @return VOID
*/
VOID
ReadIrpBasedBuffer()
{
BOOL Status;
ULONG ReturnedLength;
REGISTER_NOTIFY_BUFFER RegisterEvent;
DWORD ErrorNum;
HANDLE Handle;
UINT32 OperationCode;
RegisterEvent.hEvent = NULL;
RegisterEvent.Type = IRP_BASED;
//
// Keep the packet reader on a dedicated synchronous handle. It blocks on
// a pending IOCTL while the main debugger handle continues sending other
// synchronous IOCTLs.
//
Handle = CreateFileA(
"\\\\.\\HyperDbgDebuggerDevice",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, /// lpSecurityAttirbutes
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL); /// lpTemplateFile
if (Handle == INVALID_HANDLE_VALUE)
{
ErrorNum = GetLastError();
if (ErrorNum == ERROR_ACCESS_DENIED)
{
ShowMessages("err, access denied\nare you sure you have administrator "
"rights?\n");
}
else if (ErrorNum == ERROR_GEN_FAILURE)
{
ShowMessages("err, a device attached to the system is not functioning\n"
"vmx feature might be disabled from BIOS or VBS/HVCI is active\n");
}
else
{
ShowMessages("err, CreateFile failed with (%x)\n", ErrorNum);
}
g_DeviceHandle = NULL;
Handle = NULL;
return;
}
//
// allocate buffer for transferring messages
//
CHAR * OutputBuffer = (CHAR *)malloc(UsermodeBufferSize);
try
{
while (!g_IsMessageLoggingWindowClosed)
{
//
// Clear the buffer
//
ZeroMemory(OutputBuffer, UsermodeBufferSize);
Status = DeviceIoControl(
Handle, // Handle to device
IOCTL_REGISTER_EVENT, // IO Control Code (IOCTL)
&RegisterEvent, // Input Buffer to driver.
SIZEOF_REGISTER_EVENT * 2, // Length of input buffer in bytes. (x 2 is bcuz as the
// driver is x64 and has 64 bit values)
OutputBuffer, // Output Buffer from driver.
UsermodeBufferSize, // Length of output buffer in bytes.
&ReturnedLength, // Bytes placed in buffer.
NULL // synchronous call
);
if (!Status)
{
//
// Error occurred for second time, and we show the error message
//
// ShowMessages("ioctl failed with code 0x%x\n", GetLastError());
//
// if we reach here, the packet is probably failed, it might
// be because of using flush command
//
continue;
}
//
// Compute the received buffer's operation code
//
memcpy(&OperationCode, OutputBuffer, sizeof(UINT32));
// ShowMessages("Returned Length : 0x%x \n", ReturnedLength);
// ShowMessages("Operation Code : 0x%x \n", OperationCode);
//
// Check if the operation code contains mandatory debuggee bit
// If that's the case, we shouldn't wait (sleep) for new messages
//
if ((OperationCode & OPERATION_MANDATORY_DEBUGGEE_BIT) == 0)
{
Sleep(DefaultSpeedOfReadingKernelMessages); // we're not trying to eat all of the CPU ;)
}
switch (OperationCode)
{
case OPERATION_LOG_NON_IMMEDIATE_MESSAGE:
if (g_BreakPrintingOutput)
{
//
// means that the user asserts a CTRL+C or CTRL+BREAK Signal
// we shouldn't show or save anything in this case
//
continue;
}
ShowMessages("%s", OutputBuffer + sizeof(UINT32));
break;
case OPERATION_LOG_MESSAGE_MANDATORY:
ShowMessages("%s", OutputBuffer + sizeof(UINT32));
break;
case OPERATION_LOG_INFO_MESSAGE:
if (g_BreakPrintingOutput)
{
//
// means that the user asserts a CTRL+C or CTRL+BREAK Signal
// we shouldn't show or save anything in this case
//
continue;
}
ShowMessages("%s", OutputBuffer + sizeof(UINT32));
break;
case OPERATION_LOG_ERROR_MESSAGE:
if (g_BreakPrintingOutput)
{
//
// means that the user asserts a CTRL+C or CTRL+BREAK Signal
// we shouldn't show or save anything in this case
//
continue;
}
ShowMessages("%s", OutputBuffer + sizeof(UINT32));
break;
case OPERATION_LOG_WARNING_MESSAGE:
if (g_BreakPrintingOutput)
{
//
// means that the user asserts a CTRL+C or CTRL+BREAK Signal
// we shouldn't show or save anything in this case
//
continue;
}
ShowMessages("%s", OutputBuffer + sizeof(UINT32));
break;
case OPERATION_COMMAND_FROM_DEBUGGER_CLOSE_AND_UNLOAD_VMM:
KdCloseConnection();
break;
case OPERATION_DEBUGGEE_USER_INPUT:
KdHandleUserInputInDebuggee((DEBUGGEE_USER_INPUT_PACKET *)(OutputBuffer + sizeof(UINT32)));
break;
case OPERATION_DEBUGGEE_REGISTER_EVENT:
KdRegisterEventInDebuggee(
(PDEBUGGER_GENERAL_EVENT_DETAIL)(OutputBuffer + sizeof(UINT32)),
ReturnedLength);
break;
case OPERATION_DEBUGGEE_ADD_ACTION_TO_EVENT:
KdAddActionToEventInDebuggee(
(PDEBUGGER_GENERAL_ACTION)(OutputBuffer + sizeof(UINT32)),
ReturnedLength);
break;
case OPERATION_DEBUGGEE_CLEAR_EVENTS:
KdSendModifyEventInDebuggee(
(PDEBUGGER_MODIFY_EVENTS)(OutputBuffer + sizeof(UINT32)),
TRUE);
break;
case OPERATION_DEBUGGEE_CLEAR_EVENTS_WITHOUT_NOTIFYING_DEBUGGER:
KdSendModifyEventInDebuggee(
(PDEBUGGER_MODIFY_EVENTS)(OutputBuffer + sizeof(UINT32)),
FALSE);
break;
case OPERATION_HYPERVISOR_DRIVER_IS_SUCCESSFULLY_LOADED:
//
// Indicate that driver (Hypervisor) is loaded successfully
//
SetEvent(g_IsDriverLoadedSuccessfully);
break;
case OPERATION_HYPERVISOR_DRIVER_END_OF_IRPS:
//
// End of receiving messages (IRPs), nothing to do
// it will just end the thread at next round because of the check of
// g_IsMessageLoggingWindowClosed at the beginning of the loop
//
break;
case OPERATION_COMMAND_FROM_DEBUGGER_RELOAD_SYMBOL:
//
// Pause debugger after getting the results
//
KdReloadSymbolsInDebuggee(TRUE,
((PDEBUGGEE_SYMBOL_REQUEST_PACKET)(OutputBuffer + sizeof(UINT32)))->ProcessId);
break;
case OPERATION_NOTIFICATION_FROM_USER_DEBUGGER_PAUSE:
//
// handle pausing packet from user debugger
//
UdHandleUserDebuggerPausing(
(PDEBUGGEE_UD_PAUSED_PACKET)(OutputBuffer + sizeof(UINT32)));
break;
default:
//
// Check if there are available output sources
//
if (!g_OutputSourcesInitialized || !ForwardingCheckAndPerformEventForwarding(OperationCode,
OutputBuffer + sizeof(UINT32),
ReturnedLength - sizeof(UINT32) - 1))
{
if (g_BreakPrintingOutput)
{
//
// means that the user asserts a CTRL+C or CTRL+BREAK Signal
// we shouldn't show or save anything in this case
//
continue;
}
ShowMessages("%s", OutputBuffer + sizeof(UINT32));
}
break;
}
}
}
catch (const std::exception &)
{
ShowMessages("err, exception occurred in creating handle or parsing buffer\n");
}
free(OutputBuffer);
//
// close handle
//
if (!CloseHandle(Handle))
{
ShowMessages("err, closing handle 0x%x\n", GetLastError());
}
}
/**
* @brief Create a thread for pending buffers
*
* @param Data
* @return DWORD Device Handle
*/
DWORD WINAPI
IrpBasedBufferThread(PVOID Data)
{
//
// Do stuff. This will be the first function called on the new
// thread. When this function returns, the thread goes away. See
// MSDN for more details. Test Irp Based Notifications
//
ReadIrpBasedBuffer();
return 0;
}