mirror of
https://github.com/HyperDbg/HyperDbg.git
synced 2026-07-11 18:19:36 +00:00
347 lines
10 KiB
C++
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;
|
|
}
|