![]() |
Всем привет!
Когда-тоя началразговор о том, как развлекалось наше старшее поколение, какие придумывали техники обхода дизассемблеров, и как противостояли отладчикам. Сейчас вот выбралось пару свободных деньков и решил продолжить эту тему, собрав в ней наиболее интересные на мой взгляд моменты. Не нужно сбрасывать со-счетов старые финты программирования – на их основе и сейчас создаются крепости, поскольку любые идеи имеют тенденцию заканчиваться, а ничего нового большинство из нас придумать не в состоянии. 1. Самомодификация кода Система MS-DOS была колыбелью ныне могущественной империи Win. Она выгодно отличалась тем, что предоставляла программистам полную свободу действий, т.к. защита любого уровня в ней отсутствовала как сущность. Вплоть до Win2K это была поистине золотая эпоха, с благоприятной почвой для самовыражения. Вирусы и прочая нечисть плодилась с первой космической скоростью, а программисты закинув ноги на стол старались удивить друг-друга доселе невиданными идеями. (чего только стоит один червь Морриса, который в 88-году заразил чуть-ли не добрую половину сети ARPANET). Именно в то время разум гомосапиенса придумал первые стелс-вирусы, начал применять полиморфные движки, криптографию, и многое другое. Отдельную нишу в этом котле занял и код, который модифицировал сам-себя. Несмотря на то, что техника требовала хороших знаний формата команд процессора, нервов и огромной самоотдачи – результат того стоил. Наблюдая как код мутирует прямо на глазах в реальном времени, антивирусы сходили с ума и полностью отказывались предпринимать какие-либо попытки анализа. Чтобы хоть как-то взять ситуацию под контроль, аверы стали применять эвристику, на которую хакеры тут-же нашли управу. Самомодификация это то направление, зубрить которое не имеет смысла. Тут главное понять суть и предоставляемые процессором возможности, а дальше можно будет на автомате творить весьма интересные вещи. Поскольку тему невозможно охватить всю и сразу, то здесь мы возродим лишь парочку забытых идей. https://forum.antichat.xyz/attachmen...95f37ee16c.png На рисунке выше представлен формат инструкций современных процессоров х86-32/64, где только поле "Код операции" является обязательным, а остальные могут отсутствовать в инструкциях. Размер опкода пляшет в диапазоне 1..3 байта, и в клинических случаях хвост его может торчать даже в соседнем поле "Mod-R/M". Как правило, 2..3-байтными опкодами кодируются инструкции SIMD, поэтому на данный момент они не интересны – нам будет достаточно взять на вооружение формат 1-байтного кода операции, на карту которого указывает красная стрелка. Как видно из деталей битовой карты, младшая тетрада опкода достаточно творческая, и в ней закодировано аж 5 определений. В зависимости от типа инструкции, младший бит[0] задаёт размер операндов – если он сброшен в нуль, значит операнды размером 1-байт, и соответственно единичное его состояния указывает на 2 и более байтный операнд (word, dword, qword). Три младших бита[2:0] кодируют 8 регистров общего назначения РОН: Код: Код:
Инструкция Код HEX Опкод BINКод:
JZ, JS, JBC-подобный: Код:
startОбратите внимание, как в условных инструкциях кодируется адрес перехода. Команды этого типа могут совершать прыжки только в пределах 127-байт, что кодируется всего одним байтом (в данном случае 06,04,02,00) –это адреса относительно текущего. Если переход осуществляется вперёд, под его адрес отводится младшая половина байта в диапазоне от 00h до 7Fh, а это как-раз макс.127. Если-же прыгаем назад, то для адресации используется уже старшая половина 80..FFh (байт со-знаком). В случае, когда нужен условный прыжок выше этого порога, придётся использовать безусловный JMP, который может отправить нас хоть в космос. 1.0. Бит направления Однако более широкий интерес для самомодификации предоставляет поле "Направление" в опкоде – под него выделен бит[1]. Оно введено инженерами Intel для обозначения операнда-приёмника: нулевое значение присваивает результат правому операнду, а единица – левому. Так, манипулируя этим битом при помощи Код:
OR/ANDC-подобный: Код:
;Основное условие при написание самомодифицируемого кода, это доступ к "секции-кода" на запись. Здесь нужно отметить, что в этом нет ничего криминального, и антивирусы никак не реагируют на это обстоятельство. В наше время софт разбух до таких размеров, что программисты сжимают и упаковывают все свои продукты, а чтобы при старте потом его распаковать, секции-кода по любому требуется доступ на запись. Если-бы аверы обращали на это внимание, то в природе не осталось-бы ни одного софта. 1.1. Бит направления при операнде с непосредственным значением Ладно.. теперь мы знаем, что бит[1] направления, способен менять операнды местами. Но рассмотрим другую ситуацию, когда один из операндов регистр (или память), а второй – непосредственное значение. Ясно, что это значение не может быть приёмником, например инструкция Код:
ADD EAX,0x55Код:
55hКод:
0x00000055Когда операнд = значение, единичное состояние этого бита отсекает нули слева, в результате чего мы экономим как минимум 1-байт, а в лучшем случае целых 3-байта. Радует то, что все современные компиляторы осведомлены об этом нюансе, и по умолчанию взводят бит[1] в опкоде инструкции. Однако если его умышленно сбросить в нуль, то процессор не дополнит значение Код:
55hКод:
ADD EAX,55hКод:
55hКод:
55hКод:
0x22334455C-подобный: Код:
sectionОбратите внимание на опкод(83h) по адресу Код:
0x0040200dКод:
ANDКод:
81hКод:
ADDКод:
0x2233442. Прячем код от дизассемблеров В те далёкие время приличный дебагер был роскошью, и всё на что могли рассчитывать кодокопатели – это штатный debug.com, или в лучшем случае "TurboDebugger". Правда позже появился более приличный "AVP-Util" от аверов из лаборатории Касперского, но и он мог отлаживать только досовские приложения. Дела поправились лишь с приходом классики всех времён и народов "Soft-Ace". Таким образом, основным оружием были дизассемблеры типа "Hiew", которые не отлаживали приложения, а лишь предоставляли взору его код. Одним из запоминающихся способов сокрытия исходника от посторонних глаз предложил вирус под названием CALL.243 (в младенчестве JUMP.466), который прятал полезную нагрузку в адресах переходов. Он был прост до неприличия, зато кроме инструкций Код:
CALLИнструкция Код:
CALLКод:
FF15hКод:
Е8hhttps://forum.antichat.xyz/attachmen...5de7be5d7f.png Теперь, если взять один реальный Код:
CALLКод:
XOR BYTE[EDI],77h + INC EDIКод:
CALLВ примере ниже, в качестве адреса реального вызова я использую текущий($) + смещение, которое получается(6). Так осуществляется вызов следующей инструкции Код:
CALL $+6C-подобный: Код:
@@C-подобный: Код:
format pe console3. Заключение Качество кода имеет различные метрики – в некоторых случаях нужно стремиться к его оптимизации, а в некоторых наоборот приправить так, чтобы не оставить взломщику никаких шансов. Старшее поколение программистов оставило нам огромный багаж знаний, а представленные здесь примеры лишь капля в этом океане. Однако опыт приобретается не сразу, а со-временем по таким вот мелким наякам. На сегодня это всё, о чём я хотел сказать, удачи пока! |
Вот прям идеально, запрос посланный в космос пришёл в виде твоей статьи!)) как раз читаю хакинк: искусство эксплоита, и там ассемблер разбирается . Надеюсь мои капельки все воедино соберутся, а потом из ручеечка получится что то типа Байкала, чистое и глубокое знание. Спасибо за статью! Жду еще
|
Да, asm прикольная вещь, и хоть я на нем писал не под х86, а под avr, но все же. Очень заставляет трепетно к битам относится, а так же позволяет из подпрограммы (вызов call) не только возвращаться в вызывающий участок кода (вызов ret), но и уходить в совершенно далёкие и абсолютно другие дебри (через jmp).
|
Как всегда очень интересно вас читать! Очень много интересных идей и знаний я открыл благодаря вам! Спасибо, буду ждать ваши статьи!!!
|
| Время: 09:56 |