Window hooks in c# - c#

Im trying to hook up to other windows from csharp. Im using SetWindowsHookEx, but no luck with converting it fom c++ t c#.
I found this thread here
but it wasnt solved. The problem is that SetWindowsHookEx returns 0.
It includes best code samle i found:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowDrawer
{
public partial class Form1 : Form
{
private delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);
static IntPtr hHook;
IntPtr windowHandle;
uint processHandle;
HookProc PaintHookProcedure;
[System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
static extern System.IntPtr FindWindowByCaption(int ZeroOnly, string lpWindowName);
[System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "SetWindowsHookEx", SetLastError = true)]
static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, uint dwThreadId);
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
// When you don't want the ProcessId, use this overload and pass IntPtr.Zero for the second parameter
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[System.Runtime.InteropServices.DllImport("kernel32.dll", CharSet =System.Runtime.InteropServices.CharSet.Auto)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
PaintHookProcedure = new HookProc(PaintHookProc);
windowHandle = FindWindowByCaption(0, "Untitled - Notepad");
uint threadID = GetWindowThreadProcessId(windowHandle, out processHandle);
IntPtr hMod = System.Runtime.InteropServices.Marshal.GetHINSTANCE(typeof(Form1).Module);
// HERE IS THE PROBLEM. WHAT THE HECK DO I PASS INTO THE LAST 2 PARAMS? I get a null pointer
hHook = SetWindowsHookEx(WH_GETMESSAGE, PaintHookProcedure, hMod, threadID);
}
public int PaintHookProc(int nCode, IntPtr wParam, IntPtr lParam)
{
// Do some painting here.
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
private const int WM_PAINT = 15;
private const int WH_GETMESSAGE = 3;
}
}
Any help, advices?

The WH_GETMESSAGE hook is a global hook. It requires a DLL that can be injected into another process. The hMod argument. There's a problem, you can't write such a DLL in a managed language. The target process won't have the CLR initialized.
There's a code project that offers such a DLL, maybe you can make it work. Black belt required.

Have you looked at the EasyHook project? It seems to be a pretty active project. Microsoft also have an example on their site.

Related

Listen for system wide click using Mono and C#?

I want to use mono to write a simple CL tool that registers every click around the system. I understand that I can access this from Windows Forms? Which is like the wrapper around the internal Windows API?
Sorry I this is a real stupid question but coming from a JS background where its just AddEventListener this is kind of confusing, or badly documented. Thanks
What you're looking for is in user32.dll
Here're some links about it:
http://pinvoke.net/default.aspx/user32.GetAsyncKeyState
https://msdn.microsoft.com/en-us/library/windows/desktop/ms646293(v=vs.85).aspx
looking up that the user press a key or not?
The first link contains examples of how to use the dll.
You can do multiple things with this dll. For example, what you're after is
[DllImport("User32.dll")]
private static extern short GetAsyncKeyState(System.Windows.Forms.Keys vKey);
[DllImport("User32.dll")]
private static extern short GetAsyncKeyState(System.Int32 vKey);
For this, you'll need to check the key every time you want to check whether the key is down. You can either use the virtual key code or use the Keys class.
If you also want to simulate mouse events, e.g send a left click to the system, the following code is what you're after. (more info here)
[DllImport("user32.dll")]
static extern void mouse_event(uint dwFlags, int dx, int dy, uint dwData, int dwExtraInfo);
I did a similar thing not long ago, however I was hooking into the keyboard and not the mouse. The process is similar, however it is a lot easier to hook into a specific program. The code is below on how I solved my problem.
In the following code, I created an event which triggered whenever a key was pressed and sent the Key Code as the event argument.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace KeyHook {
public class KeyHook {
const int WH_KEYBOARD_LL = 13;
const int WM_KEYDOWN = 0x0100;
const int WM_KEYUP = 0x0101;
delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
LowLevelKeyboardProc _proc { get; set; }
IntPtr _hookID { get; set; }
public delegate void KeyHandler(Keys k);
public event KeyHandler OnKeyDown;
public event KeyHandler OnKeyUp;
public KeyHook() {
Initialize();
_hookID = SetHook(_proc);
}
void Initialize() {
this._proc = HookCallback;
this._hookID = IntPtr.Zero;
Application.ApplicationExit += Application_ApplicationExit;
}
void Application_ApplicationExit(object sender, EventArgs e) {
UnhookWindowsHookEx(_hookID);
}
IntPtr SetHook(LowLevelKeyboardProc proc) {
using (Process curProcess = Process.GetCurrentProcess()) {
using (ProcessModule curModule = curProcess.MainModule) {
return SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle
(curModule.ModuleName), 0);
}
}
}
IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) {
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN) {
if (this.OnKeyDown != null) {
this.OnKeyDown((Keys)Marshal.ReadInt32(lParam));
}
} else if (nCode >= 0 && wParam == (IntPtr)WM_KEYUP) {
if (this.OnKeyUp != null) {
this.OnKeyUp((Keys)Marshal.ReadInt32(lParam));
}
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
#region dll Imports
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod,
uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern IntPtr GetModuleHandle(string lpModuleName);
#endregion
}
}

C#, Need help to seperate one beginner program

As beginner lesson I want to port this tutorial http://null-byte.wonderhowto.com/how-to/create-simple-hidden-console-keylogger-c-sharp-0132757/ to a Windows Form Application.
This should show a user what keys are pressed inside a label called 'lblMessage'.
I have separeted the code now into two pieces.
Form1.cs
using System.Windows.Forms;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.IO;
namespace WindowsFormsApplication3
{
public partial class Form1 : Form
{
public GlobalKeyHook hook = new GlobalKeyHook();
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
// Origin
// _hookID = SetHook(_proc);
hook._hookID = hook.SetHook(_proc);
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
// Origin
// UnhookWindowsHookEx(_hookID);
hook.UnhookWindowsEx(_hookID);
}
}
}
GlobalKeyHook.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.IO;
namespace WindowsFormsApplication3
{
class GlobalKeyHook : Form
{
#region DLLs
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
#endregion
#region Fields and delegation
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private static LowLevelKeyboardProc _proc = HookCallback;
public static IntPtr _hookID = IntPtr.Zero;
public delegate IntPtr LowLevelKeyboardProc(
int nCode, IntPtr wParam, IntPtr lParam);
#endregion
public GlobalKeyHook()
{
IntPtr hookID = _hookID;
LowLevelKeyboardProc proc = _proc;
}
static Form form = new Form();
#region Methods
private static IntPtr HookCallback(
int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
Console.WriteLine((Keys)vkCode);
form.Text = vkCode.ToString();
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
public static IntPtr SetHook(LowLevelKeyboardProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_KEYBOARD_LL, proc,
GetModuleHandle(curModule.ModuleName), 0);
}
}
#endregion
}
}
But I am not able to use the public static IntPtr _hookID, the method SetHook() or the DLL UnhookWindowsHookEx in the Form1 class. Is it not possible to use this "types" from another class?
Not sure this will solve all your problems but may help you avoid a few of them down the line.
If this is .net 4.0 or higher your SetWindowsHookEX() call will likely return 0 (it failed) because .net no longer emulates a native module for managed dlls. To fix this you can add a DllImport for LoadLibrary() like this:
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Ansi)]
public static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)]string lpFileName);
Then somewhere before you call SetWindowsHookEX() do this:
IntPtr hinstDLL = UnsafeMethods.LoadLibrary("user32.dll");
and call SetWindowsHookEX() like this:
SetWindowsHookEx(WH_KEYBOARD_LL, proc,
hinstDLL, 0);
Basically SetWindowsHookEX() needs a valid module handle which it verifies but never actually uses it. the reason to load user32 is that since you are p/invoking functions from it you def have it.
Also, in your constructor just set it to IntPtr.Zero. No need make _hookID if you always are setting it to IntPtr.Zero. It is also worth noting that if the computer you are running this on has less than win7sp1 using IntPtr.Zero won't work (99% sure at least.)
I would strongly suggest you check out This set of hooks They have a decent implementation of a hook library that you can easily extend however you want.
You need to set your GlobalKeyHook class to public class GlobalKeyHook.

Listening for global keyboard events while computer is locked

I'm experimenting with keyboard events and what you can do with them and I've found alot of tutorials and open source libraries to listen for keyboard events in other processes. I came up with the idea to create a simple 'hack' to lock the computer and then listen for the keyboard events. I figured I could force the user to input their password to unlock their computer and then I would've listened to the user input and thus obtaining the password specified. Here is the simple sample code I found on the internet which will listen for global keyboard events:
using System;
using System.Diagnostics;
using System.Windows.Forms;
using System.Runtime.InteropServices;
class InterceptKeys
{
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private static LowLevelKeyboardProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
public static void Main()
{
_hookID = SetHook(_proc);
Application.Run();
UnhookWindowsHookEx(_hookID);
}
private static IntPtr SetHook(LowLevelKeyboardProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_KEYBOARD_LL, proc,
GetModuleHandle(curModule.ModuleName), 0);
}
}
private delegate IntPtr LowLevelKeyboardProc(
int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr HookCallback(
int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
Console.WriteLine((Keys)vkCode);
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
}
This works out quiet well, but for some reason there seems to be a exception when listening to keyboard inputs when the computer is locked? I'm not sure why it doesn't work, perhaps it's a security thing. Anyways it would be awesome if one could do this.
If this is on Windows, the locked screen is actually a different Window Station and is not owned by the interactive user, so therefore the interactive user cannot interact with it in any way (as a security measure). To interact with the lock screen, and logon in general, take a look at creating a Credential Provider

Override The WindowProc Of A Different Process? [duplicate]

Im trying to hook up to other windows from csharp. Im using SetWindowsHookEx, but no luck with converting it fom c++ t c#.
I found this thread here
but it wasnt solved. The problem is that SetWindowsHookEx returns 0.
It includes best code samle i found:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowDrawer
{
public partial class Form1 : Form
{
private delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);
static IntPtr hHook;
IntPtr windowHandle;
uint processHandle;
HookProc PaintHookProcedure;
[System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
static extern System.IntPtr FindWindowByCaption(int ZeroOnly, string lpWindowName);
[System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "SetWindowsHookEx", SetLastError = true)]
static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, uint dwThreadId);
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
// When you don't want the ProcessId, use this overload and pass IntPtr.Zero for the second parameter
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[System.Runtime.InteropServices.DllImport("kernel32.dll", CharSet =System.Runtime.InteropServices.CharSet.Auto)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
PaintHookProcedure = new HookProc(PaintHookProc);
windowHandle = FindWindowByCaption(0, "Untitled - Notepad");
uint threadID = GetWindowThreadProcessId(windowHandle, out processHandle);
IntPtr hMod = System.Runtime.InteropServices.Marshal.GetHINSTANCE(typeof(Form1).Module);
// HERE IS THE PROBLEM. WHAT THE HECK DO I PASS INTO THE LAST 2 PARAMS? I get a null pointer
hHook = SetWindowsHookEx(WH_GETMESSAGE, PaintHookProcedure, hMod, threadID);
}
public int PaintHookProc(int nCode, IntPtr wParam, IntPtr lParam)
{
// Do some painting here.
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
private const int WM_PAINT = 15;
private const int WH_GETMESSAGE = 3;
}
}
Any help, advices?
The WH_GETMESSAGE hook is a global hook. It requires a DLL that can be injected into another process. The hMod argument. There's a problem, you can't write such a DLL in a managed language. The target process won't have the CLR initialized.
There's a code project that offers such a DLL, maybe you can make it work. Black belt required.
Have you looked at the EasyHook project? It seems to be a pretty active project. Microsoft also have an example on their site.

CallbackOnCollectedDelegate at Application.Run(new Form1())

I made a very small application that captures the screen inside games using SlimDX.
(I press left click to capture)
The capture works (atleast when I click on the form itself) but as soon as I click on firefox or any other application, I get this exception :
A callback was made on a garbage collected delegate of type 'CaptureScreen!CaptureScreen.Form1+WinEventDelegate::Invoke'. This may cause application crashes, corruption and data loss. When passing delegates to unmanaged code, they must be kept alive by the managed application until it is guaranteed that they will never be called.
at this line in my program.cs:
Application.Run(new Form1());
My Form1.cs (the designer itself has no controls)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using Microsoft.DirectX.Direct3D;
namespace CaptureScreen
{
public partial class Form1 : Form
{
private const uint WINEVENT_OUTOFCONTEXT = 0;
private const uint EVENT_SYSTEM_FOREGROUND = 3;
private const int WH_MOUSE_LL = 14;
private const int WM_LBUTTONDOWN = 513;
delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
IntPtr m_hhook;
[DllImport("user32.dll")]
static extern bool UnhookWinEvent(IntPtr hWinEventHook);
[DllImport("user32.dll")]
static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags);
[DllImport("user32.dll")]
static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
public Form1()
{
m_hhook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, WinEventProc, 0, 0, WINEVENT_OUTOFCONTEXT);
hookProc = new HookProc(LowLevelMouseProc);
hook = SetWindowsHookEx(WH_MOUSE_LL, hookProc, GetModuleHandle(null), 0);
InitializeComponent();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
UnhookWinEvent(m_hhook);
UnhookWindowsHookEx(hook);
}
void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
if (eventType == EVENT_SYSTEM_FOREGROUND)
{
StringBuilder sb = new StringBuilder(500);
GetWindowText(hwnd, sb, sb.Capacity);
}
}
[DllImport("kernel32.dll")]
static extern IntPtr GetModuleHandle(string moduleName);
[DllImport("user32.dll")]
static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll")]
public static extern int UnhookWindowsHookEx(IntPtr hhook);
[DllImport("user32.dll")]
static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, uint wParam, IntPtr lParam);
delegate IntPtr HookProc(int nCode, uint wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern IntPtr GetForegroundWindow();
private HookProc hookProc;
private IntPtr hook;
IntPtr LowLevelMouseProc(int nCode, uint wParam, IntPtr lParam)
{
if (nCode >= 0 && (IntPtr)wParam == (IntPtr)WM_LBUTTONDOWN)
{
CaptureScreen();
}
return CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam);
}
private void CaptureScreen()
{
StreamReader reader = new StreamReader(Path.GetFullPath("../../Counter.txt"));
string currentpic = reader.ReadLine();
if (string.IsNullOrEmpty(currentpic))
currentpic = "0";
reader.Close();
Bitmap bitmap = Direct3DCapture.CaptureWindow(GetForegroundWindow());
bitmap.Save(Path.GetFullPath("../../ScreenCapture/Test" + currentpic + ".gif"), ImageFormat.Gif);
StreamWriter writer = new StreamWriter(Path.GetFullPath("../../Counter.txt"));
writer.Write((int.Parse(currentpic)) + 1);
writer.Close();
}
public readonly uint DWM_EC_DISABLECOMPOSITION = 0;
public readonly uint DWM_EC_ENABLECOMPOSITION = 1;
[DllImport("dwmapi.dll", EntryPoint = "DwmEnableComposition")]
protected static extern uint Win32DwmEnableComposition(uint uCompositionAction);
}
}
the class that captures the screen can be found here:
http://spazzarama.wordpress.com/2009/02/07/screencapture-with-direct3d/
Any idea on how I can fix this?
Your problem is that you are just passing WinEventProc to SetWinEventHook, which will implicitly create a delegate that is eligible to be GCed once the current method exits (if not sooner!) You are seeing the consequences of that fact.
You will need to create a new member of Form1 of type WinEventDelegate, and use that as the parameter:
private WinEventDelegate winEventProc;
and then make use of it in your call to SetWinEventHook:
this.winEventProc = new WinEventDelegate(WinEventProc);
m_hhook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, this.winEventProc, 0, 0, WINEVENT_OUTOFCONTEXT);
That should ensure that your delegate stays alive as long as you need.
I had this problem also and have a similar solution to #dlev already in place but it does not work. I found if you mark the member static, it prevents it from being collected.
private static WinEventDelegate winEventProc;
There is a MSDN link which may help you to solve your problem.
Let The CLR Find Bugs For You With Managed Debugging Assistants

Categories