Win32 Hooks DLL injection into Applications Built against "Any CPU"

4.2k views Asked by At

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.

4

There are 4 answers

1
Yahia On

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 !

0
Zenexer On

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.

2
Louis Ricci On

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.

1
Davita On

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.