ВЗЛОМXOR_KEY, между прочим, тоже следует сделать случайным.randomizeXOR_KEY = rndnum mod 0xFFКод перед морфингомd8d1 | fcom st0, st1d8c9 | fmul st0, st1d8d4 | fcom st0, st4d8ed | fsubr st0, st5d8d6 | fcom st0, st6d8c2 | fadd st0, st2Отлично! Теперь группируем, создаем макрос gen_trash, принимающийпараметром количество генерируемых инструкций. Улучшить этот макросможно, сделав параметром не количество инструкций, а максимальныйразмер в байтах. Еще лучшим ходом будет параметр, являющийся пределомслучайному количеству инструкций/размеру в байтах. Реализуемпервый, упрощенный, но немного уступающий другим вариант:macro gen_trash length {repeat lengthrandomizevariant = randseed mod VARIANTSif variant = 0gen_leaelse if variant = 1gen_fpuend ifend repeat}Теперь для генерации 10 случайных инструкций указываем в коде:gen_trash 10. Следует расширить этот макрос, что не составиттруда. Добавляй как можно больше инструкций\вариантов: ветвления;статистику повторения инструкций; порядок следования (кучаFPU-инструкций вперемешку с обычным кодом — это подозрительно,ты не находишь? Или десяток инструкций lea, идущих подряд? А бесконтрольныйгенератор вполне может творить такое). Идей в процесседолжно возникать великое множество — пробуй все, что придет вголову, не ограничивай себя. Теперь пара слов об использованиимакроса gen_trash. Сделаем простой расшифровщик, разбавленныймусором:gen_trash 15mov eax, .CodeStartUSEDREG1 = REAXgen_trash 27mov ecx, CodeSizeUSEDREG2 = RECXgen_trash 20.again:xor byte[eax], XOR_KEYgen_trash 37inc eaxgen_trash 10loop .againgen_trash 43058При большом количестве мусора и при достойном его качестве не такпросто будет разобраться, что же в коде происходит, и как отделить егоот мусора. Улучшить генератор можно, добавив работу с локальными\глобальными переменными, различные переходы, ветвления, процедуры,различные варианты инструкций, сложные инструкции видаlea eax,[ ecx*4+100 ]... Но — главное!.. Самое главное — не забывай,что код должен быть схожим с генерируемым нормальным компилятороми одновременно хитрым, запутанным. Изучи частоту повторенийинструкций в распространенных или входящих в состав операционнойсистемы программ, а затем примени эту статистику в своем генераторе.0XACED1A ÀÍÒÈÎÒËÀÄÊÀНи одна защита кода просто не представляется без антиотладочныхтрюков. Добавим и мы, но будем хитрее. Сделаем вставку случайногоантиотладочного трюка в случайном месте, то есть просто добавим кмакросу gen_trash, и трюк будет генерироваться наравне с инструкциями.Простой пример — если отладчик обнаружен, выполняетсяпереход на случайный адрес в пределах секции кода.macro adbg {randomizevariant = rndnum mod Nrandomizedestination = (rndnum mod ((ENTRY_POINT + 0x1000)- ENTRY_POINT)) + ENTRY_POINTif vatiant = 0invoke IsDebuggerPresenttest eax,eaxjnz $+destinationelse if variant = N.....}Также трюки следует разбавлять мусором. Добавляй больше антиотладки— больше сюрпризов исследователю.0XACE ÈËÈ ÐÀÍÄÎÌÈÇÀÖÈß API-ÂÛÇÎÂÎÂПомимо бинарного мусора, код следует сделать высокоуровневым.Вполне послужит для этого Windows API. Функции могут не нестисмысла, а могут быть и неотъемлемой частью программы. Простойпример вставки случайного API-вызова:macro gen_trash_api {randomizeRandomParam1 = rndnum mod 0xFFFFFFFFrandomizeRandomParam2 = rndnum mod 0xFFFFFFFFrandomizevariant = rndnum mod 4if variant = 0invoke IsBadReadPtr,RandomParam1,RandomParam2else if variant = 1invoke IsBadWritePtr,RandomParam1,RandomParam2else if variant = 2invoke IsBadCodePtr,RandomParam1else if variant = 3invoke GetLastErrorend if}Не стоит забывать, что API-функции не сохраняют регистры Eax, EcxXÀÊÅÐ 08 /139/ 10
Обфусцированный movКод после морфингаи Edx. Сохраняй значения этих регистров, если в них содержатсяи используются важные значения. Вставим вызов этого макроса вgen_trash. Подключи фантазию; вызовы функций не обязательнодолжны быть одиночными, высокоуровневый мусор должен взаимодействоватьс бинарным — не подкопаешься. Неплохо будет эмулироватьнекоторые функции, то есть реализовать их код у себя. Вызов илииспользование своего кода являются вариантами, пример:macro GetLastError {rndvariant = rndnum mod 2if variant = 0mov eax,[fs:18h]mov eax,[eax+TEB.LastError]else if variant = 1invoke GetLastErrorend if}0XA11A5, ÈËÈ ÌÅÒÀÌÎÐÔÈÍÃМетаморфинг я реализовал как замену инструкций своими функциональнымианалогами. FASM позволяет переопределять инструкциимакросами, что очень удобно. Возьмем, к примеру, инструкцию movreg32_1, reg32_2. Какие могут быть аналоги? Первое, что приходит вголову (вообще их можно придумать великое множество):push reg32_2pop reg32_1push reg32_2mov reg32_1,[esp]add esp,4push reg32_2xchg reg32_1,reg32_2pop reg32_1Примени фантазию, не следуй шаблонам, и за небольшой промежутоквремени можно будет написать достаточное количество аналогов длявсех инструкций. Напишем макрос, переопределяющий инструкциюmov. Обязательно проверяем, что аргументы являются регистрами, таккак у нас есть замена только этого варианта:macro mov arg1,arg2 {if (arg1 eqtype eax) & (arg2 eqtype eax)rndvariant = rndnum mod 4if variant = 0push arg2pop arg1else if variant = 1}Проверяем:push arg2mov arg1,[esp]add esp,4else if variant = 2push arg2xchg arg1,arg2pop arg2else if variant = 3mov arg1,arg2end ifelsemov arg1,arg2end ifmov eax,ecxmov ecx,ecxmov edx,espИтог:51 | push ecx91 | xchg ecx, eax59 | pop ecx89e5 | mov ebp, esp53 | push ebx59 | pop ecxЗамечательно, не правда ли? Добавив как можно больше инструкцийи вариантов замены, можно добиться замечательных результатов.0XAB1E, ÈËÈ ÏÅÐÌÓÒÀÖÈßЗдесь все тоже предельно просто и дает мощный результат. Нам нужноизменить расположение некоторых блоков кода без изменения функциональностии без повреждения кода. Для начала за блоки возьмемпроцедуры, далее эти блоки следует максимально уменьшить. Надспособом случайного изменения блоков кода я недолго думал, возможно,есть более изящное решение — подумай. Суть такова: каждую процедуруоборачиваем в макрос, создаем для нее переменную — флаг,сигнализирующий об использовании, дабы не вставлять процедурынесколько раз. Например (пермутируем три процедуры, скелет), кодглавной структуры теперича выглядит так:fproc_1 = 0fproc_2 = 0...entry $;êîä ãëàâíîé ïðîöåäóðû...while (flag_1 = 0) | (flag_2 = 0)randomizesequence = rndnum mod 2if sequence = 0if flag_1 = 0proc_1XÀÊÅÐ 08 /139/ 10 059