diff --git a/CREDITS.md b/CREDITS.md index 3d5b0072..49454b29 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -29,4 +29,5 @@ Just so you know – the attributions listed on this credits page are acknowledg - unrustled.jimmies for helping us debug and fix issues, and his contributions in HyperDbg - Hari Mishal ([@harimishal1](https://github.com/harimishal1)) for his works on the hypertrace project for supporting Last Branch Record (LBR) - Masoud Rahimi Jafari ([@masoudrahimi01](https://github.com/masoudrahimi01)) for his works on the hypertrace project for supporting Intel Processor Trace (PT) -- Abolfazl Hassani ([@FallinBinary](https://github.com/FallinBinary)) for his contributions in HyperDbg \ No newline at end of file +- Abolfazl Hassani ([@FallinBinary](https://github.com/FallinBinary)) for his contributions in HyperDbg +- Hossein Shirdel ([@nikzad66](https://github.com/nikzad66)) for his contributions in HyperDbg \ No newline at end of file diff --git a/hyperdbg/hyperkd/code/debugger/commands/DebuggerCommands.c b/hyperdbg/hyperkd/code/debugger/commands/DebuggerCommands.c index 2f530a49..7b62b2e9 100644 --- a/hyperdbg/hyperkd/code/debugger/commands/DebuggerCommands.c +++ b/hyperdbg/hyperkd/code/debugger/commands/DebuggerCommands.c @@ -1529,6 +1529,104 @@ DebuggerCommandCpuid(PDEBUGGER_CPUID_REQUEST_RESPONSE DebuggerCpuidRequest) return STATUS_SUCCESS; } +/** + * @brief Handle User IN request in vmx-root mode + * + * @param DebuggerUserInRequest perform IN instruction (user specified) + * @return NTSTATUS + */ +NTSTATUS +DebuggerCommandUserIn(PDEBUGGER_USER_IN_REQUEST_RESPONSE DebuggerUserInRequest) +{ + SHORT Register = DebuggerUserInRequest->UserChosenRegister; + USHORT Port = DebuggerUserInRequest->PortAddress; + + // + // Zero out memory buffer + // + RtlZeroMemory(DebuggerUserInRequest, SIZEOF_DEBUGGER_USER_IN_REQUEST_RESPONSE); + + // + // we're already in kernel mode, so there is no need to check for CPL and IOPL, TSS and etc. + // + + // + // handle I/O instructions + // + switch (Register) + { + // + // store the results in the Data field + // + case AL_8_BIT_REGISTER: + DebuggerUserInRequest->Data = CpuIoInByte(Port); + + break; + + case AX_16_BIT_REGISTER: + DebuggerUserInRequest->Data = CpuIoInWord(Port); + + break; + + case EAX_32_BIT_REGISTER: + DebuggerUserInRequest->Data = CpuIoInDword(Port); + + break; + } + + DebuggerUserInRequest->KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL; + + return STATUS_SUCCESS; +} + +/** + * @brief Handle User OUT request in vmx-root mode + * + * @param DebuggerUserInRequest perform OUT instruction (user specified) + * @return NTSTATUS + */ +NTSTATUS +DebuggerCommandUserOut(PDEBUGGER_USER_OUT_REQUEST_RESPONSE DebuggerUserOutRequest) +{ + SHORT Register = DebuggerUserOutRequest->UserChosenRegister; + USHORT Port = DebuggerUserOutRequest->PortAddress; + UINT32 Value = DebuggerUserOutRequest->Value; + + // + // Zero out memory buffer + // + RtlZeroMemory(DebuggerUserOutRequest, SIZEOF_DEBUGGER_USER_OUT_REQUEST_RESPONSE); + + // + // we're already in kernel mode, so there is no need to check for CPL and IOPL, TSS and etc. + // + + // + // handle I/O instructions + // + switch (Register) + { + case AL_8_BIT_REGISTER: + __outbyte(Port, (UCHAR)Value); + + break; + + case AX_16_BIT_REGISTER: + __outword(Port, (USHORT)Value); + + break; + + case EAX_32_BIT_REGISTER: + __outdword(Port, Value); + + break; + } + + DebuggerUserOutRequest->KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL; + + return STATUS_SUCCESS; +} + /** * @brief Perform the command finished signal * diff --git a/hyperdbg/hyperkd/code/debugger/kernel-level/Kd.c b/hyperdbg/hyperkd/code/debugger/kernel-level/Kd.c index 3fdaf881..89305a12 100644 --- a/hyperdbg/hyperkd/code/debugger/kernel-level/Kd.c +++ b/hyperdbg/hyperkd/code/debugger/kernel-level/Kd.c @@ -2261,6 +2261,8 @@ KdDispatchAndPerformCommandsFromDebugger(PROCESSOR_DEBUGGING_STATE * DbgState) PDEBUGGEE_STEP_PACKET SteppingPacket; PDEBUGGER_FLUSH_LOGGING_BUFFERS FlushPacket; PDEBUGGER_CPUID_REQUEST_RESPONSE CpuidPacket; + PDEBUGGER_USER_IN_REQUEST_RESPONSE InPacket; + PDEBUGGER_USER_OUT_REQUEST_RESPONSE OutPacket; PDEBUGGER_CALLSTACK_REQUEST CallstackPacket; PDEBUGGER_SINGLE_CALLSTACK_FRAME CallstackFrameBuffer; PDEBUGGER_DEBUGGER_TEST_QUERY_BUFFER TestQueryPacket; @@ -2552,6 +2554,44 @@ KdDispatchAndPerformCommandsFromDebugger(PROCESSOR_DEBUGGING_STATE * DbgState) break; + case DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_MODE_USER_IN_INSTRUCTION: + + InPacket = (DEBUGGER_USER_IN_REQUEST_RESPONSE *)(((CHAR *)TheActualPacket) + sizeof(DEBUGGER_REMOTE_PACKET)); + + // + // Receieve IN instruction result + // + DebuggerCommandUserIn(InPacket); + + // + // Send the result of IN instruction back to the debugger + // + KdResponsePacketToDebugger(DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGEE_TO_DEBUGGER, + DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_DEBUGGEE_RESULT_OF_USER_IN_INSTRUCTION, + (CHAR *)InPacket, + sizeof(DEBUGGER_USER_IN_REQUEST_RESPONSE)); + + break; + + case DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_MODE_USER_OUT_INSTRUCTION: + + OutPacket = (DEBUGGER_USER_OUT_REQUEST_RESPONSE *)(((CHAR *)TheActualPacket) + sizeof(DEBUGGER_REMOTE_PACKET)); + + // + // Receieve OUT instruction result + // + DebuggerCommandUserOut(OutPacket); + + // + // Send the result of OUT instruction back to the debugger + // + KdResponsePacketToDebugger(DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGEE_TO_DEBUGGER, + DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_DEBUGGEE_RESULT_OF_USER_OUT_INSTRUCTION, + (CHAR *)OutPacket, + sizeof(DEBUGGER_USER_OUT_REQUEST_RESPONSE)); + + break; + case DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_MODE_CALLSTACK: CallstackPacket = (DEBUGGER_CALLSTACK_REQUEST *)(((CHAR *)TheActualPacket) + sizeof(DEBUGGER_REMOTE_PACKET)); diff --git a/hyperdbg/hyperkd/code/driver/Ioctl.c b/hyperdbg/hyperkd/code/driver/Ioctl.c index 16817ab2..f8df9e7a 100644 --- a/hyperdbg/hyperkd/code/driver/Ioctl.c +++ b/hyperdbg/hyperkd/code/driver/Ioctl.c @@ -411,6 +411,8 @@ DrvDispatchVmmIoControl(PIRP Irp, PIO_STACK_LOCATION IrpStack, BOOLEAN * DoNotCh PDEBUGGER_MODIFY_EVENTS DebuggerModifyEventRequest; PDEBUGGER_FLUSH_LOGGING_BUFFERS DebuggerFlushBuffersRequest; PDEBUGGER_CPUID_REQUEST_RESPONSE DebuggerCpuidRequest; + PDEBUGGER_USER_IN_REQUEST_RESPONSE DebuggerUserInRequest; + PDEBUGGER_USER_OUT_REQUEST_RESPONSE DebuggerUserOutRequest; PDEBUGGER_PREALLOC_COMMAND DebuggerReservePreallocPoolRequest; PDEBUGGER_PREACTIVATE_COMMAND DebuggerPreactivationRequest; PDEBUGGER_APIC_REQUEST DebuggerApicRequest; @@ -864,6 +866,62 @@ DrvDispatchVmmIoControl(PIRP Irp, PIO_STACK_LOCATION IrpStack, BOOLEAN * DoNotCh break; + case IOCTL_DEBUGGER_USER_IN: + + // + // Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP + // + if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_DEBUGGER_USER_IN_REQUEST_RESPONSE, + (PVOID *)&DebuggerUserInRequest, + Irp, + IrpStack, + &InBuffLength, + &OutBuffLength)) + { + Status = STATUS_INVALID_PARAMETER; + break; + } + + // + // Perform IN instruction + // + DebuggerCommandUserIn(DebuggerUserInRequest); + + // + // Adjust the status and output size + // + DrvAdjustStatusAndSetOutputSize(SIZEOF_DEBUGGER_USER_IN_REQUEST_RESPONSE, DoNotChangeInformation, Irp, &Status); + + break; + + case IOCTL_DEBUGGER_USER_OUT: + + // + // Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP + // + if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_DEBUGGER_USER_OUT_REQUEST_RESPONSE, + (PVOID *)&DebuggerUserOutRequest, + Irp, + IrpStack, + &InBuffLength, + &OutBuffLength)) + { + Status = STATUS_INVALID_PARAMETER; + break; + } + + // + // Perform OUT instruction + // + DebuggerCommandUserOut(DebuggerUserOutRequest); + + // + // Adjust the status and output size + // + DrvAdjustStatusAndSetOutputSize(SIZEOF_DEBUGGER_USER_OUT_REQUEST_RESPONSE, DoNotChangeInformation, Irp, &Status); + + break; + case IOCTL_DEBUGGER_ATTACH_DETACH_USER_MODE_PROCESS: // diff --git a/hyperdbg/hyperkd/header/debugger/commands/DebuggerCommands.h b/hyperdbg/hyperkd/header/debugger/commands/DebuggerCommands.h index 86f357a7..d5e47822 100644 --- a/hyperdbg/hyperkd/header/debugger/commands/DebuggerCommands.h +++ b/hyperdbg/hyperkd/header/debugger/commands/DebuggerCommands.h @@ -48,6 +48,12 @@ DebuggerCommandFlush(PDEBUGGER_FLUSH_LOGGING_BUFFERS DebuggerFlushBuffersRequest NTSTATUS DebuggerCommandCpuid(PDEBUGGER_CPUID_REQUEST_RESPONSE DebuggerCpuidRequest); +NTSTATUS +DebuggerCommandUserIn(PDEBUGGER_USER_IN_REQUEST_RESPONSE DebuggerUserInRequest); + +NTSTATUS +DebuggerCommandUserOut(PDEBUGGER_USER_OUT_REQUEST_RESPONSE DebuggerUserOutRequest); + NTSTATUS DebuggerCommandSignalExecutionState(PDEBUGGER_SEND_COMMAND_EXECUTION_FINISHED_SIGNAL DebuggerFinishedExecutionRequest); diff --git a/hyperdbg/include/SDK/headers/Connection.h b/hyperdbg/include/SDK/headers/Connection.h index ae758a1fc..cad5b6df 100644 --- a/hyperdbg/include/SDK/headers/Connection.h +++ b/hyperdbg/include/SDK/headers/Connection.h @@ -76,6 +76,8 @@ typedef enum _DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_MODE_CHANGE_CORE, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_MODE_FLUSH_BUFFERS, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_MODE_USER_CPUID_REQUEST, + DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_MODE_USER_IN_INSTRUCTION, + DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_MODE_USER_OUT_INSTRUCTION, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_MODE_CALLSTACK, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_MODE_TEST_QUERY, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_MODE_CHANGE_PROCESS, @@ -119,6 +121,8 @@ typedef enum _DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_DEBUGGEE_RESULT_OF_FORMATS, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_DEBUGGEE_RESULT_OF_FLUSH, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_DEBUGGEE_RESULT_OF_USER_CPUID, + DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_DEBUGGEE_RESULT_OF_USER_IN_INSTRUCTION, + DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_DEBUGGEE_RESULT_OF_USER_OUT_INSTRUCTION, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_DEBUGGEE_RESULT_OF_CALLSTACK, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_DEBUGGEE_RESULT_TEST_QUERY, DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_DEBUGGEE_RESULT_OF_REGISTERING_EVENT, diff --git a/hyperdbg/include/SDK/headers/Ioctls.h b/hyperdbg/include/SDK/headers/Ioctls.h index df5d54ae..66739f06 100644 --- a/hyperdbg/include/SDK/headers/Ioctls.h +++ b/hyperdbg/include/SDK/headers/Ioctls.h @@ -396,6 +396,20 @@ #define IOCTL_DEBUGGER_CPUID \ CTL_CODE(FILE_DEVICE_UNKNOWN, IOCTL_VMM_IOCTL + 0x27, METHOD_BUFFERED, FILE_ANY_ACCESS) +/** + * @brief ioctl, to perform IN instruction + * + */ +#define IOCTL_DEBUGGER_USER_IN \ + CTL_CODE(FILE_DEVICE_UNKNOWN, IOCTL_VMM_IOCTL + 0x28, METHOD_BUFFERED, FILE_ANY_ACCESS) + +/** + * @brief ioctl, to perform OUT instruction + * + */ +#define IOCTL_DEBUGGER_USER_OUT \ + CTL_CODE(FILE_DEVICE_UNKNOWN, IOCTL_VMM_IOCTL + 0x29, METHOD_BUFFERED, FILE_ANY_ACCESS) + ////////////////////////////////////////////////// // HyperTrace IOCTLs // ////////////////////////////////////////////////// diff --git a/hyperdbg/include/SDK/headers/RequestStructures.h b/hyperdbg/include/SDK/headers/RequestStructures.h index 70d60d9f..c5bb84cf 100644 --- a/hyperdbg/include/SDK/headers/RequestStructures.h +++ b/hyperdbg/include/SDK/headers/RequestStructures.h @@ -1774,3 +1774,47 @@ typedef struct _DEBUGGER_CPUID_REQUEST_RESPONSE } DEBUGGER_CPUID_REQUEST_RESPONSE, *PDEBUGGER_CPUID_REQUEST_RESPONSE; // ============================================================================================== + +#define SIZEOF_DEBUGGER_USER_IN_REQUEST_RESPONSE \ + sizeof(DEBUGGER_USER_IN_REQUEST_RESPONSE) + +/** + * @brief Cpu registers for I/O instructions (related to _DEBUGGER_USER_IN_REQUEST_RESPONSE + * and SIZEOF_DEBUGGER_USER_OUT_REQUEST_RESPONSE structs) + * + */ +typedef enum _DEBUGGER_CPU_REGISTER_USER_IO +{ + AL_8_BIT_REGISTER, + AX_16_BIT_REGISTER, + EAX_32_BIT_REGISTER +} DEBUGGER_CPU_REGISTER_USER_IO; + +/** + * @brief Request and response for user IN instruction + * + */ +typedef struct _DEBUGGER_USER_IN_REQUEST_RESPONSE +{ + DEBUGGER_CPU_REGISTER_USER_IO UserChosenRegister; // from enum data type (_DEBUGGER_CPU_REGISTER_USER_IO) + USHORT PortAddress; // totally 65,536 (2^16) port address (0 - 65,535) + ULONG Data; // returned result + + UINT32 KernelStatus; +} DEBUGGER_USER_IN_REQUEST_RESPONSE, *PDEBUGGER_USER_IN_REQUEST_RESPONSE; + +// ============================================================================================== + +#define SIZEOF_DEBUGGER_USER_OUT_REQUEST_RESPONSE \ + sizeof(DEBUGGER_USER_OUT_REQUEST_RESPONSE) + +typedef struct _DEBUGGER_USER_OUT_REQUEST_RESPONSE +{ + DEBUGGER_CPU_REGISTER_USER_IO UserChosenRegister; // from enum data type (_DEBUGGER_CPU_REGISTER_USER_IO) + USHORT PortAddress; // totally 65,536 (2^16) port address (0 - 65,535) + UINT32 Value; // the value to be written to the port address + + UINT32 KernelStatus; +} DEBUGGER_USER_OUT_REQUEST_RESPONSE, *PDEBUGGER_USER_OUT_REQUEST_RESPONSE; + +// ============================================================================================== diff --git a/hyperdbg/include/SDK/imports/user/HyperDbgLibImports.h b/hyperdbg/include/SDK/imports/user/HyperDbgLibImports.h index 112dbc97..604a2fec 100644 --- a/hyperdbg/include/SDK/imports/user/HyperDbgLibImports.h +++ b/hyperdbg/include/SDK/imports/user/HyperDbgLibImports.h @@ -336,6 +336,20 @@ hyperdbg_u_pt_mmap(HYPERTRACE_PT_MMAP_PACKETS * MmapRequest); IMPORT_EXPORT_LIBHYPERDBG BOOLEAN hyperdbg_u_request_cpuid(UINT32 FunctionId, UINT32 SubFunctionId); +// +// IN instruction related command +// Exported functionality of the 'uin' +// +IMPORT_EXPORT_LIBHYPERDBG BOOLEAN +hyperdebg_u_in_instruction(DEBUGGER_USER_IN_REQUEST_RESPONSE InRequest); + +// +// OUT instruction related command +// Exported functionality of the 'uout' +// +IMPORT_EXPORT_LIBHYPERDBG BOOLEAN +hyperdebg_u_out_instruction(DEBUGGER_USER_OUT_REQUEST_RESPONSE OutRequest); + // // Transparent mode related command // Exported functionality of the '!hide', and '!unhide' commands diff --git a/hyperdbg/libhyperdbg/code/common/common.cpp b/hyperdbg/libhyperdbg/code/common/common.cpp index 09556ded..c4c8c660 100644 --- a/hyperdbg/libhyperdbg/code/common/common.cpp +++ b/hyperdbg/libhyperdbg/code/common/common.cpp @@ -342,7 +342,7 @@ ConvertStringToUInt64(string TextToConvert, PUINT64 Result) } /** - * @brief check and convert string to a 32 bit unsigned it and also + * @brief check and convert string to a 32 bit unsigned int and also * check for special notations like 0x etc. * @param TextToConvert the target string * @param Result result will be save to the pointer @@ -433,6 +433,95 @@ ConvertStringToUInt32(string TextToConvert, PUINT32 Result) } } +/** + * @brief check and convert string to a 16 bit unsigned int and also + * check for special notations like 0x etc. + * @param TextToConvert the target string + * @param Result result will be save to the pointer + * @return BOOLEAN shows whether the conversion was successful or not + */ +BOOLEAN +ConvertStringToUInt16(string TextToConvert, PUINT16 Result) +{ + BOOLEAN IsDecimal = FALSE; // By default everything is hex + + if (TextToConvert.rfind("0x", 0) == 0 || TextToConvert.rfind("0X", 0) == 0 || + TextToConvert.rfind("\\x", 0) == 0 || + TextToConvert.rfind("\\X", 0) == 0) + { + TextToConvert = TextToConvert.erase(0, 2); + } + else if (TextToConvert.rfind('x', 0) == 0 || + TextToConvert.rfind('X', 0) == 0) + { + TextToConvert = TextToConvert.erase(0, 1); + } + else if (TextToConvert.rfind("0n", 0) == 0 || TextToConvert.rfind("0N", 0) == 0 || + TextToConvert.rfind("\\n", 0) == 0 || + TextToConvert.rfind("\\N", 0) == 0) + { + TextToConvert = TextToConvert.erase(0, 2); + IsDecimal = TRUE; + } + else if (TextToConvert.rfind('n', 0) == 0 || + TextToConvert.rfind('N', 0) == 0) + { + TextToConvert = TextToConvert.erase(0, 1); + IsDecimal = TRUE; + } + + TextToConvert.erase(remove(TextToConvert.begin(), TextToConvert.end(), '`'), + TextToConvert.end()); + + int Base = IsDecimal ? 10 : 16; + + if (IsDecimal) + { + if (!IsDecimalNotation(TextToConvert)) + { + return FALSE; + } + } + else + { + if (!IsHexNotation(TextToConvert)) + { + return FALSE; + } + } + + try + { + size_t Pos = 0; + unsigned long UL = std::stoul(TextToConvert, &Pos, Base); // use stoul (unsigned long) for 16-bit values + + // + // check for 16-bit overflow (0 - 65,535) + // + if (Pos != TextToConvert.size() || UL > (std::numeric_limits::max)()) + { + return FALSE; + } + + *Result = static_cast(UL); + return TRUE; + } + catch (std::invalid_argument const &) + { + // + // Bad input: std::invalid_argument thrown + // + return FALSE; + } + catch (std::out_of_range const &) + { + // + // Integer overflow: std::out_of_range thrown + // + return FALSE; + } +} + /** * @brief check and convert command token to a 64 bit unsigned integer * @@ -554,6 +643,28 @@ ConvertTokenToUInt32(CommandToken TargetToken, PUINT32 Result) return ConvertStringToUInt32(TargetTokenValue, Result); } +/** + * @brief check and convert command token to a 16 bit unsigned integer + * + * @param TargetToken the target command token + * @param Result result will be save to the pointer + * + * @return BOOLEAN shows whether the conversion was successful or not + */ +BOOLEAN +ConvertTokenToUInt16(CommandToken TargetToken, PUINT16 Result) +{ + // + // Extract the token type and value from the tuple + // + std::string TargetTokenValue = std::get<1>(TargetToken); + + // + // Convert the token value to 32 bit unsigned integer + // + return ConvertStringToUInt16(TargetTokenValue, Result); +} + /** * @brief checks whether the string ends with a special string or not * diff --git a/hyperdbg/libhyperdbg/ucpuid.cpp b/hyperdbg/libhyperdbg/code/debugger/commands/debugging-commands/ucpuid.cpp similarity index 99% rename from hyperdbg/libhyperdbg/ucpuid.cpp rename to hyperdbg/libhyperdbg/code/debugger/commands/debugging-commands/ucpuid.cpp index 2c932cac..2bd7e402 100644 --- a/hyperdbg/libhyperdbg/ucpuid.cpp +++ b/hyperdbg/libhyperdbg/code/debugger/commands/debugging-commands/ucpuid.cpp @@ -43,6 +43,10 @@ CommandUserCpuidHelp() /** * @brief ucpuid command show messages * + * @param FunctionId + * @param SubFunctionId + * @param CpuidRequest + * * @return VOID */ VOID @@ -2065,9 +2069,12 @@ CommandShowUserCpuidMessage(UINT32 FunctionId, /** * @brief ucpuid command handler * - * @return VOID + * @param FunctionId + * @param SubFunctionId + * + * @return BOOLEAN */ -VOID +BOOLEAN CommandCpuidRequestCpuid(UINT32 FunctionId, UINT32 SubFunctionId) { BOOL Status; @@ -2082,15 +2089,14 @@ CommandCpuidRequestCpuid(UINT32 FunctionId, UINT32 SubFunctionId) // // It's on a debugger mode // - KdSendUserCpuidPacketToDebuggee(FunctionId, SubFunctionId); - return; + return KdSendUserCpuidPacketToDebuggee(FunctionId, SubFunctionId); } else { // // It's on a local debugging mode // - AssertShowMessageReturnStmt(g_IsKdModuleLoaded, g_DeviceHandle, ASSERT_MESSAGE_KD_NOT_LOADED, ASSERT_MESSAGE_DRIVER_NOT_LOADED, AssertReturn); + AssertShowMessageReturnStmt(g_IsKdModuleLoaded, g_DeviceHandle, ASSERT_MESSAGE_KD_NOT_LOADED, ASSERT_MESSAGE_DRIVER_NOT_LOADED, AssertReturnFalse); // // By the way, we don't need to send an input buffer @@ -2113,17 +2119,19 @@ CommandCpuidRequestCpuid(UINT32 FunctionId, UINT32 SubFunctionId) if (!Status) { ShowMessages("ioctl failed with code 0x%x\n", PlatformGetLastError()); - return; + return FALSE; } if (CpuidRequest->KernelStatus == DEBUGGER_OPERATION_WAS_SUCCESSFUL) { CommandShowUserCpuidMessage(FunctionId, SubFunctionId, CpuidRequest); + return TRUE; } else { - ShowMessages("Receiving CPUID result was not successful :(\n"); + ShowMessages("Receiving CPUID result was not successful\n"); + return FALSE; } } } diff --git a/hyperdbg/libhyperdbg/code/debugger/commands/debugging-commands/uin.cpp b/hyperdbg/libhyperdbg/code/debugger/commands/debugging-commands/uin.cpp new file mode 100644 index 00000000..2179850b --- /dev/null +++ b/hyperdbg/libhyperdbg/code/debugger/commands/debugging-commands/uin.cpp @@ -0,0 +1,251 @@ +/** + * @file uin.cpp + * @author Nikzad (Hossein Shirdel) + * @brief uin command - read from i/o port address (user specified) + * @details + * @version 0.24 + * @date 2026-08-01 + * + * @copyright This project is released under the GNU Public License v3. + * + */ +#include "pch.h" + +// +// Global Variables +// +extern BOOLEAN g_IsKdModuleLoaded; +extern BOOLEAN g_IsSerialConnectedToRemoteDebuggee; + +/** + * @brief help of the uin command + * + * @return VOID + */ +VOID +CommandUserInHelp() +{ + ShowMessages( + "uin : Read from I/O port (User IN)\n\n" + "Syntax : uin \n\n" + "Parameters :\n" + " register : Destination register: AL, AX, or EAX (case-insensitive)\n" + " port : I/O port address (hex or decimal, 0x0000 - 0xFFFF)\n\n" + "Examples :\n" + " uin al 0x60 Read a byte from keyboard port\n" + " uin Ax 0x3F8 Read a word from COM1\n" + " uin EAX 0xCF8 Read 32-bit from PCI config address\n"); +} + +/** + * @brief uin command show messages + * + * @param UserChosenRegister + * @param PortAddress + * @param Data + * + * @return VOID + */ +VOID +CommandShowUserInMessage(USHORT UserChosenRegister, + USHORT PortAddress, + ULONG Data) +{ + const char * RegisterName = ""; + + switch (UserChosenRegister) + { + case AL_8_BIT_REGISTER: + RegisterName = "AL"; + break; + case AX_16_BIT_REGISTER: + RegisterName = "AX"; + break; + case EAX_32_BIT_REGISTER: + RegisterName = "EAX"; + break; + } + + ShowMessages(" Port: 0x%04X (%d)\n", PortAddress, PortAddress); + ShowMessages(" Register: %s\n", RegisterName); + ShowMessages(" Result: 0x%08X\n", Data); +} + +/** + * @brief uin command handler + * + * @param InRequest + * + * @return BOOLEAN + */ +BOOLEAN +CommandUserInRequest(DEBUGGER_USER_IN_REQUEST_RESPONSE InRequest) +{ + BOOL Status; + ULONG ReturnedLength; + USHORT UserChosenRegister = InRequest.UserChosenRegister; + USHORT PortAddress = InRequest.PortAddress; + + if (g_IsSerialConnectedToRemoteDebuggee) + { + // + // It's on a debugger mode + // + return KdSendUserInPacketToDebuggee(InRequest); + } + else + { + // + // It's on a local debugging mode + // + AssertShowMessageReturnStmt(g_IsKdModuleLoaded, g_DeviceHandle, ASSERT_MESSAGE_KD_NOT_LOADED, ASSERT_MESSAGE_DRIVER_NOT_LOADED, AssertReturnFalse); + + // + // 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_DEBUGGER_USER_IN, // IO Control Code (IOCTL) + &InRequest, // Input Buffer to driver. + SIZEOF_DEBUGGER_USER_IN_REQUEST_RESPONSE, // Input buffer length + &InRequest, // Output Buffer from driver. + SIZEOF_DEBUGGER_USER_IN_REQUEST_RESPONSE, // 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; + } + + if (InRequest.KernelStatus == DEBUGGER_OPERATION_WAS_SUCCESSFUL) + { + // + // The Data field is initialized to 0 before the ioctl call. + // After the ioctl call, the Data field is populated, so we shouldn't define Data variable + // before ioctl. Therefore, Data field must be defined after ioctl in order to be passed to + // CommandShowUserInMessage function, because IOCTL will populate Data field. + // + ULONG Data = InRequest.Data; + CommandShowUserInMessage(UserChosenRegister, PortAddress, Data); + + return TRUE; + } + else + { + ShowMessages("Receiving IN instruction result was not successful\n"); + return FALSE; + } + } +} + +/** + * @brief uin command handler + * + * @param CommandTokens + * @param Command + * + * @return VOID + */ +VOID +CommandUserIn(vector CommandTokens, string Command) +{ + DEBUGGER_USER_IN_REQUEST_RESPONSE InRequest = {}; + USHORT Port = 0; + BOOL SetRegister = FALSE; + BOOL SetPort = FALSE; + BOOLEAN IsFirstCommand = TRUE; + + if (CommandTokens.size() != 3) + { + ShowMessages("incorrect use of the '%s'\n\n", + GetCaseSensitiveStringFromCommandToken(CommandTokens.at(0)).c_str()); + CommandUserInHelp(); + return; + } + + for (auto Section : CommandTokens) + { + if (IsFirstCommand == TRUE) + { + IsFirstCommand = FALSE; + continue; + } + + // + // Parse Register (first parameter) + // + if (!SetRegister) + { + string RegisterStr = GetCaseSensitiveStringFromCommandToken(Section); + + // + // convert to lowercase for case-insensitive comparison + // + transform(RegisterStr.begin(), RegisterStr.end(), RegisterStr.begin(), ::tolower); + + // + // convert register string to enum + // + if (RegisterStr == "al") + { + InRequest.UserChosenRegister = AL_8_BIT_REGISTER; + } + else if (RegisterStr == "ax") + { + InRequest.UserChosenRegister = AX_16_BIT_REGISTER; + } + else if (RegisterStr == "eax") + { + InRequest.UserChosenRegister = EAX_32_BIT_REGISTER; + } + else + { + ShowMessages("invalid cpu register, please use `al`, `ax`, or `eax` (case-insensitive)\n\n"); + } + + SetRegister = TRUE; + continue; + } + + if (!SetPort) + { + // + // Parse Port Address (second parameter) + // + if (!ConvertTokenToUInt16(Section, &Port)) + { + ShowMessages("please specify a correct hex/dec value for port address\n\n"); + CommandUserInHelp(); + return; + } + + InRequest.PortAddress = Port; + + SetPort = TRUE; + continue; + } + } + + // + // Check if register and port address was provided + // + if (!SetRegister || !SetPort) + { + ShowMessages("missing required parameters\n"); + ShowMessages("Usage: uin \n\n"); + CommandUserInHelp(); + return; + } + + // + // use IN instruction + // + CommandUserInRequest(InRequest); +} diff --git a/hyperdbg/libhyperdbg/code/debugger/commands/debugging-commands/uout.cpp b/hyperdbg/libhyperdbg/code/debugger/commands/debugging-commands/uout.cpp new file mode 100644 index 00000000..756ca316 --- /dev/null +++ b/hyperdbg/libhyperdbg/code/debugger/commands/debugging-commands/uout.cpp @@ -0,0 +1,268 @@ +/** + * @file uout.cpp + * @author Nikzad (Hossein Shirdel) + * @brief uout command - write from cpu register to i/o port address (user specified) + * @details + * @version 0.24 + * @date 2026-08-01 + * + * @copyright This project is released under the GNU Public License v3. + * + */ +#include "pch.h" + +// +// Global Variables +// +extern BOOLEAN g_IsKdModuleLoaded; +extern BOOLEAN g_IsSerialConnectedToRemoteDebuggee; + +/** + * @brief help of the uout command + * + * @return VOID + */ +VOID +CommandUserOutHelp() +{ + ShowMessages( + "uout : Write to I/O port (User OUT)\n\n" + "Syntax : uout \n\n" + "Parameters :\n" + " register : Source register: AL, AX, or EAX (case-insensitive)\n" + " port : I/O port address (hex or decimal, 0x0000 - 0xFFFF)\n" + " value : Value to write (hex or decimal)\n\n" + "Examples :\n" + " uout al 0x60 0xED Write to keyboard controller\n" + " uout AX 0x3F8 0x004D Write word to COM1\n" + " uout Eax 0xCF8 0x80000000 Write 32-bit to PCI config address\n"); +} + +/** + * @brief uout command show messages + * + * @param UserChosenRegister + * @param PortAddress + * @param Value + * + * @return VOID + */ +VOID +CommandShowUserOutMessage(USHORT UserChosenRegister, + USHORT PortAddress, + UINT32 Value) +{ + const char * RegisterName = ""; + + switch (UserChosenRegister) + { + case AL_8_BIT_REGISTER: + RegisterName = "AL"; + break; + case AX_16_BIT_REGISTER: + RegisterName = "AX"; + break; + case EAX_32_BIT_REGISTER: + RegisterName = "EAX"; + break; + } + + ShowMessages(" Port: 0x%04X (%d)\n", PortAddress, PortAddress); + ShowMessages(" Register: %s\n", RegisterName); + ShowMessages(" Entered Value: 0x%08X\n", Value); +} + +/** + * @brief uout command handler + * + * @param OutRequest + * + * @return BOOLEAN + */ +BOOLEAN +CommandUserOutRequest(DEBUGGER_USER_OUT_REQUEST_RESPONSE OutRequest) +{ + BOOL Status; + ULONG ReturnedLength; + USHORT UserChosenRegister = OutRequest.UserChosenRegister; + USHORT PortAddress = OutRequest.PortAddress; + UINT32 Value = OutRequest.Value; + + if (g_IsSerialConnectedToRemoteDebuggee) + { + // + // It's on a debugger mode + // + return KdSendUserOutPacketToDebuggee(OutRequest); + } + else + { + // + // It's on a local debugging mode + // + AssertShowMessageReturnStmt(g_IsKdModuleLoaded, g_DeviceHandle, ASSERT_MESSAGE_KD_NOT_LOADED, ASSERT_MESSAGE_DRIVER_NOT_LOADED, AssertReturnFalse); + + // + // 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_DEBUGGER_USER_OUT, // IO Control Code (IOCTL) + &OutRequest, // Input Buffer to driver. + SIZEOF_DEBUGGER_USER_OUT_REQUEST_RESPONSE, // Input buffer length + &OutRequest, // Output Buffer from driver. + SIZEOF_DEBUGGER_USER_OUT_REQUEST_RESPONSE, // 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; + } + + if (OutRequest.KernelStatus == DEBUGGER_OPERATION_WAS_SUCCESSFUL) + { + CommandShowUserOutMessage(UserChosenRegister, PortAddress, Value); + + return TRUE; + } + + else + { + ShowMessages("Receiving OUT instruction result was not successful\n"); + + return FALSE; + } + } +} + +/** + * @brief uout command handler + * + * @param CommandTokens + * @param Command + * + * @return VOID + */ +VOID +CommandUserOut(vector CommandTokens, string Command) +{ + DEBUGGER_USER_OUT_REQUEST_RESPONSE OutRequest = {}; + USHORT Port = 0; + UINT32 Value = 0; + BOOL SetRegister = FALSE; + BOOL SetPort = FALSE; + BOOL SetValue = FALSE; + BOOLEAN IsFirstCommand = TRUE; + + if (CommandTokens.size() != 4) + { + ShowMessages("incorrect use of the '%s'\n\n", + GetCaseSensitiveStringFromCommandToken(CommandTokens.at(0)).c_str()); + CommandUserOutHelp(); + return; + } + + for (auto Section : CommandTokens) + { + if (IsFirstCommand == TRUE) + { + IsFirstCommand = FALSE; + continue; + } + + // + // Parse Register (first parameter) + // + if (!SetRegister) + { + string RegisterStr = GetCaseSensitiveStringFromCommandToken(Section); + + // + // convert to lowercase for case-insensitive comparison + // + transform(RegisterStr.begin(), RegisterStr.end(), RegisterStr.begin(), ::tolower); + + // + // convert register string to enum + // + if (RegisterStr == "al") + { + OutRequest.UserChosenRegister = AL_8_BIT_REGISTER; + } + else if (RegisterStr == "ax") + { + OutRequest.UserChosenRegister = AX_16_BIT_REGISTER; + } + else if (RegisterStr == "eax") + { + OutRequest.UserChosenRegister = EAX_32_BIT_REGISTER; + } + else + { + ShowMessages("invalid cpu register, please use `al`, `ax`, or `eax` (case-insensitive)\n\n"); + } + + SetRegister = TRUE; + continue; + } + + // + // Parse Port Address (second parameter) + // + if (!SetPort) + { + if (!ConvertTokenToUInt16(Section, &Port)) + { + ShowMessages("please specify a correct hex/dec value for port address\n\n"); + CommandUserOutHelp(); + return; + } + + OutRequest.PortAddress = Port; + + SetPort = TRUE; + continue; + } + + // + // Parse Value (third parameter) + // + if (!SetValue) + { + if (!ConvertTokenToUInt32(Section, &Value)) + { + ShowMessages("please specify a correct hex/dec value for Value\n\n"); + CommandUserOutHelp(); + return; + } + + OutRequest.Value = Value; + + SetValue = TRUE; + continue; + } + } + + // + // Check if register, port address, and value was provided + // + if (!SetRegister || !SetPort || !SetValue) + { + ShowMessages("missing required parameters\n"); + ShowMessages("Usage: uout \n\n"); + CommandUserOutHelp(); + return; + } + + // + // use OUT instruction + // + CommandUserOutRequest(OutRequest); +} diff --git a/hyperdbg/libhyperdbg/code/debugger/core/interpreter.cpp b/hyperdbg/libhyperdbg/code/debugger/core/interpreter.cpp index d5503b8c..852ec9dd 100644 --- a/hyperdbg/libhyperdbg/code/debugger/core/interpreter.cpp +++ b/hyperdbg/libhyperdbg/code/debugger/core/interpreter.cpp @@ -1423,6 +1423,9 @@ InitializeCommandsDictionary() g_CommandsList["ucpuid"] = {&CommandUserCpuid, &CommandUserCpuidHelp, DEBUGGER_COMMAND_USER_CPUID_ATTRIBUTES}; g_CommandsList["cpuid"] = {&CommandUserCpuid, &CommandUserCpuidHelp, DEBUGGER_COMMAND_USER_CPUID_ATTRIBUTES}; + g_CommandsList["uin"] = {&CommandUserIn, &CommandUserInHelp, DEBUGGER_COMMAND_USER_IN_ATTRIBUTES}; + g_CommandsList["uout"] = {&CommandUserOut, &CommandUserOutHelp, DEBUGGER_COMMAND_USER_OUT_ATTRIBUTES}; + g_CommandsList["pause"] = {&CommandPause, &CommandPauseHelp, DEBUGGER_COMMAND_PAUSE_ATTRIBUTES}; g_CommandsList[".pause"] = {&CommandPause, &CommandPauseHelp, DEBUGGER_COMMAND_PAUSE_ATTRIBUTES}; diff --git a/hyperdbg/libhyperdbg/code/debugger/kernel-level/kd.cpp b/hyperdbg/libhyperdbg/code/debugger/kernel-level/kd.cpp index fd7eba48..f13fc231 100644 --- a/hyperdbg/libhyperdbg/code/debugger/kernel-level/kd.cpp +++ b/hyperdbg/libhyperdbg/code/debugger/kernel-level/kd.cpp @@ -339,6 +339,9 @@ KdSendFlushPacketToDebuggee() /** * @brief Send a CPUID request to the debuggee * + * @param FunctionId + * @param SubFunctionId + * * @return BOOLEAN */ BOOLEAN @@ -368,6 +371,66 @@ KdSendUserCpuidPacketToDebuggee(UINT32 FunctionId, UINT32 SubFunctionId) return TRUE; } +/** + * @brief Send IN instruction to the debuggee + * + * @param InRequest + * + * @return BOOLEAN + */ +BOOLEAN +KdSendUserInPacketToDebuggee(DEBUGGER_USER_IN_REQUEST_RESPONSE InRequest) +{ + // + // Send 'uin' command as packet + // + if (!KdCommandPacketAndBufferToDebuggee( + DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGER_TO_DEBUGGEE_EXECUTE_ON_VMX_ROOT, + DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_MODE_USER_IN_INSTRUCTION, + (CHAR *)&InRequest, + sizeof(DEBUGGER_USER_IN_REQUEST_RESPONSE))) + { + return FALSE; + } + + // + // Wait until the result of IN instruction received + // + DbgWaitForKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_USER_IN_RESULT); + + return TRUE; +} + +/** + * @brief Send OUT instruction to the debuggee + * + * @param OutRequest + * + * @return BOOLEAN + */ +BOOLEAN +KdSendUserOutPacketToDebuggee(DEBUGGER_USER_OUT_REQUEST_RESPONSE OutRequest) +{ + // + // Send 'uout' command as packet + // + if (!KdCommandPacketAndBufferToDebuggee( + DEBUGGER_REMOTE_PACKET_TYPE_DEBUGGER_TO_DEBUGGEE_EXECUTE_ON_VMX_ROOT, + DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_ON_VMX_ROOT_MODE_USER_OUT_INSTRUCTION, + (CHAR *)&OutRequest, + sizeof(DEBUGGER_USER_OUT_REQUEST_RESPONSE))) + { + return FALSE; + } + + // + // Wait until the result of OUT instruction received + // + DbgWaitForKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_USER_OUT_RESULT); + + return TRUE; +} + /** * @brief Send a callstack request to the debuggee * @param BaseAddress diff --git a/hyperdbg/libhyperdbg/code/debugger/kernel-level/kernel-listening.cpp b/hyperdbg/libhyperdbg/code/debugger/kernel-level/kernel-listening.cpp index 81e88b30..5f5638f2 100644 --- a/hyperdbg/libhyperdbg/code/debugger/kernel-level/kernel-listening.cpp +++ b/hyperdbg/libhyperdbg/code/debugger/kernel-level/kernel-listening.cpp @@ -58,6 +58,8 @@ ListeningSerialPortInDebugger() PDEBUGGEE_DETAILS_AND_SWITCH_THREAD_PACKET ChangeThreadPacket; PDEBUGGER_FLUSH_LOGGING_BUFFERS FlushPacket; PDEBUGGER_CPUID_REQUEST_RESPONSE CpuidPacket; + PDEBUGGER_USER_IN_REQUEST_RESPONSE InPacket; + PDEBUGGER_USER_OUT_REQUEST_RESPONSE OutPacket; PDEBUGGER_CALLSTACK_REQUEST CallstackPacket; PDEBUGGER_SINGLE_CALLSTACK_FRAME CallstackFramePacket; PDEBUGGER_DEBUGGER_TEST_QUERY_BUFFER TestQueryPacket; @@ -602,6 +604,54 @@ StartAgain: break; + case DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_DEBUGGEE_RESULT_OF_USER_IN_INSTRUCTION: + + InPacket = (DEBUGGER_USER_IN_REQUEST_RESPONSE *)(((CHAR *)TheActualPacket) + sizeof(DEBUGGER_REMOTE_PACKET)); + + if (InPacket->KernelStatus == DEBUGGER_OPERATION_WAS_SUCCESSFUL) + { + USHORT UserChosenRegister = InPacket->UserChosenRegister; + USHORT PortAddress = InPacket->PortAddress; + ULONG Data = InPacket->Data; + + CommandShowUserInMessage(UserChosenRegister, PortAddress, Data); + } + else + { + ShowErrorMessage(InPacket->KernelStatus); + } + + // + // Signal the event relating to receiving result of IN instruction + // + DbgReceivedKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_USER_IN_RESULT); + + break; + + case DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_DEBUGGEE_RESULT_OF_USER_OUT_INSTRUCTION: + + OutPacket = (DEBUGGER_USER_OUT_REQUEST_RESPONSE *)(((CHAR *)TheActualPacket) + sizeof(DEBUGGER_REMOTE_PACKET)); + + if (OutPacket->KernelStatus == DEBUGGER_OPERATION_WAS_SUCCESSFUL) + { + USHORT UserChosenRegister = OutPacket->UserChosenRegister; + USHORT PortAddress = OutPacket->PortAddress; + UINT32 Value = OutPacket->Value; + + CommandShowUserOutMessage(UserChosenRegister, PortAddress, Value); + } + else + { + ShowErrorMessage(OutPacket->KernelStatus); + } + + // + // Signal the event relating to receiving result of OUT instruction + // + DbgReceivedKernelResponse(DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_USER_OUT_RESULT); + + break; + case DEBUGGER_REMOTE_PACKET_REQUESTED_ACTION_DEBUGGEE_RESULT_OF_CALLSTACK: CallstackPacket = (DEBUGGER_CALLSTACK_REQUEST *)(((CHAR *)TheActualPacket) + sizeof(DEBUGGER_REMOTE_PACKET)); diff --git a/hyperdbg/libhyperdbg/code/export/export.cpp b/hyperdbg/libhyperdbg/code/export/export.cpp index d5dc56e0..cfc997dd 100644 --- a/hyperdbg/libhyperdbg/code/export/export.cpp +++ b/hyperdbg/libhyperdbg/code/export/export.cpp @@ -1044,4 +1044,30 @@ hyperdbg_u_request_cpuid(UINT32 FunctionId, UINT32 SubFunctionId) CommandCpuidRequestCpuid(FunctionId, SubFunctionId); return TRUE; -} \ No newline at end of file +} + +/** + * @brief I/O instruction (IN) + * + * @param InRequest + * + * @return BOOLEAN TRUE if successful, FALSE otherwise + */ +BOOLEAN +hyperdebg_u_in_instruction(DEBUGGER_USER_IN_REQUEST_RESPONSE InRequest) +{ + return CommandUserInRequest(InRequest); +} + +/** + * @brief I/O instruction (OUT) + * + * @param OutRequest + * + * @return BOOLEAN TRUE if successful, FALSE otherwise + */ +BOOLEAN +hyperdebg_u_out_instruction(DEBUGGER_USER_OUT_REQUEST_RESPONSE OutRequest) +{ + return CommandUserOutRequest(OutRequest); +} diff --git a/hyperdbg/libhyperdbg/header/common/common.h b/hyperdbg/libhyperdbg/header/common/common.h index 4eb9a0ff..2a5039ef 100644 --- a/hyperdbg/libhyperdbg/header/common/common.h +++ b/hyperdbg/libhyperdbg/header/common/common.h @@ -247,12 +247,18 @@ ConvertStringToUInt64(string TextToConvert, PUINT64 Result); BOOLEAN ConvertStringToUInt32(string TextToConvert, PUINT32 Result); +BOOLEAN +ConvertStringToUInt16(string TextToConvert, PUINT16 Result); + BOOLEAN ConvertTokenToUInt64(CommandToken TargetToken, PUINT64 Result); BOOLEAN ConvertTokenToUInt32(CommandToken TargetToken, PUINT32 Result); +BOOLEAN +ConvertTokenToUInt16(CommandToken TargetToken, PUINT16 Result); + std::string GetCaseSensitiveStringFromCommandToken(CommandToken TargetToken); diff --git a/hyperdbg/libhyperdbg/header/debugger/commands/commands.h b/hyperdbg/libhyperdbg/header/debugger/commands/commands.h index 647c828d..02931adf 100644 --- a/hyperdbg/libhyperdbg/header/debugger/commands/commands.h +++ b/hyperdbg/libhyperdbg/header/debugger/commands/commands.h @@ -304,6 +304,12 @@ typedef std::map CommandType; #define DEBUGGER_COMMAND_USER_CPUID_ATTRIBUTES \ DEBUGGER_COMMAND_ATTRIBUTE_LOCAL_COMMAND_IN_DEBUGGER_MODE +#define DEBUGGER_COMMAND_USER_IN_ATTRIBUTES \ + DEBUGGER_COMMAND_ATTRIBUTE_LOCAL_COMMAND_IN_DEBUGGER_MODE + +#define DEBUGGER_COMMAND_USER_OUT_ATTRIBUTES \ + DEBUGGER_COMMAND_ATTRIBUTE_LOCAL_COMMAND_IN_DEBUGGER_MODE + #define DEBUGGER_COMMAND_UNLOAD_ATTRIBUTES NULL #define DEBUGGER_COMMAND_SCRIPT_ATTRIBUTES \ @@ -650,6 +656,12 @@ CommandFlush(vector CommandTokens, string Command); VOID CommandUserCpuid(vector CommandTokens, string Command); +VOID +CommandUserIn(vector CommandTokens, string Command); + +VOID +CommandUserOut(vector CommandTokens, string Command); + VOID CommandPause(vector CommandTokens, string Command); diff --git a/hyperdbg/libhyperdbg/header/debugger/commands/help.h b/hyperdbg/libhyperdbg/header/debugger/commands/help.h index d27cae46..c0328728 100644 --- a/hyperdbg/libhyperdbg/header/debugger/commands/help.h +++ b/hyperdbg/libhyperdbg/header/debugger/commands/help.h @@ -174,6 +174,12 @@ CommandFlushHelp(); VOID CommandUserCpuidHelp(); +VOID +CommandUserInHelp(); + +VOID +CommandUserOutHelp(); + VOID CommandPauseHelp(); diff --git a/hyperdbg/libhyperdbg/header/debugger/core/debugger.h b/hyperdbg/libhyperdbg/header/debugger/core/debugger.h index 4b0a2133..2cdd56c9 100644 --- a/hyperdbg/libhyperdbg/header/debugger/core/debugger.h +++ b/hyperdbg/libhyperdbg/header/debugger/core/debugger.h @@ -65,6 +65,8 @@ #define DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_HYPERTRACE_LBR_DUMP_RESULT 0x20 #define DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_HYPERTRACE_PT_OPERATION_RESULT 0x21 #define DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_USER_CPUID_RESULT 0x22 +#define DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_USER_IN_RESULT 0x23 +#define DEBUGGER_SYNCRONIZATION_OBJECT_KERNEL_DEBUGGER_USER_OUT_RESULT 0x24 ////////////////////////////////////////////////// // Event Details // @@ -221,7 +223,7 @@ CommandEventsClearAllEventsAndResetTags(); VOID CommandFlushRequestFlush(); -VOID +BOOLEAN CommandCpuidRequestCpuid(UINT32 FunctionId, UINT32 SubFunctionId); VOID @@ -229,6 +231,22 @@ CommandShowUserCpuidMessage(UINT32 FunctionId, UINT32 SubFunctionId, PDEBUGGER_CPUID_REQUEST_RESPONSE CpuidRequest); +BOOLEAN +CommandUserInRequest(DEBUGGER_USER_IN_REQUEST_RESPONSE InRequest); + +BOOLEAN +CommandUserOutRequest(DEBUGGER_USER_OUT_REQUEST_RESPONSE OutRequest); + +VOID +CommandShowUserInMessage(USHORT UserChosenRegister, + USHORT PortAddress, + ULONG Data); + +VOID +CommandShowUserOutMessage(USHORT UserChosenRegister, + USHORT PortAddress, + UINT32 Value); + UINT64 GetCommandAttributes(const string & FirstCommand); diff --git a/hyperdbg/libhyperdbg/header/debugger/kernel-level/kd.h b/hyperdbg/libhyperdbg/header/debugger/kernel-level/kd.h index 7ab34974..b58b8a39 100644 --- a/hyperdbg/libhyperdbg/header/debugger/kernel-level/kd.h +++ b/hyperdbg/libhyperdbg/header/debugger/kernel-level/kd.h @@ -116,6 +116,12 @@ KdSendFlushPacketToDebuggee(); BOOLEAN KdSendUserCpuidPacketToDebuggee(UINT32 FunctionId, UINT32 SubFunctionId); +BOOLEAN +KdSendUserInPacketToDebuggee(DEBUGGER_USER_IN_REQUEST_RESPONSE InRequest); + +BOOLEAN +KdSendUserOutPacketToDebuggee(DEBUGGER_USER_OUT_REQUEST_RESPONSE OutRequest); + BOOLEAN KdSendCallStackPacketToDebuggee(UINT64 BaseAddress, UINT32 Size, diff --git a/hyperdbg/libhyperdbg/libhyperdbg.vcxproj b/hyperdbg/libhyperdbg/libhyperdbg.vcxproj index 81674601..df80f354 100644 --- a/hyperdbg/libhyperdbg/libhyperdbg.vcxproj +++ b/hyperdbg/libhyperdbg/libhyperdbg.vcxproj @@ -199,6 +199,9 @@ msbuild "$(SolutionDir)dependencies\zydis\msvc\Zydis.sln" /m /p:Configuration="R + + + @@ -247,7 +250,6 @@ msbuild "$(SolutionDir)dependencies\zydis\msvc\Zydis.sln" /m /p:Configuration="R - Create Create diff --git a/hyperdbg/libhyperdbg/libhyperdbg.vcxproj.filters b/hyperdbg/libhyperdbg/libhyperdbg.vcxproj.filters index 81c07a6b..12d45b65 100644 --- a/hyperdbg/libhyperdbg/libhyperdbg.vcxproj.filters +++ b/hyperdbg/libhyperdbg/libhyperdbg.vcxproj.filters @@ -742,7 +742,13 @@ code\debugger\misc - + + code\debugger\commands\debugging-commands + + + code\debugger\commands\debugging-commands + + code\debugger\commands\debugging-commands