Maximize
Bookmark

VX Heavens

Library Collection Sources Engines Constructors Simulators Utilities Links Forum

"DELAYED CODE" technology (version 1.1)

Z0mbie
Top Device Online [10]
Октябрь 2000

[Вернуться к списку] [Комментарии (0)]

Введение

Итак, мы написали вирус. Будет написан антивир, и через некоторое время все инфицированные компьютеры будут вылечены. Эта статья о том, как увеличить продолжительность этого периода.

Идея

Вставим в вирус "изменяющий код", то есть код, который сработает, скажем, через два месяца, и изменит некоторые команды около вирусной точки входа (и/или любые другие характеристики вируса). В результате чего изменится контрольная сумма, и вирус перестанет определяться.

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

Существует только один способ запретить анализ "изменяющего кода" - скрыть его от всех. И есть следующие реализации этого способа:

  1. Ждать получения изменяющего кода из Интернета, либо зашифровать код и ждать получения ключа расшифровки.
  2. Зашифровать код так, чтобы его расшифровка заняла как раз требуемое время, например обозначенные выше два месяца. ("delayed code")

Как можно видеть, последний вариант позволяет написать полностью автоматический вирус со скрытыми свойствами.

Теория (кривая хрень, использовать которую мы на самом деле не будем)

Извратим буфер из случайных чисел A[] некоторым хэшируем алгоритмом столько раз N, чтобы это заняло некоторый период T. В результате чего получим буфер B[], который и будет использоваться для шифровки/расшифровки "отложенного" кода.

Отметим, что эти N итераций никак нельзя распараллелить на несколько компьютеров, так что минимальное время шифровки/расшифровки будет ограничиваться только максимальной скоростью процессора.

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

Итак, все свое свободное время вирус будет посвящать зашифровке буфера A[], пока он не превратится в B[]. После того, как на шифровку будет потрачено N итераций (время T) полученным буфером B[] будет расшифрован "отложенный" код. Ну и запущен, само собой.

Теория (теперь правильная)

Основная проблема предыдущих рассуждений в том, что преобразование A[] в B[] и у нас и у вируса занимает одинаковое время. А мы не хотим тратить пару месяцев своего времени на всякую хуйню.

Так что будем использовать RSA. Тот самый хитроизъебский алгоритм, который используется в PGP. Основное его достоинство в том, что шифровка и расшифровка производятся с использованием разных ключей.

Итак, сгенерим рандомный буфер A[] и зашифруем им наш код. После чего N раз зашифруем A[] и получим B[]. Теперь, в отличие от описанной ранее шифровки хэширующим алгоритмом, вирус будет повторять отнюдь не ту же самую операцию. Вирус будет расшифровывать буфер B[] обратно в A[].

В шифровании будет использован маленький ключ, а в расшифровании - большой. Это значит что расшифровка займет во много раз больше времени, чем зашифровка. Например пара часов у нас, и несколько месяцев у них.

Зависимость времени шифрования и расшифрования

Здесь задача такая: вычислить, сколько времени T (или итераций N) нужно потратить на зашифровку, чтобы на расшифровку пришлось, скажем пара месяцев.

Как вы знаете, шифрование алгоритмом RSA выглядит так:

	шифровка:    encr = (text ^ e) % m
	расшифровка: text = (encr ^ d) % m
	где {e,m} и {d,m} - открытый и закрытый ключи.
	('^' означает возведение в степень,
	'%' означает модуль, или же остаток от деления)

Как правило, число e маленькое, например 3, 17, 50003 и так далее. А вот число d весьма нехилое, состоящее из например 1023х бит.

В нашей схеме шифрования не будет таких понятий как открытый/закрытый ключ, числа d и m - открытые, а чему равно e несложно догадаться. Вот наша схема:

Шифровка (шифруем "изменяющий код", у себя дома)Расшифровка (расшировка "изменяющего кода", на инфицированных машинах)
  • A[] <-- любые данные
  • шифруем код буфером A[]
  • x = A[]

    N раз: x = (x ^ e) % m

    B[] = x

  • сохраняем буфер B[] в вирусе
  • x = B[]

    N раз: x = (x ^ d) % m

    A[] = x

  • расшифровываем код буфером A[]

Далее расмотрим процедуру 'modexp'.

// modexp:   возводит в степень и возвращает модуль
// действие: x = (a ^ e) % m

void modexp(bignumber& x,   // выход
            bignumber a,    // вход
            bignumber e,    // степень
            bignumber m,    // модуль
{
    x = 1;
    bignumber t = a;
    for (int i = 0; i <= MaxBit(e); i++)
    {
       if (e.GetBit[i] == 1)
          x = (x * t) % m;        // modmult()
       t = (t * t) % m;           // modmult()
    }
}
 

Как можно видеть, modexp() вызывает процедуру modmult() (e.#bit + e.#bit1 - 1) раз. (-1 взялась оттуда, что самое последнее умножение не происходит; хоть это и не показано в приведенной подпрограмме) Задачей подпрограммы modmult() является умножить два числа и вернуть результат по модулю. Короче говоря, число вызовов процедуры modmult() пропорционально времени шифровки и расшифровки. Отсюда:

Decr.time = Encr.time * (D.#bit+D.#bit1 - 1) / (E.#bit1+E.#bit1 - 1) * K где:

#bit
общее количество бит в D или E
#bit1
количество единичных бит (принимая число за рандомное, можно сказать что их половина. хотя в дальнейшем будем их подсчитывать для конкретных ключей)
#bit + #bit1 - 1
общее число вызовов modmult()
K = 0.9+-10%
Коэффициент, появился из-за того, что каждый modmult() выполняется переменное время, плюс там всякая оптимизация. По видимому, при N-->oo K-->1

Пример

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

Во-первых, сделаем RSA ключ. Пусть это будет 1024-битный ключ, e = 3. Выполняем: 'KEYGEN.EXE KEY\DPGN 1024 3 3' Параметры полученного ключа: 1024-bit N, E==3, D=1023-bit/519*'1'

Пропорциональность времени шифровки/расшифровки (в теории): ratio = (1023+519-1)/(2+2-1)*0.9 = 462+-10%

Но мы хотим большую точность, так что проведем пару вычислений, так сказать оттарируем ключ.

    Выполняем: 'DGPGN.EXE e 100'
    результат: 100 итераций, время шифровки = 815 мс
    Выполняем: 'DGPGN.EXE d 100'
    результат: 100 итераций, время расшифровки = 360228 мс

    ratio = 360228/815 = 441

Теперь посчитаем N для 10-минутной расшифровки.

Если 100 итераций расшифровки занимают 360228 мс, а N итераций должны занять 10*60*1000 мс (10 минут), то N = 60*10*1000 * 100 / 360228 = 167

Если 167 итераций расшифровки должны занять 60*10*1000 мс, то время шифровки = 60*10*1000 / 441 = 1360 мс.

Таким образом чуть больше секунды шифровки потребуют расшифровки в течение 10-ти минут.

Проверим.

    Выполняем: 'DPGN.EXE e 167'
    время шифровки: 1268 мс
    Выполняем: 'DPGN.EXE d 167'
    время расшифровки: 600477 мс = 10 минут 0.5 секунд

Некоторые другие результаты: (пропорциональность времени верна только для этого ключа)

РасшифровкаШифровкаN (1024х-битный ключ)
K5-100Celeron-500
10 min 1.3 sec 167 950
1 hour 7.8 sec 1000 5700
1 day 3 min 24000 136800
1 week 21 min 168000 957600
1 month 1.5 hour 672000 3830400
1 year 18 hours 8064000 45964800
16 months 1 day    
10 years 1 week    
40 years 1 month    

Как увеличить скорость вычислений

Алгоритм расшифровки 'text = (encr ^ d) % m' может быть представлен так:

a = ((encr % p) ^ dp) % p            // dp = d % (p-1)
b = ((encr % q) ^ dq) % q            // dq = d % (q-1)
if (b < a) b += q
text = a + p * (((b - a) * u) % q)       // u: (u * p) % q = 1

Таким образом время расшифровки будет увеличено в несколько раз. Но мы публикуем только d и m, и я не знаю, можно ли с их помощью найти p и q.

Как замедлить скорость вычислений

Поскольку d не является уникальным ключом, а некоторые его варианты могут быть вычислены по формуле:
d' = d + (p-1)*(q-1) * t, где t=0,1,2,...,
то можно увеличить d до необходимой длины, тем самым замедлив скорость вычислений в десятки раз.

Однако тут все упирается в следующее: смогут и станут ли те, кто хочет произвести DPGN-расшифровку быстрее всех остальных, найти p и q, зная d'. Если смогут, то они вычислят оригинальное d, и тогда их расшифровка будет произведена в те же десятки раз быстрее, что нежелательно.

Остальные фичи

  1. На практике, совсем не нужно хранить число итераций N, достаточно будет простой CRC. Таким образом никто не будет знать, что ЭТО такое и когда ОНО будет запущено. Также, следует добавлять к N некоторый случайный элемент, не делая его кратным например 1000 и не делая время расшифровки кратным например одному дню.
  2. Я не уверен, но - может быть - операция {N раз: x = (x ^ d) % m} может быть заменена на что нибудь более быстрое (не p и q), используя какую-нибудь извращенную математику или что-то, чего я не заметил. Чтобы такого не произошло, можно ввести дополнительную шифровку между вызовами modexp()а, например проксорить (ну а что ж еще):
    N раз:
    {
    	x = (x ^ d) % m;
    	x = x xor <что-нибудь>;
    }
    

    Программа DPGN.EXE ксорит всего пару двордов, но этого хватит.

Использование "отложенного кода" (что криптовать?)

[Вернуться к списку] [Комментарии (0)]
deenesitfrplruua