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

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

Go to the documentation of this file.
00001 
00007 #include "stdafx.h"
00008 #include <tchar.h>
00009 #include "../kdvm/kdrpc.h"
00010 #include <bzscmn/bzscmn.h>
00011 #include "tablemgr.h"
00012 #include "../rpcdispatch/rpcdisp.h"
00013 #include "../rpcdispatch/kdcomdisp.h"
00014 #include "../rpcdispatch/reporter.h"
00015 
00016 StatusReporter *g_pReporter = NULL;
00017 static RPCTableManager *g_pManager = NULL;
00018 static volatile LONG s_CallCount = 0;
00019 static bool s_bUnload = false;
00020 extern "C" HANDLE s_hThreadEvent = INVALID_HANDLE_VALUE;
00021 
00022 static HANDLE s_hThread = INVALID_HANDLE_VALUE;
00023 
00025 class InterlockedIncrementer
00026 {
00027 private:
00028         (volatile LONG) *m_pPtr;
00029 
00030 public:
00031         inline InterlockedIncrementer(volatile LONG *pPtr)
00032                 : m_pPtr(pPtr)
00033         {
00034                 InterlockedIncrement(m_pPtr);
00035         }
00036 
00037         ~InterlockedIncrementer()
00038         {
00039                 InterlockedDecrement(m_pPtr);
00040         }
00041 };
00042 
00043 #ifdef KDVMWARE_USE_PROXY
00044 
00045 int MaxDelay = 0;
00046 static char ReplyBuffer[262144];
00047 
00048 static bool KDRPCProxyHandler(void *pContext, int ChannelNumber, char *pCommandBody, unsigned CommandBodyLength, char **ppReply, unsigned *pReplyLen)
00049 {
00050         InterlockedIncrementer inc(&s_CallCount);
00051         DWORD done = 0;
00052         DWORD tick = GetTickCount();
00053         for (;;)
00054         {
00055                 BOOL b = CallNamedPipe(_T("\\\\.\\pipe\\kdvmware_proxypipe"), pCommandBody, CommandBodyLength, ReplyBuffer, sizeof(ReplyBuffer), &done, INFINITE);
00056                 if (b)
00057                 {
00058                         int delay = (int)(GetTickCount() - tick);
00059                         if (delay > MaxDelay)
00060                                 MaxDelay = delay;
00061                         break;
00062                 }
00063                 int er = GetLastError();
00064                 if ((GetTickCount() - tick) > 1000)
00065                 {
00066                         *pReplyLen = 0;
00067                         return false;
00068                 }
00069         }
00070         *pReplyLen = done;
00071         *ppReply = ReplyBuffer;
00072         return true;
00073 }
00074 
00075 #else
00076 
00077 static KdRpcDispatcher *s_pClient = NULL;
00078 
00079 static bool KDRPCDirectHandler(void *pContext, int ChannelNumber, char *pCommandBody, unsigned CommandBodyLength, char **ppReply, unsigned *pReplyLen)
00080 {
00081         InterlockedIncrementer inc(&s_CallCount);
00082         if (!s_pClient)
00083                 return false;
00084         *pReplyLen = s_pClient->OnRequest(pCommandBody, CommandBodyLength, ppReply);
00085         return true;
00086 }
00087 
00088 #endif
00089 
00090 unsigned SessionNameFromVMCmdLineW(wchar_t *pszCmdLine, wchar_t *pName, size_t MaxNameLength);
00091 
00092 extern "C" DWORD PatcherThreadMain(LPVOID lpParam);
00093 
00094 DWORD PatcherThreadMain(LPVOID lpParam)
00095 {
00096         HINSTANCE hThisDll = (HINSTANCE)lpParam;
00097 #ifndef KDVMWARE_USE_PROXY
00098         TCHAR tsz[MAX_PATH] = {0,};
00099         
00100         wchar_t wszCmdLine[2048] = {0,};
00101         String pipeName = _T("\\\\.\\pipe\\kd_");
00102         String pipeEnding;
00103         wcsncpy(wszCmdLine, GetCommandLineW(), sizeof(wszCmdLine)/sizeof(wszCmdLine[0]));
00104         if (SessionNameFromVMCmdLineW(wszCmdLine, tsz, sizeof(tsz)/sizeof(tsz[0])) && tsz[0])
00105         {
00106                 pipeEnding = tsz;
00107         }
00108         else
00109         {
00110                 GetCurrentDirectory(__countof(tsz), tsz);
00111                 FilePath fp(tsz);
00112                 pipeEnding = fp.GetFileName();
00113         }
00114 
00115         size_t pos = -1;
00116         for (;;)
00117         {
00118                 pos = pipeEnding.find(' ', pos + 1);
00119                 if (pos == String::npos)
00120                         break;
00121                 pipeEnding[pos] = '_';
00122         }
00123         pipeName += pipeEnding;
00124         wcsncpy(g_pReporter->GetStatusPointer()->PipeName, pipeName.c_str(), __countof(g_pReporter->GetStatusPointer()->PipeName));
00125         s_pClient = new KdRpcDispatcher(new KdComDispatcher(pipeName.c_str()));
00126 #endif
00127 
00128         g_pManager = new RPCTableManager(hThisDll);
00129         bool forceRepatch = false;
00130         while (!s_bUnload)
00131         {
00132 #ifdef KDVMWARE_USE_PROXY
00133                 if (!g_pManager->InstallHandler(g_szRPCCommandHeader, sizeof(g_szRPCCommandHeader)-2, KDRPCProxyHandler, NULL, forceRepatch))
00134 #else
00135                 if (!g_pManager->InstallHandler(g_szRPCCommandHeader, sizeof(g_szRPCCommandHeader)-2, KDRPCDirectHandler, NULL, forceRepatch))
00136 #endif
00137                 {
00138                         g_pReporter->GetStatusPointer()->PatchErrorPlus1 = ERROR_UNIDENTIFIED_ERROR + 1;
00139                         return 0;
00140                 }
00141                 g_pReporter->GetStatusPointer()->PatchErrorPlus1 = ERROR_SUCCESS + 1;
00142                 if (s_EnableLogging && (g_pReporter->GetStatusPointer()->DebugLevel >= DebugLevelTracePatching))
00143                         g_pReporter->LogLineIfEnabled(_T("VMWare reset monitor activated...\r\n"));
00144                 while (!s_bUnload)
00145                 {
00146                         Sleep(1000);
00147                         if (g_pManager->IsEntryModified())
00148                         {
00149                                 g_pReporter->GetStatusPointer()->PatchErrorPlus1 = 0;
00150                                 if (s_EnableLogging && (g_pReporter->GetStatusPointer()->DebugLevel >= DebugLevelTracePatching))
00151                                         g_pReporter->LogLineIfEnabled(_T("Virtual machine reset. RPC handler table reinitialized.\r\nPatching table once again...\r\n"));
00152                                 Sleep(200);
00153                                 g_pReporter->GetStatusPointer()->OSDetected = false;
00154                                 forceRepatch = true;
00155                                 break;
00156                         }
00157                 }
00158         }
00159         if (s_EnableLogging && (g_pReporter->GetStatusPointer()->DebugLevel >= DebugLevelTracePatching))
00160                 g_pReporter->LogLineIfEnabled(_T("VMWare reset monitor thread: exitting\r\n"));
00161         return 0;
00162 }
00163 
00164 /*
00165         The patcher thread will not actually terminate while the FreeLibrary() call (and our DllMain callback)
00166         is active, as NTDLL holds the loader lock for that.
00167         Instead, we call the SetEvent() for our event indicating the end of the thread and let it return directly
00168         to the KERNEL32 code that called our ThreadBody bypassing our DLL code. That allows safely unloading the DLL
00169         by the thread waiting for the event after the event is set.
00170 */
00171 
00172 #ifndef _WIN64
00173 DWORD __declspec(naked) CALLBACK ThreadBody(LPVOID lpParam)
00174 {
00175         __asm
00176         {
00177                 push [esp+4]
00178                 call PatcherThreadMain
00179                 add esp, 4
00180                 mov eax, s_hThreadEvent
00181                 mov [esp+4], eax
00182                 jmp dword ptr [SetEvent]
00183         }
00184 }
00185 #else
00186 extern "C" DWORD CALLBACK ThreadBody(LPVOID lpParam);
00187 #endif
00188 
00189 bool HookVmware(HINSTANCE hThisDll)
00190 {
00191         TCHAR tsz[MAX_PATH];
00192         GetModuleFileName(GetModuleHandle(0), tsz, __countof(tsz));
00193         if (!_tcsstr(tsz, _T("vmware-vmx.exe")))
00194                 return true;
00195         DisableThreadLibraryCalls((HMODULE)hThisDll);
00196         s_CallCount = 0;
00197         g_pReporter = new StatusReporter();
00198         ASSERT(g_pReporter);
00199         s_bUnload = false;
00200         DWORD dwID;
00201         s_hThreadEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
00202         s_hThread = CreateThread(NULL, 0, ThreadBody, (LPVOID)hThisDll, 0, &dwID);
00203         if (s_hThread == INVALID_HANDLE_VALUE)
00204                 return false;
00205         return true;
00206 }
00207 
00208 void UnhookVmware()
00209 {
00210         if (!g_pReporter)
00211                 return;
00212         if (s_EnableLogging && (g_pReporter->GetStatusPointer()->DebugLevel >= DebugLevelTracePatching))
00213                 g_pReporter->LogLineIfEnabled(_T("Waiting for reset monitor thread to terminate...\r\n"));
00214         s_bUnload = true;
00215         HANDLE hObjs[2] = {s_hThreadEvent, s_hThread};
00216         if (WaitForMultipleObjects(2, hObjs, FALSE, INFINITE) == (WAIT_OBJECT_0 + 1))
00217         {
00218                 if (s_EnableLogging && (g_pReporter->GetStatusPointer()->DebugLevel >= DebugLevelTracePatching))
00219                         g_pReporter->LogLineIfEnabled(_T("WARNING! Reset monitor thread was forcibly terminated (VMWare exitting?)\r\n"));
00220         }
00221         CloseHandle(s_hThreadEvent);
00222         CloseHandle(s_hThread);
00223         if (s_EnableLogging && (g_pReporter->GetStatusPointer()->DebugLevel >= DebugLevelTracePatching))
00224                 g_pReporter->LogLineIfEnabled(_T("Unpatching RPC handler table...\r\n"));
00225 
00226         if (g_pManager)
00227                 g_pManager->RestoreOriginalHandler();
00228 
00229         if (s_EnableLogging && (g_pReporter->GetStatusPointer()->DebugLevel >= DebugLevelTracePatching))
00230                 g_pReporter->LogLineIfEnabled(_T("Waiting for all previously started RPC calls to complete...\r\n"));
00231 
00232         for (int i = 0; i < 10; i++)
00233         {
00234                 if (s_CallCount)
00235                         i = 0;
00236                 Sleep(100);
00237         }
00238 
00239         if (s_EnableLogging && (g_pReporter->GetStatusPointer()->DebugLevel >= DebugLevelTracePatching))
00240                 g_pReporter->LogLineIfEnabled(_T("Unloading...\r\n"));
00241 
00242         delete g_pManager;
00243         g_pManager = NULL;
00244 #ifndef KDVMWARE_USE_PROXY
00245         delete s_pClient;
00246         s_pClient = NULL;
00247 #endif
00248         delete g_pReporter;
00249         g_pReporter = NULL;
00250 }