cleanup for resync serial codes and update CHANGELOG.md

This commit is contained in:
sina 2026-08-01 20:49:02 +02:00
parent 12cd4250b5
commit a24c8c0a91
8 changed files with 200 additions and 210 deletions

View file

@ -4,25 +4,43 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.23.0.0] - 2026-XX-XX
## [0.23.0.0] - 2026-08-03
New release of the HyperDbg Debugger.
### Added
- Added the 'ucpuid' command ([link](https://docs.hyperdbg.org/commands/debugging-commands/ucpuid))([link](https://github.com/HyperDbg/HyperDbg/pull/658))
- Added the 'ucpuid' command, thanks to [@nikzad66](https://github.com/nikzad66) ([link](https://docs.hyperdbg.org/commands/debugging-commands/ucpuid))([link](https://github.com/HyperDbg/HyperDbg/pull/658))
- Added floating-point support in the script engine ([link](https://docs.hyperdbg.org/commands/scripting-language/data-types-and-operators))([link](https://github.com/HyperDbg/HyperDbg/pull/655))
- Added new platform functions for missed CPUID wrapper ([link](https://github.com/HyperDbg/HyperDbg/commit/dd38a30d224d05bb9cfab28f6024db8cc51acffd))
- Added guards and compilation flags in CMake ([link](https://github.com/HyperDbg/HyperDbg/commit/860f736bd21a274930420a12ed7eac970732717a))
- Added SDK function for the 'ucpuid' command ([link](https://docs.hyperdbg.org/commands/debugging-commands/ucpuid))([link](https://github.com/HyperDbg/HyperDbg/pull/659))
- Added a new socket platform API and named-pipe Linux file ([link](https://github.com/HyperDbg/HyperDbg/commit/6683c2dc3db640e8b75786570759daf4e630c7f0))
- Added unix implementation of 'asm-vmx-checks.asm', and made naming convention for both files ([link](https://github.com/HyperDbg/HyperDbg/commit/7141e23aadd6cc92d7edf1259fc0a6438a96737a))
- Added the hwdbg files to the CMake files and replaced the platform files, 'RTLZeroMemory' ([link](https://github.com/HyperDbg/HyperDbg/commit/f5f822a46f5aa3041cda6f7a1c29aaf18f705f15))
- Added ucpuid to CMakeList.txt and made it portable ([link](https://github.com/HyperDbg/HyperDbg/commit/8583d99d14eed83e982df08106d8f50d04c36e6a))
- Script engine Linux build completed, and added undefined references with empty stubs for the Linux port and updated the CMake file accordingly ([link](https://github.com/HyperDbg/HyperDbg/commit/5175381c7304a268660377f3ed1c2e8860f96c55))
- Added missing files to the CMake build file and swept them for the Platform functions and guarded Windows-only code ([link](https://github.com/HyperDbg/HyperDbg/commit/4bf987a5968a65eebdbb69f514e50ee08d74aa34))
- Added stub for vendorID on the 'pci-id.cpp' file ([link](https://github.com/HyperDbg/HyperDbg/commit/600eaa47ba7bc5731c677030dea7d0562e95b97b))
- Added Linux kernel module build file (Kbuild) ([link](https://github.com/HyperDbg/HyperDbg/commit/e8650e43ac563d451c835b1a01c0241929cf3c2c))
- Added PlatformCPU Linux implementation ([link](https://github.com/HyperDbg/HyperDbg/commit/953af9388a163b9e71f48bc68966f8e670fcef27))
- Added 'vprintk' in the kernel module files for Linux ([link](https://github.com/HyperDbg/HyperDbg/commit/652721be62f759535d59fec5e603923076bc62b0))
### Changed
- Updated variable types and added float types in the script engine ([link](https://github.com/HyperDbg/HyperDbg/commit/d44c726dff91402a1f093455b69449b65657bce0))
- Porting status update and terminate thread platform call ([link](https://github.com/HyperDbg/HyperDbg/commit/a29e210ab067d4a96a0d130f61aeed5b53387565))
- Sweep and extra guards and some new platform functions ([link](https://github.com/HyperDbg/HyperDbg/commit/926070135d44b7459409e1cce1d4595426062daa))
- Fix UInt32 conversion for negative (signed) values ([link](https://github.com/HyperDbg/HyperDbg/commit/d4132ee7db092140b526d4cd31e445114aa470ec))
- Fix 'UInt32' conversion for negative (signed) values ([link](https://github.com/HyperDbg/HyperDbg/commit/d4132ee7db092140b526d4cd31e445114aa470ec))
- Fix the 'snprintf_s' wrapper function for cross-platform compilation ([link](https://github.com/HyperDbg/HyperDbg/commit/aa96eaa617c0c1a432682b83a5021ac4963182d1))
- Changed 'CpuIdEx' variants to a cross-platform 'CpuCpuIdEx' ([link](https://github.com/HyperDbg/HyperDbg/commit/c13f45f8b05743c5d87d3a50687507defe54af2b))
- Updated number of CPUs to a cross-platform function ([link](https://github.com/HyperDbg/HyperDbg/commit/5fdd2e7738e6f68ed5ff516467fbc5bfdaec9759))
- Empty Linux stub for the keystone library ([link](https://github.com/HyperDbg/HyperDbg/commit/f938929a8cd8391a00c52f39dd9a129a7abf9b33))
- Build file edit for first build on 'hyperdbg-cli' ([link](https://github.com/HyperDbg/HyperDbg/commit/2024cb9374e29fbd511ba931ab8b2bf7d483457c))
- Fixed bug that made script-engine segfault, so we can type commands now ([link](https://github.com/HyperDbg/HyperDbg/commit/bdc7a150cbefbc3d85a05d2a995bad4db34fc321))
- Resync serial stream on framing overflow instead of flooding the debuggee, thanks to [@munraimix](https://github.com/munraimix) ([link](https://github.com/HyperDbg/HyperDbg/pull/663))([link](https://github.com/HyperDbg/HyperDbg/issues/661))
- Resync libhyperdbg's serial receivers on framing overflow too, thanks to [@munraimix](https://github.com/munraimix) ([link](https://github.com/HyperDbg/HyperDbg/pull/663))([link](https://github.com/HyperDbg/HyperDbg/issues/661))
- Updated Linux port documentation ([link](https://github.com/HyperDbg/HyperDbg/commit/622ea9df9730e3fe0a8ff22f035772631308ac36))
### Removed
- Removed unused serial codes ([link](https://github.com/HyperDbg/HyperDbg/commit/b77df6a62bacf4bff29198b3d1acd7961a3e7f38))
## [0.22.0.0] - 2026-07-20
New release of the HyperDbg Debugger.

View file

@ -87,12 +87,6 @@ SerialConnectionCheckForTheEndOfTheBuffer(PUINT32 CurrentLoopIndex, BYTE * Buffe
return FALSE;
}
//
// Set when the serial stream desyncs so the warning is logged once per episode
// (cleared on the next good frame) instead of on every overflow
//
static BOOLEAN g_SerialConnectionDesyncReported = FALSE;
/**
* @brief Discard bytes until the next end of buffer marker to re-align the
* stream to a frame boundary after a desync
@ -438,6 +432,11 @@ SerialConnectionPrepare(PDEBUGGER_PREPARE_DEBUGGEE DebuggeeRequest)
return STATUS_UNSUCCESSFUL;
}
//
// Not in the desync state (reset desync flag)
//
g_SerialConnectionDesyncReported = FALSE;
//
// Prepare the structures needed for connecting remote port
//

View file

@ -213,6 +213,13 @@ BOOLEAN g_IsWaitingForUserModeProcessEntryToBeCalled;
*/
BOOLEAN g_InterceptBreakpointsAndEventsForCommandsInRemoteComputer;
/**
* Set when the serial stream desyncs so the warning is logged once per episode
* (cleared on the next good frame) instead of on every overflow
*
*/
BOOLEAN g_SerialConnectionDesyncReported;
/**
* @brief Global test flag (for testing purposes)
*

View file

@ -32,6 +32,7 @@ CommandEptHookHelp()
ShowMessages("\t\te.g : !epthook fffff801deadb000\n");
ShowMessages("\t\te.g : !epthook fffff801deadb000 pid 400\n");
ShowMessages("\t\te.g : !epthook fffff801deadb000 core 2 pid 400\n");
ShowMessages("\t\te.g : !epthook nt!ExAllocatePoolWithTag script { printf(\"hook triggered at: %%llx\\n\", $context); }\n");
ShowMessages("\t\te.g : !epthook fffff801deadb000 script { printf(\"hook triggered at: %%llx\\n\", $context); }\n");
ShowMessages("\t\te.g : !epthook fffff801deadb000 asm code { nop; nop; nop }\n");
}

View file

@ -31,6 +31,7 @@ extern DEBUGGER_EVENT_AND_ACTION_RESULT
g_DebuggeeResultOfAddingActionsToEvent;
extern BOOLEAN g_IsSerialConnectedToRemoteDebuggee;
extern BOOLEAN g_IsSerialConnectedToRemoteDebugger;
extern BOOLEAN g_KdReceiveFromDebuggerDesyncReported;
extern BOOLEAN g_IsDebuggerConntectedToNamedPipe;
extern BOOLEAN g_IsDebuggeeRunning;
extern BOOLEAN g_IsKdModuleLoaded;
@ -1657,20 +1658,84 @@ KdReadByteFromDebuggeeSerial(CHAR * ReadData, DWORD * NoBytesRead)
#endif // _WIN32
}
/**
* @brief Read a single byte from the debugger over the serial link
*
* @details Debuggee-side counterpart of KdReadByteFromDebuggeeSerial(); reads
* through the read-from-debugger overlapped structure so the framing loop and
* the resync path share one implementation.
*
* @param ReadData receives the byte that was read
* @param NoBytesRead receives the number of bytes actually read
*
* @return BOOLEAN TRUE on a successful read, FALSE on a hard read error
*/
static BOOLEAN
KdReadByteFromDebuggerSerial(CHAR * ReadData, DWORD * NoBytesRead)
{
#ifdef _WIN32
//
// Try to read one byte in overlapped I/O (in debuggee)
//
if (!ReadFile(g_SerialRemoteComPortHandle, ReadData, sizeof(CHAR), 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);
return TRUE;
#else
//
// Linux: read one byte through the cross-platform serial transport
// (the 5s read timeout is applied inside the platform layer)
//
return PlatformSerialReadByte(g_SerialRemoteComPortHandle,
ReadData,
NoBytesRead,
PLATFORM_SERIAL_IO_DEBUGGEE);
#endif // _WIN32
}
/**
* @brief Discard bytes until the next end-of-buffer marker, re-aligning the
* debugger-side serial receiver to a frame boundary after a desync
*
* @details Mirrors SerialConnectionResyncToNextFrame() on the debuggee side.
* @details Mirrors SerialConnectionResyncToNextFrame() on the debuggee side
* Bounded by SERIAL_RESYNC_MAX_BYTES so a dead or garbage link cannot spin
* forever.
* forever
*
* @param IsDebuggee
*
* @return BOOLEAN TRUE if a marker was found (stream re-aligned), FALSE if too
* many bytes arrived without one (treat the link as dead)
*/
static BOOLEAN
KdResyncDebuggeeStreamToNextFrame()
BOOLEAN
KdResyncStreamToNextFrame(DEBUGGER_PACKET_RESYNC_ENUM ReSyncType)
{
BOOL Status;
BYTE Window[SERIAL_END_OF_BUFFER_CHARS_COUNT] = {NULL_ZERO, NULL_ZERO, NULL_ZERO, NULL_ZERO};
UINT32 Discarded = 0;
@ -1679,14 +1744,72 @@ KdResyncDebuggeeStreamToNextFrame()
CHAR ReadData = NULL_ZERO;
DWORD NoBytesRead = 0;
if (!KdReadByteFromDebuggeeSerial(&ReadData, &NoBytesRead))
if (ReSyncType == DEBUGGER_PACKET_RESYNC_DEBUGGEE)
{
//
// It is for the debuggee
//
if (!KdReadByteFromDebuggeeSerial(&ReadData, &NoBytesRead))
{
return FALSE;
}
}
else if (ReSyncType == DEBUGGER_PACKET_RESYNC_DEBUGGER)
{
//
// It is for the debugger
//
if (!KdReadByteFromDebuggerSerial(&ReadData, &NoBytesRead))
{
return FALSE;
}
}
else if (ReSyncType == DEBUGGER_PACKET_RESYNC_LISTENING)
{
#ifdef _WIN32
Status = ReadFile(g_SerialRemoteComPortHandle, &ReadData, sizeof(ReadData), &NoBytesRead, NULL);
#else
//
// Linux: read one byte through the cross-platform serial transport
//
Status = PlatformSerialReadByte(g_SerialRemoteComPortHandle,
&ReadData,
&NoBytesRead,
PLATFORM_SERIAL_IO_DEBUGGEE);
#endif // _WIN32
if (!Status)
{
return FALSE;
}
}
else
{
ShowMessages("err, invalid resync type\n");
return FALSE;
}
if (NoBytesRead == 0)
{
continue;
if (ReSyncType == DEBUGGER_PACKET_RESYNC_DEBUGGEE || ReSyncType == DEBUGGER_PACKET_RESYNC_LISTENING)
{
//
// For the debuggee and listening
//
continue;
}
else if (DEBUGGER_PACKET_RESYNC_DEBUGGER)
{
//
// For the debugger
//
//
// The read timed out with no data: the link is idle, so stop
// discarding and let the caller fall back to its idle handling.
//
return FALSE;
}
}
Window[0] = Window[1];
@ -1754,7 +1877,7 @@ KdReceivePacketFromDebuggee(CHAR * BufferToSave,
g_KdSerialReceiverDesyncReported = TRUE;
}
if (!KdResyncDebuggeeStreamToNextFrame())
if (!KdResyncStreamToNextFrame(DEBUGGER_PACKET_RESYNC_DEBUGGEE))
{
//
// Too many bytes without a marker: treat the link as dead.
@ -1790,129 +1913,6 @@ KdReceivePacketFromDebuggee(CHAR * BufferToSave,
return TRUE;
}
//
// Set when the debuggee-side serial receiver (packets coming from the debugger)
// desyncs, so the warning is shown once per episode (cleared on the next good
// frame) instead of on every overflow while the stream stays desynced.
//
static BOOLEAN g_KdReceiveFromDebuggerDesyncReported = FALSE;
/**
* @brief Read a single byte from the debugger over the serial link
*
* @details Debuggee-side counterpart of KdReadByteFromDebuggeeSerial(); reads
* through the read-from-debugger overlapped structure so the framing loop and
* the resync path share one implementation.
*
* @param ReadData receives the byte that was read
* @param NoBytesRead receives the number of bytes actually read
*
* @return BOOLEAN TRUE on a successful read, FALSE on a hard read error
*/
static BOOLEAN
KdReadByteFromDebuggerSerial(CHAR * ReadData, DWORD * NoBytesRead)
{
#ifdef _WIN32
//
// Try to read one byte in overlapped I/O (in debuggee)
//
if (!ReadFile(g_SerialRemoteComPortHandle, ReadData, sizeof(CHAR), 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);
return TRUE;
#else
//
// Linux: read one byte through the cross-platform serial transport
// (the 5s read timeout is applied inside the platform layer)
//
return PlatformSerialReadByte(g_SerialRemoteComPortHandle,
ReadData,
NoBytesRead,
PLATFORM_SERIAL_IO_DEBUGGEE);
#endif // _WIN32
}
/**
* @brief Discard bytes until the next end-of-buffer marker, re-aligning the
* debuggee-side serial receiver to a frame boundary after a desync
*
* @details Mirrors KdResyncDebuggeeStreamToNextFrame(). This receiver runs with
* a 5s comm read timeout, so a zero-byte read means the link went idle; treat
* that as a dead link and bail rather than spin. Bounded by
* SERIAL_RESYNC_MAX_BYTES so a garbage link cannot spin forever either.
*
* @return BOOLEAN TRUE if a marker was found (stream re-aligned), FALSE if the
* link went idle or too many bytes arrived without a marker
*/
static BOOLEAN
KdResyncDebuggerStreamToNextFrame()
{
BYTE Window[SERIAL_END_OF_BUFFER_CHARS_COUNT] = {NULL_ZERO, NULL_ZERO, NULL_ZERO, NULL_ZERO};
UINT32 Discarded = 0;
while (Discarded < SERIAL_RESYNC_MAX_BYTES)
{
CHAR ReadData = NULL_ZERO;
DWORD NoBytesRead = 0;
if (!KdReadByteFromDebuggerSerial(&ReadData, &NoBytesRead))
{
return FALSE;
}
if (NoBytesRead == 0)
{
//
// The read timed out with no data: the link is idle, so stop
// discarding and let the caller fall back to its idle handling.
//
return FALSE;
}
Window[0] = Window[1];
Window[1] = Window[2];
Window[2] = Window[3];
Window[3] = (BYTE)ReadData;
Discarded++;
if (Window[0] == SERIAL_END_OF_BUFFER_CHAR_1 &&
Window[1] == SERIAL_END_OF_BUFFER_CHAR_2 &&
Window[2] == SERIAL_END_OF_BUFFER_CHAR_3 &&
Window[3] == SERIAL_END_OF_BUFFER_CHAR_4)
{
return TRUE;
}
}
return FALSE;
}
/**
* @brief Receive packet from the debugger
*
@ -1979,7 +1979,7 @@ KdReceivePacketFromDebugger(CHAR * BufferToSave,
g_KdReceiveFromDebuggerDesyncReported = TRUE;
}
if (!KdResyncDebuggerStreamToNextFrame())
if (!KdResyncStreamToNextFrame(DEBUGGER_PACKET_RESYNC_DEBUGGER))
{
//
// The link went idle or stayed garbage past the bound: treat it

View file

@ -18,6 +18,7 @@
extern BYTE g_CurrentRunningInstruction[MAXIMUM_INSTR_SIZE];
extern HANDLE g_SerialRemoteComPortHandle;
extern BOOLEAN g_IsSerialConnectedToRemoteDebuggee;
extern BOOLEAN g_ListeningDebuggeeDesyncReported;
extern BOOLEAN g_IsDebuggeeRunning;
extern BOOLEAN g_IgnoreNewLoggingMessages;
extern BOOLEAN g_SharedEventStatus;
@ -1451,75 +1452,6 @@ StartAgain:
return TRUE;
}
//
// Set when the debuggee-side listening loop desyncs, so the warning is shown
// once per episode (cleared on the next good frame) instead of on every
// overflow while the stream stays desynced.
//
static BOOLEAN g_ListeningDebuggeeDesyncReported = FALSE;
/**
* @brief Discard bytes until the next end-of-buffer marker, re-aligning the
* debuggee-side listening loop to a frame boundary after a desync
*
* @details Bounded by SERIAL_RESYNC_MAX_BYTES so a dead or garbage link cannot
* spin forever.
*
* @return BOOLEAN TRUE if a marker was found (stream re-aligned), FALSE on a
* read error or if too many bytes arrived without a marker
*/
static BOOLEAN
ListeningDebuggeeResyncToNextFrame()
{
BYTE Window[SERIAL_END_OF_BUFFER_CHARS_COUNT] = {NULL_ZERO, NULL_ZERO, NULL_ZERO, NULL_ZERO};
UINT32 Discarded = 0;
while (Discarded < SERIAL_RESYNC_MAX_BYTES)
{
char ReadData = NULL_ZERO;
DWORD NoBytesRead = 0;
BOOL Status;
#ifdef _WIN32
Status = ReadFile(g_SerialRemoteComPortHandle, &ReadData, sizeof(ReadData), &NoBytesRead, NULL);
#else
//
// Linux: read one byte through the cross-platform serial transport
//
Status = PlatformSerialReadByte(g_SerialRemoteComPortHandle,
&ReadData,
&NoBytesRead,
PLATFORM_SERIAL_IO_DEBUGGEE);
#endif // _WIN32
if (!Status)
{
return FALSE;
}
if (NoBytesRead == 0)
{
continue;
}
Window[0] = Window[1];
Window[1] = Window[2];
Window[2] = Window[3];
Window[3] = (BYTE)ReadData;
Discarded++;
if (Window[0] == SERIAL_END_OF_BUFFER_CHAR_1 &&
Window[1] == SERIAL_END_OF_BUFFER_CHAR_2 &&
Window[2] == SERIAL_END_OF_BUFFER_CHAR_3 &&
Window[3] == SERIAL_END_OF_BUFFER_CHAR_4)
{
return TRUE;
}
}
return FALSE;
}
/**
* @brief Check if the remote debugger needs to pause the system
*
@ -1623,7 +1555,7 @@ StartAgain:
g_ListeningDebuggeeDesyncReported = TRUE;
}
if (!ListeningDebuggeeResyncToNextFrame())
if (!KdResyncStreamToNextFrame(DEBUGGER_PACKET_RESYNC_LISTENING))
{
goto StartAgain;
}

View file

@ -41,6 +41,22 @@ public:
};
#endif // _WIN32
//////////////////////////////////////////////////
// enums //
//////////////////////////////////////////////////
/**
* @brief Type of resync
*
*/
typedef enum _DEBUGGER_PACKET_RESYNC_ENUM
{
DEBUGGER_PACKET_RESYNC_DEBUGGEE,
DEBUGGER_PACKET_RESYNC_DEBUGGER,
DEBUGGER_PACKET_RESYNC_LISTENING
} DEBUGGER_PACKET_RESYNC_ENUM;
//////////////////////////////////////////////////
// Functions //
//////////////////////////////////////////////////
@ -228,6 +244,9 @@ KdSendPcitreePacketToDebuggee(PDEBUGGEE_PCITREE_REQUEST_RESPONSE_PACKET PcitreeP
BOOLEAN
KdSendPcidevinfoPacketToDebuggee(PDEBUGGEE_PCIDEVINFO_REQUEST_RESPONSE_PACKET PcidevinfoPacket);
BOOLEAN
KdResyncStreamToNextFrame(DEBUGGER_PACKET_RESYNC_ENUM ReSyncType);
VOID
KdUninitializeConnection();

View file

@ -238,6 +238,20 @@ BOOLEAN g_IsRunningInstruction32Bit = FALSE;
*/
HANDLE g_SerialListeningThreadHandle = NULL;
/**
* Set when the debuggee-side serial receiver (packets coming from the debugger)
* desyncs, so the warning is shown once per episode (cleared on the next good
* frame) instead of on every overflow while the stream stays desynced.
*/
BOOLEAN g_KdReceiveFromDebuggerDesyncReported = FALSE;
/**
* Set when the debuggee-side listening loop desyncs, so the warning is shown
* once per episode (cleared on the next good frame) instead of on every
* overflow while the stream stays desynced.
*/
BOOLEAN g_ListeningDebuggeeDesyncReported = FALSE;
/**
* @brief In debugger (not debuggee), we save the handle
* of the user-mode listening thread for remote system here