private static void Release(Type InEntryPoint) { if (InEntryPoint == null) { return; } LocalHook.Release(); }
/// <summary> /// Installs an unmanaged hook. After this you'll have to activate it by setting a proper <see cref="ThreadACL"/>. /// <see cref="HookRuntimeInfo"/> WON'T be supported! Refer to the native "LhBarrierXxx" APIs to /// access unmanaged hook runtime information. /// </summary> /// <remarks> /// <para> /// Note that not all entry points are hookable! In general methods like <c>CreateFileW</c> /// won't cause any trouble. But there may be methods that are not hookable because their /// entry point machine code is not eligable to be hooked. You should test all hooks on /// common environments like "Windows XP x86/x64 SP1/SP2/SP3" and "Windows Vista x86/x64 (SP1)". /// This is the only way to ensure that your application will work well on most machines. /// </para><para> /// Unmanaged hooks will require a native DLL which handles the requests. This way /// you will get a high-performance interface, because /// a switch from unmanaged to managed code seems to be rather time consuming without doing anything /// useful (at least nothing visible); so a hook omitting this switch will be handled one or two /// orders of magnitudes faster until finally your handler gains execution. But as a managed hook is still executed /// within at last 1000 nano-seconds, even the "slow" managed implementation will be fast enough in most /// cases. With C++.NET you would be able to provide such native high-speed hooks for frequently /// called API methods, while still using managed ones for usual API methods, within a single assembly! /// A pure unmanaged, empty hook executes in approx. 70 nano-seconds, which is incredible fast /// considering the thread deadlock barrier and thread ACL negotiation that are already included in this benchmark! /// </para> /// </remarks> /// <param name="InTargetProc">A target entry point that should be hooked.</param> /// <param name="InNewProc">A handler with the same signature as the original entry point /// that will be invoked for every call that has passed the Thread Deadlock Barrier and various integrity checks.</param> /// <param name="InCallback">An uninterpreted callback that will later be available through <c>LhBarrierGetCallback()</c>.</param> /// <returns> /// A handle to the newly created hook. /// </returns> /// <exception cref="OutOfMemoryException"> /// Not enough memory available to complete the operation. On 64-Bit this may also indicate /// that no memory can be allocated within a 31-Bit boundary around the given entry point. /// </exception> /// <exception cref="ArgumentException"> /// The given function pointer does not map to executable memory (valid machine code) or /// you passed <c>null</c> as delegate. /// </exception> /// <exception cref="NotSupportedException"> /// The given entry point contains machine code that can not be hooked. /// </exception> /// <exception cref="InsufficientMemoryException"> /// The maximum amount of hooks has been installed. This is currently set to MAX_HOOK_COUNT (1024). /// </exception> public static LocalHook CreateUnmanaged( IntPtr InTargetProc, IntPtr InNewProc, IntPtr InCallback) { LocalHook Result = new LocalHook(); Result.m_Callback = InCallback; Result.m_Handle = Marshal.AllocCoTaskMem(IntPtr.Size); Result.m_SelfHandle = GCHandle.Alloc(Result, GCHandleType.Weak); // workitem/13695 & workitem/25580 Marshal.WriteIntPtr(Result.m_Handle, IntPtr.Zero); try { NativeAPI.LhInstallHook( InTargetProc, InNewProc, InCallback, Result.m_Handle); } catch (Exception e) { Marshal.FreeCoTaskMem(Result.m_Handle); Result.m_Handle = IntPtr.Zero; Result.m_SelfHandle.Free(); throw e; } Result.m_ThreadACL = new HookAccessControl(Result.m_Handle); return(Result); }
/// <summary> /// Installs a managed hook. After this you'll have to activate it by setting a proper <see cref="ThreadACL"/>. /// </summary> /// <remarks> /// <para> /// Note that not all entry points are hookable! In general methods like <c>CreateFileW</c> /// won't cause any trouble. But there might be methods that are not hookable because their /// entry point machine code is not eligable to be hooked. You should test all hooks on /// common environments like "Windows XP x86/x64 SP2/SP3" and "Windows Vista x86/x64 (SP1)". /// This is the only way to ensure that your application will work well on most machines. /// </para><para> /// Your handler delegate has to use the <see cref="UnmanagedFunctionPointerAttribute"/> and /// shall map to the same native method signature, otherwise the application will crash! The best /// way is to use predefined delegates used in related P-Invoke implementations usually found with Google. /// If you know how to write such native delegates you won't need internet resources of course. /// I recommend using C++.NET which allows you to just copy the related windows API to your managed /// class and thread it as delegate without any changes. This will also speed up the whole thing /// because no unnecessary marshalling is required! C++.NET is also better in most cases because you /// may access the whole native windows API from managed code without any effort what significantly eases /// writing of hook handlers. /// </para> /// <para> /// The given delegate is automatically prevented from being garbage collected until the hook itself /// is collected... /// </para> /// </remarks> /// <param name="InTargetProc">A target entry point that should be hooked.</param> /// <param name="InNewProc">A handler with the same signature as the original entry point /// that will be invoked for every call that has passed the Fiber Deadlock Barrier and various integrity checks.</param> /// <param name="InCallback">An uninterpreted callback that will later be available through <see cref="HookRuntimeInfo.Callback"/>.</param> /// <returns> /// A handle to the newly created hook. /// </returns> /// <exception cref="OutOfMemoryException"> /// Not enough memory available to complete the operation. On 64-Bit this may also indicate /// that no memory can be allocated within a 31-Bit boundary around the given entry point. /// </exception> /// <exception cref="ArgumentException"> /// The given function pointer does not map to executable memory (valid machine code) or /// you passed <c>null</c> as delegate. /// </exception> /// <exception cref="NotSupportedException"> /// The given entry point contains machine code that can not be hooked. /// </exception> /// <exception cref="InsufficientMemoryException"> /// The maximum amount of hooks has been installed. This is currently set to MAX_HOOK_COUNT (1024). /// </exception> public static LocalHook Create( IntPtr InTargetProc, Delegate InNewProc, Object InCallback) { LocalHook Result = new LocalHook(); Result.m_Callback = InCallback; Result.m_HookProc = InNewProc; Result.m_Handle = Marshal.AllocCoTaskMem(IntPtr.Size); Result.m_SelfHandle = GCHandle.Alloc(Result, GCHandleType.Weak); Marshal.WriteIntPtr(Result.m_Handle, IntPtr.Zero); try { NativeAPI.LhInstallHook( InTargetProc, Marshal.GetFunctionPointerForDelegate(Result.m_HookProc), GCHandle.ToIntPtr(Result.m_SelfHandle), Result.m_Handle); } catch (Exception e) { Marshal.FreeCoTaskMem(Result.m_Handle); Result.m_Handle = IntPtr.Zero; Result.m_SelfHandle.Free(); throw e; } Result.m_ThreadACL = new HookAccessControl(Result.m_Handle); return(Result); }