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

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

Go to the documentation of this file.
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         //First process should always be the system process. That way, we can simply ignore it and use Process32Next() every time we want to find a next session.
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                 //Skip VirtualBox processes not running any VMs
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))  //Thread already finished
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))  //Thread already finished
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 }