示例#1
0
BOOLEAN
NTAPI
KdpPrintString(IN PSTRING Output)
{
    STRING Data, Header;
    DBGKD_DEBUG_IO DebugIo;
    USHORT Length = Output->Length;

    /* Copy the string */
    RtlMoveMemory(KdpMessageBuffer, Output->Buffer, 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 = DbgKdPrintStringApi;
    DebugIo.ProcessorLevel = (USHORT)KeProcessorLevel;
    DebugIo.Processor = KeGetCurrentPrcb()->Number;
    DebugIo.u.PrintString.LengthOfString = Length;
    Header.Length = sizeof(DBGKD_DEBUG_IO);
    Header.Buffer = (PCHAR)&DebugIo;

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

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

    /* Check if the user pressed CTRL+C */
    return KdpPollBreakInWithPortLock();
}
示例#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;
}