Главная » Статьи » Крэкинг |
Автор: Алексей Кирюшкин
|
Вступление Идея Что дает и чего не дает данный способ Порядок применения CSelfSafe |
Вступление
Автор должен чистосердечно раскаяться в том, что идея данного способа использования CRC для защиты исполняемых файлов от искажения целиком и полностью украдена им из книги Лу Гринзоу “Философия программирования Windows 95/NT” (Символ, Санкт-Петербург,1997), однако просит принять во внимание следующие, смягчающие его вину обстоятельства:
- В книге исходники приведены не полностью, не хватает одного заголовочного файла.
- Используется CRC16
- Собственно реализация, безусловно, рабочая, но, IMHO, уж больно “мутная”.
Что еще мог сделать в этой ситуации русский программист? Конечно, только одно – “переписать это все нафиг” :).
Вступление
Автор должен чистосердечно раскаяться в том, что идея данного способа использования CRC для защиты исполняемых файлов от искажения целиком и полностью украдена им из книги Лу Гринзоу “Философия программирования Windows 95/NT” (Символ, Санкт-Петербург,1997), однако просит принять во внимание следующие, смягчающие его вину обстоятельства:
- В книге исходники приведены не полностью, не хватает одного заголовочного файла.
- Используется CRC16
- Собственно реализация, безусловно, рабочая, но, IMHO, уж больно “мутная”.
Что еще мог сделать в этой ситуации русский программист? Конечно, только одно – “переписать это все нафиг” :).
Идея
Для тех, кто не читал Лу Гринзоу (фи:( ) приведу идею метода. Для того, чтобы при подсчёте CRC учитывались только данные исполняемого файла и не учитывалась сама CRC, добавим в исходные тексты программы следующую глобальную структуру данных CRC_DATA:
struct CRC_DATA |
Придуманная нами уникальная (в пределах файла) метка label поможет найти в исполняемом файле нашей программы место (DWORD crc), где находится рассчитанная CRC, и которое поэтому не должно учитываться при подсчёте.
ПРИМЕЧАНИЕ В рассматриваемой далее реализации не имеет значения кратность длины метки установленному в свойствах проекта выравниванию – Struct Member Aligment, т.к. переменная CrcData.crc, как таковая, нигде в программе не используется. Она нужна только как гарантия наличия 4-х неиспользуемых байт после метки. Именно эти 4 байта будут использоваться для записи и чтения CRC. В зависимости от длины метки и используемого выравнивания они могут совпадать, а могут и не совпадать с 4-мя байтами переменной CrcData.crc. |
Что дает и чего не дает данный способ
Начну с конца – использование CRC затрудняет, но не исключает полностью возможность искажения файла злоумышленником (см. например [1]), так что о 100%-й надежности определения факта искажения речь не идет. Утешимся, однако, тем, что под нашим контролем останутся искажения при передаче по каналам связи, записи/перезаписи, изменения, внесённые вирусами, а также малолетними «хацкерами» с редакторами ресурсов в руках.
Другие способы самоконтроля целостности исполняемого файла
Использование стандартного поля PE-заголовка и функции MapFileAndCheckSum
Установив в свойствах проекта опцию Set CheckSum (ключ /RELEASE) мы заставим линкер после каждой перекомпиляции рассчитывать контрольную сумму для файла и записывать ее в соответствующее поле PE-заголовка. Следующий код демонстрирует способ проверки контрольной суммы при запуске exe-файла:
// checksumm.cpp : © Павел Блудов http://www.rsdn.ru/Users/Profile.aspx?uid=507 |
- Достоинства: Все очень просто
- Недостатки: Если известно, что файл защищен данным способом пересчитать для измененного файла контрольную сумму очень просто – место хранения и функция расчета контрольной суммы - стандартные.
Использование криптографии – цифровая подпись
- Достоинства: Правильная реализация обеспечивает высокую криптографическую стойкость, подделка подписи, в отличии от CRC практически не возможна.
- Недостатки: Проблема однако в том, что в рассматриваемом случае самопроверки исполняемого файла весь код проверки подписи будет находится в том же самом исполняемом файле, и доступен для взлома точно также как и механизм проверки CRC, а значит нет практически никакого реального увеличения надежности проверки.
Реализация
В демонстрационном проекте (VC7) приведены исходные тексты класса CSelfSafe, делающего для нас необходимую минимальную работу по контролю целостности файла и расчету CRC:
#pragma once |
Оставим пока в стороне конструкторы и способы задания имени контролируемого файла, начнем с основных моментов.
Поиск места для записи/ чтения CRC кода
- Используем отображения контролируемого файла в память, чтобы иметь возможность работать с ним, как с обычной последовательностью байтов.
- Применим алгоритм стандартной библиотеки C++ search, чтобы найти в нем нашу метку, обозначающую место хранения CRC.
- Проверим, что после этой метки еще осталось место для записи 4-х байт CRC кода.
- Повторим поиск от конца метки до конца файла, чтобы убедиться в том, что в файле случайно не образовалось еще одной такой же последовательности байт, т.к. в этом случае нам не удастся определить правильное место для хранения CRC кода.
ПРИМЕЧАНИЕ Ситуация с двумя метками регулярно возникает для Debug-версий исполняемых файлов. Помогает полная перекомпиляция. |
Ниже приведена реализация метода поиска места для CRC - OpenFileAndFindCRCpos():
// открыть файл и найти место для CRC |
Подсчет CRC и запись подсчитанной суммы в файл
После получения от OpenFileAndFindCRCpos() указателя на место для хранения CRC в файле нам остается только подсчитать CRC32, исключив из подсчета те самые четыре байта, в которых будет храниться CRC, и записать на это место подсчитанную сумму:
// подсчитать и записать CRC для заданного файла |
В данной реализации использована таблица для расчета CRC32, приведенная в [1].
Контроль CRC
Ищем место, где хранится CRC, считываем контрольную сумму, сохраненную в файле, и сравниваем с рассчитанной:
// подсчитать и сверить CRC для заданного файла |
Порядок применения CSelfSafe
Пример использования метода дан в демонстрационном проекте.
Создайте объект класса CSelfSafe, передав ему в конструкторе или в методе NewFile() HMODULE или строку с именем контролируемого файла. В процедуре запуска exe или dll, а также, в порядке паранойи, по некоторым событиям в вашей программе вызывайте метод CheckCRC() для контроля целостности.
Естественно, после каждой перекомпиляции программы на нее надо натравливать утилитку, которая, используя тот же самый CSelfSafe, будет с помощью метода WriteCRC() подсчитывать CRC и записывать ее в нужное место. Это, пожалуй, единственное неудобство при использовании данного метода, но с другой стороны, зачем еще нужен Post Build Step?
Не забудьте поменять для себя последовательность байтов в метке на нечто более редко встречающееся для затруднения обнаружения ее в исполняемом файле, с одной стороны, и для исключения ложных срабатываний при поиске, с другой стороны.
Тестовая программа из демонстрационного проекта при запуске с параметром (именем исполняемого файла) рассчитывает для него (файла) контрольную сумму и записывает в предназназначенное для этого место, а при запуске без параметра производит самопроверку CRC:
int _tmain( int argc, _TCHAR* argv[] ) |
Дополнительная информация по CRC
- Anarchriz/DREAD. “CRC, и как его восстановить”
- Ross N. Williams. “Элементарное руководство по CRC алгоритмам обнаружения ошибок”
Всего комментариев: 0 | |