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
00166
00167
00168
00169
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 }