// Send string messages and tracing for logging and monitoring
BOOLEAN LogSendMessageToQueue(UINT32 OperationCode, BOOLEAN IsImmediateMessage, BOOLEAN ShowCurrentSystemTime, const char* Fmt, ...)
char LogMessage[PacketChunkSize];
char TempMessage[PacketChunkSize];
char TimeBuffer[20] = { 0 };
IsVmxRootMode = GuestState[KeGetCurrentProcessorNumber()].IsOnVmxRootMode;
if (ShowCurrentSystemTime)
// It's actually not necessary to use -1 but because user-mode code might assume a null-terminated buffer so
// it's better to use - 1
// We won't use this because we can't use in any IRQL
/*Status = RtlStringCchVPrintfA(TempMessage, PacketChunkSize - 1, Fmt, ArgList);*/
SprintfResult = vsprintf_s(TempMessage, PacketChunkSize - 1, Fmt, ArgList);
// Check if the buffer passed the limit
// Probably the buffer is large that we can't store it
// Fill the above with timer
LARGE_INTEGER SystemTime, LocalTime;
KeQuerySystemTime(&SystemTime);
ExSystemTimeToLocalTime(&SystemTime, &LocalTime);
RtlTimeToTimeFields(&LocalTime, &TimeFields);
// We won't use this because we can't use in any IRQL
/*Status = RtlStringCchPrintfA(TimeBuffer, RTL_NUMBER_OF(TimeBuffer),
"%02hd:%02hd:%02hd.%03hd", TimeFields.Hour,
TimeFields.Minute, TimeFields.Second,
TimeFields.Milliseconds);
// Append time with previous message
Status = RtlStringCchPrintfA(LogMessage, PacketChunkSize - 1, "(%s)\t %s", TimeBuffer, TempMessage);*/
// this function probably run without error, so there is no need to check the return value
sprintf_s(TimeBuffer, RTL_NUMBER_OF(TimeBuffer), "%02hd:%02hd:%02hd.%03hd", TimeFields.Hour,
TimeFields.Minute, TimeFields.Second,
TimeFields.Milliseconds);
// Append time with previous message
SprintfResult = sprintf_s(LogMessage, PacketChunkSize - 1, "(%s - core : %d - vmx-root? %s)\t %s", TimeBuffer, KeGetCurrentProcessorNumberEx(0), IsVmxRootMode ? "yes" : "no", TempMessage);
// Check if the buffer passed the limit
// Probably the buffer is large that we can't store it
// It's actually not necessary to use -1 but because user-mode code might assume a null-terminated buffer so
// it's better to use - 1
// We won't use this because we can't use in any IRQL
/* Status = RtlStringCchVPrintfA(LogMessage, PacketChunkSize - 1, Fmt, ArgList); */
SprintfResult = vsprintf_s(LogMessage, PacketChunkSize - 1, Fmt, ArgList);
// Check if the buffer passed the limit
// Probably the buffer is large that we can't store it
// Use std function because they can be run in any IRQL
// RtlStringCchLengthA(LogMessage, PacketChunkSize - 1, &WrittenSize);
WrittenSize = strnlen_s(LogMessage, PacketChunkSize - 1);
if (LogMessage[0] == '\0') {
return LogSendBuffer(OperationCode, LogMessage, WrittenSize);
// Check if we're in Vmx-root, if it is then we use our customized HIGH_IRQL Spinlock, if not we use the windows spinlock
SpinlockLock(&VmxRootLoggingLockForNonImmBuffers);
KeAcquireSpinLock(&MessageBufferInformation[Index].BufferLockForNonImmMessage, &OldIRQL);
// If log message WrittenSize is above the buffer then we have to send the previous buffer
if ((MessageBufferInformation[Index].CurrentLengthOfNonImmBuffer + WrittenSize) > PacketChunkSize - 1 && MessageBufferInformation[Index].CurrentLengthOfNonImmBuffer != 0)
// Send the previous buffer (non-immediate message)
Result = LogSendBuffer(OPERATION_LOG_NON_IMMEDIATE_MESSAGE,
MessageBufferInformation[Index].BufferForMultipleNonImmediateMessage,
MessageBufferInformation[Index].CurrentLengthOfNonImmBuffer);
// Free the immediate buffer
MessageBufferInformation[Index].CurrentLengthOfNonImmBuffer = 0;
RtlZeroMemory(MessageBufferInformation[Index].BufferForMultipleNonImmediateMessage, PacketChunkSize);
// We have to save the message
RtlCopyBytes(MessageBufferInformation[Index].BufferForMultipleNonImmediateMessage +
MessageBufferInformation[Index].CurrentLengthOfNonImmBuffer, LogMessage, WrittenSize);
MessageBufferInformation[Index].CurrentLengthOfNonImmBuffer += WrittenSize;
// Check if we're in Vmx-root, if it is then we use our customized HIGH_IRQL Spinlock, if not we use the windows spinlock
SpinlockUnlock(&VmxRootLoggingLockForNonImmBuffers);
KeReleaseSpinLock(&MessageBufferInformation[Index].BufferLockForNonImmMessage, OldIRQL);