• Main Page
  • Related Pages
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

E:/PROJECTS/cvsed/mixed/VIRTUA~1/kdvm/kdvm.cpp

Go to the documentation of this file.
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 //#define VIRTUALKD_BENCHMARK_AND_EXIT
00020 //Driver v1.1 does 100K test requests in ~7.21 sec (~13K requests/sec) under VMWare
00021 //Driver v2.0 does 1M test requests in ~16 sec (~62K requests/sec) under VirtualBox
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                 //SendableKdBuffer should be KD_BUFFER minus pData field (used in serialization). If not, an error will popup here:
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                         //Retry request if a droppable packet was not delivered
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 }