示例#1
0
bool __stdcall KdComDispatcher::KdSendPacket(ULONG PacketType,
											 PKD_BUFFER FirstBuffer,
											 PKD_BUFFER SecondBuffer,
											 PKD_CONTEXT KdContext)
{
	m_PacketLogger.OnSendReceivePacket(g_pReporter->GetStatusPointer()->LogAllPackets != 0,
									   true,
									   PacketType,
									   FirstBuffer,
									   SecondBuffer,
									   KdContext);

	if (!m_RandomValidContextRecord.GetSize() && (PacketType == 2))
		if (FirstBuffer && FirstBuffer->pData)
			if (*((unsigned *)FirstBuffer->pData) == DbgKdReadControlSpaceApi)
				if (SecondBuffer && SecondBuffer->Length && SecondBuffer->pData)
				{
					m_RandomValidContextRecord.EnsureSize(SecondBuffer->Length);
					memcpy(m_RandomValidContextRecord.GetData(), SecondBuffer->pData, SecondBuffer->Length);
					m_RandomValidContextRecord.SetSize(SecondBuffer->Length);
				}

#ifdef KDCLIENT_REPORT_PERFORMANCE_INFORMATION
	g_pReporter->GetStatusPointer()->OSDetected = true;
#endif
#ifdef KDCLIENT_ENABLE_TRACE_ASSIST
	switch (PacketType)
	{
	case KdPacketType3:
		if (FirstBuffer && SecondBuffer && (*((ULONG *)FirstBuffer->pData) == 0x3230))
		{
			FixVerifierUnicodeReport(SecondBuffer);
			if (g_pReporter->GetStatusPointer()->TraceAssistUpdatePending)
			{
				m_TraceAssistant.ReloadParams();
				g_pReporter->GetStatusPointer()->TraceAssistUpdatePending = false;				
			}
			if (m_TraceAssistant.TraceLine((char *)SecondBuffer->pData, SecondBuffer->Length))
			{
#ifdef KDCLIENT_REPORT_PERFORMANCE_INFORMATION
				g_pReporter->GetStatusPointer()->BytesSent += (FirstBuffer->Length + SecondBuffer->Length + sizeof(KD_PACKET_HEADER) + 1);
				g_pReporter->GetStatusPointer()->PacketsSent++;
#endif
				return true;
			}
		}
		break;
	}
#endif

	ASSERT(FirstBuffer);
	KD_PACKET_HEADER header;
	unsigned checksum = KdpComputeChecksum(FirstBuffer->pData, FirstBuffer->Length);
	unsigned totalLength = FirstBuffer->Length;
	if (SecondBuffer)
	{
		totalLength += SecondBuffer->Length;
		checksum += KdpComputeChecksum(SecondBuffer->pData, SecondBuffer->Length);
	}
	
	header.Signature = '0000';
	header.PacketType = (USHORT)PacketType;
	header.Checksum = checksum;
	header.TotalDataLength = totalLength;
	KdCompNumberRetries = KdCompRetryCount;

	if (KdTraceEnabled && (g_pReporter->GetStatusPointer()->DebugLevel >= DebugLevelTraceKdCom))
	{
			TCHAR tsz[512];
			_sntprintf(tsz, __countof(tsz), _T("Sending normal packet (type = %d, id = %08X, len = %d)...\r\n"),
					header.PacketType,
					KdCompNextPacketIdToSend,
					header.TotalDataLength);
			g_pReporter->LogLineIfEnabled(tsz);
	}

	unsigned RetryNumber = 0;

	for (;;)
	{
		//SIMPLIFY: The classical KdCompRetryCount-related scheme is replaced by infinite retrying with
		//fallback to VM. In case we get looped here (inside GuestRPC dispatcher), VMWare hangs.
		//if (!KdCompNumberRetries)
		if (RetryNumber)
		{
			/*bool bCanDrop = false;
			switch (PacketType)
			{
			case KdPacketType3:
				bCanDrop = *((ULONG *)FirstBuffer->pData) == 0x3230;
				break;
			case KdPacketType7:
				bCanDrop = *((ULONG *)FirstBuffer->pData) == 0x3031;
				break;
			case KdPacketType11:
				bCanDrop = *((ULONG *)FirstBuffer->pData) == 0x3430;
				break;
			}
			if (bCanDrop)*/
			{
				//As returning false will result in automatic packet retrying, we do not loop here forever any more, if a packet send failed.
				//Instead, we return false and wait for this call to be retried by KDVMWARE.DLL.
				KD_DEBUGGER_NOT_PRESENT = TRUE;
				KdResetPacketNumbering(true);
				if (KdTraceEnabled && (g_pReporter->GetStatusPointer()->DebugLevel >= DebugLevelTraceKdCom))
					g_pReporter->LogLineIfEnabled(_T("Acknowledgment timeout\r\n"));
				return false;
			}
		}

		if (KdTraceEnabled && (g_pReporter->GetStatusPointer()->DebugLevel >= DebugLevelTraceKdComAll))
		{
				TCHAR tsz[512];
				_sntprintf(tsz, __countof(tsz), _T("KdSendPacket(): sending (%d)\r\n"),
						header.PacketType);
				g_pReporter->LogLineIfEnabled(tsz);
		}

		header.PacketID = KdCompNextPacketIdToSend;
		m_Pipe.Send(&header, sizeof(header));
		m_Pipe.Send(FirstBuffer->pData, FirstBuffer->Length);
		if (SecondBuffer && SecondBuffer->Length)
			m_Pipe.Send(SecondBuffer->pData, SecondBuffer->Length);
		unsigned char ch = 0xAA;
		m_Pipe.Send(&ch, 1);
#ifdef KDCLIENT_REPORT_PERFORMANCE_INFORMATION
		g_pReporter->GetStatusPointer()->DebuggerConnected = m_Pipe.IsClientConnected();
#endif
		switch (KdReceivePacket(KdPacketAcknowledge, NULL, NULL, NULL, KdContext, NULL))
		{
		case KD_RECV_CODE_TIMEOUT:
			KdCompNumberRetries--;
			RetryNumber++;
			break;
		case KD_RECV_CODE_OK:
			KdCompNextPacketIdToSend &= 0xFFFFFFF7;
		    KdCompRetryCount = KdContext->RetryCount;
			if (++m_PacketsSentFromLastReset >= KdMinPacketCountForSuccessfulLink)
				m_SequentialResetCount = 0;
			if (KdTraceEnabled && (g_pReporter->GetStatusPointer()->DebugLevel >= DebugLevelTraceKdCom))
				g_pReporter->LogLineIfEnabled(_T("Packet acknowledged\r\n"));
#ifdef KDCLIENT_REPORT_PERFORMANCE_INFORMATION
			g_pReporter->GetStatusPointer()->BytesSent += (header.TotalDataLength + sizeof(KD_PACKET_HEADER) + 1);
			g_pReporter->GetStatusPointer()->PacketsSent++;
#endif
			return true;
		}
	}
}
示例#2
0
//WARNING! This code is experimental and serves as a workaround for MS debug engine hanging, when a remote machine stops responding.
//The main idea is to send a 'NTOSKRNL unloaded' message when a VM process is terminating, or DLL is unloading.
//Everything works perfectly, if the target is running at that time, however, if the target is stopped, the message will not be
//processed normally, as the debugger does not expect it. Simple resending does not help, as too many copies of that message
//may drive WinDbg into a permanent 'out of sync' state. This code tries to detect, how and when to send such message.
void KdComDispatcher::SimulateWindowsTermination()
{
	SystemTerminationPacket packet;
	InitializeSystemTerminationPacket(packet);

	m_Notifier.SignalSessionTerminationAndWaitForAck();
	m_PacketLogger.OnWindowsTerminationSimulated();
	
	KD_BUFFER first = {0,}, second = {0,};
	first.Length = sizeof(packet);
	first.pData = (PUCHAR)packet;
	KD_CONTEXT ctx = {0,};

	bool RequireAdditionalTerminationPacket = false;

	while (!KdSendPacket(7, &first, &second, &ctx))
	{
		if (!m_Pipe.IsClientConnected())
		{
			m_PacketLogger.OnWindowsTerminationSimDone("debugger disconnected");
			return;
		}
		RequireAdditionalTerminationPacket = true;	//Target is not running and debugger is not ready to receive a packet. We'll repeat it later.
	}

	//Packet type 2 always has buffer 1 of size 0x38
	static char szBuf1[0x38], szBuf2[KdMaxBufferSize];

	ULONG unused = 0;

	BazisLib::DateTime dtStart = BazisLib::DateTime::Now();
	const int NoControlPacketTimeout = 1500;

	for (;;)
	{
		if (!m_Pipe.IsClientConnected())
		{
			m_PacketLogger.OnWindowsTerminationSimDone("debugger disconnected");
			return;
		}

		first.MaxLength = sizeof(szBuf1);
		first.pData = (PUCHAR)szBuf1;
		second.MaxLength = sizeof(szBuf2);
		second.pData = (PUCHAR)szBuf2;

		KD_RECV_CODE code = KdReceivePacket(2, &first, &second, &unused, &ctx, NULL);
		if (!m_Pipe.IsClientConnected())
		{
			m_PacketLogger.OnWindowsTerminationSimDone("debugger disconnected");
			return;
		}

		if (code == KD_RECV_CODE_TIMEOUT)
		{
			if ((BazisLib::DateTime::Now() - dtStart).GetTotalMilliseconds() < NoControlPacketTimeout)
				continue;

			m_PacketLogger.OnWindowsTerminationSimDone("timeout");
			return;
		}
		if (code != KD_RECV_CODE_OK)
			continue;

		if ((*((unsigned *)szBuf1) == DbgKdContinueApi2) || (*((unsigned *)szBuf1) == DbgKdContinueApi))
		{
			if (RequireAdditionalTerminationPacket)
			{
				first.Length = sizeof(packet);
				first.pData = (PUCHAR)packet;
				if (!KdSendPacket(7, &first, &second, &ctx))
				{
					m_PacketLogger.OnWindowsTerminationSimDone("type 7 packet not acknowledged");
					return;
				}
				RequireAdditionalTerminationPacket = false;
				continue;
			}
			m_PacketLogger.OnWindowsTerminationSimDone("continue command received");
			return;
		}

		((unsigned *)szBuf1)[2] = 0;	//Set ReturnStatus in DBGKD_MANIPULATE_STATE64 to STATUS_SUCCESS

		if ((*((unsigned *)szBuf1) == DbgKdReadControlSpaceApi))
		{
			second.Length = (USHORT)m_RandomValidContextRecord.GetSize();
			second.pData = (PUCHAR)m_RandomValidContextRecord.GetData();
		}

		if ((*((unsigned *)szBuf1) == DbgKdSetContextApi))
		{
			second.Length = 0;
			second.pData = NULL;
		}
		

		//If we have received a type 2 packet, other than 'continue', simply echo the packet back.
		//Packet-level layer of WinDbg will return a successful status code, while higher level will
		//most likely treat it as an error. However, then WinDbg will receive our termination packet
		//and will disconnect from session.
		KdSendPacket(2, &first, &second, &ctx);
		RequireAdditionalTerminationPacket = true;
	}
	m_PacketLogger.OnWindowsTerminationSimDone("unexpected");
}
示例#3
0
BOOLEAN
NTAPI
KdpPromptString(IN PSTRING PromptString,
                IN PSTRING ResponseString)
{
    STRING Data, Header;
    DBGKD_DEBUG_IO DebugIo;
    ULONG Length = PromptString->Length;
    KDSTATUS Status;

    /* Copy the string to the message buffer */
    RtlCopyMemory(KdpMessageBuffer,
                  PromptString->Buffer,
                  PromptString->Length);

    /* Make sure we don't exceed the KD Packet size */
    if ((sizeof(DBGKD_DEBUG_IO) + Length) > PACKET_MAX_SIZE)
    {
        /* Normalize length */
        Length = PACKET_MAX_SIZE - sizeof(DBGKD_DEBUG_IO);
    }

    /* Build the packet header */
    DebugIo.ApiNumber = DbgKdGetStringApi;
    DebugIo.ProcessorLevel = (USHORT)KeProcessorLevel;
    DebugIo.Processor = KeGetCurrentPrcb()->Number;
    DebugIo.u.GetString.LengthOfPromptString = Length;
    DebugIo.u.GetString.LengthOfStringRead = ResponseString->MaximumLength;
    Header.Length = sizeof(DBGKD_DEBUG_IO);
    Header.Buffer = (PCHAR)&DebugIo;

    /* Build the data */
    Data.Length = PromptString->Length;
    Data.Buffer = KdpMessageBuffer;

    /* Send the packet */
    KdSendPacket(PACKET_TYPE_KD_DEBUG_IO, &Header, &Data, &KdpContext);

    /* Set the maximum lengths for the receive */
    Header.MaximumLength = sizeof(DBGKD_DEBUG_IO);
    Data.MaximumLength = sizeof(KdpMessageBuffer);

    /* Enter receive loop */
    do
    {
        /* Get our reply */
        Status = KdReceivePacket(PACKET_TYPE_KD_DEBUG_IO,
                                 &Header,
                                 &Data,
                                 &Length,
                                 &KdpContext);

        /* Return TRUE if we need to resend */
        if (Status == KdPacketNeedsResend) return TRUE;

        /* Loop until we succeed */
    } while (Status != KdPacketReceived);

    /* Don't copy back a larger response than there is room for */
    Length = min(Length, ResponseString->MaximumLength);

    /* Copy back the string and return the length */
    RtlCopyMemory(ResponseString->Buffer, KdpMessageBuffer, Length);
    ResponseString->Length = (USHORT)Length;

    /* Success; we don't need to resend */
    return FALSE;
}