@@ -19,21 +19,25 @@ This license can be found at:
1919#include < rpc.h>
2020#include < sddl.h>
2121#include < common/log.h>
22+ #include < common/apiHook.h>
2223#include < local/nvdaControllerInternal.h>
2324#include " nvdaHelperLocal.h"
2425#include " dllImportTableHooks.h"
2526#include " rpcsrv.h"
2627
27- DllImportTableHooks* oleaccHooks = NULL ;
28- DllImportTableHooks* uiaCoreHooks = NULL ;
28+ decltype (&SendMessageW) real_SendMessageW = nullptr;
29+ decltype (&SendMessageTimeoutW) real_SendMessageTimeoutW = nullptr;
30+ decltype (&OpenClipboard) real_OpenClipboard = nullptr;
31+
32+ bool isSecureModeNVDAProcess=false ;
2933
3034typedef struct _RPC_SECURITY_QOS_V5_W {
3135 unsigned long Version;
3236 unsigned long Capabilities;
3337 unsigned long IdentityTracking;
3438 unsigned long ImpersonationType;
3539 unsigned long AdditionalSecurityInfoType;
36- union
40+ union
3741 {
3842 RPC_HTTP_TRANSPORT_CREDENTIALS_W *HttpCredentials;
3943 } u;
@@ -53,7 +57,7 @@ handle_t createRemoteBindingHandle(wchar_t* uuidString) {
5357 if ((rpcStatus=RpcBindingFromStringBinding (stringBinding,&bindingHandle))!=RPC_S_OK ) {
5458 LOG_ERROR (L" RpcBindingFromStringBinding failed with status " <<rpcStatus);
5559 return NULL ;
56- }
60+ }
5761 // On Windows 8 we must allow AppContainer servers to communicate back to us
5862 // Detect Windows 8 by looking for RpcServerRegisterIf3
5963 HANDLE rpcrt4Handle=GetModuleHandle (L" rpcrt4.dll" );
@@ -106,7 +110,7 @@ DWORD WINAPI bgSendMessageThreadProc(LPVOID param) {
106110 bgSendMessageData.error = ERROR_CANCELLED ;
107111 break ;
108112 }
109- if (SendMessageTimeoutW (bgSendMessageData.hwnd , bgSendMessageData.Msg , bgSendMessageData.wParam , bgSendMessageData.lParam , bgSendMessageData.fuFlags , std::min (remainingTimeout, CANCELSENDMESSAGE_CHECK_INTERVAL ), &bgSendMessageData.dwResult ) != 0 ) {
113+ if (real_SendMessageTimeoutW (bgSendMessageData.hwnd , bgSendMessageData.Msg , bgSendMessageData.wParam , bgSendMessageData.lParam , bgSendMessageData.fuFlags , std::min (remainingTimeout, CANCELSENDMESSAGE_CHECK_INTERVAL ), &bgSendMessageData.dwResult ) != 0 ) {
110114 // Success.
111115 bgSendMessageData.error = 0 ;
112116 break ;
@@ -147,7 +151,7 @@ LRESULT cancellableSendMessageTimeout(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM
147151 DWORD currentThreadId = GetCurrentThreadId ();
148152 if (currentThreadId == mainThreadId && GetWindowThreadProcessId (hwnd, NULL ) == mainThreadId) {
149153 // We're sending a message to our own thread, so just forward the call.
150- return SendMessageTimeoutW (hwnd, Msg, wParam, lParam, fuFlags, uTimeout, lpdwResult);
154+ return real_SendMessageTimeoutW (hwnd, Msg, wParam, lParam, fuFlags, uTimeout, lpdwResult);
151155 }
152156
153157 if (currentThreadId != mainThreadId) {
@@ -167,7 +171,7 @@ LRESULT cancellableSendMessageTimeout(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM
167171 SetLastError (ERROR_CANCELLED );
168172 return 0 ;
169173 }
170- if ((ret = SendMessageTimeoutW (hwnd, Msg, wParam, lParam, fuFlags, std::min (remainingTimeout, CANCELSENDMESSAGE_CHECK_INTERVAL ), lpdwResult)) != 0 || GetLastError () != ERROR_TIMEOUT ) {
174+ if ((ret = real_SendMessageTimeoutW (hwnd, Msg, wParam, lParam, fuFlags, std::min (remainingTimeout, CANCELSENDMESSAGE_CHECK_INTERVAL ), lpdwResult)) != 0 || GetLastError () != ERROR_TIMEOUT ) {
171175 // Success or error other than timeout.
172176 return ret;
173177 }
@@ -232,44 +236,40 @@ LRESULT WINAPI fake_SendMessageTimeoutW(HWND hwnd, UINT Msg, WPARAM wParam, LPAR
232236 return cancellableSendMessageTimeout (hwnd, Msg, wParam, lParam, fuFlags, uTimeout, lpdwResult);
233237}
234238
235- void nvdaHelperLocal_initialize () {
239+ // A replacement OpenClipboard function to disable the use of the clipboard in a secure mode NVDA process
240+ // Simply returns false without calling the original OpenClipboard
241+ BOOL WINAPI fake_OpenClipboard (HWND hwndOwner) {
242+ return false ;
243+ }
244+
245+ void nvdaHelperLocal_initialize (int secureMode) {
246+ if (secureMode) {
247+ isSecureModeNVDAProcess = true ;
248+ }
236249 startServer ();
237250 mainThreadId = GetCurrentThreadId ();
238251 cancelCallEvent = CreateEvent (NULL , TRUE , FALSE , NULL );
239252 bgSendMessageData.execEvent = CreateEvent (NULL , FALSE , FALSE , NULL );
240253 bgSendMessageData.completeEvent = CreateEvent (NULL , FALSE , FALSE , NULL );
241254 bgSendMessageData.isActive = false ;
242255 CloseHandle (CreateThread (NULL , 0 , bgSendMessageThreadProc, NULL , 0 , NULL ));
243- HMODULE oleacc = LoadLibraryA (" oleacc.dll" );
244- if (!oleacc)
245- return ;
246- oleaccHooks = new DllImportTableHooks (oleacc);
247- oleaccHooks->requestFunctionHook (" USER32.dll" , " SendMessageW" , fake_SendMessageW);
248- oleaccHooks->requestFunctionHook (" USER32.dll" , " SendMessageTimeoutW" , fake_SendMessageTimeoutW);
249- oleaccHooks->hookFunctions ();
250- HMODULE uiaCore = LoadLibraryA (" UIAutomationCore.dll" );
251- // It is not an error if UIA isn't present.
252- if (uiaCore) {
253- uiaCoreHooks = new DllImportTableHooks (uiaCore);
254- uiaCoreHooks->requestFunctionHook (" USER32.dll" , " SendMessageW" , fake_SendMessageW);
255- uiaCoreHooks->requestFunctionHook (" USER32.dll" , " SendMessageTimeoutW" , fake_SendMessageTimeoutW);
256- uiaCoreHooks->hookFunctions ();
256+ // Begin API hooking transaction
257+ apiHook_beginTransaction ();
258+ // Hook SendMessageW and SendMessageTimeoutW to ensure that
259+ // we can cancel such calls when they would otherwise freeze NVDA's process.
260+ apiHook_hookFunction_safe (SendMessageW, fake_SendMessageW, &real_SendMessageW);
261+ apiHook_hookFunction_safe (SendMessageTimeoutW, fake_SendMessageTimeoutW, &real_SendMessageTimeoutW);
262+ // For secure mode NVDA process, hook OpenClipboard to disable usage of the clipboard
263+ if (isSecureModeNVDAProcess) {
264+ apiHook_hookFunction_safe (OpenClipboard, fake_OpenClipboard, &real_OpenClipboard);
257265 }
266+ // Enable all registered API hooks by committing the transaction
267+ apiHook_commitTransaction ();
258268}
259269
260270void nvdaHelperLocal_terminate () {
261- if (uiaCoreHooks) {
262- uiaCoreHooks->unhookFunctions ();
263- FreeLibrary (uiaCoreHooks->targetModule );
264- delete uiaCoreHooks;
265- uiaCoreHooks = NULL ;
266- }
267- if (oleaccHooks) {
268- oleaccHooks->unhookFunctions ();
269- FreeLibrary (oleaccHooks->targetModule );
270- delete oleaccHooks;
271- oleaccHooks = NULL ;
272- }
271+ // Unregister and terminate API hooks
272+ apiHook_terminate ();
273273 // Terminate the background SendMessage thread.
274274 bgSendMessageData.hwnd = NULL ;
275275 SetEvent (bgSendMessageData.execEvent );
0 commit comments