System wide Windows CBT hook not working properly - c#

I'm trying to hook a CBT hook on Windows OSes. I'm currently using Windows 7 x64.
I've read many threads talking about this issue, but none has solved my problem. The application runs well; the hook is installed and I can see some notifications coming.
Actually the problems arised is that the application is not notified about CBT hook of other processes running on the same machine.
The application is written in C# (using Microsoft .NET). Here is a running sample:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Text;
using System.Threading;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace WindowsHook
{
class Program
{
[STAThread]
static void Main(string[] args)
{
uint thid = (uint)AppDomain.GetCurrentThreadId();
bool global = true;
mHookDelegate = Marshal.GetFunctionPointerForDelegate(new HookProc(ManagedCallback));
if (global == true) {
mNativeWrapperInstance = LoadLibrary("Native_x64.dll");
thid = 0;
} else {
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
mNativeWrapperInstance = GetModuleHandle(curModule.ModuleName);
}
}
mNativeWrappedDelegate = AllocHookWrapper(mHookDelegate);
mHookHandle = SetWindowsHookEx(/*WH_CBT*/5, mNativeWrappedDelegate, mNativeWrapperInstance, thid);
if (mHookHandle == IntPtr.Zero)
throw new Win32Exception(Marshal.GetLastWin32Error());
Application.Run(new Form());
if (FreeHookWrapper(mNativeWrappedDelegate) == false)
throw new Win32Exception("FreeHookWrapper has failed");
if (FreeLibrary(mNativeWrapperInstance) == false)
throw new Win32Exception("FreeLibrary has failed");
if (UnhookWindowsHookEx(mHookHandle) == false)
throw new Win32Exception(Marshal.GetLastWin32Error());
}
static int ManagedCallback(int code, IntPtr wParam, IntPtr lParam)
{
Trace.TraceInformation("Code: {0}", code);
if (code >= 0) {
return (0);
} else {
return (CallNextHookEx(mHookHandle, code, wParam, lParam));
}
}
delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);
static IntPtr mHookHandle;
static IntPtr mHookDelegate;
static IntPtr mNativeWrapperInstance = IntPtr.Zero;
static IntPtr mNativeWrappedDelegate = IntPtr.Zero;
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int hook, IntPtr callback, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", SetLastError = true)]
internal static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll")]
internal static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll")]
private static extern IntPtr LoadLibrary(string lpFileName);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool FreeLibrary(IntPtr hModule);
[DllImport("Native_x64.dll")]
private static extern IntPtr AllocHookWrapper(IntPtr callback);
[DllImport("Native_x64.dll")]
private static extern bool FreeHookWrapper(IntPtr wrapper);
[DllImport("Native_x64.dll")]
private static extern int FreeHooksCount();
}
}
AllocHookWrapper and FreeHookWrapper are imported routines from a DLL (Native_x64.dll) compiler for x64 platform, located at the same directory of the application. AllocHookWrapper stores the function pointer (of the managed routine) and returns the DLL routine calling the function pointer).
Here is the code of the DLL:
#include "stdafx.h"
#include "iGecko.Native.h"
#ifdef _MANAGED
#pragma managed(push, off)
#endif
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define WRAPPER_NAME(idx) Wrapper ## idx
#define WRAPPER_IMPLEMENTATION(idx) \
LRESULT WINAPI WRAPPER_NAME(idx)(int code, WPARAM wparam, LPARAM lparam) \
{ \
if (sHooksWrapped[idx] != NULL) \
return (sHooksWrapped[idx])(code, wparam, lparam); \
else \
return (0); \
}
#define WRAPPER_COUNT 16
HOOKPROC sHooksWrapped[WRAPPER_COUNT] = { NULL };
WRAPPER_IMPLEMENTATION(0x00);
WRAPPER_IMPLEMENTATION(0x01);
WRAPPER_IMPLEMENTATION(0x02);
WRAPPER_IMPLEMENTATION(0x03);
WRAPPER_IMPLEMENTATION(0x04);
WRAPPER_IMPLEMENTATION(0x05);
WRAPPER_IMPLEMENTATION(0x06);
WRAPPER_IMPLEMENTATION(0x07);
WRAPPER_IMPLEMENTATION(0x08);
WRAPPER_IMPLEMENTATION(0x09);
WRAPPER_IMPLEMENTATION(0x0A);
WRAPPER_IMPLEMENTATION(0x0B);
WRAPPER_IMPLEMENTATION(0x0C);
WRAPPER_IMPLEMENTATION(0x0D);
WRAPPER_IMPLEMENTATION(0x0E);
WRAPPER_IMPLEMENTATION(0x0F);
const HOOKPROC sHookWrappers[] = {
WRAPPER_NAME(0x00),
WRAPPER_NAME(0x01),
WRAPPER_NAME(0x02),
WRAPPER_NAME(0x03),
WRAPPER_NAME(0x04),
WRAPPER_NAME(0x05),
WRAPPER_NAME(0x06),
WRAPPER_NAME(0x07),
WRAPPER_NAME(0x08),
WRAPPER_NAME(0x09),
WRAPPER_NAME(0x0A),
WRAPPER_NAME(0x0B),
WRAPPER_NAME(0x0C),
WRAPPER_NAME(0x0D),
WRAPPER_NAME(0x0E),
WRAPPER_NAME(0x0F)
};
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
return (TRUE);
}
#ifdef _MANAGED
#pragma managed(pop)
#endif
extern "C" IGECKONATIVE_API HOOKPROC WINAPI AllocHookWrapper(HOOKPROC wrapped)
{
for(int i = 0; i < WRAPPER_COUNT; i++) {
if (sHooksWrapped[i] == NULL) {
sHooksWrapped[i] = wrapped;
return sHookWrappers[i];
}
}
return (NULL);
}
extern "C" IGECKONATIVE_API BOOL WINAPI FreeHookWrapper(HOOKPROC wrapper)
{
for(int i = 0; i < WRAPPER_COUNT; i++) {
if (sHookWrappers[i] == wrapper) {
sHooksWrapped[i] = NULL;
return TRUE;
}
}
return (FALSE);
}
extern "C" IGECKONATIVE_API INT WINAPI FreeHooksCount()
{
int c = 0;
for(int i = 0; i < WRAPPER_COUNT; i++) {
if (sHooksWrapped[i] == NULL)
c++;
}
return (c);
}
Actually I'm interested about window related events (creation, destruction) on a certain system, but I'm actually unable to being notified by the OS...
What's going on? What have I missed?
Note that I'm running with the Administratos group.
I've found this interesting section in this page
Global hooks are not supported in the .NET Framework
You cannot implement global hooks in Microsoft .NET Framework. To install a global hook, a hook must have a native DLL export to insert itself in another process that requires a valid, consistent function to call into. This behavior requires a DLL export. The .NET Framework does not support DLL exports. Managed code has no concept of a consistent value for a function pointer because these function pointers are proxies that are built dynamically.
I thought to do the trick by implementing a native DLL containing the hook callback, which calls the managed callback. However, the managed callback is called only in the process which calls the SetWindowsHookEx routine and not called by other processes.
What are the possible workarounds?
Maybe allocating heap memory storing a process id (the managed one), and sending user messages describing the hooked functions?
What I'm trying to achieve is a system wide monitor, which detect new processes executed, detect created windows position and size, as well closed windows, moved windows, minimized/maximized windows. Successively the monitor shall detect mouse and keyboard events (always system-wide) and also it has to "emulate" mouse and keyboard events.
Every process in the same desktop has to be monitored, indepently by the archiveture (32 or 64 bit) and by the underlying framework (native or managed).
The monitor shall force process windows position, size and movements, and shall be able to act as local user in order to allow remote user to act as a local user (something like VNC).

Sorry but I don't understand the sense of "wrapping" unmanaged DLL and usage of ManagedCallback as the hook inside of managed EXE.
You should understand, that the method which you use as the callback of system wide CBT hook (parameter of SetWindowsHookEx) must be loaded in the address space of all process (it will be done a DLL injection of the module where hook function is implemented). In Windows SDK (MSDN) you can read following (see remark on http://msdn.microsoft.com/en-us/library/ms644990(VS.85).aspx):
SetWindowsHookEx can be used to inject
a DLL into another process. A 32-bit
DLL cannot be injected into a 64-bit
process, and a 64-bit DLL cannot be
injected into a 32-bit process. If an
application requires the use of hooks
in other processes, it is required
that a 32-bit application call
SetWindowsHookEx to inject a 32-bit
DLL into 32-bit processes, and a
64-bit application call
SetWindowsHookEx to inject a 64-bit
DLL into 64-bit processes. The 32-bit
and 64-bit DLLs must have different
names.
Moreover you write in your question about system wide hook and use not 0 as the last parameter of SetWindowsHookEx. One more problem: as the third parameter of SetWindowsHookEx (HINSTANCE hMod) you use an instance of not the dll with the code of hook (the code of hook you have currently in the EXE).
So my suggestion: you have to write a new native code for implementation of system wide CBT hook and place it inside a DLL. I recommend you also to choose a base address (linker switch) for the DLL, which is not a standard value to reduce DLL rebasing. It is not mandatory but this will save memory resources.
Sorry for the bad news, but in my opinion your current code should be full rewritten.
UPDATED based on update in the question: One more time I repeat, that if you call in one process SetWindowsHookEx to set a CBT hook, you should give as a parameter the module instance (the start address) of a DLL and the address of a function in the DLL which implement the hook. It is not important from which process you call SetWindowsHookEx function. The DLL used as a parameter will be loaded (injected) in all processes of the same windows station which use User32.dll. So you have some native restrictions. If you want support both 32-bit and 64-bit platforms you have to implement two dlls: one 32-bit and 64-bit DLL. Moreover there are a problem with the usage of different .NET versions in the same process. It should be theoretically possible to do this only with .NET 4.0. In general it is very complex problem. And you should understand it I write about a DLL I mean not only the DLL, but all its dependencies. So if you implement a native DLL which call a managed DLL (.NET DLL) it would be not possible.
So if you want use global CBT hook you have to implement if as a two native DLLs (one 32-bit and 64-bit) and set install the hook inside of two processes (one 32-bit and 64-bit). So do exact what is described in the remark of the SetWindowsHookEx documentation http://msdn.microsoft.com/en-us/library/ms644990(VS.85).aspx (see above quote). I see no more easier ways.

Related

How to access the message queue in Mono on a Linux machine?

I'm writing a game in C# and Mono. I execute the game loop and render whenever the window is idle (that is to say, when the message queue is empty). I understand how to do this on Windows (use P/Invoke to import PeekMessage from "User32.dll"), but I don't know how to get the same information about the state of the message queue on a Linux build. I've browsed the Mono repo on Github, and it doesn't look like direct access to the message queue is exposed. The version of Linux I'm running is Peppermint, if that helps. Any guidance on this would be much appreciated.
bool WindowIsIdle()
{
#if Windows
NativeMessage result;
return PeekMessage(out result, IntPtr.Zero, 0, 0, 0) == 0;
#elif Linux
return false; //how can I get this information?
#endif
}
#if Windows
//Imports a native Win32 function for checking the windows message queue
[System.Runtime.InteropServices.DllImport("User32.dll")]
static extern int PeekMessage(out NativeMessage message, IntPtr handle, uint filterMin, uint filterMax, uint remove);
struct NativeMessage
{
IntPtr Handle;
uint Message;
IntPtr WParameter;
IntPtr LParameter;
uint Time;
Point Location;
}
#endif

Calling WaitForSingleObject from C#

I am trying to call WaitForSingleObject method from C#, as documented here:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms687032(v=vs.85).aspx
In order to call this function I need to create a Handle, or I need to get a Handle of type IntPtr, how can it be done?
I've tried this function that I found:
http://www.pinvoke.net/default.aspx/kernel32.WaitForSingleObject
[DllImport("coredll.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto)]
public static extern IntPtr CreateEvent(HANDLE lpEventAttributes, [In, MarshalAs(UnmanagedType.Bool)] bool bManualReset, [In, MarshalAs(UnmanagedType.Bool)] bool bIntialState, [In, MarshalAs(UnmanagedType.BStr)] string lpName);
Or for instance, when I am getting handle from console:
IntPtr handle = Process.GetCurrentProcess().MainWindowHandle;
It throws a DllNotFoundException.
What's the issue here?
I need it in order to run the process with this function call, and to take a dump form its process, for my ClrMd library learning.
Any help will be appreciated.
Code sample:
static void Main(string[] args)
{
var autoEvent = new AutoResetEvent(false);
//this is where I get the DllNotFoundException
WaitForSingleObject(autoEvent.Handle, WAIT_TIMEOUT );
}
[DllImport("kernel32.dll")]
static extern uint WaitForMultipleObjects(uint nCount, IntPtr[] lpHandles, bool bWaitAll, uint dwMilliseconds);
public const Int32 WAIT_TIMEOUT = 0x102;
I would not go through WinApi to get this from C#: you have EventWaitHandler and other synchronization objects in C#, use them:
WaitHandle wh = new EventWaitHandler();
//do whatever you need
...
WaitHandler.WaitOne(wh); // equivalent to WaitForSingleObject in WinApi
you can use wh.SafeWaitHandle if you really need to interop with WinApi
Also I suspect Process.GetCurrentProcess().MainWindowHandle cannot work in a Console Application, that has not any window at all
I want to call native method (WaitForMultipleObjects) which waits for some handle (don't really mind which one), then I want to see it on thread stack using ClrMd library, from dump file
OK, so what about new ManualResetEvent(false).WaitOne()? This should show up in the dump file. And it's reliable.
Just picking any existing handle is not reliable because it might be signaled or be destroyed at any time. Or, you might change its state by waiting. There is no need, a ManualResetEvent can create you a fresh handle.
My mistake I've posted WaitForMultipleObjects instead of WaitForSingleObject, the main issue was that WaitForSingleObject stayed with DllImport("coredll.dll"...) I don't know where did I found it but I did...
Sorry for the confusion

Can WH_MOUSE catch global events?

I'm trying to develop a WPF C# application that captures mouse clicks even (especially) if it's in background in order to start another task.
On MSDN documentation ( http://msdn.microsoft.com/en-us/library/windows/desktop/ms644990(v=vs.85).aspx ) I can read that WH_MOUSE should have either a global or thread scope.
I instantiate my hook handle this way:
hHook = SetWindowsHookEx(WH_MOUSE,
MouseHookProcedure,
(IntPtr)0,
AppDomain.GetCurrentThreadId());
where MouseHookProcedure is the delegate of my callback function and WH_MOUSE value is 7 (following Winuser.h).
The code works but it can only catch local clicks (I just need WM_LBUTTONDOWN messages), the clicks inside the window. I need to catch clicks also outside the window, and when the window is in background.
I tried hooking to WH_MOUSE_LL (with a value of 14), but it's not working.
For the most part I followed this:
http://support.microsoft.com/kb/318804
with some changes since I am using WPF and not WinForms.
The documentation about Hooks is a bit confusing.
All in all I'd like to know:
Can WH_MOUSE detect mouse messages globally? If yes, what am I doing wrong?
Can I hook from a .NET C# code to a WH_MOUSE_LL? If yes, how?
Thanks in advance.
It's possible with WH_MOUSE_LL and you need it.
In my case I developed a global keyboard maybe this could help you.
I needed to call LoadLibrary in the third parameters.
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Auto)]
private static extern IntPtr LoadLibrary(string fileName);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook, KeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
void MyFunction(){
[...]
SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProcedure, LoadLibrary("user32.dll"), 0);
}
Technically you should be able to have a global mouse hook implemented in C#. You would then pass zero as the last arguments to SetWindowsHookEx and your hook procedure must reside in a DLL, not an EXE. That's because the DLL will be injected into every process that has windows belonging to the same desktop as the hooking application. For this same reason writing global hooks in .NET is not actually recommended by most because it causes the CLR to be loaded into every desktop process, which can carry substantial overhead.

Receiving Windows Message on C# from managed Dll using p/invoke

I have to call some native C functions from C# using p/invoke. So far, I had no problems marshaling the different methods and structures to C#. Where my problem resides is in the fact that many of the methods I have to call are asynchronous, and return their final results to my WinForms application through Windows Messages. For instance, I have a call to a method that has the following signature in C:
HRESULT AsyncOpenSession( LPSTR lpszLogicalName,
HANDLE hApp,
LPSTR lpszAppID,
DWORD dwTraceLevel,
DWORD dwTimeOut,
USHORT lphService,
HWND hWnd,
DWORD dwSrvcVersionsRequired,
LPWFSVERSION lpSrvcVersion,
LPWFSVERSION lpSPIVersion,
ULONG lpRequestID );
Where lpszAppID expects to receive the NAME of my application (MyApp.exe) and hWnd is a pointer to the WINDOW HANDLE of my application, which I obtain with a call to
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
public static IntPtr GetCurrentWindowHandle()
{
IntPtr handle = GetForegroundWindow();
return handle;
}
The imported signature is:
[DllImport("MSXFS.DLL", BestFitMapping = true, CharSet = CharSet.Auto, SetLastError = true)]
private static extern int AsyncOpenSession([MarshalAs(UnmanagedType.LPStr)] string lpszLogicalName,
IntPtr hApp,
[MarshalAs(UnmanagedType.LPStr)] string lpszAppID,
UInt32 dwTraceLevel,
UInt32 dwTimeOut,
out Int32 lphService,
IntPtr hWnd,
UInt32 dwSrvcVersionsRequired,
out WFSVersion lpSrvcVersion,
out WFSVersion lpSPIVersion,
out Int32 lpRequestID);
I call the method as follows:
Int32 r = AsyncOpenSession(lpszLogicalName,
appHanlder,
"MyApp.exe",
dwTraceLevel,
dwTimeOut,
out hServ,
GetCurrentWindowHandle(),
dwSrvcVersionsRequired,
out srvcVersion,
out spiVersion,
out requestID);
Initially, the method call returns a result code that indicates the requested call has been put to the execution queue. Any time after the original call the native Dll completes the execution of the request and send a Windows Message to the application by means of its windows handle and name. The Windows Message code for this method is defined as follows:
#define WM_USER 0x0400
#define OPEN_SESSION_COMPLETE (WM_USER + 1)
More info about Windows Messages here: http://msdn.microsoft.com/en-us/library/windows/desktop/ms644931(v=vs.85).aspx
In my application I have overridden the method WndProc to be able to control the Windows Messages as follows:
protected override void WndProc(ref Message m)
{
const int wm_user = 0x0400;
const int OPEN_SESSION_COMPLETE = wm_user + 1;
switch (m.Msg)
{
case OPEN_SESSION_COMPLETE:
txtEventsState.Text = m.ToString();
break;
}
base.WndProc(ref m);
}
But I never receive a Windows Message with this code. There are no error in logs or event viewer. I know my call to the method succeeded because I do not get any error code and because it is mandatory to have an opened session before calling other methods, and I can call other methods that need a session handler successfully (no error code either).
My imported signature and call to the method is in a class library project that my application is referencing. Am I doing something wrong here? Can anyone give a light on what could be happening? I do not have access to the native code, just to a test application the shows that the Windows Messages are being sent by the native C Dll.
Thank to everybody in advance.
So, here it the deal: GetForegroundWindow() is not retriving the correct Window Handle. It happens that my application has two windows. One is the main form that I use for my test and the other displays all results and logging I am doing. So, the method was actually returning the Handle of the loggin window and not the form windows.
Using this.Handle and passing that value to the native methods made everything work correctly.
Thanks to Hans for pointing this out.

Simulating Keys C# .Net

I am working on VS 2010 Ultimate. I have created a simple console application about 25-30 rows. So I want in the Main() function simply to simulate pressing "ALT+TAB" in a while cycle. Hoh can I do that - I cant use SendKeys class cause it "Provides methods for sending keystrokes to an application." I want just when I start my console application to simulate 1000 times pressing "ALT+TAB" without attaching it to anny applications. Something like this:
using System;
using System.Windows.Forms;
namespace nagradite
{
class Program
{
static void Main()
{
int i = 1000;
while( i > 0 )
{
// PRESS "ALT+TAB"
i--;
}
}
}
}
what should I type instead of // PRESS "ALT+TAB"
Use "%{TAB}" for Alt+TAB
SendKeys.Send("%{TAB}");
SendKeys.Send("%{TAB} 1000"); //if you want to do same by 1000 times as you stated
Reference http://msdn.microsoft.com/en-us/library/system.windows.forms.sendkeys.send.aspx
I think you can use SendMessage for finding keys you can see http://www.blizzhackers.cc/viewtopic.php?t=396398, your parent window is null (desktop)
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
You can try a Win32 API called SendInput. It allows you to simulate keyboard/mouse input events and does not require a HWND target. However, I don't know if this will actually trigger system-wide keyboard shortcuts such as ALT+TAB.
MSDN - http://msdn.microsoft.com/en-us/library/ms646310(v=vs.85).aspx
PInvoke.Net - http://www.pinvoke.net/default.aspx/user32.sendinput

Categories