- Implement NtUserRegisterUserApiHook and NtUserUnregisterUserApiHook

svn path=/branches/GSoC_2011/ThemesSupport/; revision=52650
This commit is contained in:
Giannis Adamopoulos 2011-07-12 08:43:43 +00:00
parent 723267ac2a
commit 7950b8eb63
7 changed files with 296 additions and 22 deletions

View file

@ -5,6 +5,13 @@
#define HOOKID_TO_FLAG(HookId) (1 << ((HookId) + 1))
#define ISITHOOKED(HookId) (((PTHREADINFO)PsGetCurrentThreadWin32Thread())->fsHooks & HOOKID_TO_FLAG(HookId))
/* NOTE: the following definition is not a real hook but
a pseudo-id that will be used only for
injecting user api hook module to all processes.
It is used internally in win32k */
#define WH_APIHOOK WH_MAX + 1
typedef struct tagEVENTHOOK
{
THROBJHEAD head;
@ -43,4 +50,10 @@ PHOOK FASTCALL IntGetNextHook(PHOOK Hook);
LRESULT FASTCALL UserCallNextHookEx( PHOOK pHook, int Code, WPARAM wParam, LPARAM lParam, BOOL Ansi);
BOOL FASTCALL IntUnhookWindowsHook(int,HOOKPROC);
BOOL FASTCALL UserLoadApiHook();
BOOL IntLoadHookModule(int iHookID, HHOOK hHook, BOOL Unload);
BOOL FASTCALL UserUnregisterUserApiHook(BOOL Block);
extern PPROCESSINFO ppiUahServer;
/* EOF */

View file

@ -7,6 +7,7 @@
#define MSQ_NORMAL 0
#define MSQ_ISHOOK 1
#define MSQ_ISEVENT 2
#define MSQ_INJECTMODULE 3
#define QSIDCOUNTS 6

View file

@ -30,6 +30,7 @@
#define W32PF_NOWINDOWGHOSTING (0x01000000)
#define W32PF_MANUALGUICHECK (0x02000000)
#define W32PF_CREATEDWINORDC (0x04000000)
#define W32PF_APIHOOKLOADED (0x08000000)
extern BOOL ClientPfnInit;
extern HINSTANCE hModClient;

View file

@ -24,8 +24,220 @@ typedef struct _HOOKPACK
PVOID pHookStructs;
} HOOKPACK, *PHOOKPACK;
UNICODE_STRING strUahModule;
UNICODE_STRING strUahInitFunc;
PPROCESSINFO ppiUahServer;
/* PRIVATE FUNCTIONS *********************************************************/
/* Calls ClientLoadLibrary in user32 in order to load or unload a module */
BOOL
IntLoadHookModule(int iHookID, HHOOK hHook, BOOL Unload)
{
PPROCESSINFO ppi;
HMODULE hmod;
ppi = PsGetCurrentProcessWin32Process();
DPRINT("IntLoadHookModule. Client PID: %d\n", PsGetProcessId(ppi->peProcess));
/* Check if this is the api hook */
if(iHookID == WH_APIHOOK)
{
if(!Unload && !(ppi->W32PF_flags & W32PF_APIHOOKLOADED))
{
/* Call ClientLoadLibrary in user32 */
hmod = co_IntClientLoadLibrary(&strUahModule, &strUahInitFunc, Unload, TRUE);
if(hmod != 0)
{
ppi->W32PF_flags |= W32PF_APIHOOKLOADED;
return TRUE;
}
return FALSE;
}
else if(Unload && (ppi->W32PF_flags & W32PF_APIHOOKLOADED))
{
/* Call ClientLoadLibrary in user32 */
hmod = co_IntClientLoadLibrary(NULL, NULL, Unload, TRUE);
if(hmod != 0)
{
ppi->W32PF_flags &= ~W32PF_APIHOOKLOADED;
return TRUE;
}
return FALSE;
}
return TRUE;
}
UNIMPLEMENTED;
return FALSE;
}
/*
IntHookModuleUnloaded:
Sends a internal message to all threads of the requested desktop
and notifies them that a global hook was destroyed
and an injected module must be unloaded.
As a result, IntLoadHookModule will be called for all the threads that
will receive the special purpose internal message.
*/
BOOL
IntHookModuleUnloaded(PDESKTOP pdesk, int iHookID, HHOOK hHook, BOOL Block)
{
PTHREADINFO ptiCurrent;
PLIST_ENTRY ListEntry;
ULONG_PTR Result;
PPROCESSINFO ppiCsr;
DPRINT("IntHookModuleUnloaded: iHookID=%d\n", iHookID);
ppiCsr = PsGetProcessWin32Process(CsrProcess);
ListEntry = pdesk->PtiList.Flink;
while(ListEntry != &pdesk->PtiList)
{
ptiCurrent = CONTAINING_RECORD(ListEntry, THREADINFO, PtiLink);
/* FIXME: do some more security checks here */
/* FIXME: the first check is a reactos specific hack for system threads */
if(!PsIsSystemProcess(ptiCurrent->ppi->peProcess) &&
ptiCurrent->ppi != ppiCsr)
{
if(ptiCurrent->ppi->W32PF_flags & W32PF_APIHOOKLOADED)
{
DPRINT("IntHookModuleUnloaded: sending message to PID %d, ppi=0x%x\n", PsGetProcessId(ptiCurrent->ppi->peProcess), ptiCurrent->ppi);
co_MsqSendMessage( ptiCurrent->MessageQueue,
0,
iHookID,
TRUE,
(LPARAM)hHook,
0,
Block,
MSQ_INJECTMODULE,
&Result);
}
}
ListEntry = ListEntry->Flink;
}
return TRUE;
}
BOOL
FASTCALL
UserLoadApiHook()
{
return IntLoadHookModule(WH_APIHOOK, 0, FALSE);
}
BOOL
FASTCALL
UserRegisterUserApiHook(
PUNICODE_STRING pstrDllName,
PUNICODE_STRING pstrFuncName)
{
PTHREADINFO pti, ptiCurrent;
HWND *List;
PWND DesktopWindow, pwndCurrent;
ULONG i;
ULONG_PTR Result;
PPROCESSINFO ppiCsr;
pti = PsGetCurrentThreadWin32Thread();
ppiCsr = PsGetProcessWin32Process(CsrProcess);
/* Fail if the api hook is already registered */
if(gpsi->dwSRVIFlags & SRVINFO_APIHOOK)
{
return FALSE;
}
DPRINT("UserRegisterUserApiHook. Server PID: %d\n", PsGetProcessId(pti->ppi->peProcess));
/* Register the api hook */
gpsi->dwSRVIFlags |= SRVINFO_APIHOOK;
strUahModule = *pstrDllName;
strUahInitFunc = *pstrFuncName;
ppiUahServer = pti->ppi;
/* Broadcast an internal message to every top level window */
DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
List = IntWinListChildren(DesktopWindow);
if (List != NULL)
{
for (i = 0; List[i]; i++)
{
pwndCurrent = UserGetWindowObject(List[i]);
if(pwndCurrent == NULL)
{
continue;
}
ptiCurrent = pwndCurrent->head.pti;
/* FIXME: the first check is a reactos specific hack for system threads */
if(PsIsSystemProcess(ptiCurrent->ppi->peProcess) ||
ptiCurrent->ppi == ppiCsr)
{
continue;
}
co_MsqSendMessage( ptiCurrent->MessageQueue,
0,
WH_APIHOOK,
FALSE, /* load the module */
0,
0,
TRUE,
MSQ_INJECTMODULE,
&Result);
if(Result == FALSE)
{
DPRINT1("Failed to inject module to process %d\n", PsGetProcessId(ptiCurrent->ppi->peProcess));
}
}
ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
}
return TRUE;
}
BOOL
FASTCALL
UserUnregisterUserApiHook(BOOL Block)
{
PTHREADINFO pti;
pti = PsGetCurrentThreadWin32Thread();
/* Fail if the api hook is not registered */
if(!(gpsi->dwSRVIFlags & SRVINFO_APIHOOK))
{
return FALSE;
}
/* Only the process that registered the api hook can uregister it */
if(ppiUahServer != PsGetCurrentProcessWin32Process())
{
return FALSE;
}
DPRINT1("UserUnregisterUserApiHook. Server PID: %d\n", PsGetProcessId(pti->ppi->peProcess));
/* Unregister the api hook */
gpsi->dwSRVIFlags &= ~SRVINFO_APIHOOK;
ppiUahServer = NULL;
ReleaseCapturedUnicodeString(&strUahModule, UserMode);
ReleaseCapturedUnicodeString(&strUahInitFunc, UserMode);
/* Notify all applications that the api hook module must be unloaded */
return IntHookModuleUnloaded(pti->rpdesk, WH_APIHOOK, 0, TRUE);
}
static
LRESULT
FASTCALL
@ -1527,4 +1739,64 @@ CLEANUP:
END_CLEANUP;
}
BOOL
APIENTRY
NtUserRegisterUserApiHook(
PUNICODE_STRING m_dllname1,
PUNICODE_STRING m_funname1,
DWORD dwUnknown3,
DWORD dwUnknown4)
{
BOOL ret;
UNICODE_STRING strDllNameSafe;
UNICODE_STRING strFuncNameSafe;
NTSTATUS Status;
/* Probe and capture parameters */
Status = ProbeAndCaptureUnicodeString(&strDllNameSafe, UserMode, m_dllname1);
if(!NT_SUCCESS(Status))
{
EngSetLastError(RtlNtStatusToDosError(Status));
return FALSE;
}
Status = ProbeAndCaptureUnicodeString(&strFuncNameSafe, UserMode, m_funname1);
if(!NT_SUCCESS(Status))
{
ReleaseCapturedUnicodeString(&strDllNameSafe, UserMode);
EngSetLastError(RtlNtStatusToDosError(Status));
return FALSE;
}
UserEnterExclusive();
/* Call internal function */
ret = UserRegisterUserApiHook(&strDllNameSafe, &strFuncNameSafe);
UserLeave();
/* Cleanup only in case of failure */
if(ret == FALSE)
{
ReleaseCapturedUnicodeString(&strDllNameSafe, UserMode);
ReleaseCapturedUnicodeString(&strFuncNameSafe, UserMode);
}
return ret;
}
BOOL
APIENTRY
NtUserUnregisterUserApiHook(VOID)
{
BOOL ret;
UserEnterExclusive();
ret = UserUnregisterUserApiHook(TRUE);
UserLeave();
return ret;
}
/* EOF */

View file

@ -811,6 +811,12 @@ co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue)
Message->Msg.wParam,
Message->Msg.lParam);
}
else if(Message->HookMessage == MSQ_INJECTMODULE)
{
Result = IntLoadHookModule(Message->Msg.message,
(HHOOK)Message->Msg.lParam,
Message->Msg.wParam);
}
else if ((Message->CompletionCallback)
&& (Message->CallBackSenderQueue == MessageQueue))
{ /* Call the callback routine */

View file

@ -889,20 +889,6 @@ NtUserRealWaitMessageEx(
return 0;
}
BOOL
APIENTRY
NtUserRegisterUserApiHook(
PUNICODE_STRING m_dllname1,
PUNICODE_STRING m_funname1,
DWORD dwUnknown3,
DWORD dwUnknown4)
{
UserEnterExclusive();
UNIMPLEMENTED;
UserLeave();
return 0;
}
BOOL
APIENTRY
NtUserRegisterRawInputDevices(
@ -1036,14 +1022,6 @@ NtUserPaintMenuBar(
return 0;
}
BOOL
APIENTRY
NtUserUnregisterUserApiHook(VOID)
{
UNIMPLEMENTED;
return 0;
}
BOOL
APIENTRY
NtUserGetLayeredWindowAttributes(

View file

@ -122,6 +122,9 @@ NtUserCallNoParam(DWORD Routine)
case NOPARAM_ROUTINE_RELEASECAPTURE:
RETURN( (DWORD_PTR)IntReleaseCapture());
case NOPARAM_ROUTINE_LOADUSERAPIHOOK:
RETURN(UserLoadApiHook());
default:
DPRINT1("Calling invalid routine number 0x%x in NtUserCallNoParam\n", Routine);
EngSetLastError(ERROR_INVALID_PARAMETER);