Продолжаем тему написания кейлоггера. Немного обдумав концепцию, я пришел к некоторому решению которое опишу далее по тексту.
Итак, мой дорогой читатель, мы научились узнавать нажата ли клавиша, но в таком виде использовать логгер, лично мне, очень неудобно. Вот не хочу я каждый раз проверять нажата ли клавиша которая мне нужна, я ленивый. Хочу что бы когда ее нажали, я первый об этом узнал и уже, если нужно, что-то предпринял.
Надеюсь ты читал про [Ссылки могут видеть только зарегистрированные пользователи. ] в c#, иначе далее придется туго! Хотя всегда можно скопировать исходник в конце статьи и даже не париться. В любом случае советую изучить, не раз пригодится.
Сейчас мы будем переделывать наш прошлый класс, который сам будет проверять нажаты ли нужные нам кнопки и уведомлять нас в случае нажатия, а далее уже по нашему усмотрению. Для этого необходимо иметь в классе список клавиш на проверку, далее, за очень короткий промежуток времени проверять каждую из них. Создадим класс с именем KeyWatcher и добавим метод WinApi с константой из прошлой статьи и методом IsPressing. Далее объявим в классе две новые переменные, это массив Keys и Timer из пространства имен System.Timers, главное не перепутать, таймеров там много!
Также, нам нужен метод, который подпишется на событие таймера и будет проверять по нему какие кнопки нажаты и сам генерировать событие! Я назвал этот метод OnTimer, но к реализации вернемся позже. В конструкторе класса предлагаю инициализировать переменные:
В аргумент конструктора требуем список клавиш о нажатии которых нужно уведомлять.
Класс сконструирован. Теперь остается сделать реализацию метода OnTimer и добавить в наш класс событие на которое можно подписаться, при чем событие должно быть с параметром, что бы явно знать какая из клавиш нам пришла. Когда я первый раз делал набросок класса, запускал таймер сразу в конструкторе с очень коротким интервалом, это не правильно подумал я, потому что не факт что сразу после запуска кто-то подпишется, а таймер будет тратить процессорное время впустую и я выпилил эту идею и придумал новую. Мы будем запускать таймер только в том случае, если кто-то подписался на событие и отключать его сразу после того как все отписались, очень хорошее решение на мой взгляд. Правда это немного усложняет код, но это ничего, какой читер боится сложностей?
Для реализации умного таймера, нам нужно добавить приватное событие в классе и инкапсулировать логику подписки с помощью свойства. Кстати, в .net есть замечательный класс [Ссылки могут видеть только зарегистрированные пользователи. ] который мы будем использовать как параметр в событиях.
Вот такая несложная система у нас будет. Теперь нужно определить наш метод OnTimer и добавить еще один метод для удобства, который будет генерировать событие - OnPressed:
Код:
private void OnTimer ( Object sender, System.Timers.ElapsedEventArgs e )
{
foreach( var key in _chekingKeys )
{
if ( IsPressing ( key ) ) OnPressed ( key );
}
}
private void OnPressed( Keys key )
{
var buffer = _pressed;
buffer?.Invoke ( this, new KeyEventArgs ( key ) );
}
А также добавим метод который очистит ресурсы таймера и заодно отпишет нас от его события:
Код:
public void Close ()
{
_timer.Close ();
_timer.Elapsed -= OnTimer;
}
В целом наш класс готов для использования. Проверим как он работает, добавив такой код в мейне:
Код:
var keys = Enum.GetValues(typeof(Keys)).Cast<Keys>();
var keyWatcher = new KeyWatcher(keys);
keyWatcher.Pressed += KeyWatcherPressed;
WriteLine ( $"{nameof ( KeyWatcher )} запущен, нажмите любую клавишу что бы остановить программу" );
ReadLine ();
keyWatcher.Pressed -= KeyWatcherPressed;
keyWatcher.Close ();
И реализация метода который подписался на событие:
Код:
private static void KeyWatcherPressed( Object sender, KeyEventArgs e )
{
WriteLine ( $"{e.KeyData.ToString ()} is pressed" );
}
На этом всё. Исходники из данной статьи под спойлером.