Pull to refresh

Comments 25

Очень давно (больше 20 лет назад) я написал интерактивный дизассемблер, подобный IDA — с возможностью тегирования любого байта кодового сегмента (код, данные [со спецификацией простых и сложных типов и указателей на них], неопределенный, подозрительный) и атрибутами (точка_входа, процедура, потеря_управления). Можно было запускать пробный анализ с любой точки, а также видеть набор инструкций с произвольным смещением относительно текущего блока любого типа — то есть, можно было посмотреть интерактивный листинг, скажем со смещения +1 прямо рядом с основным. Этот тул был сделан для однокристальных МК, которые, конечно, колятся несравнимо легче, чем современные «большие» процессоры, но имхо ручной анализ кода после подозрительных мест — а это прерывание дерева исполнения, скажем процедурой (выход из нее может подменять адрес возврата в стеке), индексного джампа или прямого колдовства со стеком — сможет распознать неадекватность хотя бы по обращению по бесмыссленным адресам или странной побочной логике выполнения набора инструкций со смещением. Здесь для инженера-реверсера главное — догадаться, что стеганография имеет место быть в этом бинарном куске, хотя бы по одному подозрительному месту. Дальше уже дело техники — можно и тул написать, который облегчит выуживание параллельных цепочек
Наверное я не очень понимаю, но:

— Дизассемблеры и так постоянно 'пускаются по ложному следу', при дизассемблировании именно этот параметр на постоянном контроле, и навык опознавания такого момента у хакеров хорошо развит.

— Против трассировки такая обфускация (и наверное любая другая, любое однопоточное решение) никак не поможет, а значит сводит результат всех усилий к нулю.
Эх, часто данную технику использовали не для запутывания, а во всяких Hugi Size Coding Competition. Вот там были неимоверные шедевры!
натыкался в IDA на подобный код — обнаруживается по странных джампах на срединьі инструкций. Если отменить то, что дизасемблировала сама ІДА и указать ей началом инструкции место джампа, то получается совсем другой код. Даже проникся уважением к написавшему такой ювелирный код — но как защита оно никакое ;)
CMOVcc, пожалуйста уберите из списка и, если хотите, добавьте PREFETCHxxx (их довольно много разных).
Описанной технологии уж лет 20 как, может и поболее.

Если только не используются специальные программы, которые таким образом могут запутать достаточно большой кусок кода (а такие программы ранее точно были), то не надейтесь. А, впрочем, не надейтесь по-любому. :)

IDA Pro (а автор про нее, очевидно, знает) и скриптик, чтобы автоматизировать процесс — и все эти потуги успешно расшифрованы — достаточно только точку входа найти. А весь мусор можно просто скрыть, например заменив на лету теми же NOPами. И такому скриптику любой размер мусорного кода будет нипочем.

Высший пилотаж был бы использовать одни и те же байтовые блоки для двух реально используемых цепочек инструкций, чтобы если IDA показывает инструкцию одной цепочки, то одна или две инструкции другой цепочки — портятся. Но насколько мне помнится, такая дичь не встречалась. Да и это был бы просто вопрос чуть большего неудобства — пришлось бы дополнительные финты к IDA пристраивать…
Лучше уж придумать свой байт-код и виртуальную машину его испольнения. Как было (есть?) у HASPа и многих других. Мороки по анализу и раскодированию таких защит гораздо, на мой взгляд, больше.
Такие монструозные инструкции у меня всегда вызывают повышенный интерес, а уж NOP отличный от 0x90 абсолютно всегда.
Вот тоже хотел заметить, что 9-байтовый NOP — это довольно чёткое палево, особенно когда они все длинные (пусть и несколько рассеянные по коду). На самом деле я давно уже не ковырялся с дизасемблированием, но раньше мне никогда не попадалось никаких, кроме однобайтовых, отличющихся только длинной серии. Даже не подозревал о том, что другие существуют. Возможно современные компиляторы их используют активнее.
Интересен смысл их наличия. Это такой способ ускорить обработку, сведя 9 байт в одну команду вместо 9 (пусть и быстрых)?
Такие монструозные NOPы служат в целях отладки, чтобы не править десяток байт, а всего 3-4 закинуть. В релизной версии софта — пффф, General Failure, u haz biin detekted
В современных процессорах анализатор склеивает что 9 обычных, что один длинный, согласно StackOverflow, поэтому разницы нет. Появляется разница при работе со специфичными кристаллами.
Тогда тем более непонятно, зачем их вообще придумали.
Специфичные х86 — это которые?
Медленные, где тики на счету. Мопед не мой, я лишь интересовался этим вопросом, когда писал короткие патчи на ассемблере. www.ragestorm.net/blogs/?p=14
А открыть официальную документацию, где инглишем по белому написано как именно выбирать NOPы (и да, там целых три пункта и подробное объяснение «почему так») — не судьба, нэ?

Или вот статейка — там даже целый раздел есть «оптимизация NOPов» с графиками и цифрами.

Всё-таки не стоит забывать о том, что Stack Overflow — это таки свалка, где кто угодно может писать что угодно…
Например, студийный компилятор использует многобайтовые nop (я встречал пятибайтовые) для выравнивания кода.
О, а с какими флагами он это делает?
Не знаю как в студии, но в GCC он это делает всегда, когда вы компилируете под Pentium Pro или новее. То есть сегодня — почти всегда.

Просто потому что многобайтные nop'ы быстрее. Но он всегда использует нули в DISP.
Анализ подобного кода это скорее базовое упражнение для человека изучающего возможности любого вменяемого дизасемблера, нежели серьезный прием по затруднению анализа кода. Даже дедушка hiew позволял задавать разные точки входа.
Кстати, что сейчас модно вместо hiew? Лучше под линукс.
Хмм, а часть функционала от radare2 вам пойдет?
К слову о beye. Последняя версия из svn не собирается, ну и вообще sourceforge та ещё площадка.

Выложил на github'е репу со всей историей изменений, в мастере оставил последнюю собирающуюся на современных дистрах версию, все последующие изменения вынес в отдельную ветку (lastest_svn), исходники релиза 6.1.0 с sourceforge тоже в отдельную ветку положил.

В общем, если у кого-нибудь будет настроение поэкспериментировать с ним — удобнее всего начать отсюда:
github.com/unxed/biew
Hiew под линуксом запускается через wineconsole и работает, хоть и не растягивается на весь экран. :(
К подходу, как отметили выше, интерес сугубо академический: при всех усилиях на сокрытие стойкость к анализу низкая. Потому что на стороне взломщика играет энтропия :)
Этот же подход неплохо описан в этой бумаге: Obfuscation of Executable Code to Improve Resistance to Static Disassembly, раздел junk insertion.

Авторы отмечают одну интересную особенность: «само-лечащийся дизассемблер» (self-repairing disassembly). Дизассемблер может встретить несколько «мусорных» инструкций, но рано или поздно он вернется на верный трэк.
Кроме того, этот метод имеет разное влияние на разные дизассемблеры. В случае линейного алгоритма неверно распознаны в среднем 39% инструкций, а в случае рекурсивного алгоритма — 25%.

Ну и конечно непонятно как этот подход по мнению VolKarev помогает в случае динамического анализа.
Sign up to leave a comment.

Articles

Change theme settings