Публично доступные фильтры работают чисто на E8 практически. В коде x86/x64 в некоторых случаях записывается адрес относительно текущей позиции, (инструкции CALL/JMP в основном) и получается, что вызов одной и той же функции в разных местах кодируется по-разному, т.е. даже если блок кода совпадает, с этим вызовом, то полного матча не будет. В общем, называется это "фильтр E8", пошло в оригинале от cab/LZX и сейчас везде - rar, bcj в 7z и т.п. Потом я с этим экспериментировал и написал flt32, из которого Павлов сделал bcj2. Там в общем-то суть та же, но адреса из коллов и т.п. выдираются в отдельные потоки, т.е. вообще не сжимаются в контексте вызова - без требования совпадения адреса совпадает больше паттернов кода. Ну и у меня были дополнительные идеи, типа смещение в add esp,xxx после колла кодировать вместе с адресом. Потом Дима Шкарин посмотрел на flt32 и запилил таки фильтр на основе дизасма. Смысл в том, что так можно _все_ левые константы убрать в отдельные потоки, включая регистры. http://compression.ru/ds/disasm32.rar http://nishi.dreamhosters.com/u/disasm32_sh0.rar В общем, сейчас есть три более-менее дизасма - в шкаринской дурилке, nosso и winrk, но все три закрытые коммерческие (Шкарин выложил только заготовку, она сжатие не улучшает). Потом появились и опен-соурс реализации, например "dispack" из kkrunchy ( http://encode.ru/threads/557-disasm-based-executable-s-filter ) и chromium/courgette (это дифф/апдейтер от хрома). Однако, к сожалению, dispack устарел (нет поддержки x64 и новых векторных расширений), да и по фактическому алгоритму работы он не слишком лучше, чем bcj2. Courgette более интересен, т.к. там в свежих версиях есть поддержка x64 и даже arm, но собственно алгоритм препроцессинга там даже хуже dispack, а код написан с использованием STL и новых фич C++, так что для непосредственного использования непригоден (динамическая аллокация крайне нежелательна при работе любых кодеков - она тормозит, и приводит к побочным эффектам типа фрагментации памяти, которые потом требуется отдельно обрабатывать). Впрочем, задачи же есть и помимо экзешных фильтров. Есть много задач, где точный дизасм актуален - реверсинг, те же защиты, разного рода преобразования кода. Например, интересно было бы транслировать старые win16 программы в COFF32 - по апи они совпадают, просто поддержку 16-битного кода MS дропнули. Или, аналогично, преобразование x86 кода в x64. Есть много случаев, когда какая-то либа только в 32 битах, а приложение в целом пора бы уже портировать. Большие проблемы в иде при сравнении версий программ. Там как бы есть сигнатуры для таких задач, но они бедные по функционалу (фактически можно только метки расставить), и в них переменные только адреса, код самих инструкций вбивается как константа, т.е. включая регистры. Поэтому применимо это только для бинарных либ, причем для каждой версии либы надо заново сигнатуры генерировать. В общем, до сих пор нет решения, чтобы если ты одну версию программы в той же иде уже разобрал, то в новую версию можно было всё совпадающее по структуре сразу переносить. Короче, нужен хороший дизасм, чтобы: 1) сохранялась _вся_ информация о коде (асм от иды обычно невозможно автоматически скомпилировать в корректный код, даже если код без извращений - приходится руками допиливать); 2) был устройчив к фаззингу (т.е. пригоден для автоматической обработки любых данных); 3) были все современные расширения системы команд; и префиксы являются самой большой проблемой для меня, на данный момент, т.к. реально встречается сгенерированный компиляторами код инструкций с 3-4 префиксами, причем у разных компиляторов эти префиксы могут идти в разном порядке. Т.е. как минимум это точно надо предусматривать, т.к. префиксы влияют на декодирование инструкции в т.ч. И если слишком все упростить, то получится, что при парсинге какого-нибудь 66F2F2F2F2F2F2F2F2F2F2F2B80000 не учтешь самый первый префикс, декодируешь два байта следующей инструкции как часть константы в mov eax, и дальше съедет весь дизасм функции. В общем, в exe-фильтре это надо больше для уменьшения избыточности, т.к. некорректный препроцессинг рандомных данных как инструкций явно ухудшит последующее сжатие. Но в экзе-фильтре это и не смертельно - в любом случае, нужна будет возможность кодировать просто бинарные данные тоже, помимо кода. Собственно, существующие экзе-фильтры примерно так и работают - дизасм там очень неполный, но какой-то эффект есть и так. В т.ч. и поэтому хотелось бы новый дизасм делать более продвинутым - т.к. это не первая попытка, и в этой области есть уже конкуренты. Ну а для реверсинга, автоматической распаковки и т.п. задач, полная поддержка префиксов - это просто must have. Потому что защиты сейчас в рамках корректного кода что угодно могут сделать, и надо уметь это корректно трассировать. Теперь насчет префиксов в бинарной структуре. Тупая реализация будет выглядеть примерно так: - все относящиеся к инструкции префиксы (до 14 сейчас) сохраняются в структуре-дескрипторе инструкции; - в специальных полях указывается смещение актуальных инструкций каждого типа (их 5-6 разных типов, по несколько вариантов в каждом, например rep/repnz) - хз что делать, когда префикс используется как часть кода (например F3 90 = rep nop = pause) - актуальные префиксы дополнительно кодируются как флаги в дескрипторе (типа разрядности полей адреса и immediate) - при восстановлении инструкции из дескриптора, новые префиксы генерируются по флагам и вставляются в сохраненные позиции. Это сработает, но остаются проблемы. 1) возможны проблемы со старым кодом, где не было ограничения по длине префикса (а у меня есть такой код, в моих старых программах например); 2) возможны проблемы с будущими процессорами, если они вдруг решат увеличить максимальную длину инструкции до 31 байта скажем; (а это уже актуально - http://stackoverflow.com/a/18972014/395609 тут есть примеры корректных инструкций с кодом по 16 байт, т.е. они не будут работать, хоть и корректные - это тоже проблема для компилятора сейчас, т.к. есть случаи попроще с более осмысленным векторным кодом и несколькими префиксами, которые могут не влезть в 15 байт и вызвать падение программы, хоть код и корректный) 3) понадобится хранить 14 + 5(позиции актуальных) + 1 (длина строки префиксов) = 20 байт в дескрипторе каждой инструкции. Это примерно как вся остальная инфа по инструкции - т.е. расход памяти увеличивается вдвое при такой поддержке префиксов, при этом у большинства инструкций префиксов нет. Были идеи насчет сжатия строки префиксов (актуальные хранятся во флагах, значит уже 14-5=9, т.е. для x86 всего получается 9^11 вариантов, т.е. log(9**11)/log(256)=4.358 байт требуется для хранения), но префиксы REX/XOP/VEX/EVEX с x64 сильно портят картину (REX это коды 0x4?, 16 вариантов), а VEX вообще мультибайтные). При этом для REX написано "The use of multiple REX prefixes is undefined, although processors seem to use only the last REX prefix.", а с VEX непонятно, но есть впечатление, что их тоже можно повторять. https://en.wikipedia.org/wiki/VEX_prefix