Win32 Hooks DLL injection into Applications Built against "Any CPU"
Asked Answered
M

4

7

I am working on a project which captures all User Interactions. MSDN tells (this)

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.

My Question is, what happens if an application was built against Any CPU. Do I need to call SetWindowsHookEx from a DLL built against Any CPU.

I have written HookLogger_32.exe loading HookFunctions_32.dll (both x86) and HookLogger_64.exe loading HookFunctions_64.dll (both x64) setting WH_CBT and WH_MOUSE globally (not a specific thread).

The HookLogger_32.exe, HookLogger_64.exe, HookFunctions_32.dll and HookFunctions_64.dll are written in C++.

When I click on a .NET application built against Any CPU, these DLLs get injected (through SetWindowHookEx). The Windows OS hangs & I have to forcefully restart my machine.

When the same .NET application is built against x86 or x64, and when I click on the application after the HookLoggers (both 32 & 64 bit) are started everything is working fine.

Any reasons for this undefined behavior.

The platform on which I am working is a 64-bit machine.

Mosqueda answered 27/1, 2012 at 9:41 Comment(5)
Does it work correctly when built for 32/64 or crash there as well?Intermixture
@pst: its working correctly when built for 32/64. Its a hello world WPF application.Mosqueda
Sounds like this might be related : #1507768Nonlinearity
You left out the "The 32-bit and 64-bit DLLs must have different names." bit. If the DLL is built as Any CPU, it may not matter to .NET - the runtime can load the same binary regardless of the host process target architecture - but maybe the hooking implementation inside Windows depends on the file names being different. So just make two copies of the Any CPU-targeted DLL and try to load the "32-bit" one from a 32-bit process, and the "64-bit" one from a 64-bit process.Mann
@cynic: I have DLLs with different names. And the DLLs are built in C++ against x86 & x64 (I can't build against Any CPU using C++)Mosqueda
F
3

You need to inject from a DLL with a corresponding bitnse - i.e. "any CPU" becomes either 32 or 64 bit at runtime... and your DLL must match the runtime bitness !

Something useful in your situation is known as "side-by-side assembly" (two versions of the same assembly, one 32 and the other 64 bit)... I think you will find these helpful:

Here you can find a nice walkthrough which contains lots of helpful information pieces - it describes .NET DLL wrapping C++/CLI DLL referencing a native DLL

UPDATE:

To make hooking really easy and robust see this well-tested and free library - among other things it works with AnyCPU !

Fonda answered 4/2, 2012 at 20:10 Comment(1)
Another bid for EasyHook from me. Having done detours in C/C++, EasyHook makes it easy.Confucian
B
0

I guess your main problem is that you are trying to inject a .NET assembly to native process and that surely won't work. I'm not even sure if SetWindowsHookEx supports injecting .NET assembly in CLR process. The solution to your problem is:

  1. Rewrite/Recompile your dll using native compiler such as C++/Delphi/VB etc, for x86 and x64 platform.
  2. Make sure your dll depends on system libraries only. For example, it shouldn't depend on any dll that doesn't ship with windows, because you may crash target process. You can use "Dependency Walker" tool to identify dependencies.
  3. As mentioned in MSDN, you should have an executable injector for each cpu you wish to support. In this case x86 and x64.

Or you could use a better injection/hooking library such as madCodeHook or Detours. This way you will overcome problem #3, not to mentioned dozens of pros they provide.

Bentonbentonite answered 4/2, 2012 at 22:57 Comment(1)
The code from which I am calling SetWindowsHookEx, and the DLL which is being injected are built using C++ (both x86 and x64). And the application on which I am hooking is a .NET application built against Any CPU. And the machine I am using is 64 bit.Mosqueda
I
0

Just from your description of the problem my guess is... Your Any CPU compiled program is loading an x86 stub which is firing your 32bit hook, then the x86 stub checks and sees that the environment has 64bit support and launches the 64bit CLR version.

In this scenario your 32bit hook dll is getting the WH_SHELL message and is trying to inject into a process (the x86 stub) that has already ended OR its injecting the 32bit hook into the 64bit CLR process. Thus your "very ambiguous and needs to be elaborated on" system crash.

If you care to elaborate about what your code is actually doing, then more help (and less generalizations and 'just use program A') will be given. Are you actually injecting code into the process or are you calling SetWindowsHookEx with the dwThreadId of the process.

Inventor answered 7/2, 2012 at 13:4 Comment(2)
I am not injecting code, I am calling SetWindowHookEx globally. The OS is hanging only when I click on the HelloWorld .NET application built against Any CPU. Check the Question I have updated.Mosqueda
@Mosqueda - thanks for clarifying. You should have your HookLogger EXEs log every message they receive to a log file (separate log file for 32bit and 64bit of course). Then when you recover from the system freeze you can see what happened right before. Make sure they OPEN/APPEND/CLOSE the log file for each message that comes in. My guess is the Any CPU assembly is triggering your x86 HookLogger AND your x64 HookLogger.Inventor
H
0

On a 32-bit computer, it should be pretty obvious was bitness an Any CPU application takes on.

A 64-bit computer gets two separate installations of the .NET Framework: one for each bitness. A .NET application compiled as with Any CPU as the target normally runs on the 64-bit installation, but it can also run on the 32-bit installation if referenced by another application that directly targets x86. Thus, you can only be sure what you're getting if you know how the application is being run: as an independent process, or via reference.

I wouldn't make any assumptions. Don't assume the process is 64-bit on a 64-bit computer: it can potentially be 32-bit. Check it properly to see which mode it is running in. Then, inject from 32-bit or 64-bit accordingly.

The reason that you must use the same bitness as the target process is that, for technical reasons into which I won't get, such hooks cannot cross what is called the SysWOW barrier. SysWOW is what allows 32-bit applications to run on a 64-bit computer, 16-bit applications to run on a 32-bit computer, etc. You are "crossing the barrier" when you communicate between applications running on different sides of SysWOW--that is, one is running within SysWOW (32-bit), and the other is not (64-bit). Simply put, a process must be entirely in or out of SysWOW. Thus, you cannot have add 32-bit code to a 64-bit process, and vice versa.

Harcourt answered 8/2, 2012 at 7:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.