How to hook an application?

感情迁移 提交于 2019-12-01 01:32:30

One issue with your code is that hhookProc can be garbage collected while your native code still needs it. Use GC.KeepAlive or put in in a static variable.

The hMod param should probably be null, since you specified a thread in your own process:

hMod [in]

Type: HINSTANCE

A handle to the DLL containing the hook procedure pointed to by the lpfn parameter. The hMod parameter must be set to NULL if the dwThreadId parameter specifies a thread created by the current process and if the hook procedure is within the code associated with the current process.


But I think this only works for windows on the thread you specify.

In theory you can specify threads in other applications or even a global hook. The specified callback then gets called on the corresponding thread, even if that thread is in another process, in which case your dll gets injected into that process(that's the reason you need to specify the module handle in the first place).

But I believe that's not possible with .net code, because the mechanism for injecting into other processes and calling the hook method over there doesn't work with JIT compiled code.

Like most SetWindowsHookEx hooks, WH_CBT hooks require that the hook callback lives in a separate Win32 DLL that will get loaded into the target process. This essentially requires that the hook is written in C/C++, C# won't work here.

(Low-level mouse and keyboard hooks are two exceptions to this rule. It might also be possible to use other hooks in C# but only if you are hooking one of your own threads, so dwThreadId is the id of a thread in the current process, not 0. I haven't confirmed this, though. And you need to make sure you're using the Win32 threadid, so using GetCurrentThreadId is probably the best bet here.)

If you want to watch for new windows appearing from another app, an alternative C#-friendly approach is to use the SetWinEventHook API instead, specify WINEVENT_OUTOFCONTEXT (which is the magic flag that gets the events delivered to your own process, removing the need for a DLL and making C# usable here) and hook for the EVENT_OBJECT_CREATE and EVENT_OBJECT_SHOW events. You can listen to either your own process/thread's events, or to all processes/threads on the current desktop.

This will get you all sorts of "create" and show notifications, including those for child HWNDs within dialog, and even items within listboxes and similar; so you'll need to filter to extract only those for top-level HWNDs: eg. check that idObject==OBJID_WINDOW and idChild==0; that hwnd is visible (IsVisible()) and is top-level.

Note that using WinEvents requires that the thread that calls SetWinEventHook is pumping messages - which is typically the case anyway if it's a thread with UI. If not, you may need to add a message loop (GetMessage/TranslateMessage) manually. And you'll also want to use GC.KeepAlive() with the callback here also to prevent it from getting collected until after you call UnhookWinEvents.

This won't work in C#

Scope: Thread

If the application installs a hook procedure for a thread of a different application, the procedure must be in a DLL.

(Documentation of SetWindowsHookEx)

Scope: Global

To install a global hook, a hook must have a native DLL export to inject 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.

(Source)

I'm not familiar with the NativeMethod class you are referencing, but I'll make some assumptions and try to make some ground. My guess this has to do with what handle you are hooking. The

dummy.MainWindowHandle

represents the front most window's handle, which is usually what you are looking for. However, in this case, you are opening a MessageBox.Show() which likely has a different handle than the one you have hooked to.

I'd assume that

IntPtr hwndMod = NativeMethods.GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName);

is probably going to return the same result as

dummy.Refresh();
IntPtr hwndMod = dummy.MainWindowHandle;

So I think it's safe to say that they might be giving you the handle you aren't looking for.

Perhaps try to make a test WinForm application. That way you can grab the proper handle. Just make sure to use

dummy.WaitForInputIdle();
dummy.Refresh(); 

before grabbing the handle to make sure you are grabbing the right handle at launch time.

I see it is a console application , so console application doesn't enter a windows messages loop.

simple solution is to include system.windows.forms

and simply type application.start() in your main and things will be fine :)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!