Сейчас на форуме: UniSoft, laslo, bartolomeo (+5 невидимых) |
eXeL@B —› Программирование —› Несколько слов про обфускацию |
Посл.ответ | Сообщение |
|
Создано: 17 ноября 2011 23:58 · Поправил: ARCHANGEL · Личное сообщение · #1 Здавтсвуйте, товарищи. Хотел обсудить неторые вопросы, связанные с обфускацией софта. Представим, что у нас есть пермутация с генератором случайных чисел. Причём мутатор проходит код не один раз, а, скажем, раз 1000. В общем, многократно. Допустим, на входе у нас было: Code:
После первого прохода: Code:
Это была чистая мутация, т.е. не было ни одной мусорной инструкции, просто одни инструкции заменялись другими по определённому набору правил. Грубо говоря, у нас в мутаторе есть некое множество инструкций А, которые могут подвергаться мутации. Каждый элемент такого множества расширяется до алгебры, т.е. для всех a, принадлежащих А, носитель состоит из а, сигнатура задаётся конечным, пусть и не очень большим (порядка 5-10 элементов) множеством. Таким образом, имеем множество алгебр В | {b[i],sign}. Т.е. пока всё вполне реально запрограммировать. Идём дальше, известно, что шаг пермутатора - мутация с последующим добавлением мусора. Мусор тоже самый примитивный - nop; mov eax,eax; pushfd+popfd и т.д. Т.е. нет цели косить под компиляторы, под другие проты и т.д. Возвращаясь к нашему примеру выше, понятно, что это - только мутация, мутация с мусором выглядела бы вот так: Code:
И этого следует, что генертор мусора просто делает случайную (на основе генератора случайных чисел) выборку из некоего множества инструкций С. Элементы множества - не обязательно отдельные инструкции, это могут быть пары, тройки и т.д. При одном проходе пермутирующего движка следует вначале вычистить мусор, потом по заранее определённым правилам выполнить обратные преобразования кода. Предположим, что однократное наложение пермутации полностью обратимо. Идём дальше, когда пермутация накладывается многократно, мусор, добавленный во время предыдущих проходов, также мутирует. Это приводит к тому, что паттерны, годные для детекта чистого мусора, становятся непригодными. Code:
Более того, движок пермутатора сохраняет информацию о мутирующих командах, т.е. он знает, что Code:
это одна команда xchg eax,edx и может вставить мусор в середину такой команды. Например: Code:
Т.е. на стадии мутации всегда есть структуры, описывающие отдельные команды, и мутатор знает, в какую конструкцию можно вставить дополнительные инструкции. Естественно, в финальном приложении эта структура будет недоступна. К чему я веду. К тому, что в результате таких преобразований наступает момент, когда теряется возможность отделить мусор от немусора, т.к. нельзя сформировать чёткие правила. Структура инструкции дополняется новыми инструкциями, положения которых случайны. Внимание, вопрос - есть ли способ такое заломать после 1000 проходов пермутации? ----- Stuck to the plan, always think that we would stand up, never ran. |
|
Создано: 18 ноября 2011 00:29 · Личное сообщение · #2 |
|
Создано: 18 ноября 2011 00:31 · Поправил: reversecode · Личное сообщение · #3 ARCHANGEL пишет: Внимание, вопрос - есть ли способ такое заломать после 1000 проходов пермутации? что подразумевается под этим? если преобразовать в относительно базовый(начальный вид) то теоретически возможно на практике хз, я из инструментов знаю только hexrays, где ильфак заявлял что в версии 1.6 какая то обфускация будет обрабатыватся и приводится к базовому виду - хз у кого есть уже 1.6 проверте и второй инструмент это скрипты на питоне optimize, все для тойже ida я не проверял но на картинках они вроде какую то простую обфускацию снимают |
|
Создано: 18 ноября 2011 00:32 · Поправил: daFix · Личное сообщение · #4 Тут уже нужен мощный оптимизатор. Долго думал как бороться с этим, но до реализации не доходило. В любом случае тут нужен эмулятор кода с последующим анализом состояний процесса после выполнения каждой комманды. Критерии анализа конкретно для вашего кода: 1.Проверяем с каким регистром работаем. Если несколько комманд подряд работают с одним и тем-же регистром, тогда выделяем блок комманд и оптимизируем его. Для этого как-же потребуется эмулятор. 2.Смотрим взаимоисключаемые инструкции. Для этого шага так-же потребуется эмулятор. И эти два шага крутить очень долго, пока код не свернётся. Но тут надо придумать по каким критериям выбирать участки для анализа. Это только мои размышления на эту тему, не надо ругаться Помню, где-то советовали подсовывать код в компиляторы от майкрософта так как в них есть оптимизация и код на выходе будет уже почище Поправь "inc eac" ----- Research For Food | Сообщение посчитали полезным: ARCHANGEL |
|
Создано: 18 ноября 2011 00:34 · Поправил: vden · Личное сообщение · #5 <ИМХО>Можно например так: перевести исследуемую функцию с асма в промежуточный код. Применить оптимизации: удаление мёртвых переменных, распространение переменных/констант (в цикле, пока возможно). То что получиться можно изучать или перевести в асм. Но этот метод затратный по времени как написания самого движка так и его работы. К примеру мой неоптимизированный движок 1000 инструкций обрабатывал около 5 сек, что мне кажется долго. В некоторых протекторах двухлетней давности очистка была довольно хорошая. Правда там замусоривание и на глаз было видно.</ИМХО> upd. вообщем-то это уже до меня сказали upd2. естественно нужно отслеживать стек, поток данных и поток кода. если есть полиморф то больше вручную придётся. |
|
Создано: 18 ноября 2011 00:35 · Личное сообщение · #6 r_e Это потому, что вам известен размер конкретного блока. А теперь представьте, что вам не даны ни начало блока, ни его размер. Возьмёте слишком короткий блок - не захватите Code:
Возьмёте слишком длинный - в анализ могут попасть другие мусорные инструкции, которые выполняют операции с регистром флагов, типа, мусорных cld и т.д. И как в таком случае отличить вырожденный от невырожденного? ----- Stuck to the plan, always think that we would stand up, never ran. |
|
Создано: 18 ноября 2011 00:56 · Личное сообщение · #7 reversecode пишет: что подразумевается под этим? если преобразовать в относительно базовый(начальный вид) Именно. daFix пишет: Тут уже нужен мощный оптимизатор. Что бы по этому поводу стоящее почитать? Для этого шага так-же потребуется эмулятор. Это вообще интерес - они вообще нормальные в природе есть? ----- Stuck to the plan, always think that we would stand up, never ran. |
|
Создано: 18 ноября 2011 01:02 · Поправил: daFix · Личное сообщение · #8 ARCHANGEL пишет: Это вообще интерес - они вообще нормальные в природе есть? Кто-то из тутошних гуру точно кодил эмуль, думаю что он тут отпишется. Вроде даже bowrouco ARCHANGEL пишет: Что бы по этому поводу стоящее почитать? mak раньше тут выдавал тонны теории по этому поводу, но она далека от реализации была. Сейчас попробую найти одну старую тему, где было много интересных мыслей было ADDED: Интересное по теме Вот она! https://ssl.exelab.ru/f/action=vthread&forum=6&topic=13288&page=0 ----- Research For Food |
|
Создано: 18 ноября 2011 01:52 · Личное сообщение · #9 ARCHANGEL То что вы описали это не пермутация, а самый простой морфинг. Пермутация заключается в декомпиляции кода - он описывается некоторым языком, далее этот код изменяется и компилируется. Например генерация этого так скажем псевдокода из тела, изменение его и компиляция также не пермутация - это метаморфизм. > Более того, движок пермутатора сохраняет информацию о мутирующих командах, т.е. он знает, что.. Это очень просто решается. Нужны две процедуры. dREGS и dFLAGS. Каждая из них состоит из двух процедур, например INEFLAGS и OUTEFLAGS - это проверяемые и изменяемые флаги. Также и для регистров. Это базовая информация, которую возвращает дизасм. Далее граф анализируется(если не вдаваться в подробности, то это обход всех ветвей от указанной инструкции и определение тех самых dREGS - факт того, что регистр изменяется), если не используются некоторые регистры, то их можно использовать для мусора - это холостые инстуркции. Таким же образом паразитные инструкции удаляются. Если инструкция изменяет регистр, а далее значение этого регситра не используется, а он вновь изменяется, то это паразитная инструкция. Таких условий можно множество задать, по ним находятся блоки удовлетворяющие условиям и удаляются. Например push eax/pop eax - значение регситра eax не используется, так как оно обратно в тотже регистр загружается со стека. Это определяется балансом стека. push eax/mov eax,edx/pop edx - аналог находится в графе по источнику и изменяемым регистрам. Но это уже требует в нормальном случае описание псевдокодом, тоесть декомпиляцию, иначе просто обработка по таблицам всех условий не эффективна. В промежуточном варианте можно ввести в граф псевдоописатели, тогда такой блок удаляется и на его место вставляется описатель, который идентифицирует каким либо образом этот обмен. В общем задача эта весьма сложная. У пермутации есть недостаток - в каждом покалении размер кода сильно растёт, именно изза сложности отделения мусора. |
|
Создано: 18 ноября 2011 03:04 · Поправил: reversecode · Личное сообщение · #10 то что описал клерк делает хексрейс, тоесть построение графа+REGS+FLAGS+оптимизация и вот етап оптимизации и выбрасывает не нужные инструкции или приводит их в базовому виду но судить насколько он этот оптимизатор продвинут пока сложно, я пока приостановил реверс хр но сам хексрей в плагинах перед преобразованием в спевдокод выбрасывает массив mbl_array_t который содержит оптимизированый псевдо asm некоторые данны этого массива определить удалось некоторые нет да и в принципе декомпиль Vamit-a тоже где то на таких приципах REGS/FLAGS построен с графами вот не знаю есть или нет у него ветвления обрабатываются наверняка но ветвления это не совсем графы так что задача в полне посильна и реализуема |
|
Создано: 18 ноября 2011 05:27 · Поправил: PE_Kill · Личное сообщение · #11 ARCHANGEL пишет: К тому, что в результате таких преобразований наступает момент, когда теряется возможность отделить мусор от немусора, т.к. нельзя сформировать чёткие правила. Это заблуждение, т.к. такое возможно лишь при высокоуровневой мутации, да и то очень ограниченно, чего в вашем посте нет. На примере кода, который является конечным, всё деморфится банальным обратным анализом, грубо, но работать будет. Т.е. если полностью дизассемблировать блок и идти, от ret назад, то: Первый проход: Code:
Второй проход: Code:
Третий проход: Code:
Далее подключаем оптимизатор, кодить не сложнее чем деморфер, учитывать только разных конструкций больше. Еще раз, это просто грубая модель. ----- Yann Tiersen best and do not fuck |
|
Создано: 18 ноября 2011 08:27 · Личное сообщение · #12 ARCHANGEL Внимание, вопрос - есть ли способ такое заломать после 1000 проходов пермутации? Можно утвердительно ответить, что способы есть, если вопрос касается только мутации, но не виртуализации - и здесь не нужны никакие шаблоны, всё делается статическим анализом стека, регистров, флагов и условий переходов (если, конечно мутатор умеет вставлять ложные переходы). Говорили про графы, но для решения этой задачи их строить и решать необязательно есть более простой способ деобфускации - N проходов по коду на каждом из которых посредством анализа состояний регистров (USE, CHANGE, INIT) и отслеживания вершины/содержимого стека вырезаются лишние инструкции с сохранением логики работы кода. N ограничено и не будет превышать кол-во проходов мутатора/обфускатора. Эта логика реализована в VMSweeper и успешно работает... ----- Everything is relative... |
|
Создано: 18 ноября 2011 08:34 · Личное сообщение · #13 Vamit > для решения этой задачи их строить и решать необязательно есть более простой способ деобфускации - N проходов по коду Граф трассируется для этой цели, это раскрытие ссылок. Иначе каждую инструкцию прижётся вновь дизасмить, также и весь код. Например на одном из проходов нужно определить ссылку на процедуру или есчо какуюто инфу не связанную с текущей инструкцией - придётся вновь весь код анализировать, а это нормально не решается, получится ацкая рекурсия, на которую и стека может не хватить. При изменении любой инструкции придётся пересчитывать все ветвления, в графе ничего не нужно пересчитывать. Таких нюансов слишком много, по мойму без графа сие не решается в принципе, по любому нужно гдето хранить инфу связанную с инструкциями. |
|
Создано: 18 ноября 2011 09:24 · Личное сообщение · #14 bowrouco пишет: Таких нюансов слишком много, по мойму без графа сие не решается в принципе, по любому нужно гдето хранить инфу связанную с инструкциями. Тут под графом имеется ввиду группировка инструкций, разбиение на блоки, дробление и прочее. Вот это, в данном случае делать вовсе не обязательно. А инструкции естественно нужно где то хранить, в моем примере достаточно массива с указателями на инструкции, т.е. даже не связный список. ----- Yann Tiersen best and do not fuck |
|
Создано: 18 ноября 2011 10:04 · Личное сообщение · #15 |
|
Создано: 18 ноября 2011 13:10 · Личное сообщение · #16 |
|
Создано: 18 ноября 2011 19:52 · Личное сообщение · #17 |
|
Создано: 19 ноября 2011 02:10 · Личное сообщение · #18 В общем, ситуация мне ясна, всем отписавшимся - спасибо. Основную идею я уловил, дальше, полагаю, обсуждать нечего, потому тему прикрою, ибо может начаться дискуссия, отличная от задуманной первоначально. Если появится какая-то дополнительная информация - порошу, чтоб открыли топик. ----- Stuck to the plan, always think that we would stand up, never ran. |
eXeL@B —› Программирование —› Несколько слов про обфускацию |
Эта тема закрыта. Ответы больше не принимаются. |