Регистрация Главная Сообщество
Сообщения за день Справка Регистрация

Ответ
 
Опции темы
Старый 05.03.2016, 17:24   #1
 Разведчик
Аватар для HideFebruary
 
HideFebruary лучик света в грозовом небеHideFebruary лучик света в грозовом небеHideFebruary лучик света в грозовом небеHideFebruary лучик света в грозовом небеHideFebruary лучик света в грозовом небеHideFebruary лучик света в грозовом небеHideFebruary лучик света в грозовом небе
Регистрация: 25.02.2016
Сообщений: 5
Популярность: 771
Сказал(а) спасибо: 0
Поблагодарили 5 раз(а) в 5 сообщениях
 
По умолчанию KeyLogger [2]

Предыдущая статья: KeyLogger [1]

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

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

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

Код:
private readonly Dictionary<Keys, bool> _cacheFlag;
В методе OnTimer изменим логику. Сначала мы узнаем нажата ли клавиша и достанем прошлый флаг. Если в прошлый раз она была нажата и сейчас тоже, то мы пропускаем этот момент и ничего не делаем. Если сейчас клавиша нажата, а в прошлый раз была не нажата, то собственно, уведомляем о нажатии. Если же сейчас клавиша не нажата, а в прошлый раз была нажата, уведомляем о том, что клавишу отпустили. Все достаточно логично.

Код:
private void OnTimer ( Object sender, System.Timers.ElapsedEventArgs e )
        {
            foreach( var key in _checkingKeys )
            {
                var pressing = IsPressing( key );
                var flag = _cacheFlag[key];

                if ( pressing && !flag ) OnAction ( key, KeyAction.Pressed );
                if ( !pressing && flag ) OnAction ( key, KeyAction.UnPressed );

                _cacheFlag [ key ] = pressing;
            }
        }
Как можно заметить, появился новый метод OnAction, который принимает в себя значение клавиши и флаг того, что за действие было произведено, в этом методе уже происходит непосредственное уведомление подписчиков.

Код:
private void OnAction( Keys key, KeyAction action )
        {
            var buffer = ActionHappened;
            buffer?.Invoke ( this, new KeyActionEventArgs ( key, action ) );
        }
В этом методе можно заметить еще одни изменения, это добавление нового класса KeyActionEventArgs который служит нашей собственной реализацией параметров уведомления, добавление перечисления KeyAction и изменение самого события. KeyAction состоит всего из двух флагов.

Код:
public enum KeyAction
    {
        Pressed,
        UnPressed,
    }
А вот как я придумал реализовать класс параметров события:

Код:
public class KeyActionEventArgs : EventArgs
    {
        public KeyActionEventArgs( Keys key, KeyAction action )
        {
            TimeAction = DateTime.UtcNow;

            Key = key;
            KeyAction = action;
        }

        public readonly DateTime TimeAction;
        public readonly Keys Key;
        public KeyAction KeyAction;
    }
В классе мы знаем, что за кнопка пришла, какое действие и точное время по UTC когда произошло событие, время нужно для анализа логов.

Реализация самого события тоже изменилась, теперь у него нет оберточного свойства которое инкапсулирует наш умный таймер, как показали тесты это лишняя логика и она никак не влияет на нагрузку процессора. Событие теперь выглядит так:

Код:
public event EventHandler<KeyActionEventArgs> ActionHappened;
С таймером мы все же кое-что сделаем. Так как нам не нужно следить больше за его запуском, он постоянно будет работать. Учитывая, что инстансов нашего класса может быть много, соответственно таймеров тоже будет много и это не хорошо как минимум с точки зрения концепции. Я предлагаю сделать один таймер общий для всех инстансов, пометив его статичным.

Код:
private readonly static System.Timers.Timer _timer;
А инициализировать и запускать его будем в статичном конструкторе. Для тех кто не знает, статичный конструктор вызывается один раз при первом обращении к классу и служит как раз для относительно безопасной инициализации статических переменных.

Код:
static KeyWatcher ()
        {
            const double interval = 10;
            _timer = new System.Timers.Timer ( interval );
            _timer.Start ();
        }
Теперь осталось изменить обычный конструктор нашего класса. В нем мы добавили инициализацию флагов клавиш. А также изменим аргумент приходящий в конструктор, для более удобного использования. Кто не знает, params перед типом аргумента означает, что мы можем передавать массив значений без явного определения массива, просто через запятую и это очень здорово.

Код:
public KeyWatcher( params Keys[] keys )
        {
            _checkingKeys = keys.Distinct ().ToArray ();
            _cacheFlag = new Dictionary<Keys, bool> ();
            
            foreach( var key in _checkingKeys )
            {
                _cacheFlag [ key ] = false;
            }

            _timer.Elapsed += OnTimer;
        }
Решил добавить еще и стандартный конструктор (который без параметров), также для более удобного использования когда нам нужно смотреть за всеми клавишами.

Код:
public KeyWatcher () : this ( Enum.GetValues ( typeof ( Keys ) ).Cast<Keys> ().ToArray () )
{
}
Кстати, метод IsPressing теперь выглядит вот так:
Код:
public static bool IsPressing ( Keys key )
            => Convert.ToBoolean ( GetAsyncKeyState ( key ) );
Это намного быстрее работает и константа теперь не требуется.

Класс готов к использованию. Проверим его таким кодом в мейне:

Код:
    class Program
    {
        static void Main ( string [ ] args )
        {
            var keyWatcher = new KeyWatcher();
            keyWatcher.ActionHappened += KeyWatcherActionHappened;
            ReadLine ();

            keyWatcher.Close ();
        }

        private static void KeyWatcherActionHappened ( Object sender, KeyActionEventArgs e )
        {
            if( e.KeyAction == KeyAction.UnPressed )
            {
                if ( e.Key != Keys.ShiftKey ) return;
                WriteLine ( $"{e.Key.ToString ()} is UnPressed" );
            }

            WriteLine ( $"{e.Key.ToString()} is pressed" );
        }
    }
Тут мы выводим все кнопки которые нажались и информацию о том когда отпустили шифт.

Исходник под спойлером.
Спойлер
________________
code safe my friend

Последний раз редактировалось MembRupt; 06.03.2016 в 11:07. Причина: Подправил готовый исходник, был недописан
  Ответить с цитированием
Пользователь сказал cпасибо:
Sinyss (23.05.2016)
Ответ

Метки
c sharp, dotnet, keylogger


Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход

Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
[Статья] KeyLogger [1] HideFebruary C# 0 03.03.2016 23:25
[Программа] KGB Keylogger alexmaggot Школа Читера 2 16.01.2015 12:15
Keylogger dimabb Архив 1 06.05.2012 00:55

Заявление об ответственности / Список мошенников

Часовой пояс GMT +4, время: 00:19.

Пишите нам: [email protected]
Copyright © 2024 vBulletin Solutions, Inc.
Translate: zCarot. Webdesign by DevArt (Fox)
G-gaMe! Team production | Since 2008
Hosted by GShost.net