/* $Id: tsmfhook.cpp 46593 2013-06-17 14:32:51Z vboxsync $ */ /** @file * VBoxMMR - Multimedia Redirection */ /* * Copyright (C) 2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; * you can redistribute it and/or modify it under the terms of the GNU * General Public License (GPL) as published by the Free Software * Foundation, in version 2 as it comes in the "COPYING" file of the * VirtualBox OSE distribution. VirtualBox OSE is distributed in the * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. */ #include "stdafx.h" #include "tsmfhook.h" #include "tsmf.h" #include "logging.h" #include #include #include #include #include #include #include #include #define CODECAVE_SIZE 0x64 /* Generic byte code for API calls redirection. * It corresponds to the following set of instructions: * push ebp * mov ebp, esp * pop ebp * mov eax, 0DEADBEEFh * jmp eax */ static const char g_szCodeCave[] = "\x55\x8B\xEC\x5D\xB8\xEF\xBE\xAD\xDE\xFF\xE0"; const WCHAR *g_pwszMMRFlags = L"VBoxMMR"; const WCHAR *g_pwszMMRAdditions = L"SOFTWARE\\Oracle\\VirtualBox Guest Additions"; const char *g_pszVRDETSMF = "/vrde/tsmf"; const DWORD g_dwMMRCodeCavingEnabled = 0x00000002; BOOL g_bMMRCodeCavingIsEnabled = TRUE; BOOL MMRCodeCavingIsEnabled() { LONG lResult; HKEY hKey; DWORD dwType = 0; DWORD dwValue = 0; DWORD dwSize = sizeof(dwValue); BOOL fEnabled = TRUE; lResult = RegOpenKeyExW( HKEY_LOCAL_MACHINE, g_pwszMMRAdditions, 0, KEY_QUERY_VALUE, &hKey); if (lResult == ERROR_SUCCESS) { lResult = RegQueryValueExW( hKey, g_pwszMMRFlags, NULL, &dwType, (BYTE *) &dwValue, &dwSize); RegCloseKey(hKey); if (lResult == ERROR_SUCCESS && dwSize == sizeof(dwValue) && dwType == REG_DWORD) { fEnabled = g_dwMMRCodeCavingEnabled & dwValue; VBoxMMRHookLog("VBoxMMR: Registry setting: %d\n", dwValue); } } return fEnabled; } /* Events, which are specific for the tsmf channel. */ #define VBOX_TSMF_HCH_CREATE_ACCEPTED (VBOX_HOST_CHANNEL_EVENT_USER + 0) #define VBOX_TSMF_HCH_CREATE_DECLINED (VBOX_HOST_CHANNEL_EVENT_USER + 1) #define VBOX_TSMF_HCH_DISCONNECTED (VBOX_HOST_CHANNEL_EVENT_USER + 2) RTTHREAD hDetachMonitor = NIL_RTTHREAD; uint32_t nUserData = 1; HANDLE ghVBoxDriver = NULL; using std::map; using std::list; using std::queue; extern bool isWMP; CRITICAL_SECTION CreateLock; HANDLE hCreateEvent; uint32_t g_nCreateResult = VBOX_TSMF_HCH_CREATE_DECLINED; TRACEHANDLE g_hTraceSession = NULL; struct HookEntry { LPCSTR DllName; LPCSTR FunctionName; PVOID HookFuncAddr; PVOID *OrigFuncAddrPtr; PVOID *MMRFuncAddrPtr; }; struct HostChannelCtx { RTTHREAD thread; bool fShutdown; uint32_t u32HGCMClientId; uint8_t au8EventData[4]; }; HostChannelCtx g_HostChannelCtx = {0}; struct ReadReq { PBYTE Buffer; LPOVERLAPPED_COMPLETION_ROUTINE Func; LPOVERLAPPED lpOverlapped; HANDLE hThread; DWORD cbRead; DWORD ErrorCode; }; VOID CALLBACK APCProc(ULONG_PTR dwParam) { ReadReq *pReq = (ReadReq *) dwParam; if (NULL != g_hTraceSession) { /* Size FieldTypeFlags */ TraceEventData Event; // = { { sizeof(Event), (USHORT) 0, }, h }; ZeroMemory(&Event, sizeof(Event)); Event.Header.Size = sizeof(Event.Header) + sizeof(Event.ReadEnd); Event.Header.Class.Type = EVENT_TRACE_TYPE_DC_END; Event.Header.Class.Version = 0; Event.Header.Class.Level = TRACE_LEVEL_INFORMATION; Event.Header.Flags = WNODE_FLAG_TRACED_GUID; Event.Header.Guid = ChannelReadCategoryId; Event.ReadEnd.ErrorCode = pReq->ErrorCode; if (0 == pReq->ErrorCode) { DWORD cbToTrace = min(((PCHANNEL_PDU_HEADER) pReq->Buffer)->length, sizeof(Event.ReadEnd.Data)); CopyMemory(Event.ReadEnd.Data, pReq->Buffer, cbToTrace); } else Event.Header.Size -= sizeof(Event.ReadEnd.Data); TraceEvent(g_hTraceSession, &Event.Header); } pReq->Func(pReq->ErrorCode, pReq->cbRead, pReq->lpOverlapped); CloseHandle(pReq->hThread); delete pReq; } class VBOX_RDP_CHANNEL { static list ChannelList; static map ChannelMap; DWORD m_Id; CRITICAL_SECTION m_Lock; queue m_BufferList; queue m_ReqList; // we need to ignore the first write operation(s), as they are handled by VRDP for us // we probably don't want this in the final solution. DWORD m_nWriteOps; protected: void DoCompleteRead(PBYTE pBuffer, ReadReq *pReq) { uint32_t u32DataSize = *((uint32_t *) pBuffer); // FIXME : we really want the VBox RDP server to preserve these for us PCHANNEL_PDU_HEADER pPduHdr = (PCHANNEL_PDU_HEADER) pReq->Buffer; pPduHdr->length = u32DataSize; pPduHdr->flags = CHANNEL_FLAG_ONLY; CopyMemory(++pPduHdr, pBuffer + sizeof(u32DataSize), u32DataSize); pReq->cbRead = u32DataSize + sizeof(CHANNEL_PDU_HEADER); pReq->ErrorCode = ERROR_SUCCESS; delete [] pBuffer; QueueUserAPC(APCProc, pReq->hThread, (ULONG_PTR) pReq); } public: VBOX_RDP_CHANNEL(DWORD Id) : m_Id(Id), m_nWriteOps(0) { ChannelList.push_back(this); ChannelMap[Id] = this; InitializeCriticalSection(&m_Lock); }; ~VBOX_RDP_CHANNEL() { DeleteCriticalSection(&m_Lock); ChannelMap.erase(m_Id); ChannelList.remove(this); while (!m_ReqList.empty()) { ReadReq *req = m_ReqList.front(); req->cbRead = 0; req->ErrorCode = ERROR_BROKEN_PIPE; QueueUserAPC(APCProc, req->hThread, (ULONG_PTR) req); m_ReqList.pop(); } } void PushRequest(PBYTE Buffer, LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionFunc) { ReadReq *req = new ReadReq; req->Buffer = Buffer; req->Func = lpCompletionFunc; req->lpOverlapped = lpOverlapped; // the pseudo handle returned by GetCurrentTHread() can not be used with QueueUserAPC() BOOL b = DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &req->hThread, THREAD_SET_CONTEXT, FALSE, 0); EnterCriticalSection(&m_Lock); if (!m_BufferList.empty()) { PBYTE pBuffer = m_BufferList.front(); DoCompleteRead(pBuffer, req); m_BufferList.pop(); } else { m_ReqList.push(req); } LeaveCriticalSection(&m_Lock); } void PushBuffer(PBYTE pBuffer) { EnterCriticalSection(&m_Lock); if (!m_ReqList.empty()) { ReadReq *req = m_ReqList.front(); DoCompleteRead(pBuffer, req); m_ReqList.pop(); } else { m_BufferList.push(pBuffer); } LeaveCriticalSection(&m_Lock); } static bool IsInstance(HANDLE hObject) { for (list::iterator iter = ChannelList.begin(); iter != ChannelList.end(); ++iter) { if (hObject == *iter) return true; } return false; } static uint32_t ChannelCount() { return ChannelList.size(); } DWORD GetId() { return m_Id; } static VBOX_RDP_CHANNEL * GetFromId(DWORD Id) { map::iterator iter = ChannelMap.find(Id); if (iter != ChannelMap.end()) return (VBOX_RDP_CHANNEL *) iter->second; return NULL; } #ifdef TRACE void RequestWritten(const DWORD *pSharedHdr) { // avoid filling up the map too much if (pSharedHdr[2] != 0x100 && pSharedHdr[2] != 0x101 && pSharedHdr[2] != 0x106 && pSharedHdr[2] != 0x107 && pSharedHdr[2] != 0x108) return; LARGE_INTEGER li; li.HighPart = (pSharedHdr[0] & 0x3FFFFFFF); li.LowPart = pSharedHdr[1]; m_ServerReqMap[li.QuadPart] = pSharedHdr[2]; } #endif }; list VBOX_RDP_CHANNEL::ChannelList; map VBOX_RDP_CHANNEL::ChannelMap; const IMAGE_IMPORT_DESCRIPTOR * GetImportDescriptor(HMODULE hMod) { const PBYTE pBaseAddr = (PBYTE) hMod; const IMAGE_DOS_HEADER *pDosHdr = (IMAGE_DOS_HEADER *) pBaseAddr; const size_t nOptHdrOffset = pDosHdr->e_lfanew + 4 + sizeof(IMAGE_FILE_HEADER); const IMAGE_OPTIONAL_HEADER *pOptHdr = (IMAGE_OPTIONAL_HEADER *) (pBaseAddr + nOptHdrOffset); const size_t nImportDescOffset = pOptHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; return (IMAGE_IMPORT_DESCRIPTOR *) (pBaseAddr + nImportDescOffset); } DWORD ReadLoadedImage(LPCVOID pBaseAddr) { DWORD nCCAddress = 0; PIMAGE_SECTION_HEADER pTextSectionHdr = 0; PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)pBaseAddr; PIMAGE_NT_HEADERS32 pNtFileHdr = (PIMAGE_NT_HEADERS32)((DWORD)pBaseAddr + pDosHdr->e_lfanew); DWORD nNumberOfSections = pNtFileHdr->FileHeader.NumberOfSections; PIMAGE_SECTION_HEADER pSectionsHdr = (PIMAGE_SECTION_HEADER)((DWORD)pBaseAddr + pDosHdr->e_lfanew + sizeof(IMAGE_NT_HEADERS32)); for (DWORD i = 0; i < nNumberOfSections; i++) { PIMAGE_SECTION_HEADER pSectionHdr = &pSectionsHdr[i]; if (!_stricmp((char*)pSectionHdr->Name, ".text")) { pTextSectionHdr = pSectionHdr; break; } } if(0 != pTextSectionHdr) { nCCAddress = (DWORD)pBaseAddr + pTextSectionHdr->VirtualAddress + pTextSectionHdr->SizeOfRawData; } return nCCAddress; } bool ReplaceStubAddr(BYTE* pBuffer,DWORD nBufferSize,DWORD nOld,DWORD nNew) { if ( 0 != nNew ) { for (DWORD i = 0; i < nBufferSize - sizeof(DWORD); i++) { if (*(PDWORD)(pBuffer + i) == nOld) { memcpy(pBuffer + i, &nNew, sizeof(DWORD)); return true; } } } return false; } void InstallHook(IMAGE_THUNK_DATA *pIATEntry, HookEntry pEntry,const PBYTE pBaseAddr) { SIZE_T cbWritten; static map CCAddrHistoryMap; PVOID pfnHook = pEntry.HookFuncAddr; PVOID *ppfnOrig = pEntry.OrigFuncAddrPtr; PVOID *ppfnMMR = pEntry.MMRFuncAddrPtr; LPCSTR FunctionName = pEntry.FunctionName; unsigned int nCCOffSet = sizeof(g_szCodeCave); if (NULL == *ppfnOrig) { WriteProcessMemory(GetCurrentProcess(), ppfnOrig, &pIATEntry->u1.Function, 4, &cbWritten); } if(g_bMMRCodeCavingIsEnabled) { DWORD nCodeCaveAddr = ReadLoadedImage(pBaseAddr); if (!nCodeCaveAddr) { /* If fails perform the hooking without code caving */ VBoxMMRHookLog("VBoxMMR: Retrieving code cave location had failed\n"); WriteProcessMemory(GetCurrentProcess(), &pIATEntry->u1.Function, &pfnHook, 4, (SIZE_T *) &cbWritten); return; } nCodeCaveAddr = nCodeCaveAddr - CODECAVE_SIZE; BYTE pByteCodeBuffer[CODECAVE_SIZE] = {0}; memcpy(pByteCodeBuffer, g_szCodeCave, CODECAVE_SIZE); map::iterator iter = CCAddrHistoryMap.find(nCodeCaveAddr); if (iter != CCAddrHistoryMap.end()) { nCodeCaveAddr += CCAddrHistoryMap[nCodeCaveAddr] ; iter->second += nCCOffSet; }else{ CCAddrHistoryMap[nCodeCaveAddr] = nCCOffSet; } bool bResult = ReplaceStubAddr( pByteCodeBuffer, CODECAVE_SIZE, 0xDEADBEEF, (DWORD)ppfnMMR); if (!bResult) { /* If fails perform the hooking without code caving */ VBoxMMRHookLog("VBoxMMR: Replacing code cave stub address failed\n"); WriteProcessMemory(GetCurrentProcess(), &pIATEntry->u1.Function, &pfnHook, 4, (SIZE_T *) &cbWritten); return ; } bResult = WriteProcessMemory( GetCurrentProcess(), (LPVOID)nCodeCaveAddr, pByteCodeBuffer, sizeof(g_szCodeCave), 0 ); if (!bResult) { /* If fails perform the hooking without code caving*/ VBoxMMRHookLog("VBoxMMR: Writing byte code to the text section failed\n"); WriteProcessMemory(GetCurrentProcess(), &pIATEntry->u1.Function, &pfnHook, 4, (SIZE_T *) &cbWritten); return; } bResult = WriteProcessMemory(GetCurrentProcess(), &pIATEntry->u1.Function, &nCodeCaveAddr, 4, &cbWritten); if (!bResult) { VBoxMMRHookLog("VBoXMMR: Patching the IAT failed\n"); WriteProcessMemory(GetCurrentProcess(), &pIATEntry->u1.Function, &pfnHook, 4, (SIZE_T *) &cbWritten); return; } }else { WriteProcessMemory(GetCurrentProcess(), &pIATEntry->u1.Function, &pfnHook, 4, (SIZE_T *) &cbWritten); } } void InstallHooks(const IMAGE_IMPORT_DESCRIPTOR *pDescriptor, const PBYTE pBaseAddr, HookEntry *pEntries) { DWORD nCodeCaveOffSet= 0; while(pDescriptor->FirstThunk) { LPCSTR pszDllName = (LPCSTR) (pBaseAddr + pDescriptor->Name); const IMAGE_THUNK_DATA* pThunk = (IMAGE_THUNK_DATA*) (pBaseAddr + pDescriptor->OriginalFirstThunk); IMAGE_THUNK_DATA *pIATEntry = (IMAGE_THUNK_DATA *)(pBaseAddr + pDescriptor->FirstThunk); LPCSTR pszModuleName = (LPCSTR) (pBaseAddr + pDescriptor->Name); while (pThunk->u1.Function) { for (int nIndex = 0; NULL != pEntries[nIndex].DllName; ++nIndex) { if (0 == _stricmp(pszDllName, pEntries[nIndex].DllName)) { if (0 == (pThunk->u1.AddressOfData & IMAGE_ORDINAL_FLAG)) { IMAGE_IMPORT_BY_NAME *pImport = (IMAGE_IMPORT_BY_NAME *) (pBaseAddr + pThunk->u1.AddressOfData); if (0 == strcmp((LPCSTR) pImport->Name, pEntries[nIndex].FunctionName)) { VBoxMMRHookLog("VBoxMMR: Install Hook for dll %s function %s \n", pEntries[nIndex].DllName, pEntries[nIndex].FunctionName); InstallHook(pIATEntry, pEntries[nIndex], pBaseAddr); } } } } ++pThunk; ++pIATEntry; } ++pDescriptor; } } int StartMonitor(RTTHREAD *hMonitor, PFNRTTHREAD pMonitorFn, void *pData, size_t cbStack, RTTHREADTYPE enmType, uint32_t flags, const char *pszName) { int rc; rc = RTThreadCreate(hMonitor, pMonitorFn, pData, cbStack, enmType, flags, pszName); if (RT_FAILURE(rc)) { VBoxMMRHookLog("VBoxMMR: Error starting monitor %s: %d\n", pszName, rc); } return rc; } int StopMonitor(RTTHREAD *hMonitor, const char* pszName) { int rc; if (*hMonitor != NIL_RTTHREAD) { rc = RTThreadUserSignal(*hMonitor); if (RT_SUCCESS(rc)) { // rc = RTThreadWait(*hMonitor, RT_INDEFINITE_WAIT, NULL); if (RT_FAILURE(rc)) { VBoxMMRHookLog("VBoxMMR: Error waiting for monitor %s to stop: %d\n", pszName, rc); } } else { VBoxMMRHookLog("VBoxMMR: Error sending stop signal to monitor %s: %d\n", pszName, rc); } *hMonitor = NIL_RTTHREAD; } return rc; } DECLCALLBACK(int) MonitorDetach(RTTHREAD hThreadSelf, void *pvUser) { VBoxGuestFilterMaskInfo maskInfo; DWORD cbReturned; bool bPrevious = FALSE; bool bCurrent = bPrevious; maskInfo.u32OrMask = VMMDEV_EVENT_VRDP; maskInfo.u32NotMask = 0; VBoxMMRHookLog("VBoxMMR: MonitorDetach starting\n"); if (DeviceIoControl (ghVBoxDriver, VBOXGUEST_IOCTL_CTL_FILTER_MASK, &maskInfo, sizeof (maskInfo), NULL, 0, &cbReturned, NULL)) { VBoxMMRHookLog("VBoxTray: VBoxVRDPThread: DeviceIOControl(CtlMask - or) succeeded\n"); } else { VBoxMMRHookLog("VBoxTray: VBoxVRDPThread: DeviceIOControl(CtlMask) failed\n"); return 0; } for(;;) { /* Call the host to get VRDP status and the experience level. */ VMMDevVRDPChangeRequest vrdpChangeRequest = {0}; vrdpChangeRequest.header.size = sizeof(VMMDevVRDPChangeRequest); vrdpChangeRequest.header.version = VMMDEV_REQUEST_HEADER_VERSION; vrdpChangeRequest.header.requestType = VMMDevReq_GetVRDPChangeRequest; vrdpChangeRequest.u8VRDPActive = 0; vrdpChangeRequest.u32VRDPExperienceLevel = 0; if (DeviceIoControl (ghVBoxDriver, VBOXGUEST_IOCTL_VMMREQUEST(sizeof(VMMDevVRDPChangeRequest)), &vrdpChangeRequest, sizeof(VMMDevVRDPChangeRequest), &vrdpChangeRequest, sizeof(VMMDevVRDPChangeRequest), &cbReturned, NULL)) { bCurrent = ( vrdpChangeRequest.u8VRDPActive == 1) ? TRUE : FALSE; if (bCurrent != bPrevious) { VBoxMMRHookLog( "VBoxMMR: VRDP active status changed: %d\n", vrdpChangeRequest.u8VRDPActive); if (bCurrent == FALSE && VBOX_RDP_CHANNEL::ChannelCount() > 0) { VBoxMMRHookLog("VBoxMMR: exiting ...\n"); ExitProcess(0); break; } } bPrevious = bCurrent; } else { VBoxMMRHookLog("VBoxMMR: VBoxVRDPThread: Error from DeviceIoControl VBOXGUEST_IOCTL_VMMREQUEST\n"); } if (RTThreadUserWait(hThreadSelf, 1000) == VINF_SUCCESS) { VBoxMMRHookLog("VBoxMMR: detach monitor received stop signal\n"); break; } } VBoxMMRHookLog("VBoxMMR: MonitorDetach stopping\n"); return VINF_SUCCESS; } /* * WTSQuerySessionInformationW */ BOOL (WINAPI * g_pfnWTSQuerySessionInformation)(HANDLE, DWORD, WTS_INFO_CLASS, LPWSTR *, DWORD *) = NULL; BOOL WINAPI MMRWTSQuerySessionInformation(HANDLE hServer, DWORD SessionId, WTS_INFO_CLASS WTSInfoClass, LPWSTR *ppBuffer, DWORD *pBytesReturned) { BOOL b = g_pfnWTSQuerySessionInformation(hServer, SessionId, WTSInfoClass, ppBuffer, pBytesReturned); if (WTSIsRemoteSession == WTSInfoClass) { PBYTE pb = (PBYTE) *ppBuffer; *pb = 1; return b; } else if (WTSClientProtocolType == WTSInfoClass) { PUSHORT pus = (PUSHORT) *ppBuffer; *pus = 2; return b; } return b; } BOOL WINAPI LocalWTSQuerySessionInformation(HANDLE hServer, DWORD SessionId, WTS_INFO_CLASS WTSInfoClass, LPWSTR *ppBuffer, DWORD *pBytesReturned) { return MMRWTSQuerySessionInformation( hServer, SessionId, WTSInfoClass, ppBuffer, pBytesReturned); } /* * WriteFile */ BOOL (WINAPI *g_pfnWriteFile)(HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED) = NULL; BOOL WINAPI MMRWriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped) { BOOL b = TRUE; if (NULL != g_hTraceSession) { /* Size FieldTypeFlags */ TraceEventData Event; // = { { sizeof(Event), (USHORT) 0, }, h }; ZeroMemory(&Event, sizeof(Event)); Event.Header.Size = sizeof(Event.Header) + sizeof(Event.WriteStart); Event.Header.Class.Type = EVENT_TRACE_TYPE_DC_START; Event.Header.Class.Version = 0; Event.Header.Class.Level = TRACE_LEVEL_INFORMATION; Event.Header.Flags = WNODE_FLAG_TRACED_GUID; Event.Header.Guid = ChannelWriteCategoryId; Event.WriteStart.Channel = hFile; DWORD cbToTrace = min(nNumberOfBytesToWrite, sizeof(Event.WriteStart.Data)); CopyMemory(Event.WriteStart.Data, lpBuffer, cbToTrace); TraceEvent(g_hTraceSession, &Event.Header); } if (VBOX_RDP_CHANNEL::IsInstance(hFile)) { VBOX_RDP_CHANNEL *pChannel = (VBOX_RDP_CHANNEL *) hFile; *lpNumberOfBytesWritten = 0; int rc = VbglR3HostChannelSend( pChannel->GetId(), g_HostChannelCtx.u32HGCMClientId, (void *) lpBuffer, nNumberOfBytesToWrite); if (RT_SUCCESS(rc)) { *lpNumberOfBytesWritten = nNumberOfBytesToWrite; } VBoxMMRHookLog( "VBoxMMR: TSMF send, channel: %d, sent: %d, result: %d\n", pChannel->GetId(), *lpNumberOfBytesWritten, rc); } else { b = g_pfnWriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped); } return b; } BOOL WINAPI LocalWriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped) { return MMRWriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped); } /* /* * ReadFileEx */ BOOL (WINAPI *g_pfnReadFileEx)(HANDLE, LPVOID, DWORD, LPOVERLAPPED, LPOVERLAPPED_COMPLETION_ROUTINE) = 0; BOOL WINAPI MMRReadFileEx(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) { BOOL br = TRUE; if (NULL != g_hTraceSession) { /* Size FieldTypeFlags */ TraceEventData Event; // = { { sizeof(Event), (USHORT) 0, }, h }; ZeroMemory(&Event, sizeof(Event)); Event.Header.Size = sizeof(Event.Header) + sizeof(Event.ReadStart); Event.Header.Class.Type = EVENT_TRACE_TYPE_DC_START; Event.Header.Class.Version = 0; Event.Header.Class.Level = TRACE_LEVEL_INFORMATION; Event.Header.Flags = WNODE_FLAG_TRACED_GUID; Event.Header.Guid = ChannelReadCategoryId; Event.ReadStart.Channel = hFile; TraceEvent(g_hTraceSession, &Event.Header); } if (VBOX_RDP_CHANNEL::IsInstance(hFile)) { VBOX_RDP_CHANNEL *pChannel = (VBOX_RDP_CHANNEL *) hFile; pChannel->PushRequest((PBYTE) lpBuffer, lpOverlapped, lpCompletionRoutine); } else { br = g_pfnReadFileEx(hFile, lpBuffer, nNumberOfBytesToRead, lpOverlapped, lpCompletionRoutine); } return br; } BOOL WINAPI LocalReadFileEx(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) { return MMRReadFileEx(hFile, lpBuffer, nNumberOfBytesToRead, lpOverlapped, lpCompletionRoutine); } /* * CloseHandle */ BOOL (WINAPI * g_pfnCloseHandle)(HANDLE) = NULL; BOOL WINAPI MMRCloseHandle(HANDLE hObject) { if (NULL != g_hTraceSession) { /* Size FieldTypeFlags */ TraceEventData Event; // = { { sizeof(Event), (USHORT) 0, }, h }; ZeroMemory(&Event, sizeof(Event)); Event.Header.Size = sizeof(Event.Header) + sizeof(Event.Close); Event.Header.Class.Type = EVENT_TRACE_TYPE_DC_START; Event.Header.Class.Version = 0; Event.Header.Class.Level = TRACE_LEVEL_INFORMATION; Event.Header.Flags = WNODE_FLAG_TRACED_GUID; Event.Header.Guid = ChannelCloseCategoryId; Event.Close.Channel = hObject; TraceEvent(g_hTraceSession, &Event.Header); } if (VBOX_RDP_CHANNEL::IsInstance(hObject)) { VBOX_RDP_CHANNEL *pChannel = (VBOX_RDP_CHANNEL *) hObject; VbglR3HostChannelDetach( pChannel->GetId(), g_HostChannelCtx.u32HGCMClientId); delete pChannel; return TRUE; } return g_pfnCloseHandle(hObject); } BOOL WINAPI LocalCloseHandle(HANDLE hObject) { return MMRCloseHandle(hObject); } /* * CancelIo */ BOOL (WINAPI * g_pfnCancelIo)(HANDLE) = 0; BOOL WINAPI MMRCancelIo(HANDLE hFile) { if (VBOX_RDP_CHANNEL::IsInstance(hFile)) { // FIXME return TRUE; } return g_pfnCancelIo(hFile); } BOOL WINAPI LocalCancelIo(HANDLE hFile) { return MMRCancelIo(hFile); } /* * WinStationIsSessionRemoteable */ BOOL (WINAPI *g_pfnWinStationIsSessionRemoteable)(HANDLE, DWORD, PVOID) = NULL; BOOL WINAPI MMRWinStationIsSessionRemoteable(HANDLE hServer, DWORD hSession, PVOID c) { BOOL b = g_pfnWinStationIsSessionRemoteable(hServer, hSession, c); PBYTE pb = (PBYTE) c; VBoxMMRHookLog("VBoxMMR: LocalWinStationIsSessionRemoteable() = %d -> 1\n", (int) *pb); *pb = 1; return b; } BOOL WINAPI LocalWinStationIsSessionRemoteable(HANDLE hServer, DWORD hSession, PVOID c) { return MMRWinStationIsSessionRemoteable(hServer, hSession, c); } /* * WinStationVirtualOpenEx */ HANDLE (WINAPI *g_pfnWinStationVirtualOpenEx)(HANDLE, DWORD, LPSTR, DWORD) = NULL; HANDLE WINAPI MMRWinStationVirtualOpenEx(HANDLE hServer, DWORD hSession, LPSTR pVirtualName, DWORD flags) { // assert(WTS_CURRENT_SERVER == hServer) // assert(WTS_CURRENT_SESSION == hSession) HANDLE h = g_pfnWinStationVirtualOpenEx(hServer, hSession, pVirtualName, flags); if (NULL == h && 0 != g_HostChannelCtx.u32HGCMClientId) { uint32_t u32ChannelHandle = 0; uint32_t u32Flags = 0x00; /* Not used currently. */ EnterCriticalSection(&CreateLock); g_nCreateResult = VBOX_TSMF_HCH_CREATE_DECLINED; int rc = VbglR3HostChannelAttach( &u32ChannelHandle, g_HostChannelCtx.u32HGCMClientId, "/vrde/tsmf", u32Flags); if (RT_SUCCESS(rc)) { WaitForSingleObject(hCreateEvent, 5000); if (g_nCreateResult == VBOX_TSMF_HCH_CREATE_ACCEPTED) { h = new VBOX_RDP_CHANNEL(u32ChannelHandle); if (hDetachMonitor == NIL_RTTHREAD) { StartMonitor(&hDetachMonitor, MonitorDetach, &nUserData, 0, RTTHREADTYPE_INFREQUENT_POLLER, RTTHREADFLAGS_WAITABLE, "mmrpoll"); } } else { VBoxMMRHookLog("VBoxMMR: Unable to open channel: %d\n", g_nCreateResult); } } else { VBoxMMRHookLog("VBoxMMR: Error attaching channel: %d\n", rc); } LeaveCriticalSection(&CreateLock); } if (NULL != g_hTraceSession) { /* Size FieldTypeFlags */ TraceEventData Event; // = { { sizeof(Event), (USHORT) 0, }, h }; ZeroMemory(&Event, sizeof(Event)); Event.Header.Size = sizeof(Event.Header) + sizeof(Event.Open); Event.Header.Class.Type = EVENT_TRACE_TYPE_DC_END; Event.Header.Class.Version = 0; Event.Header.Class.Level = TRACE_LEVEL_INFORMATION; Event.Header.Flags = WNODE_FLAG_TRACED_GUID; Event.Header.Guid = ChannelOpenCategoryId; Event.Open.Channel = h; TraceEvent(g_hTraceSession, &Event.Header); } return h; } HANDLE WINAPI LocalWinStationVirtualOpenEx(HANDLE hServer, DWORD hSession, LPSTR pVirtualName, DWORD flags) { return MMRWinStationVirtualOpenEx(hServer, hSession, pVirtualName, flags); } /* * GetSystemMetrics */ int (WINAPI *g_pfnGetSystemMetrics)(int) = NULL; int WINAPI MMRGetSystemMetrics(int nIndex) { const char *format = (nIndex < 100) ? "VBoxMMR: GetSystemMetrics(%d)\n" : "VBoxMMR: GetSystemMetrics(0x%x)\n"; VBoxMMRHookLog(format, nIndex); if (0x1000 == nIndex) return 1; return g_pfnGetSystemMetrics(nIndex); } int WINAPI LocalGetSystemMetrics(int nIndex) { return MMRGetSystemMetrics(nIndex); } HookEntry g_TSMFHooks[] = { { "winsta.dll", "WinStationIsSessionRemoteable", LocalWinStationIsSessionRemoteable, (PVOID *) &g_pfnWinStationIsSessionRemoteable, (PVOID *) &MMRWinStationIsSessionRemoteable }, { "winsta.dll", "WinStationVirtualOpenEx", LocalWinStationVirtualOpenEx, (PVOID *) &g_pfnWinStationVirtualOpenEx, (PVOID *) &MMRWinStationVirtualOpenEx }, { "user32.dll", "GetSystemMetrics", LocalGetSystemMetrics, (PVOID *) &g_pfnGetSystemMetrics, (PVOID *) &MMRGetSystemMetrics}, { "kernel32.dll", "ReadFileEx", LocalReadFileEx, (PVOID *) &g_pfnReadFileEx, (PVOID *) &MMRReadFileEx }, { "kernel32.dll", "WriteFile", LocalWriteFile, (PVOID *) &g_pfnWriteFile,(PVOID *) &MMRWriteFile }, { "kernel32.dll", "CloseHandle", LocalCloseHandle, (PVOID *) &g_pfnCloseHandle,(PVOID *) &MMRCloseHandle }, { "kernel32.dll", "CancelIo", LocalCancelIo, (PVOID *) &g_pfnCancelIo, (PVOID *) &MMRCancelIo }, { "wtsapi32.dll", "WTSQuerySessionInformationW", LocalWTSQuerySessionInformation, (PVOID *) &g_pfnWTSQuerySessionInformation, (PVOID *) &MMRWTSQuerySessionInformation }, { NULL, NULL, NULL, NULL, NULL } }; /* * MFCreateRemoteDesktopPlugin */ HRESULT (STDAPICALLTYPE *g_pfnMFCreateRemoteDesktopPlugin)(IMFRemoteDesktopPlugin **ppPlugin) = NULL; STDAPI MMRMFCreateRemoteDesktopPlugin(IMFRemoteDesktopPlugin **ppPlugin) { HRESULT hr = g_pfnMFCreateRemoteDesktopPlugin(ppPlugin); VBoxMMRHookLog("VBoxMMR: LocalMFCreateRemoteDesktopPlugin: *ppPlugin = %p, result: %x\n", *ppPlugin, hr); static bool IsTSMFHooked = false; if (!IsTSMFHooked) { HMODULE hModule = GetModuleHandleA("tsmf"); if (hModule) { VBoxMMRHookLog("VBoxMMR: Installing hooks for tsmf.dll\n"); const IMAGE_IMPORT_DESCRIPTOR *pDescriptor = GetImportDescriptor(hModule); InstallHooks(pDescriptor, (PBYTE) hModule, g_TSMFHooks); IsTSMFHooked = true; } } return hr; } STDAPI LocalMFCreateRemoteDesktopPlugin(IMFRemoteDesktopPlugin **ppPlugin) { return MMRMFCreateRemoteDesktopPlugin(ppPlugin); } /* * GetProcAddress */ FARPROC (WINAPI *g_pfnGetProcAddress)(HMODULE, LPCSTR) = NULL; FARPROC WINAPI LocalGetProcAddress(HMODULE hModule, LPCSTR lpProcName); FARPROC WINAPI MMRGetProcAddress(HMODULE hModule, LPCSTR lpProcName); HookEntry g_MFHooks[] = { { "kernel32.dll", "GetProcAddress", LocalGetProcAddress, (PVOID *) &g_pfnGetProcAddress,(PVOID *) &MMRGetProcAddress }, { NULL, NULL, NULL, NULL, NULL } }; HookEntry g_WinMMHooks[] = { { "user32.dll", "GetSystemMetrics", LocalGetSystemMetrics, (PVOID *) &g_pfnGetSystemMetrics,(PVOID *) &MMRGetSystemMetrics}, { "kernel32.dll", "GetProcAddress", LocalGetProcAddress, (PVOID *) &g_pfnGetProcAddress,(PVOID *) &MMRGetProcAddress }, { NULL, NULL, NULL, NULL, NULL } }; HookEntry g_DShowHooks[] = { { "user32.dll", "GetSystemMetrics", LocalGetSystemMetrics, (PVOID *) &g_pfnGetSystemMetrics,(PVOID *) &MMRGetSystemMetrics }, { "kernel32.dll", "GetProcAddress", LocalGetProcAddress, (PVOID *) &g_pfnGetProcAddress,(PVOID *) &MMRGetProcAddress }, { NULL, NULL, NULL, NULL, NULL } }; FARPROC WINAPI MMRGetProcAddress(HMODULE hModule, LPCSTR lpProcName) { FARPROC ret = g_pfnGetProcAddress(hModule, lpProcName); static bool IsMFHooked = false; if (!IsMFHooked) { CHAR szBuf[512]; GetModuleFileNameA(hModule, szBuf, sizeof(szBuf)); PCHAR pc = strrchr(szBuf, '\\'); if (0 == _stricmp(pc + 1, "mf.dll")) { VBoxMMRHookLog("VBoxMMR: Installing hooks for mf.dll\n"); const IMAGE_IMPORT_DESCRIPTOR *pDescriptor = GetImportDescriptor(hModule); InstallHooks(pDescriptor, (PBYTE) hModule, g_MFHooks); IsMFHooked = true; } } static bool IsWinMMHooked = false; if (!IsWinMMHooked) { CHAR szBuf[512]; GetModuleFileNameA(hModule, szBuf, sizeof(szBuf)); PCHAR pc = strrchr(szBuf, '\\'); if (0 == _stricmp(pc + 1, "winmm.dll")) { VBoxMMRHookLog("VBoxMMR: Installing hooks for winmm.dll\n"); const IMAGE_IMPORT_DESCRIPTOR *pDescriptor = GetImportDescriptor(hModule); InstallHooks(pDescriptor, (PBYTE) hModule, g_WinMMHooks); IsWinMMHooked = true; } } // if an ordinal, all but the lower word must be 0 // FIXME: should be pointer size if (0 == ((DWORD) lpProcName & ~0xFFFF)) { CHAR szDllName[512]; if (FALSE == GetModuleFileNameA(hModule, szDllName, sizeof(szDllName))) szDllName[0] = '\0'; VBoxMMRHookLog("VBoxMMR: GetProcAddress: %u (%s)\n", (DWORD) lpProcName, szDllName); } else { if (0 == strncmp(lpProcName, "WTS", 3) || 0 == strncmp(lpProcName, "MF", 2) || 0 == strncmp(lpProcName, "GetTS", 5)) VBoxMMRHookLog("VBoxMMR: GetProcAddress: %s\n", lpProcName); if (0 == strcmp(lpProcName, "MFCreateRemoteDesktopPlugin")) { g_pfnMFCreateRemoteDesktopPlugin = (HRESULT (STDAPICALLTYPE *)(IMFRemoteDesktopPlugin **ppPlugin)) ret; ret = (FARPROC) LocalMFCreateRemoteDesktopPlugin; CHAR szDllName[512]; if (FALSE == GetModuleFileNameA(hModule, szDllName, sizeof(szDllName))) { szDllName[0] = '\0'; } } else if (0 == strcmp(lpProcName, "WTSQuerySessionInformationW")) { g_pfnWTSQuerySessionInformation = (BOOL (__stdcall *)(HANDLE,DWORD,WTS_INFO_CLASS,LPWSTR *,DWORD *)) ret; ret = (FARPROC) LocalWTSQuerySessionInformation; CHAR szDllName[512]; if (FALSE == GetModuleFileNameA(hModule, szDllName, sizeof(szDllName))) { szDllName[0] = '\0'; } } } return ret; } FARPROC WINAPI LocalGetProcAddress(HMODULE hModule, LPCSTR lpProcName) { return MMRGetProcAddress(hModule, lpProcName); } HookEntry g_WMPHooks[] = { { "user32.dll", "GetSystemMetrics", LocalGetSystemMetrics, (PVOID *) &g_pfnGetSystemMetrics, (PVOID *)&MMRGetSystemMetrics }, { "kernel32.dll", "GetProcAddress", LocalGetProcAddress, (PVOID *) &g_pfnGetProcAddress, (PVOID *)&MMRGetProcAddress }, { "mf.dll", "MFCreateRemoteDesktopPlugin", LocalMFCreateRemoteDesktopPlugin, (PVOID *) &g_pfnMFCreateRemoteDesktopPlugin, (PVOID *) &MMRMFCreateRemoteDesktopPlugin }, { "wtsapi32.dll", "WTSQuerySessionInformationW", LocalGetProcAddress, (PVOID *) &g_pfnGetProcAddress,(PVOID *) &MMRGetProcAddress }, { NULL, NULL, NULL, NULL, NULL } }; /* * Note that McAffee hooks into GetProcAddress as well (HIPIS0e011b5.dll), so there is no point * in patching "GetProcAddress" of ole32.dll */ static TRACEHANDLE g_hTraceRegistration = NULL; static ULONG WINAPI ControlCallback(WMIDPREQUESTCODE RequestCode, PVOID Context, ULONG *Reserved, PVOID pBuffer) { UNREFERENCED_PARAMETER(Context); UNREFERENCED_PARAMETER(Reserved); ULONG status = ERROR_SUCCESS; TRACEHANDLE hTraceSession = GetTraceLoggerHandle(pBuffer); switch(RequestCode) { case WMI_ENABLE_EVENTS: // Enable the provider if (NULL == g_hTraceSession) g_hTraceSession = hTraceSession; break; case WMI_DISABLE_EVENTS: // Disable the provider // igonore disable requests from other sessions if (hTraceSession == g_hTraceSession) g_hTraceSession = NULL; break; default: status = ERROR_INVALID_PARAMETER; break; } return status; } static int VBoxMMROpenBaseDriver(void) { /* Open VBox guest driver. */ DWORD dwErr = ERROR_SUCCESS; ghVBoxDriver = CreateFile(TEXT(VBOXGUEST_DEVICE_NAME), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); if (INVALID_HANDLE_VALUE == ghVBoxDriver ) { dwErr = GetLastError(); VBoxMMRHookLog("VBoxMMR: Could not open VirtualBox Guest Additions driver! Please install / start it first! Error = %08X\n", dwErr); } return RTErrConvertFromWin32(dwErr); } static void VBoxMMRCloseBaseDriver(void) { if (ghVBoxDriver) { CloseHandle(ghVBoxDriver); ghVBoxDriver = NULL; } } void ReadTSMF(uint32_t u32ChannelHandle, uint32_t u32HGCMClientId, uint32_t u32SizeAvailable) { uint32_t u32SizeReceived = 0; uint32_t u32SizeRemaining = 0; PBYTE pBuffer = (PBYTE) malloc(u32SizeAvailable + sizeof(u32SizeAvailable)); CopyMemory(pBuffer, &u32SizeAvailable, sizeof(u32SizeAvailable)); int rc = VbglR3HostChannelRecv(u32ChannelHandle, u32HGCMClientId, pBuffer + sizeof(u32SizeAvailable), u32SizeAvailable, &u32SizeReceived, &u32SizeRemaining); VBoxMMRHookLog( "VBoxMMR: TSMF recv, channel: %d, available: %d, received %d, remaining %d, result: %d\n", u32ChannelHandle, u32SizeAvailable, u32SizeReceived, u32SizeRemaining, rc); VBOX_RDP_CHANNEL *pChannel = VBOX_RDP_CHANNEL::GetFromId(u32ChannelHandle); if (RT_SUCCESS(rc) && pChannel && u32SizeReceived != 0) { DWORD *pPtr = (DWORD *) (pBuffer + sizeof(u32SizeAvailable)); if (0x01 != pPtr[2] && 0x02 != pPtr[2] && 0x80000000 != pPtr[0] && 0x40000001 != pPtr[0]) { VBoxMMRHookLog( "VBoxMMR: Unknown TSMF Data: %X %X %X\n", pPtr[0], pPtr[1], pPtr[2]); } pChannel->PushBuffer(pBuffer); } else { delete [] pBuffer; } } DECLCALLBACK(int) MonitorTSMFChannel(RTTHREAD hThreadSelf, void *pvUser) { HostChannelCtx *pCtx = (HostChannelCtx *) pvUser; VBoxMMRHookLog("VBoxMMR: MonitorTSMFChannel starting\n"); while (!pCtx->fShutdown) { uint32_t u32ChannelHandle = 0; uint32_t u32EventId = 0; uint32_t u32SizeReturned = 0; void *pvParm = &pCtx->au8EventData[0]; uint32_t cbParm = sizeof(pCtx->au8EventData); int rc = VbglR3HostChannelEventWait( &u32ChannelHandle, pCtx->u32HGCMClientId, &u32EventId, pvParm, cbParm, &u32SizeReturned); if (RT_SUCCESS(rc)) { switch(u32EventId) { case VBOX_TSMF_HCH_CREATE_ACCEPTED: { VBoxMMRHookLog("VBoxMMR: VBOX_TSMF_HCH_CREATE_ACCEPTED: channel: %d\n", u32ChannelHandle); g_nCreateResult = u32EventId; SetEvent(hCreateEvent); } break; case VBOX_TSMF_HCH_CREATE_DECLINED: { VBoxMMRHookLog("VBoxMMR: VBOX_TSMF_HCH_CREATE_DECLINED: channel: %d\n", u32ChannelHandle); g_nCreateResult = u32EventId; SetEvent(hCreateEvent); } break; case VBOX_TSMF_HCH_DISCONNECTED: { VBoxMMRHookLog("VBoxMMR: VBOX_TSMF_HCH_DISCONNECTED: channel: %d\n", u32ChannelHandle); } break; case VBOX_HOST_CHANNEL_EVENT_CANCELLED: { VBoxMMRHookLog("VBoxMMR: VBOX_HOST_CHANNEL_EVENT_CANCELLED\n"); } break; case VBOX_HOST_CHANNEL_EVENT_UNREGISTERED: { VBoxMMRHookLog("VBoxMMR: VBOX_HOST_CHANNEL_EVENT_UNREGISTERED\n"); } break; case VBOX_HOST_CHANNEL_EVENT_RECV: { VBOXHOSTCHANNELEVENTRECV *p = (VBOXHOSTCHANNELEVENTRECV *)pvParm; if (p->u32SizeAvailable > 0) { ReadTSMF(u32ChannelHandle, pCtx->u32HGCMClientId, p->u32SizeAvailable); } else { VBoxMMRHookLog("VBoxMMR: TSMF recv, channel: %d, available: 0\n", u32ChannelHandle); } } break; default: { VBoxMMRHookLog("VBoxMMR: unknown event id %d\n", u32EventId); } break; } } } VBoxMMRHookLog("VBoxMMR: MonitorTSMFChannel stopping\n"); return VINF_SUCCESS; } void InstallHooksForSystemModule(const char *pszName, HookEntry hooks[]) { /* Construct the full path to the given module and load it. */ char szPath[MAX_PATH]; UINT cchPath = GetSystemDirectoryA(szPath, MAX_PATH); size_t cbName = strlen(pszName) + 1; if (cchPath + 1 + cbName <= sizeof(szPath)) { szPath[cchPath] = '\\'; memcpy(&szPath[cchPath + 1], pszName, cbName); HMODULE hMod = LoadLibraryA(szPath); if (hMod != NULL) { VBoxMMRHookLog("VBoxMMR: Hooking %s -> %x \n", pszName, hMod); const IMAGE_IMPORT_DESCRIPTOR *pDescriptor = GetImportDescriptor(hMod); InstallHooks(pDescriptor, (PBYTE) hMod, hooks); } else VBoxMMRHookLog("VBoxMMR: Error hooking %s -> not found (last error %u)\n", pszName, GetLastError()); } else VBoxMMRHookLog("VBoxMMR: Error hooking %s -> not found\n", pszName); } TSMFHOOK_API LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam) { static bool bInit = false; if (isWMP && !bInit) { bInit = true; g_bMMRCodeCavingIsEnabled = MMRCodeCavingIsEnabled(); VBoxMMRHookLog("VBoxMMR: WMP APIs Hooking started ...\n"); HMODULE hMod = GetModuleHandleA("wmp"); if (hMod != NULL) { VBoxMMRHookLog("VBoxMMR: Hooking wmp -> %x \n",hMod); const IMAGE_IMPORT_DESCRIPTOR *pDescriptor = GetImportDescriptor(hMod); InstallHooks(pDescriptor, (PBYTE) hMod, g_WMPHooks); } else { VBoxMMRHookLog("VBoxMMR: Error hooking wmp -> not found\n"); } InstallHooksForSystemModule("winmm.dll", g_WinMMHooks); InstallHooksForSystemModule("tsmf.dll", g_TSMFHooks); InstallHooksForSystemModule("DSHOWRDPFILTER.dll", g_TSMFHooks); InstallHooksForSystemModule("MSMPEG2VDEC.dll", g_DShowHooks); InstallHooksForSystemModule("MFDS.dll", g_DShowHooks); InstallHooksForSystemModule("mf.dll", g_MFHooks); ULONG ret = RegisterTraceGuids( ControlCallback, NULL, &ProviderId, 0, NULL, NULL, NULL, &g_hTraceRegistration); if (ERROR_SUCCESS != ret) { VBoxMMRHookLog("VBoxMMR: RegisterTraceGuids failed with error code: %u\n", GetLastError()); } bool bInRDPSession = (1 == GetSystemMetrics(0x1000)); if (!bInRDPSession) { uint32_t u32HGCMClientId = 0; int rc = VbglR3HostChannelInit(&u32HGCMClientId); if (RT_SUCCESS(rc)) { uint32_t u32Size = 0; rc = VbglR3HostChannelQuery(g_pszVRDETSMF, u32HGCMClientId, VBOX_HOST_CHANNEL_CTRL_EXISTS, NULL, 0, NULL, 0, &u32Size); if (RT_SUCCESS(rc)) { hCreateEvent = CreateEvent(NULL, FALSE, FALSE, NULL); InitializeCriticalSection(&CreateLock); g_HostChannelCtx.thread = NIL_RTTHREAD; g_HostChannelCtx.u32HGCMClientId = u32HGCMClientId; StartMonitor( &g_HostChannelCtx.thread, MonitorTSMFChannel, &g_HostChannelCtx, 64*_1K, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "tsmfio"); VBoxMMROpenBaseDriver(); } else { VBoxMMRHookLog( "VBoxMMR: TSMF HGCM unavailable: hgcmid: %d, rc: %d\n", u32HGCMClientId, rc); VbglR3HostChannelTerm(u32HGCMClientId); } } else { VBoxMMRHookLog("VBoxMMR: Error connecting to HGCM: %d\n", rc); } } } return CallNextHookEx(NULL /*ignored */, nCode, wParam, lParam); } void Shutdown() { if (isWMP) { VBoxMMRHookLog("VBoxMMR: Shutdown\n"); StopMonitor(&hDetachMonitor, "mmrpoll"); VBoxMMRCloseBaseDriver(); if (g_HostChannelCtx.u32HGCMClientId != 0) { g_HostChannelCtx.fShutdown = true; VbglR3HostChannelEventCancel(0, g_HostChannelCtx.u32HGCMClientId); StopMonitor(&g_HostChannelCtx.thread, "tsmfio"); VbglR3HostChannelTerm(g_HostChannelCtx.u32HGCMClientId); } if (hCreateEvent) { CloseHandle(hCreateEvent); DeleteCriticalSection(&CreateLock); } if (g_hTraceRegistration) UnregisterTraceGuids(g_hTraceRegistration); } }