Давным-давно, в выпуске Infected Voice, Light General делал обзор языка Forth и его использование при написании вирусов. В частности, он писал: "Результирующий код компилятора занимает HЕ БОЛЕЕ 15 килобайт. (в моем случае 3400 байт!!! без компилятора ассемблерных мнемоник) Это позволяет изготовить некий "вирус + компилятор + исходник_вируса", и при каждом запуске этой мешанины мы перекомпилируем исходник вируса! Причем,можно изменить процедуру компиляции так,чтобы при каждой перекомпиляции вируса в его код компилировались некие пустые слова. А если еще пораскинуть мозгами,то можно создать слово анализирующее текст вируса и изменяющее его АЛГОРИТМ!!! (это вроде как 100% полиморфизм....)" Очень интересна именно выделенная часть текста. Кто-нибудь видел подобное? Наработки, примеры, статьи, размышления на эту тему? За линки буду очень благодарен. Спасибо.
Ну это врядли, гдето у меня валяется интерпретатор брейнфака что УРИ писал там байт 200 помоему .. на фасме .. вот сам код вируса на брейнфаке пишется цепляется интерпретатор .. ну и его морфим
sniper, идея стара как мир. Стоит учесть, что для полного перестроения на уровне результирующего машинного кода тащить за собой нужно и исходники самого компилятора, плюс исходники всего кода, который будет обеспечивать перестроение. При этом появляется дополнительное слабое место: первоначальный код, который вы будете использовать для построения следующего экземпляра появляется в памяти в неизменном виде -- соответственно, нужно что-то городить с токенизатором, чтобы он кушал сразу из зашифрованной формы и не давился. При этом сложность задачи построения алгоритмов обнаружения всей этой кухни все так же будет упираться в качество кодогенератора + качество морфилки исходника. Получаем: не смотря на то, что такая морфилка будет работать на другом уровне абстракции и реализовать ее теоретически проще -- на мой взгляд это само по себе ничего не дает, до тех пор пока у вас нет качественных решений по перечисленным выше проблемам.
DelAlt, Чушь какая то. Про метаморфизм слышали ? > При этом сложность задачи построения алгоритмов обнаружения всей этой кухни все так же будет упираться в качество кодогенератора + качество морфилки исходника. Что вы там курите.. вы хоть сами то поняли смысл своего выражения ?
Indy_, для того, чтобы получился содержательный диалог, нужно конкретизировать что вы считаете чушью и по каким причинам. второй вариант -- ставить двоеточие после "чушь какая то", тогда все вопросы снимаются.
А если ещё пораскинуть мозгами, то можно прям свой бинарный код читать, пересобирать подмешивая к нему всякий мусор и меняя инструкции или даже варианты ветвления. Класс?
Atari, не очень. Если после всех подмешиваний вы сами его же сможете нормально деобфусцировать для следующего ребилда, то обфускатор слабый. Если не сможете -- на каждом следующем экземпляре будет немножко офигеть как расти размер тушки.
Indy_, расскажите уже про метаморф. с вами стало совсем неинтересно. заходите весь в белом, но раньше сливались сообщений за 5-7, сейчас на первом. *фырк*
Да будет расти. А с измененяемой логикой по средствам компиляции исходного текста изначально должен быть очень жирный бинарь включающий в себя куски вариантов кода?
Как бы идея, естественно, нормальная - при условии ну очень маленького компилятора, потому как с большим раньше технологическая сингулярность наступит, чем проект будет закончен ) 1) укуриваемся/укалываемся/упарываемся и пишем супер-пупер-мега-мета-фалломорфирующийся интерпретатор брейнфака, упс, машины тьюринга. Благо он очень маленький, функционала минимум - можно извратиться до полной недетектируемости. Особенно если динамически менять кодирование команд (напомню, их там всего 8), и внедрять где-нибудь подальше от входа. 2) пишем для него энтропийный энкодер (любой) 3) пишем большую и неебически умную программу по фалломорфированию всего и вся (включая себя же любимуи и обязательно интепретатора) 4) пакуем энкодером программу, кладем вместе с интерпретатором Итого: у нас недектируемая фигнюлька, с ней лежит блоб "принципиально .уй проссышь чего" - задача готова. В качестве ловилки вижу только запуск в песочнице и анализ активности. Кто то меня поправит?
Ну хз, мне кажется это очень доооооолго делать из-за сложности. Хотя можно попробовать накатать тестовый вариант
Atari > А с измененяемой логикой по средствам компиляции исходного текста изначально должен быть очень жирный бинарь включающий в себя куски вариантов кода? Смотря что для вас "очень жирный". Думаю, для оптимизации пространство есть, начиная с банального сжатия, заканчивая тем, что можно не тащить сорсы компонентов, а использовать уже какую-то промежуточную форму (AST?). Т.е., необходимая для качественного ребилда информация на этом этапе все еще есть, но при этом не надо тащить с собой токенайзер/AST-билдер. Всех подводных камней сразу не просчитаешь, если есть идеи/критика -- буду рад услышать.
лучше делать проще: генератор мусора -- анализатор тупо анализирует сий мусор и забивает проц 100пудово. фолс флаги есмь первопричина отруба аверок самим же юзверем.
Такс, что такое компиляция, утрируя - это преобразование исходных кодов в машинные слова понятные ЦП. Без токенайзера (если я правильно понял, то без лексического анализатора?) Вы собираетесь разбивать, например, на B-деревья промежуточные коды или уже машинные, для последующего преобразования? Смысл тогда вообще в компиляции?! Почему не использовать просто свой же бинарь и не преобразовывать его? Я просто не вижу каких-то плюсов этого подхода, по сравнению с классическим полиморфизмом и преобразованием своего же кода.
Не класс. Речь не о шифровании или обфускации кода, а об изменении алгоритма. Вот с вариантами ветвления уже интереснее. Подкинете что-нибудь интересное? Вот тут очень похожее описание того, что ищу: "Что же представляет собой метаморфный генератор? Основой для генерации нового поколения декриптора является некий «базовый код», причем на каком языке он написан — несущественно. Он хранится внутри зашифрованного тела вируса, поэтому может быть постоянным. Там же, в теле вируса, лежит движок, который на основе каждой инструкции этого «базового» кода каждый раз генерирует новый, исполняемый, код. Это очень напоминает компилятор — на входе некоторые семантические конструкции, на выходе готовый к исполнению процессором код. Еще подобная генерация исполняемого кода на основе базового кода происходит в виртуальных машинах — в момент, когда на определённой платформе виртуальная машина исполняет подготовленный байт-код. Именно в этот момент «базовый» байт-код превращается в конкретный исполняемый, который понимает данный процессор. И, если каждую новую платформу считать новым поколением кода, то совокупность виртуальных машин под разные платформы является метаморфным генератором."
Я не вирмайкер, так что примеры только теоретические =) Когда говорил о вариантах ветвления, я имел ввиду, что заранее в exe зашиты будут различные алгоритмы, несколько вариантов заражения целевых машин, несколько вариантов поражения и прочие алгоритмы. Так вот, не использовать все алгоритмы по очереди, а при пересборке себя в новую копию выбирать случайным образом приоритетные действия для новой копии, а остальные варианты шифровать и не палить. Получиться что одна копия на одной машине крадёт данные кредиток например, а на другой он же, но в новой копии лочит файлы. В двух словах как-то так. Хз, есть ли в этом смысл, но внутренний голос говорит, что есть =)
> Вы собираетесь разбивать, например, на B-деревья промежуточные коды или уже машинные, для последующего преобразования? Смысл тогда вообще в компиляции?! Почему не использовать просто свой же бинарь и не преобразовывать его? Для понимания есть смысл взглянуть на картину шире. Первая проблема -- это выбор между вариантами: а) использовать свой бинарь и преобразовывать его -- здесь очевидная сложность и она же слабое место: если у вас качественный обфускатор (генерация трешкода с привязкой потока управления к значениям, вычисленным во время выполнения (результат работы WinAPI, переменные окружения, etc), то вы просто не сможете корректно деобфусцировать свой код в момент первого же ребилда. При этом, если вы упрощаете обфускатор, чтобы получить возможность корректно покрыть/деобфусцировать собственную тушку, то аналогичные возможности получают утилиты, которые эту тушку будут детектить. В результате выбор здесь получается между невозможным и плохим; б) хранение собственного кода в абстрактном представлении (исходник на форте, брейнфаке, байткод виртуальной машины -- в этом контексте абсолютно несущественно, важен общий подход) -- это как раз то, что описано выше как метаморфный генератор: "...Основой для генерации нового поколения декриптора является некий «базовый код», причем на каком языке он написан — несущественно. Он хранится внутри зашифрованного тела вируса, поэтому может быть постоянным. Там же, в теле вируса, лежит движок, который на основе каждой инструкции этого «базового» кода каждый раз генерирует новый, исполняемый, код". Описание вполне корректное, тушка при этом выглядит следующим образом: 1. [компилятор или интерпретатор байткода]: нативный машинный код; 2. [преобразователь/обфускатор исходника/байткода]: нативный машинный код; 3. [расшифровщик внутреннего контейнера, содержащего исходник пейлоада или его байткод]: нативный машинный код; 4. [контейнер, содержащий компилируемый исходный код или байткод первых трех компонентов + пейлоада]: абстрактное представление. Направление хорошее. Наличие абстрактного представления, во-первых, решает все проблемы, которые были в варианте (а) -- мы снимаем все ограничения на сложность/качество обфускатора, т.к. отпадает необходимость в покрытии/декомпиляции собственной тушки. Второй плюс: само наличие собственного кода в абстрактной форме дает больше возможностей для качественной обфускации, т.к. мы имеем больше входной информации, такой, которую проблематично извлечь из машинного кода. Но эта схема зачаточная, идея не развита и не учитывает динамику, она уязвима для динамического анализа по причине неизменности содержимого крипто-контейнера. При динамической распакове сигнатура может быть создана на основе содержимого контейнера, что позволит безошибочно выделять все экзмепляры из общего потока бинарников, которые заходят на анализ. После получения возможности такой группировки -- вопрос детектирования это уже дело техники. Развитие метаморфных генераторов, очевидно, должно быть в следующем направлении: 1) добавление компонента, который осуществляет перестроение абстрактного представления; в случае с использованием виртуальной машины -- каждый экземпляр должен иметь свой вариант кодирования команд и соответствующий ему декодировщик в VM-интерпретаторе; аналогично в случае с компилятором -- преобразование грамматики с соответствующим ему преобразованием лексического парсера; 2) для варианта с компиляцией есть очевидная оптимизация. мы можем пропустить процесс преобразования исходного кода в промежуточное представление и хранить абстрактную часть сразу в виде синтаксического дерева. Необходимая информация для качественной обфускации при этом остается, морфим сразу из этого вида, а код, который в классическом варианте осуществлял построение AST, просто выбрасываем, упрощая при этом систему; 3) все алгоритмы, осуществляющие преобразование абстрактной формы, так же, как и алгоритмы, осуществляющие генерацию машинного кода, должны быть гибкими и управляться набором параметров, хранящимся в отдельном блоке данных -- аналог ДНК у биологических организмов. В роли генома в данном случае выступают параметры, определяющие поведение компонентов: частоты включений для всех поддерживаемых кодгеном инструкций, глубина перестроения, вероятности использования тех или иных методов перестроения и т.д. В качестве фитнесс-функции для естественного отбора выступают сами АВ, при репликации должна происходить мутация "ДНК", все эффективные алгоритмы для этого подробно расписаны в генетике, информации по теме уйма. Экземпляры, которые не были задетекчены и имеют достаточное кол-во родителей, считаются обладателями качественной "ДНК" и могут обмениваться между собой ее случайными участками, для дальнейшей репликации. Это аналог т.н. кроссинговера. Подобная система имеет хорошие шансы самостоятельно адаптироваться к повялению новых методов детектирования, к обновлению АВ-баз и т.д.; 4) этот пункт уже в футуристику, но это может быть не так далеко, как могло бы показаться: наличие компонента, осуществляющего фаззинг системных сервисов и распределенный (между всеми активными экземплярами) автоматизированный поиск уязвимостей, способов распространения; 5) лет через 20-30 -- распределенный AI, анализирующий аналог MSDN-а для генерации фаззеров из п.4; 6) 30-40 лет -- Indy допишет парсер map-файлов, что подитожит все предыдущие достижения и будет началом для vx-революции.
Дальше все слишком туманно. Можно лишь предположить, что с целью уничтожить парсер map-файлов, Скайнет организовывает массивную DDoS-атаку на сервера Yandex Диск, после чего отправляет киборга-убийцу, который появляется в раскаленной сфере посреди поля. На фоне эмоционального напряжения от вида обугленных картофельных побегов у T800 случается конфликт с местным фермером, но уже через каких-то пару минут киборг, проанализировав список из 4-х веганов, доживших до 60-и, движется на тракторе в сторону предполагаемого местонахождения Indy. Камера отдаляется, играет "George Thorogood & The Destroyers : Bad To The Bone". На внутреннем терминале T800 высвечивается "#undef future // future is undefined".
Вы, Товарищи, не туда копаете )) полиморф должен собираться на третьих машинах, а потом запускаться в целевую среду. такими "сборочными цехами" могут быть IoT'ы.