Что такое «крючок» и как я могу написать его на Java?А как общаться с ядром, чтобы знать клавиши, нажимаемые пользователем / регистрирующиеся в ОС - PullRequest
8 голосов
/ 02 сентября 2011

Хотя я много искал, мне все еще неясно, что именно является «крючком». Например, я читал этот пост на вики-ответах :

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

Я также прочитал этот пост , но я все еще не понимаю, что такое «крючок». Может кто-нибудь объяснить, в терминах непрофессионала, что такое «крючок»? Почему именно некоторые пишут «крючок»? Кроме того, возможно ли написать «хук» на Java?

Примечание:

Я хотел написать кейлоггер на Java, и один из моих друзей сказал, что вам придется написать «хук» на C. Разве я не могу написать весь кейлоггер на Java (для работы только на Windows)?

EDIT

, пожалуйста, дайте ответ w.r.t кейлоггер. Как я могу попросить kernel предоставить информацию о нажатой клавише моему приложению, используя перехват? Или как я могу зарегистрировать свое приложение в ОС, используя JNI? Я хочу, чтобы мое приложение записывало клавиши, нажимаемые пользователем.

Ответы [ 8 ]

5 голосов
/ 02 сентября 2011

Из Хукинг - Википедия ,

В компьютерном программировании термин «хукинг» охватывает ряд методов, используемых для изменения или дополнения поведения операционной системы, приложений,или других программных компонентов путем перехвата вызовов функций или сообщений или событий, передаваемых между программными компонентами.Код, который обрабатывает такие перехваченные вызовы функций, события или сообщения, называется «ловушкой».

Хорошим примером, встроенным в Java, будет Runtime.addShutdownHook. shutdown hook - это просто инициализированный, но незапущенный поток.Когда виртуальная машина начинает свою последовательность завершения работы, она запускает все зарегистрированные обработчики завершения работы в неустановленном порядке и позволяет им запускаться одновременно.

Runtime.addShutdownHook(new Thread(){
    @Override
    public void run(){
        // do something before application terminates
    }
});
2 голосов
/ 02 сентября 2011

Я бы связал слово «ловушка» как минимум с двумя различными понятиями:

a) Шаблон наблюдателя, где класс позволяет вам добавить прослушиватель, который будет уведомлен об определенных событиях.Вы можете найти это во всем Swing, Servlet API и многих сторонних фреймворках.

b) Шаблонный метод.Абстрактный класс определяет, какие методы вызываются в каком порядке, и реализующий класс может переопределять эти методы.Примеры этого не , что распространено, но вы видите их время от времени.

1 голос
/ 08 сентября 2011

Захват событий устройства низкого уровня требует запуска собственного кода (JNI, JNA и т. Д.) И в значительной степени зависит от системы .В Linux вам, вероятно, не нужно будет общаться с ядром, скорее всего, с сервером X11.

1 голос
/ 05 сентября 2011

В вашем случае ловушка - это программный механизм для регистрации слушателя (обработчика) в ОС.Этот обработчик (например, метод в вашем приложении) будет уведомлен операционной системой при срабатывании ключевого события (нажатие клавиши).

Это всего лишь применение шаблона наблюдателя.

Вымышленный пример:

    class MyKBHandler implements ISomeKeyboardListener {
        public void onKeyDown(<params containing key info here>){
            //Your code here, doing something with the params.
        }
    }

    MyKBHandler handler = new MyKBHandler();
    <someOSLibrary>.register(handler);

Как они уже говорили вам в других ответах, сделать это невозможнов Java, не полагаясь на какой-то фрагмент нативного кода. Я думаю, что самый простой способ - выбрать язык, связанный с целевой ОС.Для окон я бы сделал это с C #.

Проверьте эту ссылку:

http://msdn.microsoft.com/en-us/library/ms632589%28VS.85%29.aspx

1 голос
/ 02 сентября 2011

Что касается кейлоггера: да, вы можете написать большую часть этого в Java, НО небольшая часть должна будет пойти в модуль JNI, потому что, например, с глобальным перехватом DLL / поток / что-то «вводится» в другие процессы.... поскольку не все процессы содержат JVM и т. д., это не будет работать в Java ... поэтому вам нужно использовать JNI и немного C для написания DLL для этой части вашего кейлоггера ...

EDIT- согласно комментарию:

В этой статье подробно описывается, что делают глобальные хуки и что подразумевается под инъекцией и т.д ...

1 голос
/ 02 сентября 2011

Вот простой пример:

public void hookableMethod(HookObject hook, String param) { 
String innerParam = param;
if(hook != null) { 
 innerParam = hook.someHookMethod(innerParam);  
}

//rest of the code is working with inner param
}

В этом упрощенном примере hookableMethod предоставляет способ для внешней сущности перехватить его - то есть передать ссылку на внешний объект, и этот внешний объект будет выполненпервый.Поэтому, если вам нужна какая-то обработка, которая не является частью исходной реализации, вы можете сделать это, просто передав ссылку, а не исправив исходный источник.

1 голос
/ 02 сентября 2011

Другие имена для этого могут быть делегатом или обратным вызовом.

Примером этого в Java является MouseListener (http://download.oracle.com/javase/tutorial/uiswing/events/mouselistener.html). MouseListener - это интерфейс с такими методами, как mouseClicked(MouseEvent e). Чтобы реагировать на действия мыши со стороны пользователя, вы должны реализовать MouseListener, и когда пользователь щелкает, библиотека Java Swing вызовет ваш класс слушателя (после того, как вы зарегистрируете его, позвонив addMouseListener.

0 голосов
/ 09 сентября 2011

Сначала вы должны определить класс менеджера, например:

package foo.bar

public class SomeHookManager {
    public static void initialize (...) {
        // <pre-initialization-routing>
        _native_init_();
        // <post-initialization-routing>
    }

    public static void registerCallback (IHookCallback callback)
    { /* save this callback */ }

    // this method will be invoked in your C code.
    protected static void invokeCallback () { /* invoke the saved callback */ }

    // this is a native method, the native modifier tells the compiler this method
    // is implemented in C, and linked at runtime.
    protected native static void _native_init_ ();
}

Затем используйте javah для генерации заголовка C, в результате получается что-то вроде ( Я не сделалфактически скомпилируйте этот код, так что это гипотетически ):

/*
 * Class:     Win32
 * Method:    _native_init_
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_foo_bar_Win32_native_init_
    (JNIEnv * env, jobject obj);

Создайте проект C, включите этот файл и реализуйте этот метод.Убедитесь, что при срабатывании фактического перехвата вызовите invokeCallback в своем коде C:

jclass cls = (*env)->GetObjectClass(env, obj);
jmethodID mId = (*env)->GetStaticMethodID(env, cls, "invokeCallback", "()V");
if (mId == 0) { /* error handling */ }
(*env)->CallStaticVoidMethod(env, cls, mId);

Скомпилируйте проект C в файл DLL, скажем hookimpl_win32.dll, и динамически скомпонуйте его где-нибудь в своем коде Java:

static {
    System.loadLibrary("hookimpl_win32"); // no need of .dll or .so in Unix alike OS's
}

Убедитесь, что dll находится в той же папке, что и ваш jar.Или укажите -Djava.library.path=/path/to/your/dlls в аргументах виртуальной машины.

Что касается того, как вы можете регистрировать каждое нажатие клавиши, ОС обычно предоставляет некоторые API для перехвата ключевого события.Для систем Windows вы можете достичь этого, перехватывая сообщения глобального ключа.У меня нет никакого опыта в других системах.В любом случае, вы можете установить правильные прерывания, что является тихим низким уровнем.Вы всегда можете погуглить свой ответ.:) * * 1021

...