Безопасность в Дельфи

       

Проект "АнтиКрэковые Мучения"


Шифрование кода. Часть II
Раздел "Анти крэковые мучения"
Шифрование кода. Часть I
Дмитрий Логинов ,
дата публикации 23.05.00

Здорово жентельмены и всевозможные миссисы.

Шутка! Просто раз уж "Королевство", то должны быть и жентельмены, не считая фаворов. Ну ладно, к делу. Что-то давно я не бывал в Королевстве. Вот смотрю о чем люди спорят. Интересные темы. Жаль только, что никто ничего не прислал в "АКМ". Я думал, раз много заинтересованных, то будет много приемов и исходников. Не видать. Наверно, все-таки это не так интересно. Но свою лямку я дотяну. В прошлый раз я привел пример с шифровкой формы. Наверно были те, кто компилил этот проект. Надеюсь, ни у кого не отформатировался винт. Цель была в том, чтобы исходники были читабельны. Т.е., передающие смысл этого приема. Этот смысл был не в том, чтобы написать не ломаемую прогу (это невозможно). А в том, что перед защитой, надо позаботиться о создании трудностей по изменению кода вашей программы, т.е. ехе-шника. Ну раз я сказал "А", мне же и говорить "Б". Не пугайтесь простоты. Восточные единоборства начинались с восьми движений. От простого можно будет переходить к сложному.
Итак, посмотрим на то, что у нас есть.
  1. Зашифрованная форма в виде отдельного файла
  2. Ввод пароля пользователем
  3. Класс способный читать зашифрованные формы
При ближайшем рассмотрении все три пункта - это недостатки. Пункт 1. Если у вас большой проект с кучей dll, vxd и прочего вспомогательного хлама, то зашифрованную форму легко спрятать. Но чаще случается, что спрятать бывает трудно. Да и сам факт игры в прятки,говорит о том, что вы ничего другого не придумали и надеетесь на глупость "кракера". Это плохая идея. Надо уважать соперника. Пункт 2. Если пользователь знает пароль, то его может узнать и "кракер". Первое достаточное условие "ломаемости" программы. Пункт 3. Если в программе есть код, расшифровывающий вспомогательные файлы программы. Значит может найтись человек, способный вытащить этот код. Например, сам разработчик, уволившийся из фирмы. А знание шифроалгоритма может дать "кракеру" возможность менять зашифрованные файлы программы. Но есть и плюсы. Главный - мы избавились от явного сравнения пароля и условного перехода в программе, наличие которого является одним из необходимых, но не достаточных условий "ломаемости" программы. Теперь нам надо "всего навсего" спрятать пароль и от пользователя и спрятать вспомогательный файл даже от разработчика. Интересная задача, не правда ли? Надеюсь до этого места все было понятно. Самое сложное - это было прочитать два предыдущих абзаца. Спрятать пароль - это первая и самая простая задача. Первое, что приходит в голову привязка к оборудованию. Затем, электронный ключ. Ключевая дискета. И лишь немногие вспоминают о самом ехе-шнике. ПОМНИТЕ, сейчас наша задача не дать менять наш код. Помня это условие, решение напрашивается само собой. ЦЫРЦ. Т.е я хотел сказать CRC, циклический код. В прилагаемом сегодня проекте я специально не написал ничего связанного с CRC. Т.к. эта задача давно решена. Важно помнить следующее.
  1. Не используйте CRC и CRC32. В их основе лежит XOR и ничего более.
  2. Не считайте контрольную сумму всего файла. Считайте контрольную только нужного вам участка. Представьте, вы подсчитали контрольную сумму всего файла. Кракеру нужно изменить какой-то фрагмент. Он меняет его и добавляет в конец файла хвост, который приводит контрольную сумму файла к нужному виду. Например, CRC=1. После изменений CRC=9. Чтобы CRC стала прежней в конец нужно добавить 8. Тогда 9 xor 8 = 1. Все код изменен, а CRC осталось прежней. Понятно? Не думайте о том, что к ехе-файлу трудно что-то добавить. Это очень простая операция. Попробуйте сами.
  3. Для подсчета контрольной суммы используйте необратимые функции, результат которых зависит от позиции байта и от размера считаемого блока. Например: for i:=0 to szBuffer do begin // I love Modula-2 too 8-) crc := crc * (i+1); // можно например поставить циклический сдвиг crc := crc + Buffer[i]; // можно поставить XOR crc := crc mod szBuffer; // а это самое простое end; Обычно это какая-нибудь хэш-функция. А т.к. хэш-функций полно в алгоритмах шифровки, можете смело их использовать. Можете написать свою.
  4. Важно то, чтобы смещения и размеры подсчитываемых блоков, тоже вычислялись, а не хранились как константы. Это просто. Например, Вы берете какой-то блок, что-то от начала файла, что кракеру никак невыгодно менять, т.к. там служебная информация для виндов. Но это не важно. Важно то, что контрольная сумма этого блока будет смещением или размером другого блока. Ну что-то в этом роде. Или другой способ. Контрольная сумма следующего блока считается не с нуля, а от контрольной суммы предыдущего. Вобщем думайте сами - здесь большое поле для этого.
Итак, с прятанием пароля закончили. Еще раз напомню - это не пароль программы. Это защита от изменения кода. В котором есть фрагменты обеспечиавющие защиту от копирования. Самое главное уяснить это. Поэтому пароль "защиты кода" мы спрятали. Вернее код привязали к самому себе. Поехали дальше? Теперь, как спрятать сам зашифрованный файл. Первый способ - это записать его в конец ехе-шника. Т.е. как ResourceFile или просто "copy name.exe+crpyt.cfm name.exe". Вуаля? Ни фига! Фигня какая-то получается. "Отцепить" такой файл проще простого. А уж "прицепить" другой... Другой способ. Никогда не обращали в Делфях на директиву компилятора {$R *.DFM}, для Буилдера это #pragma resource ? Вобщем, т.о. перед реализацией класса в ехе-шник вставляется ваш ресурс, реализующий внешний вид Формы. Беда в том, что RLINK32, отвечающий за это, строго следит за форматом вставляемого файла. Это можно обойти. Делается в два прихлопа и в три притопа. Делаете DFM-ку с картинкой (TImage), а на место картинки кладем наш спрятанный файлец. Вроде бы все прилично. Но этот способ мне не нравится, потому что... нравится другой. (Если я непонятно объяснил, просто посмотрите внимательно на DFM с картинкой. Это все объяснит.). Другой любимый способ. Можно спрятать файл в процедурку. Как? Притоп 1: Пишется прога по переводу бинарного образа файла в файл для ассемблера. Т.е. " DW , " и т.д. Притоп 2: В ваш проект вставлется процедура, что-то типа procedure TryToCall; asm end; // не пугайтесь так можно делать. Хелп разрешает. Притоп 3: Далее, сконвертируемый файлец вставляется между строками "asm" и "end". procedure TryToCall; asm DW 2815,21504,16717,20041,20294,19794,12288,61712,2,21504 // и т.д. end; // так хелп не разрешает, даже запрещает. Но компилятор закрывает глаза. Все! Куда положите эту процедурку, там она и прилинкуется. Получить ее адресочек не просто, а очень просто:buffer := @TryToCall; Конечно можно т.о. запихнуть файл в массив. Но мне, дураку такому, больше нравится процедурка. Почему? Не спрашивайте даже. Это необъяснимое явление природы. Кажется все. Прилагаемый проект bin2asm не является дизассемблером. А чем он является разберитесь сами, потом мне раскажите. Это будет ваше домашнее задание. Сидите думайте, потом приду проверю.

Дмитрий Логинов

P.S.
Насчет продолжения - есть конечно идеи. Но рекламировать не буду. Мало ли, может кто-то надумает что-то прислать. Вобщем, чаще стряхивайте пыль с вашим батонов. Пока.

Скачать проект Bin2asm.zip (5.88 K)




Содержание  Назад  Вперед