Сейчас на форуме: UniSoft, laslo, bartolomeo (+5 невидимых)

 eXeL@B —› Программирование —› Несколько слов про обфускацию
Посл.ответ Сообщение


Ранг: 681.5 (! !), 405thx
Активность: 0.420.21
Статус: Участник
ALIEN Hack Team

Создано: 17 ноября 2011 23:58 · Поправил: ARCHANGEL
· Личное сообщение · #1

Здавтсвуйте, товарищи. Хотел обсудить неторые вопросы, связанные с обфускацией софта. Представим, что у нас есть пермутация с генератором случайных чисел. Причём мутатор проходит код не один раз, а, скажем, раз 1000. В общем, многократно. Допустим, на входе у нас было:
Code:
  1. xor eax,eax
  2. inc eax
  3. retn


После первого прохода:
Code:
  1. push eax
  2. mov dword ptr [esp],0
  3. pop eax
  4. add eax,2
  5. dec eax
  6. retn


Это была чистая мутация, т.е. не было ни одной мусорной инструкции, просто одни инструкции заменялись другими по определённому набору правил. Грубо говоря, у нас в мутаторе есть некое множество инструкций А, которые могут подвергаться мутации. Каждый элемент такого множества расширяется до алгебры, т.е. для всех a, принадлежащих А, носитель состоит из а, сигнатура задаётся конечным, пусть и не очень большим (порядка 5-10 элементов) множеством. Таким образом, имеем множество алгебр В | {b[i],sign}. Т.е. пока всё вполне реально запрограммировать.

Идём дальше, известно, что шаг пермутатора - мутация с последующим добавлением мусора. Мусор тоже самый примитивный - nop; mov eax,eax; pushfd+popfd и т.д. Т.е. нет цели косить под компиляторы, под другие проты и т.д. Возвращаясь к нашему примеру выше, понятно, что это - только мутация, мутация с мусором выглядела бы вот так:

Code:
  1. nop
  2. push eax
  3. xchg eax,edx
  4. xchg eax,edx
  5. mov dword ptr [esp],0
  6. pop eax
  7. pushfd
  8. popfd
  9. add eax,2
  10. inc eax
  11. dec eax
  12. dec eax
  13. retn


И этого следует, что генертор мусора просто делает случайную (на основе генератора случайных чисел) выборку из некоего множества инструкций С. Элементы множества - не обязательно отдельные инструкции, это могут быть пары, тройки и т.д. При одном проходе пермутирующего движка следует вначале вычистить мусор, потом по заранее определённым правилам выполнить обратные преобразования кода. Предположим, что однократное наложение пермутации полностью обратимо.

Идём дальше, когда пермутация накладывается многократно, мусор, добавленный во время предыдущих проходов, также мутирует. Это приводит к тому, что паттерны, годные для детекта чистого мусора, становятся непригодными.


Code:
  1. push eax  //nop
  2. pop eax
  3. push ecx  //push eax
  4. mov ecx,eax
  5. pop eax
  6. push ecx
  7. mov ecx,eax
  8. push eax  //xchg eax,edx
  9. mov eax,edx
  10. pop edx
  11. xchg eax,edx // не мутирует
  12. mov dword ptr [esp],0 // для простоты остальные инструкции, якобы, не мутируют
  13. pop eax
  14. pushfd
  15. popfd
  16. add eax,2
  17. inc eac
  18. dec eax
  19. dec eax
  20. retn


Более того, движок пермутатора сохраняет информацию о мутирующих командах, т.е. он знает, что
Code:
  1. push eax 
  2. mov eax,edx
  3. pop edx


это одна команда xchg eax,edx и может вставить мусор в середину такой команды. Например:
Code:
  1. push eax 
  2. pushfd
  3. mov eax,edx
  4. popfd
  5. pop edx


Т.е. на стадии мутации всегда есть структуры, описывающие отдельные команды, и мутатор знает, в какую конструкцию можно вставить дополнительные инструкции. Естественно, в финальном приложении эта структура будет недоступна.

К чему я веду. К тому, что в результате таких преобразований наступает момент, когда теряется возможность отделить мусор от немусора, т.к. нельзя сформировать чёткие правила. Структура инструкции дополняется новыми инструкциями, положения которых случайны. Внимание, вопрос - есть ли способ такое заломать после 1000 проходов пермутации?

-----
Stuck to the plan, always think that we would stand up, never ran.




Ранг: 590.6 (!), 408thx
Активность: 0.360.18
Статус: Модератор

Создано: 18 ноября 2011 00:29
· Личное сообщение · #2

Отслеживать data flow, затем анализировать независимые части. Например:
Code:
  1. push eax 
  2. pushfd
  3. mov eax,edx
  4. popfd
  5. pop edx

Был бы разнесен в
Code:
  1. pushfd
  2. popfd

Code:
  1. push eax 
  2. mov eax,edx
  3. pop edx

После чего первый блок был бы удален, как вырожденный, а второй переходит на вторую итерацию.

-----
старый пень





Ранг: 1053.6 (!!!!), 1078thx
Активность: 1.060.81
Статус: Участник

Создано: 18 ноября 2011 00:31 · Поправил: reversecode
· Личное сообщение · #3

ARCHANGEL пишет:
Внимание, вопрос - есть ли способ такое заломать после 1000 проходов пермутации?

что подразумевается под этим?
если преобразовать в относительно базовый(начальный вид)
то теоретически возможно
на практике хз, я из инструментов знаю только
hexrays, где ильфак заявлял что в версии 1.6 какая то обфускация будет обрабатыватся и приводится к базовому виду - хз у кого есть уже 1.6 проверте

и второй инструмент это скрипты на питоне optimize, все для тойже ida
я не проверял но на картинках они вроде какую то простую обфускацию снимают




Ранг: 529.0 (!), 110thx
Активность: 0.290.04
Статус: Участник
5KRT

Создано: 18 ноября 2011 00:32 · Поправил: daFix
· Личное сообщение · #4

Тут уже нужен мощный оптимизатор. Долго думал как бороться с этим, но до реализации не доходило.
В любом случае тут нужен эмулятор кода с последующим анализом состояний процесса после выполнения каждой комманды.
Критерии анализа конкретно для вашего кода:
1.Проверяем с каким регистром работаем. Если несколько комманд подряд работают с одним и тем-же регистром, тогда выделяем блок комманд и оптимизируем его. Для этого как-же потребуется эмулятор.
2.Смотрим взаимоисключаемые инструкции. Для этого шага так-же потребуется эмулятор.

И эти два шага крутить очень долго, пока код не свернётся. Но тут надо придумать по каким критериям выбирать участки для анализа.
Это только мои размышления на эту тему, не надо ругаться

Помню, где-то советовали подсовывать код в компиляторы от майкрософта так как в них есть оптимизация и код на выходе будет уже почище

Поправь "inc eac"

-----
Research For Food


| Сообщение посчитали полезным: ARCHANGEL

Ранг: 112.9 (ветеран), 186thx
Активность: 0.090.01
Статус: Участник

Создано: 18 ноября 2011 00:34 · Поправил: vden
· Личное сообщение · #5

<ИМХО>Можно например так: перевести исследуемую функцию с асма в промежуточный код. Применить оптимизации: удаление мёртвых переменных, распространение переменных/констант (в цикле, пока возможно). То что получиться можно изучать или перевести в асм. Но этот метод затратный по времени как написания самого движка так и его работы. К примеру мой неоптимизированный движок 1000 инструкций обрабатывал около 5 сек, что мне кажется долго. В некоторых протекторах двухлетней давности очистка была довольно хорошая. Правда там замусоривание и на глаз было видно.</ИМХО>

upd. вообщем-то это уже до меня сказали

upd2. естественно нужно отслеживать стек, поток данных и поток кода. если есть полиморф то больше вручную придётся.




Ранг: 681.5 (! !), 405thx
Активность: 0.420.21
Статус: Участник
ALIEN Hack Team

Создано: 18 ноября 2011 00:35
· Личное сообщение · #6

r_e
Это потому, что вам известен размер конкретного блока. А теперь представьте, что вам не даны ни начало блока, ни его размер. Возьмёте слишком короткий блок - не захватите

Code:
  1. popfd
  2. pop edx


Возьмёте слишком длинный - в анализ могут попасть другие мусорные инструкции, которые выполняют операции с регистром флагов, типа, мусорных cld и т.д. И как в таком случае отличить вырожденный от невырожденного?

-----
Stuck to the plan, always think that we would stand up, never ran.





Ранг: 681.5 (! !), 405thx
Активность: 0.420.21
Статус: Участник
ALIEN Hack Team

Создано: 18 ноября 2011 00:56
· Личное сообщение · #7

reversecode пишет:
что подразумевается под этим?
если преобразовать в относительно базовый(начальный вид)


Именно.

daFix пишет:
Тут уже нужен мощный оптимизатор.

Что бы по этому поводу стоящее почитать?

Для этого шага так-же потребуется эмулятор.

Это вообще интерес - они вообще нормальные в природе есть?

-----
Stuck to the plan, always think that we would stand up, never ran.





Ранг: 529.0 (!), 110thx
Активность: 0.290.04
Статус: Участник
5KRT

Создано: 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




Ранг: 47.7 (посетитель), 17thx
Активность: 0.090
Статус: Участник

Создано: 18 ноября 2011 01:52
· Личное сообщение · #9

ARCHANGEL

То что вы описали это не пермутация, а самый простой морфинг. Пермутация заключается в декомпиляции кода - он описывается некоторым языком, далее этот код изменяется и компилируется. Например генерация этого так скажем псевдокода из тела, изменение его и компиляция также не пермутация - это метаморфизм.

> Более того, движок пермутатора сохраняет информацию о мутирующих командах, т.е. он знает, что..

Это очень просто решается. Нужны две процедуры. dREGS и dFLAGS. Каждая из них состоит из двух процедур, например INEFLAGS и OUTEFLAGS - это проверяемые и изменяемые флаги. Также и для регистров. Это базовая информация, которую возвращает дизасм. Далее граф анализируется(если не вдаваться в подробности, то это обход всех ветвей от указанной инструкции и определение тех самых dREGS - факт того, что регистр изменяется), если не используются некоторые регистры, то их можно использовать для мусора - это холостые инстуркции. Таким же образом паразитные инструкции удаляются. Если инструкция изменяет регистр, а далее значение этого регситра не используется, а он вновь изменяется, то это паразитная инструкция. Таких условий можно множество задать, по ним находятся блоки удовлетворяющие условиям и удаляются.

Например push eax/pop eax - значение регситра eax не используется, так как оно обратно в тотже регистр загружается со стека. Это определяется балансом стека.

push eax/mov eax,edx/pop edx - аналог находится в графе по источнику и изменяемым регистрам. Но это уже требует в нормальном случае описание псевдокодом, тоесть декомпиляцию, иначе просто обработка по таблицам всех условий не эффективна. В промежуточном варианте можно ввести в граф псевдоописатели, тогда такой блок удаляется и на его место вставляется описатель, который идентифицирует каким либо образом этот обмен.

В общем задача эта весьма сложная. У пермутации есть недостаток - в каждом покалении размер кода сильно растёт, именно изза сложности отделения мусора.




Ранг: 1053.6 (!!!!), 1078thx
Активность: 1.060.81
Статус: Участник

Создано: 18 ноября 2011 03:04 · Поправил: reversecode
· Личное сообщение · #10

то что описал клерк делает хексрейс, тоесть построение графа+REGS+FLAGS+оптимизация
и вот етап оптимизации и выбрасывает не нужные инструкции или приводит их в базовому виду
но судить насколько он этот оптимизатор продвинут пока сложно, я пока приостановил реверс хр
но сам хексрей в плагинах перед преобразованием в спевдокод
выбрасывает массив mbl_array_t который содержит оптимизированый псевдо asm
некоторые данны этого массива определить удалось некоторые нет

да и в принципе декомпиль Vamit-a тоже где то на таких приципах REGS/FLAGS построен
с графами вот не знаю есть или нет у него
ветвления обрабатываются наверняка
но ветвления это не совсем графы

так что задача в полне посильна и реализуема




Ранг: 793.4 (! !), 568thx
Активность: 0.740
Статус: Участник
Шаман

Создано: 18 ноября 2011 05:27 · Поправил: PE_Kill
· Личное сообщение · #11

ARCHANGEL пишет:
К тому, что в результате таких преобразований наступает момент, когда теряется возможность отделить мусор от немусора, т.к. нельзя сформировать чёткие правила.

Это заблуждение, т.к. такое возможно лишь при высокоуровневой мутации, да и то очень ограниченно, чего в вашем посте нет.

На примере кода, который является конечным, всё деморфится банальным обратным анализом, грубо, но работать будет. Т.е. если полностью дизассемблировать блок и идти, от ret назад, то:

Первый проход:
Code:
  1. nop ;push eax/pop eax
  2. xchg ecx,eax ;push ecx/mov ecx,eax/pop eax
  3. push ecx
  4. mov ecx,eax
  5. xchg eax,edx ;push eax/mov eax,edx/pop edx
  6. xchg eax,edx
  7. mov dword ptr [esp],0
  8. pop eax
  9. nop ;pushfd/popfd
  10. add eax,2
  11. inc eax
  12. dec eax
  13. dec eax
  14. retn

Второй проход:
Code:
  1. xchg ecx,eax
  2. push 0 ;push ecx/mov dword ptr [esp],0
  3. mov ecx,eax
  4. nop ;xchg eax,edx
  5. nop ;xchg eax,edx
  6. pop eax
  7. add eax,2
  8. inc eax
  9. dec eax
  10. dec eax
  11. retn

Третий проход:
Code:
  1. nop ;xchg ecx,eax/mov ecx,eax
  2. mov eax,0 ;push 0/pop eax
  3. add eax,2
  4. inc eax
  5. dec eax
  6. dec eax
  7. retn


Далее подключаем оптимизатор, кодить не сложнее чем деморфер, учитывать только разных конструкций больше. Еще раз, это просто грубая модель.

-----
Yann Tiersen best and do not fuck





Ранг: 331.1 (мудрец), 561thx
Активность: 0.190.06
Статус: Участник

Создано: 18 ноября 2011 08:27
· Личное сообщение · #12

ARCHANGEL
Внимание, вопрос - есть ли способ такое заломать после 1000 проходов пермутации?

Можно утвердительно ответить, что способы есть, если вопрос касается только мутации, но не виртуализации - и здесь не нужны никакие шаблоны, всё делается статическим анализом стека, регистров, флагов и условий переходов (если, конечно мутатор умеет вставлять ложные переходы). Говорили про графы, но для решения этой задачи их строить и решать необязательно есть более простой способ деобфускации - N проходов по коду на каждом из которых посредством анализа состояний регистров (USE, CHANGE, INIT) и отслеживания вершины/содержимого стека вырезаются лишние инструкции с сохранением логики работы кода. N ограничено и не будет превышать кол-во проходов мутатора/обфускатора.
Эта логика реализована в VMSweeper и успешно работает...

-----
Everything is relative...




Ранг: 47.7 (посетитель), 17thx
Активность: 0.090
Статус: Участник

Создано: 18 ноября 2011 08:34
· Личное сообщение · #13

Vamit

> для решения этой задачи их строить и решать необязательно есть более простой способ деобфускации - N проходов по коду

Граф трассируется для этой цели, это раскрытие ссылок. Иначе каждую инструкцию прижётся вновь дизасмить, также и весь код. Например на одном из проходов нужно определить ссылку на процедуру или есчо какуюто инфу не связанную с текущей инструкцией - придётся вновь весь код анализировать, а это нормально не решается, получится ацкая рекурсия, на которую и стека может не хватить. При изменении любой инструкции придётся пересчитывать все ветвления, в графе ничего не нужно пересчитывать. Таких нюансов слишком много, по мойму без графа сие не решается в принципе, по любому нужно гдето хранить инфу связанную с инструкциями.




Ранг: 793.4 (! !), 568thx
Активность: 0.740
Статус: Участник
Шаман

Создано: 18 ноября 2011 09:24
· Личное сообщение · #14

bowrouco пишет:
Таких нюансов слишком много, по мойму без графа сие не решается в принципе, по любому нужно гдето хранить инфу связанную с инструкциями.

Тут под графом имеется ввиду группировка инструкций, разбиение на блоки, дробление и прочее. Вот это, в данном случае делать вовсе не обязательно. А инструкции естественно нужно где то хранить, в моем примере достаточно массива с указателями на инструкции, т.е. даже не связный список.

-----
Yann Tiersen best and do not fuck





Ранг: 2014.5 (!!!!), 1278thx
Активность: 1.340.25
Статус: Модератор
retired

Создано: 18 ноября 2011 10:04
· Личное сообщение · #15

Выложи большой кусок, а лучше файл, в студию-и будет видно, разморфят обратно или нет.
Как вариант-предложить 50 баксов за разморф
Лично я ничего сложного тут не увидел, всё достаточно тривиально.



Ранг: 590.6 (!), 408thx
Активность: 0.360.18
Статус: Модератор

Создано: 18 ноября 2011 13:10
· Личное сообщение · #16

ARCHANGEL
Если не даны ни начало блока ни его размер - то нечего и анализировать. Любой анализ начинается с ЕП. Для достаточно большого участка кода даже начало не имеет большого значения. Просто на выходе получишь кусок мусора в первом блоке.

-----
старый пень




Ранг: 47.7 (посетитель), 17thx
Активность: 0.090
Статус: Участник

Создано: 18 ноября 2011 19:52
· Личное сообщение · #17

PE_Kill

Вы товарищ в этом вопросе полный нуб. Также как и про вопрос с WriteConsole(). Незачем писать если ничего не понимаете, набивать себе какойто рейтинг бессмысленно.




Ранг: 681.5 (! !), 405thx
Активность: 0.420.21
Статус: Участник
ALIEN Hack Team

Создано: 19 ноября 2011 02:10
· Личное сообщение · #18

В общем, ситуация мне ясна, всем отписавшимся - спасибо. Основную идею я уловил, дальше, полагаю, обсуждать нечего, потому тему прикрою, ибо может начаться дискуссия, отличная от задуманной первоначально. Если появится какая-то дополнительная информация - порошу, чтоб открыли топик.

-----
Stuck to the plan, always think that we would stand up, never ran.



 eXeL@B —› Программирование —› Несколько слов про обфускацию
Эта тема закрыта. Ответы больше не принимаются.
   Для печати Для печати