В Пскове есть ледовый дворец. Правда, административно не в самом Пскове, а в посёлке рядом.
·─T─┌O┐─T─┌A┐L···─Z┐┌0┐┌M┐┌B·i┌F─i┌C─┌A┐─T─i┌O┐┬N┬··························
│ │ │ │ ├─┤│ / │ ││││├┴┐┬├─ ┬│ ├─┤ │ ┬│ ││└┤ Issue #1, January-2001
··│·└─┘·│·│·│└─··└──└─┘│·│└─┘││··│└──│·│·│·│└─┘│·│··························
············································································
РЕВЕРСИРУЮЩИЙ ДВИЖОК, MistFall 1.01 [mistfall.zip]
············································································
Этот движок представляет из себя реализацию алгоритма, реверсирующего
PE EXE/DLL файлы, описанного в статье об автоматицации обратного
проектирования.
Несмотря на все глюки, движок почему-то работает. Называется движок
МИСТФАЛЬ, есть такой рассказ у Джорджа Мартина, "Мистфаль приходит утром".
Движок написан на борман C++, правда без классов и прочих фич.
Основная функция engine() с хуевой кучей параметров, идет, как и следует,
самой первой, а после нее есть еще несколько внутренних подпрограммок. Все
это дело называется kernel (не путать с маздайным) и находится в файлах
engine.cpp & .hpp; соответственно код и константы. Из кернела вызывается
так называемый внешний юзерский мутатор (mutate.cpp), коий может и должен
быть модифицирован пользователем. Мутатор, то есть, собственно инфектор,
оперирует исключительно со списком из структур, которые будем называть
хуйнями (hooy), ибо мозги уже отказывают. В хуйнях могут быть метки,
опкоды, блоки данных, словом все то, о чем говорилось в начале. Да и
вообще, вся технология описания движка точно такая же, как и в RPME,
только RPME был заточен на вирусы, а мистфаль предназначен для работы с PE
файлами.
В результате, простейший метод заражения файла таков:
1. Найти две любые подряд идущие инструкции; после первой инструкции
вставить JMP на вторую, а после JMP'а - зашифрованое тело вируса.
2. Аналогично для декриптора.
3. Аналогично для команды вызова декриптора.
Причем, это только один из вариантов. А вариантов этих должно быть
очень много (выбираться будет рандомный).
ПРИМЕНЕНИЕ В ВИРУСАХ
Прежде всего, движок жрет не просто много, а очень много памяти. При
этом, может получиться глюк на кривом файле; да и на нормальном тоже.
Аллокация памяти, как и в RPME, предоставляется движку пользователем.
Перед вызовом движка выделяйте дохуя памяти, мегабайта 32. Стратегия
аллокации весьма специфическая: движок будет только запрашивать память, и
никогда -- отдавать. Однако для каждого файла используется одна и та же
память, т.е. после возврата из движка все количество выделенной памяти
нужно сбросить в 0. То есть произвести такой глобальный release. Реально
движок использует (17*SizeOfImage) байт на временные линейные массивы,
плюс байт по 40 на каждую инструкцию/запись списка.
Код движка пермутируемый, то есть согласуется с уже описанными
правилами в тексте "требования к движкам".
Движок мог бы работать в ring-0. Но из-за большого количества
требуемой памяти возможны всякие глюки.
При работе движка, большая часть времени уходит на дизассемблирование,
предсказать это время сложно. Исходите из того, что общее время на
обработку одного файла может измеряться минутами, в реалтайме.
Ясно, что такой движок нельзя вешать на обычные системные события,
типа openfile, также как и не следует вызывать движок из простейшего
вируса перед передачей управления хосту. Передача файлов движку должна
осуществляться только в отдельной нити или процессе.
СПЕЦИАЛЬНЫЕ ФИЧИ
Движком обрабатываются только стандартные файлы. Файл считается
стандартным, если имена всех его секций известны движку, типа .text, .data
и т.п. Во всех остальных случаях считается что файл упакованый или просто
хуевый.
Для всех стандартных файлов принимается, что код присутствует только в
первой (аки кодовой) секции. Это позволяет слегка улучшить качество
дизассемблирования.
БИБЛИОТЕКА СИГНАТУР
Круто сказано, но все же. Есть возможность прикрутить к движку так
называемый мэнеджер сигнатур, оформляется он почти так же как и юзерский
мутатор.
В задачи мэнеджера сигнатур входят 2 функции:
1. поиск в файле кусков кода и
2. добавление информации о новых кусках кода в библиотеку
То есть перед дизассемблированием файла мэнеджер сигнатур загружает
свою базу, ищет в файле сигнатуры участков кода и выставляет им флаги
"для-последующего-анализа".
А после дизассемблирования мэнеджер апдейтит базу сигнатурами новых
непрерывных кусков кода.
Применительно к вирусам, база сигнатур вовсе не должна быть переносима
вместе с вирусом; она будет создаваться заново в процессе обработки
локальных дисков.
Сигнатурой же мы считаем некоторое (постоянное) число байт кода
(инструкций), не содержащих фиксапов и команд условного перехода.
Какие преимущества дает библиотека сигнатур? Вроде бы, надо для
каждого байта файла делать CMPSB с тысячами сигнатур. Но ведь есть такой
рулез, как бинарный поиск. Так что времени уходит мало.
А вот качество дизассемблирования должно улучшиться. То есть те
процедуры, которые дизассемблер бы пропустил, возможно будут найдены.
При этом, при длине сигнатур, скажем, 8 байт, и достаточно большой
базе, дизассемблер становится весьма мощной штукой. Ибо конкретные 8 байт
навряд ли встретятся в данных, а вот в коде -- запросто, и много.
Другое дело, что навряд ли нам нужно корректно обрабатывать те
процедуры, которые дизассемблер не определяет как код; может быть они
вообще не используются.
ОПИСАНИЯ ОСНОВНЫХ ФУНКЦИЙ
int __cdecl engine(
DWORD user_arg, // пользовательский параметр
BYTE* buf, // буфер с PE файлом
DWORD inbufsize, // исходная длина
DWORD* outbufsize, // указатель на длину того что получилось
DWORD maxbufsize, // макс. длина буфера
int __cdecl user_disasm(DWORD,BYTE*), // дизассемблер
void* __cdecl user_malloc(DWORD,DWORD), // аллокатор памяти
DWORD __cdecl user_random(DWORD,DWORD), // рандомер
int __cdecl user_mutate( // мутатор (см.ниже)
DWORD user_arg,
PE_HEADER* pe,
PE_OBJENTRY* oe,
hooy* root,
int __cdecl (*)(DWORD user_arg,BYTE*),
void* __cdecl (*)(DWORD user_arg,DWORD),
DWORD __cdecl (*)(DWORD user_arg,DWORD)
),
int __cdecl user_sigman( // менеджер сигнатур, можно NULL
DWORD user_arg,
PE_HEADER* pe,
PE_OBJENTRY* oe,
BYTE* memb,
DWORD* flag,
DWORD action) // 0/1
); //engine
int __cdecl mutate( //мутатор
DWORD user_arg, // пользовательский параметр
PE_HEADER* pe,
PE_OBJENTRY* oe,
hooy* root,
int __cdecl user_disasm(DWORD user_arg,BYTE*),
void* __cdecl user_malloc(DWORD user_arg,DWORD),
DWORD __cdecl user_random(DWORD user_arg,DWORD)
); //mutate
int __cdecl sigman( //менеджер сигнатур
DWORD user_arg,
PE_HEADER* pe,
PE_OBJENTRY* oe,
BYTE* memb,
DWORD* flag,
DWORD action // 0==before, 1==after
); //sigman
············································································