00001
00007 #include "stdafx.h"
00008 #include "kdxxx.h"
00009 #include "vmwrpc.h"
00010 #include "kdvm.h"
00011 #include "kdrpc.h"
00012 #include "vboxrpc.h"
00013
00014 namespace
00015 {
00016 char g_PacketBuffer[131072 + 1024];
00017 }
00018
00019
00020
00021
00022
00023 typedef BufferedRPCChannel<g_PacketBuffer, sizeof(g_PacketBuffer)> VMWareChannel;
00024 typedef BufferedVBoxChannel<g_PacketBuffer, sizeof(g_PacketBuffer)> VBoxChannel;
00025
00026 extern "C" void HalInitSystem(void *, void *);
00027
00028 #ifndef _AMD64_
00029 extern "C" void __declspec(naked) __stdcall DllEntryPoint()
00030 {
00031 __asm
00032 {
00033 jmp HalInitSystem
00034 }
00035 }
00036 #endif
00037
00038 static KD_BUFFER s_EmptyBuffer;
00039 static KD_CONTEXT s_EmptyKdContext;
00040
00041 volatile LONG KdVmActiveCallCount = 0;
00042 static bool s_bVBoxDetected = false;
00043
00044 ULONG KdVMGetActiveCallCount()
00045 {
00046 return KdVmActiveCallCount;
00047 }
00048
00049 class InterlockedIncrementer
00050 {
00051 private:
00052 (volatile LONG) *m_pPtr;
00053
00054 public:
00055 inline InterlockedIncrementer(volatile LONG *pPtr)
00056 : m_pPtr(pPtr)
00057 {
00058 InterlockedIncrement(m_pPtr);
00059 }
00060
00061 ~InterlockedIncrementer()
00062 {
00063 InterlockedDecrement(m_pPtr);
00064 }
00065 };
00066
00067 template <class DefaultRPCChannel> class ChannelHelper
00068 {
00069 public:
00070 static bool TestConnectionOnChannel(DefaultRPCChannel &chn)
00071 {
00072 unsigned char t = TestConnection;
00073 unsigned char arr[KDRPC_TEST_BUFFER_SIZE];
00074 for (int i = 0; i < sizeof(arr); i++)
00075 arr[i] = (unsigned char)i;
00076 if (!chn.Valid())
00077 return false;
00078 if (!chn.PrepareSend(sizeof(arr) + sizeof(g_szRPCCommandHeader)))
00079 return false;
00080 if (!chn.SendPartial(g_szRPCCommandHeader, sizeof(g_szRPCCommandHeader) - 1))
00081 return false;
00082 if (!chn.SendPartial(&t, sizeof(t)))
00083 return false;
00084 if (!chn.SendPartial(arr, sizeof(arr)))
00085 return false;
00086 unsigned rsize = chn.GetReplySize();
00087 int refsize = ((sizeof(g_szRPCReplySignature) + sizeof(arr) - 1) + 2);
00088 if (rsize != refsize)
00089 return false;
00090 if (!chn.Receive(arr, (sizeof(g_szRPCReplySignature) - 1) + 2))
00091 return false;
00092 if (arr[0] != '1')
00093 return false;
00094 if (memcmp(arr + 2, g_szRPCReplySignature, sizeof(g_szRPCReplySignature) - 1))
00095 return false;
00096 if (!chn.Receive(arr, sizeof(arr)))
00097 return false;
00098 if (!chn.EndReceive())
00099 return false;
00100 for (int i = 0; i < KDRPC_TEST_BUFFER_SIZE; i++)
00101 if (arr[i] != (unsigned char)(i ^ 0x55))
00102 return false;
00103 return true;
00104 }
00105
00106 #ifdef VIRTUALKD_BENCHMARK_AND_EXIT
00107 #define CONNECTION_TEST_ROUNDS 100000
00108 #else
00109 #define CONNECTION_TEST_ROUNDS 100
00110 #endif
00111
00112 static bool TestConnectionWithHost()
00113 {
00114
00115 #ifndef _AMD64_
00116 char _unused0[(int)(&((KD_BUFFER *)0)->pData) == sizeof(SendableKdBuffer)];
00117 #endif
00118
00119 #ifdef VIRTUALKD_BENCHMARK_AND_EXIT
00120 DbgPrint("VirtualKD: Starting connection self-test (%d rounds)...\n", CONNECTION_TEST_ROUNDS);
00121 #endif
00122 for (int j = 0; j < 2; j++)
00123 {
00124 DefaultRPCChannel chn;
00125 for (int i = 0; i < (CONNECTION_TEST_ROUNDS / 2); i++)
00126 {
00127 if (!TestConnectionOnChannel(chn))
00128 {
00129 #ifdef VIRTUALKD_BENCHMARK_AND_EXIT
00130 DbgPrint("VirtualKD: Connection self-test failed on round %d!\n", i);
00131 #endif
00132 return false;
00133 }
00134 }
00135 }
00136 #ifdef VIRTUALKD_BENCHMARK_AND_EXIT
00137 DbgPrint("VirtualKD: Connection self-test successful!\n");
00138 return false;
00139 #endif
00140 return true;
00141 }
00142
00143 static NTSTATUS NegotiateProtocolVersions()
00144 {
00145 DefaultRPCChannel channel;
00146 if (channel.NeedRestartInVBoxMode())
00147 {
00148 s_bVBoxDetected = true;
00149 return STATUS_RETRY;
00150 }
00151 channel.PrepareSend(5 + sizeof(g_szRPCCommandHeader) - 1);
00152 char commandType = VersionReport;
00153 int version = KDRPC_PROTOCOL_VERSION;
00154 if (!channel.SendPartial(&g_szRPCCommandHeader, sizeof(g_szRPCCommandHeader) - 1))
00155 return STATUS_CONNECTION_REFUSED;
00156 if (!channel.SendPartial(&commandType, 1))
00157 return STATUS_CONNECTION_REFUSED;
00158 channel.SendPartial(&version, 4);
00159 if (channel.GetReplySize() != (4 + 2 + sizeof(g_szRPCReplySignature) - 1))
00160 return STATUS_CONNECTION_REFUSED;
00161 char pfx[sizeof(g_szRPCReplySignature)];
00162 if (!channel.Receive(pfx, 2))
00163 return STATUS_CONNECTION_REFUSED;
00164 if ((pfx[0] != '1') || (pfx[1] != ' '))
00165 return STATUS_CONNECTION_REFUSED;
00166 if (!channel.Receive(pfx, sizeof(g_szRPCReplySignature) - 1))
00167 return STATUS_CONNECTION_REFUSED;
00168 if (memcmp(pfx, g_szRPCReplySignature, sizeof(g_szRPCReplySignature) - 1))
00169 return STATUS_CONNECTION_REFUSED;
00170 channel.Receive(&version, 4);
00171 if (version != KDRPC_PROTOCOL_VERSION)
00172 return STATUS_PROTOCOL_NOT_SUPPORTED;
00173 return STATUS_SUCCESS;
00174 }
00175
00176 static NTSTATUS KdDebuggerInitialize0(PVOID lpLoaderParameterBlock)
00177 {
00178 memset(&s_EmptyBuffer, 0, sizeof(s_EmptyBuffer));
00179 memset(&s_EmptyKdContext, 0, sizeof(s_EmptyKdContext));
00180 KdVmActiveCallCount = 0;
00181 NTSTATUS status = NegotiateProtocolVersions();
00182 if (!NT_SUCCESS(status))
00183 return status;
00184 if (!TestConnectionWithHost())
00185 return STATUS_CONNECTION_REFUSED;
00186 return STATUS_SUCCESS;
00187 }
00188
00189 static KD_RECV_CODE KdReceivePacket(
00190 __in ULONG PacketType,
00191 __inout_opt PKD_BUFFER FirstBuffer,
00192 __inout_opt PKD_BUFFER SecondBuffer,
00193 __out_opt PULONG PayloadBytes,
00194 __inout_opt PKD_CONTEXT KdContext)
00195 {
00196 InterlockedIncrementer ctr(&KdVmActiveCallCount);
00197 DefaultRPCChannel channel;
00198 char commandType = ReceivePacket;
00199 ULONG globals = 0;
00200 if (KD_DEBUGGER_NOT_PRESENT)
00201 globals |= 1;
00202 if (!channel.PrepareSend(sizeof(g_szRPCCommandHeader) + 2 * sizeof(ULONG) + 2 * sizeof(SendableKdBuffer) + sizeof(KD_CONTEXT)))
00203 return KD_RECV_CODE_FAILED;
00204 if (!channel.SendPartial(&g_szRPCCommandHeader, sizeof(g_szRPCCommandHeader) - 1))
00205 return KD_RECV_CODE_FAILED;
00206 if (!channel.SendPartial(&commandType, 1))
00207 return KD_RECV_CODE_FAILED;
00208 if (!channel.SendPartial(&PacketType, sizeof(ULONG)))
00209 return KD_RECV_CODE_FAILED;
00210 if (!channel.SendPartial(&globals, sizeof(ULONG)))
00211 return KD_RECV_CODE_FAILED;
00212 if (!channel.SendPartial(FirstBuffer ? FirstBuffer : &s_EmptyBuffer, sizeof(SendableKdBuffer)))
00213 return KD_RECV_CODE_FAILED;
00214 if (!channel.SendPartial(SecondBuffer ? SecondBuffer : &s_EmptyBuffer, sizeof(SendableKdBuffer)))
00215 return KD_RECV_CODE_FAILED;
00216 if (!channel.SendPartial(KdContext ? KdContext : &s_EmptyKdContext, sizeof(KD_CONTEXT)))
00217 return KD_RECV_CODE_FAILED;
00218 unsigned recvSize = channel.GetReplySize();
00219 unsigned minReplySize = (sizeof(g_szRPCReplySignature) + sizeof(SendableKdBuffer) * 2 + sizeof(KD_CONTEXT) + KDRPC_RECV_RETURNED_ULONGS * sizeof(ULONG) + 2);
00220 if ((recvSize == -1) || (recvSize < minReplySize))
00221 return KD_RECV_CODE_FAILED;
00222 KD_BUFFER tempBuffer;
00223 KD_CONTEXT tempContext;
00224 char pfx[sizeof(g_szRPCReplySignature)];
00225 if (!channel.Receive(pfx, 2))
00226 return KD_RECV_CODE_FAILED;
00227 if ((pfx[0] != '1') || (pfx[1] != ' '))
00228 return KD_RECV_CODE_FAILED;
00229 if (!channel.Receive(pfx, sizeof(g_szRPCReplySignature) - 1))
00230 return KD_RECV_CODE_FAILED;
00231 if (!channel.Receive(&commandType, 1))
00232 return KD_RECV_CODE_FAILED;
00233 if ((memcmp(pfx, g_szRPCReplySignature, sizeof(g_szRPCReplySignature) - 1) || (commandType != ReceivePacket)))
00234 return KD_RECV_CODE_FAILED;
00235 if (!channel.Receive(FirstBuffer ? FirstBuffer : &tempBuffer, sizeof(SendableKdBuffer)))
00236 return KD_RECV_CODE_FAILED;
00237 if (!channel.Receive(SecondBuffer ? SecondBuffer : &tempBuffer, sizeof(SendableKdBuffer)))
00238 return KD_RECV_CODE_FAILED;
00239 if (!channel.Receive(KdContext ? KdContext : &tempContext, sizeof(KD_CONTEXT)))
00240 return KD_RECV_CODE_FAILED;
00241 ULONG params[KDRPC_RECV_RETURNED_ULONGS];
00242 if (!channel.Receive(params, sizeof(ULONG) * KDRPC_RECV_RETURNED_ULONGS))
00243 return KD_RECV_CODE_FAILED;
00244 if (recvSize != (sizeof(g_szRPCReplySignature) + params[2] + params[3] + sizeof(SendableKdBuffer) * 2 + sizeof(KD_CONTEXT) + KDRPC_RECV_RETURNED_ULONGS * sizeof(ULONG) + 2))
00245 return KD_RECV_CODE_FAILED;
00246
00247 if (FirstBuffer && FirstBuffer->pData && (FirstBuffer->MaxLength >= params[2]))
00248 {
00249 if (!channel.Receive(FirstBuffer->pData, params[2]))
00250 return KD_RECV_CODE_FAILED;
00251 }
00252 if (SecondBuffer && SecondBuffer->pData && (SecondBuffer->MaxLength >= params[3]))
00253 {
00254 if (!channel.Receive(SecondBuffer->pData, params[3]))
00255 return KD_RECV_CODE_FAILED;
00256 }
00257 if (PayloadBytes)
00258 *PayloadBytes = params[1];
00259 if (!channel.EndReceive())
00260 return KD_RECV_CODE_FAILED;
00261
00262 globals = params[4];
00263 KD_DEBUGGER_NOT_PRESENT = ((globals & 1) != 0);
00264
00265 return (KD_RECV_CODE)params[0];
00266 }
00267
00268 static VOID KdSendPacket(
00269 __in ULONG PacketType,
00270 __in PKD_BUFFER FirstBuffer,
00271 __in_opt PKD_BUFFER SecondBuffer,
00272 __inout PKD_CONTEXT KdContext)
00273 {
00274 for (;;)
00275 {
00276 InterlockedIncrementer ctr(&KdVmActiveCallCount);
00277 DefaultRPCChannel channel;
00278 char commandType = SendPacket;
00279 unsigned Size1 = 0, Size2 = 0;
00280 ULONG globals = 0;
00281 if (KD_DEBUGGER_NOT_PRESENT)
00282 globals |= 1;
00283 if (FirstBuffer)
00284 Size1 = FirstBuffer->Length;
00285 if (SecondBuffer)
00286 Size2 = SecondBuffer->Length;
00287 if (!channel.PrepareSend(sizeof(g_szRPCCommandHeader) + sizeof(ULONG) * KDRPC_SEND_PASSED_ULONGS + 2 * sizeof(SendableKdBuffer) + sizeof(KD_CONTEXT) + Size1 + Size2))
00288 return;
00289 if (!channel.SendPartial(&g_szRPCCommandHeader, sizeof(g_szRPCCommandHeader) - 1))
00290 return;
00291 if (!channel.SendPartial(&commandType, 1))
00292 return;
00293 if (!channel.SendPartial(FirstBuffer ? FirstBuffer : &s_EmptyBuffer, sizeof(SendableKdBuffer)))
00294 return;
00295 if (!channel.SendPartial(SecondBuffer ? SecondBuffer : &s_EmptyBuffer, sizeof(SendableKdBuffer)))
00296 return;
00297 if (!channel.SendPartial(KdContext ? KdContext : &s_EmptyKdContext, sizeof(KD_CONTEXT)))
00298 return;
00299 ULONG params[KDRPC_SEND_PASSED_ULONGS] = {PacketType, Size1, Size2, globals};
00300 if (!channel.SendPartial(params, sizeof(params)))
00301 return;
00302 if (Size1)
00303 if (!channel.SendPartial(FirstBuffer->pData, Size1))
00304 return;
00305 if (Size2)
00306 if (!channel.SendPartial(SecondBuffer->pData, Size2))
00307 return;
00308 unsigned recvSize = channel.GetReplySize();
00309 if (recvSize != (sizeof(g_szRPCReplySignature) + 2 + sizeof(KD_CONTEXT) + sizeof(ULONG)))
00310 return;
00311 char pfx[sizeof(g_szRPCReplySignature)];
00312 if (!channel.Receive(pfx, 2))
00313 return;
00314 if ((pfx[0] != '1') || (pfx[1] != ' '))
00315 return;
00316 if (!channel.Receive(pfx, sizeof(g_szRPCReplySignature) - 1))
00317 return;
00318 if (!channel.Receive(&commandType, 1))
00319 return;
00320 if ((memcmp(pfx, g_szRPCReplySignature, sizeof(g_szRPCReplySignature) - 1) || (commandType != SendPacket)))
00321 return;
00322 KD_CONTEXT tempContext;
00323 if (!channel.Receive(KdContext ? KdContext : &tempContext, sizeof(KD_CONTEXT)))
00324 return;
00325 if (!channel.Receive(&globals, sizeof(ULONG)))
00326 return;
00327 if (!channel.EndReceive())
00328 return;
00329 KD_DEBUGGER_NOT_PRESENT = ((globals & 1) != 0);
00330
00331 if (globals & 2)
00332 continue;
00333 break;
00334 }
00335 }
00336 };
00337
00338 NTSTATUS __stdcall KdDebuggerInitialize0(PVOID lpLoaderParameterBlock)
00339 {
00340 s_bVBoxDetected = false;
00341 NTSTATUS st = ChannelHelper<VMWareChannel>::KdDebuggerInitialize0(lpLoaderParameterBlock);
00342 if ((st == STATUS_RETRY) && s_bVBoxDetected)
00343 st = ChannelHelper<VBoxChannel>::KdDebuggerInitialize0(lpLoaderParameterBlock);
00344 return st;
00345 }
00346
00347 VOID __stdcall KdSendPacket(__in ULONG PacketType,
00348 __in PKD_BUFFER FirstBuffer,
00349 __in_opt PKD_BUFFER SecondBuffer,
00350 __inout PKD_CONTEXT KdContext)
00351 {
00352 if (s_bVBoxDetected)
00353 return ChannelHelper<VBoxChannel>::KdSendPacket(PacketType, FirstBuffer, SecondBuffer, KdContext);
00354 else
00355 return ChannelHelper<VMWareChannel>::KdSendPacket(PacketType, FirstBuffer, SecondBuffer, KdContext);
00356 }
00357
00358 KD_RECV_CODE __stdcall KdReceivePacket(__in ULONG PacketType,
00359 __inout_opt PKD_BUFFER FirstBuffer,
00360 __inout_opt PKD_BUFFER SecondBuffer,
00361 __out_opt PULONG PayloadBytes,
00362 __inout_opt PKD_CONTEXT KdContext)
00363 {
00364 if (s_bVBoxDetected)
00365 return ChannelHelper<VBoxChannel>::KdReceivePacket(PacketType, FirstBuffer, SecondBuffer, PayloadBytes, KdContext);
00366 else
00367 return ChannelHelper<VMWareChannel>::KdReceivePacket(PacketType, FirstBuffer, SecondBuffer, PayloadBytes, KdContext);
00368 }