00001
00007 #include "stdafx.h"
00008 #include "patchapi.h"
00009 #include "findproc.h"
00010 #include <TlHelp32.h>
00011 #include <assert.h>
00012 #include "loader.h"
00013 #include "hook64.h"
00014 #include "32to64.h"
00015 #include <bzswin/wow64.h>
00016 #include <ShellApi.h>
00017
00018 #include "../VBoxDD/VBoxCmdLine.h"
00019
00020 BazisLib::WOW64APIProvider g_Wow64;
00021
00022 static bool IsRundll64Required(unsigned PID)
00023 {
00024 #ifdef _WIN64
00025 return false;
00026 #else
00027 return g_Wow64.IsWow64Process() && !g_Wow64.IsWow64Process(PID);
00028 #endif
00029 }
00030
00031 extern HMODULE g_hThisDll;
00032
00034 void EnableDebugPrivilege()
00035 {
00036 HANDLE hToken;
00037 LUID sedebugnameValue;
00038 TOKEN_PRIVILEGES tkp;
00039
00040 OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
00041
00042 LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &sedebugnameValue);
00043
00044 tkp.PrivilegeCount = 1;
00045 tkp.Privileges[0].Luid = sedebugnameValue;
00046 tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
00047
00048 AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(tkp), NULL, NULL);
00049
00050 CloseHandle(hToken);
00051 }
00052
00053
00054 HANDLE CreateVMSessionList()
00055 {
00056 HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
00057 if (hSnap == INVALID_HANDLE_VALUE)
00058 return INVALID_HANDLE_VALUE;
00059 PROCESSENTRY32 entry = {0, };
00060 entry.dwSize = sizeof(entry);
00061
00062 Process32First(hSnap, &entry);
00063 assert(!_tcsstr(entry.szExeFile, _T("vmware-vmx.exe")));
00064 assert(!_tcsstr(entry.szExeFile, _T("VirtualBox.exe")));
00065 return hSnap;
00066 }
00067
00068 void CloseVMSessionList( HANDLE hList )
00069 {
00070 CloseHandle(hList);
00071 }
00072
00073 unsigned GetNextVMSessionPID( HANDLE hList )
00074 {
00075 return GetNextVMSessionPIDEx(hList, NULL);
00076 }
00077
00078 unsigned GetNextVMSessionPIDEx( HANDLE hList, VMType *pVMType )
00079 {
00080 TCHAR *tszNames[] = {_T("vmware-vmx.exe"), _T("VirtualBox.exe")};
00081 unsigned PID = 0;
00082 unsigned idxMatch = 0;
00083 for (;;)
00084 {
00085 PID = FindProcessByNames(hList, tszNames, 2, false, &idxMatch);
00086 if ((PID == -1) || !PID)
00087 return 0;
00088 if (!idxMatch)
00089 break;
00090 wchar_t sessionName[MAX_PATH];
00091 if (GetVMSessionNameW(PID, sessionName, __countof(sessionName)))
00092 break;
00093
00094 }
00095 if (pVMType)
00096 {
00097 if (!PID)
00098 *pVMType = kVMUnknown;
00099 {
00100 BazisLib::WOW64APIProvider wow;
00101 #ifdef _WIN64
00102 bool Is64 = !wow.IsWow64Process(PID);
00103 #else
00104 bool Is64 = wow.IsWow64Process() && !wow.IsWow64Process(PID);
00105 #endif
00106 if (!idxMatch)
00107 *pVMType = Is64 ? kVMWare64 : kVMWare32;
00108 else
00109 *pVMType = Is64 ? kVBox64 : kVBox32;
00110 }
00111 }
00112 return PID;
00113 }
00114
00115 unsigned SessionNameFromVMWareCmdLineW(wchar_t *pszCmdLine, wchar_t *pName, size_t MaxNameLength)
00116 {
00117 wchar_t *pVmx = wcsstr(pszCmdLine, L".vmx");
00118 if (!pVmx)
00119 return 0;
00120 for (;;)
00121 {
00122 wchar_t *p = wcsstr(pVmx + 1, L".vmx");
00123 if (!p)
00124 break;
00125 pVmx = p;
00126 }
00127 if (pVmx)
00128 pVmx[0] = 0;
00129
00130 wchar_t *end = wcsrchr(pszCmdLine, '\\');
00131 if (!end)
00132 return 0;
00133 end[0] = 0;
00134 wchar_t *start = wcsrchr(pszCmdLine, '\\');
00135 if (!start)
00136 return 0;
00137 else
00138 start++;
00139
00140 size_t todo = end - start;
00141 if (todo >= MaxNameLength)
00142 todo = MaxNameLength - 1;
00143 memcpy(pName, start, todo * sizeof(wchar_t *));
00144 pName[todo] = 0;
00145 return (unsigned)todo;
00146 }
00147
00148 unsigned SessionNameFromVMCmdLineW(wchar_t *pszCmdLine, wchar_t *pName, size_t MaxNameLength)
00149 {
00150 int argc = 0;
00151 LPWSTR *pArgs = CommandLineToArgvW(pszCmdLine, &argc);
00152 if (!pArgs || !argc || !pArgs[0])
00153 return 0;
00154
00155 if (wcsstr(pArgs[0], L"vmware-vmx.exe"))
00156 return SessionNameFromVMWareCmdLineW(pszCmdLine, pName, MaxNameLength);
00157 else if (wcsstr(pArgs[0], L"VirtualBox.exe"))
00158 return VBoxCmdLineToVMNameW(pszCmdLine, pName, MaxNameLength);
00159 else
00160 return 0;
00161 }
00162
00163
00164 unsigned GetVMSessionNameW(unsigned PID, wchar_t *pName, size_t MaxNameLength)
00165 {
00166 #ifndef _WIN64
00167 if (IsRundll64Required(PID))
00168 {
00169 return (unsigned)Call64BitKDCLIENT(kGetVMSessionName, PID, pName, MaxNameLength);
00170 }
00171 #endif
00172 extern HMODULE g_hThisDll;
00173 EnableDebugPrivilege();
00174 if (!PID || !pName)
00175 return 0;
00176 wchar_t wszCmdLine[2048] = {0,};
00177 if (!RemoteDllLoader::GetRemoteCommandLineW(PID, wszCmdLine, sizeof(wszCmdLine)/sizeof(wszCmdLine[0])))
00178 return 0;
00179 return SessionNameFromVMCmdLineW(wszCmdLine, pName, MaxNameLength);
00180 }
00181
00182 bool IsVMSessionPatched( unsigned PID )
00183 {
00184 #ifndef _WIN64
00185 if (IsRundll64Required(PID))
00186 {
00187 return (Call64BitKDCLIENT(kIsSessionPatched, PID) == 1);
00188 }
00189 #endif
00190 if (GetRemoteModuleHandle64Aware(PID, _T("VBoxDD0.dll")))
00191 return true;
00192 RemoteDllLoader ldr(g_hThisDll, false);
00193 return (ldr.FindLibraryInProcess(PID, true) != 0);
00194 }
00195
00196 static bool s_bUserWarnedAboutVBox = false;
00197
00198 HANDLE StartPatcherThread( unsigned PID, DWORD *pPatcherThreadID = NULL)
00199 {
00200 EnableDebugPrivilege();
00201 if (GetRemoteModuleHandle64Aware(PID, _T("VBoxDD0.dll")))
00202 return 0;
00203 if (GetRemoteModuleHandle64Aware(PID, _T("VBoxDD.dll")))
00204 {
00205 if (!s_bUserWarnedAboutVBox)
00206 {
00207 s_bUserWarnedAboutVBox = true;
00208 MessageBox(0, _T("VirtualKD cannot patch VirtualBox on-the-fly.\r\nPlease, shut down all your VMs, rename VBoxDD.dll\t\nto VBoxDD0.dll and copy VBoxDD.dll from VirtualKD\t\npackage to VirtualBox directory."),
00209 _T("VirtualKD"),
00210 MB_ICONWARNING | MB_TASKMODAL);
00211 }
00212 return INVALID_HANDLE_VALUE;
00213 }
00214 RemoteDllLoader ldr(g_hThisDll, false);
00215 if (ldr.FindLibraryInProcess(PID))
00216 return NULL;
00217 return ldr.InitiateDLLLoading(PID, pPatcherThreadID);
00218 }
00219
00220
00221 HANDLE StartUnpatcherThread( unsigned PID, DWORD *pPatcherThreadID = NULL)
00222 {
00223 if (GetRemoteModuleHandle64Aware(PID, _T("VBoxDD0.dll")))
00224 return INVALID_HANDLE_VALUE;
00225 EnableDebugPrivilege();
00226 RemoteDllLoader ldr(g_hThisDll, false);
00227 if (!ldr.FindLibraryInProcess(PID))
00228 return NULL;
00229 return ldr.InitiateDLLUnloading(PID, true, pPatcherThreadID);
00230 }
00231
00232 static bool DoSynchronousThreadOperation(HANDLE hThread)
00233 {
00234 if (hThread == NULL)
00235 return true;
00236 else if (hThread == INVALID_HANDLE_VALUE)
00237 return false;
00238 else
00239 {
00240 WaitForSingleObject(hThread, INFINITE);
00241 CloseHandle(hThread);
00242 DWORD dwCode = 0;
00243 GetExitCodeThread(hThread, &dwCode);
00244 return (dwCode != 0);
00245 }
00246 }
00247
00248 bool PatchVMSessionIfNeeded(unsigned PID)
00249 {
00250 #ifndef _WIN64
00251 if (IsRundll64Required(PID))
00252 {
00253 return (Call64BitKDCLIENT(kPatchAndWait, PID) != 0);
00254 }
00255 #endif
00256 return DoSynchronousThreadOperation(StartPatcherThread(PID));
00257 }
00258
00259 bool UnpatchVMSessionIfNeeded(unsigned PID)
00260 {
00261 #ifndef _WIN64
00262 if (IsRundll64Required(PID))
00263 {
00264 return (Call64BitKDCLIENT(kUnpatchAndWait, PID) != 0);
00265 }
00266 #endif
00267 return DoSynchronousThreadOperation(StartUnpatcherThread(PID));
00268 }
00269
00270 HTHREAD StartVMSessionPatching(unsigned PID)
00271 {
00272 #ifndef _WIN64
00273 if (IsRundll64Required(PID))
00274 {
00275 DWORD dwID = (DWORD)Call64BitKDCLIENT(kStartVMSessionPatching, PID);
00276 EnableDebugPrivilege();
00277 if(!dwID)
00278 return 0;
00279 else if (dwID == -1)
00280 return INVALID_HANDLE_VALUE;
00281 else
00282 {
00283 HANDLE h = OpenThread(THREAD_ALL_ACCESS, FALSE, dwID);
00284 if (!h || (h == INVALID_HANDLE_VALUE))
00285 return 0;
00286 return h;
00287 }
00288 }
00289 #endif
00290 return StartPatcherThread(PID);
00291 }
00292
00293 HTHREAD StartVMSessionUnpatching(unsigned PID)
00294 {
00295 #ifndef _WIN64
00296 if (IsRundll64Required(PID))
00297 {
00298 DWORD dwID = (DWORD)Call64BitKDCLIENT(kStartVMSessionUnpatching, PID);
00299 EnableDebugPrivilege();
00300 if(!dwID)
00301 return 0;
00302 else if (dwID == -1)
00303 return INVALID_HANDLE_VALUE;
00304 else
00305 {
00306 HANDLE h = OpenThread(THREAD_ALL_ACCESS, FALSE, dwID);
00307 if (!h || (h == INVALID_HANDLE_VALUE))
00308 return 0;
00309 return h;
00310 }
00311 }
00312 #endif
00313 return StartUnpatcherThread(PID);
00314 }
00315
00316 int FindVMSessionByNameW( const wchar_t *pName )
00317 {
00318 if (!pName)
00319 return 0;
00320 wchar_t wsz[512] = {0,};
00321
00322 HANDLE hSnap = CreateVMSessionList();
00323 if (hSnap == INVALID_HANDLE_VALUE)
00324 return 0;
00325 int PID = 0;
00326 while (PID = GetNextVMSessionPID(hSnap))
00327 {
00328 if (!GetVMSessionNameW(PID, wsz, sizeof(wsz)/sizeof(wsz[0])))
00329 continue;
00330 if (!_wcsicmp(wsz, pName))
00331 break;
00332 }
00333 CloseVMSessionList(hSnap);
00334 return PID;
00335 }
00336
00337 unsigned GetVMPipeNameW(unsigned PID, wchar_t *pName, size_t MaxNameLength, bool TryReconstructingIfNotAvailable)
00338 {
00339 if (!pName)
00340 return 0;
00341 pName[0] = 0;
00342
00343 TCHAR tszMappingName[MAX_PATH];
00344 _sntprintf_s(tszMappingName, __countof(tszMappingName), _TRUNCATE, tszMappingNameFormat, PID);
00345 HANDLE hMapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READONLY, 0, sizeof(KdClientStatus), tszMappingName);
00346 KdClientStatus *pStatus = (KdClientStatus *)MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
00347 if ((hMapping == INVALID_HANDLE_VALUE) || !pStatus)
00348 {
00349 if (hMapping != INVALID_HANDLE_VALUE)
00350 CloseHandle(hMapping);
00351 if (!TryReconstructingIfNotAvailable)
00352 return 0;
00353
00354 TCHAR tszSession[MAX_PATH] = {0,};
00355 GetVMSessionNameW(PID, tszSession, __countof(tszSession));
00356 unsigned len = _snwprintf(pName, MaxNameLength, L"\\\\.\\pipe\\kd_%s", tszSession);
00357 for (int i = 0; pName[i]; i++)
00358 if (pName[i] == ' ')
00359 pName[i] = '_';
00360 return len;
00361 }
00362 unsigned len = (unsigned)wcslen(pStatus->PipeName);
00363 wcsncpy_s(pName, MaxNameLength, pStatus->PipeName, _TRUNCATE);
00364 UnmapViewOfFile(pStatus);
00365 CloseHandle(hMapping);
00366 return len;
00367 }