Системный хук Windows CBT не работает должным образом - PullRequest
2 голосов
/ 26 июня 2010

Я пытаюсь подключить CBT-хук в ОС Windows.В настоящее время я использую Windows 7 x64.

Я прочитал много тем, рассказывающих об этой проблеме, но ни одна из них не решила мою проблему.Приложение работает хорошо;Хук установлен, и я вижу, что приходят уведомления.

На самом деле возникла проблема в том, что приложение не уведомлено о перехвате CBT других процессов, выполняющихся на той же машине.

Приложение написано на C # (с использованием Microsoft .NET).Вот пример работы:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Text;
using System.Threading;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace WindowsHook
{
    class Program
    {
    [STAThread]
    static void Main(string[] args)
    {
        uint thid = (uint)AppDomain.GetCurrentThreadId();
        bool global = true;

        mHookDelegate = Marshal.GetFunctionPointerForDelegate(new HookProc(ManagedCallback));

        if (global == true) {
            mNativeWrapperInstance = LoadLibrary("Native_x64.dll");
            thid = 0;
        } else {
            using (Process curProcess = Process.GetCurrentProcess())
            using (ProcessModule curModule = curProcess.MainModule)
            {
                mNativeWrapperInstance = GetModuleHandle(curModule.ModuleName);
            }
        }

        mNativeWrappedDelegate = AllocHookWrapper(mHookDelegate);
        mHookHandle = SetWindowsHookEx(/*WH_CBT*/5, mNativeWrappedDelegate, mNativeWrapperInstance, thid);

        if (mHookHandle == IntPtr.Zero)
            throw new Win32Exception(Marshal.GetLastWin32Error());

        Application.Run(new Form());

        if (FreeHookWrapper(mNativeWrappedDelegate) == false)
            throw new Win32Exception("FreeHookWrapper has failed");
        if (FreeLibrary(mNativeWrapperInstance) == false)
            throw new Win32Exception("FreeLibrary has failed");

        if (UnhookWindowsHookEx(mHookHandle) == false)
            throw new Win32Exception(Marshal.GetLastWin32Error());
    }

    static int ManagedCallback(int code, IntPtr wParam, IntPtr lParam)
    {
        Trace.TraceInformation("Code: {0}", code);
        if (code >= 0) {
            return (0);
        } else {
            return (CallNextHookEx(mHookHandle, code, wParam, lParam));
        }
    }

    delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);

    static IntPtr mHookHandle;

    static IntPtr mHookDelegate;

    static IntPtr mNativeWrapperInstance = IntPtr.Zero;

    static IntPtr mNativeWrappedDelegate = IntPtr.Zero;

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern IntPtr GetModuleHandle(string lpModuleName);

    [DllImport("user32.dll", SetLastError = true)]
    private static extern IntPtr SetWindowsHookEx(int hook, IntPtr callback, IntPtr hMod, uint dwThreadId);

    [DllImport("user32.dll", SetLastError = true)]
    internal static extern bool UnhookWindowsHookEx(IntPtr hhk);

    [DllImport("user32.dll")]
    internal static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

    [DllImport("kernel32.dll")]
    private static extern IntPtr LoadLibrary(string lpFileName);

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool FreeLibrary(IntPtr hModule);

    [DllImport("Native_x64.dll")]
    private static extern IntPtr AllocHookWrapper(IntPtr callback);

    [DllImport("Native_x64.dll")]
    private static extern bool FreeHookWrapper(IntPtr wrapper);

    [DllImport("Native_x64.dll")]
    private static extern int FreeHooksCount();
}

}

AllocHookWrapper и FreeHookWrapper - импортированные подпрограммы из компилятора DLL (Native_x64.dll) для платформы x64, расположенного в одном каталоге приложения.AllocHookWrapper сохраняет указатель функции (управляемой подпрограммы) и возвращает подпрограмму DLL, вызывающую указатель функции).

Вот код библиотеки DLL:

#include "stdafx.h"
#include "iGecko.Native.h"

#ifdef _MANAGED
#pragma managed(push, off)
#endif

#define WIN32_LEAN_AND_MEAN
#include <windows.h>

#define WRAPPER_NAME(idx)   Wrapper ## idx

#define WRAPPER_IMPLEMENTATION(idx)                                                 \
LRESULT WINAPI WRAPPER_NAME(idx)(int code, WPARAM wparam, LPARAM lparam)        \
{                                                                               \
    if (sHooksWrapped[idx] != NULL)                                             \
        return (sHooksWrapped[idx])(code, wparam, lparam);                      \
    else                                                                        \
        return (0);                                                             \
}

#define WRAPPER_COUNT       16

HOOKPROC sHooksWrapped[WRAPPER_COUNT] = { NULL };

WRAPPER_IMPLEMENTATION(0x00);
WRAPPER_IMPLEMENTATION(0x01);
WRAPPER_IMPLEMENTATION(0x02);
WRAPPER_IMPLEMENTATION(0x03);
WRAPPER_IMPLEMENTATION(0x04);
WRAPPER_IMPLEMENTATION(0x05);
WRAPPER_IMPLEMENTATION(0x06);
WRAPPER_IMPLEMENTATION(0x07);
WRAPPER_IMPLEMENTATION(0x08);
WRAPPER_IMPLEMENTATION(0x09);
WRAPPER_IMPLEMENTATION(0x0A);
WRAPPER_IMPLEMENTATION(0x0B);
WRAPPER_IMPLEMENTATION(0x0C);
WRAPPER_IMPLEMENTATION(0x0D);
WRAPPER_IMPLEMENTATION(0x0E);
WRAPPER_IMPLEMENTATION(0x0F);

const HOOKPROC sHookWrappers[] = {
    WRAPPER_NAME(0x00),
    WRAPPER_NAME(0x01),
    WRAPPER_NAME(0x02),
    WRAPPER_NAME(0x03),
    WRAPPER_NAME(0x04),
    WRAPPER_NAME(0x05),
    WRAPPER_NAME(0x06),
    WRAPPER_NAME(0x07),
    WRAPPER_NAME(0x08),
    WRAPPER_NAME(0x09),
    WRAPPER_NAME(0x0A),
    WRAPPER_NAME(0x0B),
    WRAPPER_NAME(0x0C),
    WRAPPER_NAME(0x0D),
    WRAPPER_NAME(0x0E),
    WRAPPER_NAME(0x0F)
};

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
    return (TRUE);
}

#ifdef _MANAGED
#pragma managed(pop)
#endif

extern "C" IGECKONATIVE_API HOOKPROC WINAPI AllocHookWrapper(HOOKPROC wrapped)
{
    for(int i = 0; i < WRAPPER_COUNT; i++) {
        if (sHooksWrapped[i] == NULL) {
            sHooksWrapped[i] = wrapped;
            return sHookWrappers[i];
        }
    }

    return (NULL);
}

extern "C" IGECKONATIVE_API BOOL WINAPI FreeHookWrapper(HOOKPROC wrapper)
{
    for(int i = 0; i < WRAPPER_COUNT; i++) {
        if (sHookWrappers[i] == wrapper) {
            sHooksWrapped[i] = NULL;
            return TRUE;
        }
    }

    return (FALSE);
}

extern "C" IGECKONATIVE_API INT WINAPI FreeHooksCount()
{
    int c = 0;

    for(int i = 0; i < WRAPPER_COUNT; i++) {
        if (sHooksWrapped[i] == NULL)
            c++;
    }

    return (c);
}

На самом деле яменя интересуют события, связанные с окном (создание, уничтожение) в определенной системе, но на самом деле я не могу получать уведомления от ОС ...

Что происходит?Что я пропустил?

Обратите внимание, что я работаю с группой Administratos.


Я нашел этот интересный раздел на этой странице

Глобальные хуки не поддерживаются в .NET Framework Нельзя реализовать глобальные хуки в Microsoft .NET Framework.Чтобы установить глобальный хук, хук должен иметь собственный экспорт DLL, чтобы вставить себя в другой процесс, для которого требуется допустимая, согласованная функция для вызова.Это поведение требует экспорта DLL..NET Framework не поддерживает экспорт DLL.Управляемый код не имеет понятия согласованного значения для указателя на функцию, потому что эти указатели на функции являются прокси, которые создаются динамически.

Я решил сделать трюк, реализовав собственную DLL, содержащую обратный вызов ловушки, которыйвызывает управляемый обратный вызов.Однако управляемый обратный вызов вызывается только в процессе, который вызывает процедуру SetWindowsHookEx, и не вызывается другими процессами.

Каковы возможные обходные пути?

Возможно выделение динамической памяти для храненияидентификатор процесса (управляемый) и отправка пользовательских сообщений, описывающих подключенные функции?


Чего я добиваюсь, так это системного монитора, который обнаруживает новые выполненные процессы, обнаруживает созданныерасположение и размер окон, а также закрытые окна, сдвинутые окна, свернутые / развернутые окна.Последовательно монитор должен обнаруживать события мыши и клавиатуры (всегда общесистемные), а также он должен «эмулировать» события мыши и клавиатуры.

Каждый процесс на одном и том же рабочем столе должен независимо отслеживаться архивом (32 или 64 бита) и базовым фреймворком (собственным или управляемым).

Монитор должен принудительно обрабатывать положение, размер и перемещения окон процесса и быть в состоянии действовать как локальный пользователь, чтобы позволить удаленному пользователювыступать в роли локального пользователя (что-то вроде VNC).

1 Ответ

7 голосов
/ 26 июня 2010

Извините, но я не понимаю смысла "оборачивания" неуправляемой DLL и использования ManagedCallback в качестве ловушки внутри управляемого EXE-файла.

Вы должны понимать, что метод, который вы используете в качестве обратного вызова общесистемного хука CBT (параметр SetWindowsHookEx), должен быть загружен в адресное пространство all process (будет сделано внедрение DLL модуля где реализована функция ловушки). В Windows SDK (MSDN) вы можете прочитать следующее (см. Замечание по http://msdn.microsoft.com/en-us/library/ms644990(VS.85).aspx):

SetWindowsHookEx может использоваться для введения DLL в другой процесс. 32-битный DLL не может быть введена в 64-битную процесс, а 64-битная DLL не может быть впрыскивается в 32-битный процесс. Если приложение требует использования крючков в других процессах требуется что вызов 32-битного приложения SetWindowsHookEx для внедрения 32-разрядного DLL в 32-битные процессы, и 64-битный вызов приложения SetWindowsHookEx для внедрения 64-разрядных DLL в 64-битных процессах. 32-разрядный и 64-битные библиотеки DLL должны иметь разные имена.

Кроме того, вы пишете в своем вопросе о системном хуке и не используете 0 в качестве последнего параметра SetWindowsHookEx. Еще одна проблема: в качестве третьего параметра SetWindowsHookEx (HINSTANCE hMod) вы используете экземпляр , а не dll с кодом хука (код хука, который у вас есть в настоящее время в EXE).

Итак, мое предложение: вы должны написать новый собственный код для реализации общесистемного хука CBT и поместить его в DLL. Я также рекомендую вам выбрать базовый адрес (переключатель компоновщика) для DLL, который не является стандартным значением для уменьшения перебазирования DLL. Это не обязательно, но это сэкономит ресурсы памяти.

Извините за плохие новости, но, по моему мнению, ваш текущий код должен быть полностью переписан.

ОБНОВЛЕНО на основе обновления в вопросе: еще раз повторяю, что если вы вызываете в одном процессе SetWindowsHookEx для установки ловушки CBT, вы должны указать в качестве параметра экземпляр модуля ( начальный адрес) DLL и адрес функции в DLL, которая реализует ловушку. Не важно, из какого процесса вы вызываете функцию SetWindowsHookEx. DLL, используемая в качестве параметра, будет загружена (введена) во все процессы одной и той же станции Windows, которые используют User32.dll. Итак, у вас есть некоторые нативные ограничения. Если вы хотите поддерживать как 32-битные, так и 64-битные платформы, вам нужно реализовать две библиотеки: одну 32-битную и 64-битную DLL. Более того, существует проблема с использованием разных версий .NET в одном процессе. Теоретически должно быть возможно сделать это только с .NET 4.0. Вообще это очень сложная проблема. И вы должны понимать это, я пишу о DLL, я имею в виду не только DLL, но все ее зависимости . Поэтому, если вы реализуете собственную DLL, которая вызывает управляемую DLL (.NET DLL), это будет невозможно.

Так что, если вы хотите использовать глобальный хук CBT, вы должны реализовать в качестве двух собственных DLL (одну 32-битную и 64-битную) и установить хук внутри двух процессов (один 32- бит и 64 бит). Поэтому сделайте в точности то, что описано в примечании SetWindowsHookEx документации http://msdn.microsoft.com/en-us/library/ms644990(VS.85).aspx (см. Цитату выше). Я не вижу более простых путей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...