Теоретические основы крэкинга: Глава 3. «Критические дни» программ. — Архив WASM.RU
Все боится времени, но само время боится Пирамид
Египетская пословицаПосле того, как мы успешно установили программу, неизменно наступает торжественный момент первого запуска программы (конечно, если инсталлятор не испортил нам удовольствие, запустив программу автоматически). Немало программ содержат ограничения на время пробного использования, и потому необходимо со всей ответственностью отнестись к первому (да и не только к первому, как мы увидим в дальнейшем) запуску программы. Дело в том, что процесс исследования защиты может затянуться и Вам элементарно не хватит тех дней, которые отведены под пробное использование программы. Вы, разумеется, захотите продлить время пользования программой - и вот тут Вас может ожидать весьма неприятный сюрприз.
В общем случае задачи по неограниченному продлению триального времени программы обычно не представляют особой сложности, но в качестве дополнительных уровней защиты часто присутствуют всевозможные навесные защиты, ликвидация которых может потребовать гораздо больших трудозатрат. Поэтому надо, по возможности, предупреждать подобные ситуации, а о том, каким образом эти ситуации могут возникать, я и расскажу в этом разделе.
Возможны и другие причины, по которым Вам может потребоваться снять ограничение на время использования программы. Для некоторых программ процедура регистрации не предусмотрена в принципе, но при этом в течение испытательного срока они выполняют свои функции в полном объеме (часто такие программы помечены как Demo- и Evaluation-версии), и вполне приемлемым решением было бы неограниченное продление триального срока. Случается также, что необходимо установить бета-версию программы, у которой истек "срок годности", но более новой беты нет, а посмотреть на программу очень хочется. Так или иначе, снятие ограничений на время использования или число запусков программ - одна из актуальных задач современного крэкинга.
Представьте себе, что Вы - автор программы, и Ваша задача - ограничить "испытательный срок", в течение которого пользователь может работать с программой. Как такое можно реализовать? Выбор мест хранения информации об испытательном сроке в современных ОС довольно небогатый - содержимое некоего файла (который можно попытаться спрятать), атрибуты файлов, либо системный реестр (это актуально только для ОС Windows). Такие изменения могут быть обнаружены при помощи утилит, умеющих создавать и сравнивать снимки состояния системы. Изредка встречаются нетрадиционные решения вроде манипуляций на уровне файловой системы или использования слайсов. Использование слайсов для защиты основано на том, что последний кластер, занятый файлом, обычно заполнен не целиком, и потому в незаполненной (и невидимой для большинства программ, оперирующих с файлами) можно хранить некоторый объем информации.
В принципе, идеологических различий между реестром Windows, файлами и атрибутами отдельных файлов нет, все эти объекты могут использоваться для хранения используемых защитой данных. Действительно, аналогии в устройстве реестра и дисковой подсистемы очевидны: "ветви" реестра играют роль логических дисков, разделы - практически полные аналоги папок (убедиться на наглядном примере можно, взглянув на иконки разделов в "Редакторе реестра"), имена ключей - это имена файлов, а значения ключей - содержимое этих файлов. Аналогии можно продолжить, но для нас важно другое: поскольку файловая система подобна реестру, принципы поиска и ликвидации защитных механизмов, основанных на сокрытии информации на дисках или в реестре, во многом будут сходны. Поэтому далее я буду говорить в основном о реестре, оставляя читателю самому разобраться в том, как аналогичные механизмы могут быть реализованы на основе файловой системы (или почему они не могут быть реализованы).
Конечно, все разнообразие механизмов ограничения времени использования программы или количества запусков охватить нереально, но в этом и нет необходимости - воспользовавшись своим воображением, Вы легко продолжите список. Я лишь перечислю основные события в "жизни" программы, и их возможную связь с реализацией триальных механизмов в программах.
Первое, что приходит в голову - во время первого запуска сохранить в файле или в реестре дату (или вычислить дату, после которой программа не должна работать) и при каждом запуске сравнивать текущую дату с сохраненной, проверяя, не истек ли "срок годности" программы. Такие программы, не обнаружив в реестре пометки о дате первого запуска, как правило, считают, что текущий запуск - первый. Такое простейшее решение, как правило, и обходится простейшими средствами - достаточно обнаружить и удалить соответствующий файл или ключ реестра. Одна из модификаций этого метода - определение даты первого запуска через чтение атрибутов файлов: при создании любого файла атрибут CreationTime (дата создания файла) устанавливается автоматически, что позволяет непосредственно в процессе инсталляции "промаркировать" все устанавливаемые файлы датой установки программы. Затем программа просто проверяет при каждом запуске дату создания какого-либо файла или папки (или вообще всех файлов, созданных в процессе инсталляции) и на основе этой информации вычисляет количество дней до истечения испытательного периода. Что интересно, свойства файлов могут использоваться не только для определения даты установки программы, но и для определения текущей даты: в процессе своей работы отдельные компоненты ОС нередко ведут всевозможные "журналы" (логи) в файлах с заведомо известными именами. Проверив дату последней модификации такого файла или его содержимое, можно с некоторой погрешностью узнать текущую дату.
Как было показано выше, надежность такого метода довольно низкая и защита ориентирована в основном на психологический эффект. Более устойчивые варианты этой защиты основаны на использовании "меток", оставляемых программой в реестре в некоторые критические моменты.
Метки, создаваемые при инсталляции, обычно предназначены для предотвращения повторной установки программы (и получения дополнительного триального срока) и для противодействия попыткам "сбросить" счетчик времени удалением ключа реестра. Если инсталлятор не позволяет выполнять сложные вычисления внутри инсталляционного скрипта, метка может выглядеть как запись в реестре с фиксированным значением, наличие которого будет проверяться при первом запуске. Если для создания инсталляционного пакета использовался достаточно мощный продукт, дата инсталляции или максимальное число запусков программы может быть прописано в реестре уже в процессе установки (возможно, в зашифрованном виде). Кроме того, инсталлятор может проверить наличие сделанных ранее "меток" в реестре для предотвращения повторной инсталляции. Таким образом, гарантированно вернуть программу в рабочее состояние после окончания триального срока можно только удалением всех "меток", оставленных программой, с последующей переустановкой.
Многие из ныне существующих защит создают "метки" в момент первого запуска программы. Факт первого запуска обычно определяется простейшим способом: если программа при запуске не обнаруживает "метку", она считает, что запущена впервые, и создает "метки". Обычно создание "меток" выполняется сразу после начала исполнения программы, но изредка встречаются программы, которые выполняют эти действия при завершении программы (возможно, что существуют защиты, которые делают это в случайный момент времени). Скорее всего, таким образом разработчики защит пытались затруднить выявление защитного кода, но на деле они добились прямо противоположного эффекта: большинство операций по загрузке данных из реестра выполняется именно при запуске или изменении настроек программы, а вот запись в реестр в конце сеанса работы - операция менее распространенная. При завершении сеанса обычно сохраняется только информация о положении окон, настройках интерфейса программы и прочие подобные данные, которые, как правило, несложно отличить от защитных механизмов программы. Очевидно, что если защита использует исключительно "метки", создаваемые при первом запуске, после удаления этих "меток" программа считает, что запущена впервые, и начинает отсчет триального срока заново. Для того, чтобы пользователи не обходили эту защиту совсем уж элементарными средствами вроде удаления соответствующего ключа реестра, ключ, содержащий в себе защитную информацию, может быть "плавающим", то есть имя ключа может генерироваться случайным образом в зависимости от аппаратной конфигурации компьютера или каких-либо иных параметров. Найти вручную такой ключ среди десятков подобных практически нереально. В частности, именно такой механизм использует ASProtect. Поскольку "плавающий" ключ, сколь успешно бы он не был замаскирован, все-таки отличается от окружающих его ключей, определив признаки, которые отличают "плавающий" счетчик от обычных ключей реестра, возможно создать программу, которая бы автоматически выявляла подозрительные ключи, что подтверждается наличием как минимум трех независимо разработанных утилит, способных выявлять и удалять ключи, созданные ASprotect'ом. В любом случае, изменения в реестре, возникшие после первого запуска программы, нетрудно обнаружить при помощи программ мониторинга реестра.
Важно отметить, что программы, в которых установлено ограничение на число пробных запусков, при первом запуске всегда создают либо модифицируют один из ключей реестра. Это напрямую следует из логики их работы: для работы такой защиты необходим счетчик запусков, а создать такой счетчик можно только во время инсталляции либо при первом запуске.
Разумеется, программа, содержащая ограничение на число запусков, должна увеличивать либо уменьшать значение этого счетчика после каждого запуска. Кроме того, запись в реестр при каждом запуске возможна также и при ограничении по времени использования. Такая запись играет роль дополнительной защиты от изменения системного времени: если дата текущего запуска меньше даты предыдущего или отличается от него на считанные секунды, программа может предположить, что пользователь пытается использовать программу сверх установленного срока. Обнаружить такую защиту сравнительно легко - многократную модификацию одного и того же ключа скрыть практически невозможно, не помогают даже такие приемы, как дублирование счетчика и "плавающий" счетчик. Сбрасывается такой счетчик тоже без особых сложностей - достаточно один раз запомнить состояние соответствующих ключей реестра и затем восстанавливать его перед каждым запуском.
Интересно отметить, что даже столь простую идею, как отслеживание времени, некоторые разработчики ухитряются реализовать некорректно (по крайней мере, под ОС Windows такое встречается не так уж редко). Windows позволяет оперировать двумя типами времени: системным (оно же "всемирное", UTC) и местным (Local). Причем во многих странах местное время может быть зимним и летним. И если защита ориентируется на местное время, в день перевода часов пользователя может ожидать сюрприз: после автоматического перевода часов, выполняемого ОС, программа может просто перестать работать. Для этого нужно лишь, чтобы пользователь запустил программу непосредственно перед переходом с летнего времени на зимнее, и потом - еще один раз в течение ближайшего часа. По этому нехитрому признаку можно в известной степени судить о квалификации разработчика защиты.
Наконец, последним важным моментом в жизни программы является ее первый запуск после истечения срока триального использования. Поскольку большинство лицензионных соглашений запрещают пробное использование программы сверх установленного "испытательного срока", программа может "помочь" пользователю соблюсти условия лицензионного соглашения, сделав в реестре метку, запрещающую дальнейшую работу программы. Эта метка может быть как новым ключом в глубинах реестра (или файлом в какой-нибудь системной директории), так и особым значением уже существующего ключа. Проверка значения такого ключа также может быть встроена в инсталлятор программы, чтобы пользователь не мог просто деинсталлировать и переустановить программу.
Какие выводы следуют из всего, что было сказано выше? Во-первых, то, что триальные механизмы в программах могут быть довольно разнообразны по исполнению (и, кроме того, иногда дублируются разработчиком для повышения надежности), а их поиск и удаление требует аккуратности и терпения. Несмотря на то, что создание снимков системы требует некоторого времени, пренебрежительное отношение к этим действиям может создать Вам значительные трудности в будущем. Во-вторых, существуют критические точки, при прохождении которых рекомендуется отслеживать состояние системы. В-третьих, можно составить универсальный план действий, который с очень высокой вероятностью позволил бы выявить изменения в системе, вносимые триальными механизмами, проанализировать их и выработать способы противодействия защите. Лично я чаще всего использую следующую последовательность действий, придерживаться которой рекомендую и Вам:
- Сделать снимки состояния системы до и после установки программы.
- Сделать снимок системы перед первым запуском программы, запустить программу, сразу же закрыть ее (чтобы в снимок системы не попали изменения, возникающие при работе с программой и не имеющие отношения к функционированию защиты) и тут же сделать еще один снимок системы. Если программа запускается после инсталляции автоматически, и выполнить этот пункт не представляется возможным, мы, тем не менее, сможем обнаружить изменения, произошедшие при первом запуске, сравнив снимки, сделанные в предыдущем пункте (другое дело, что мы не сможем отличить изменения, произошедшие при инсталляции, от модификаций, внесенных в систему программой при первом запуске).
- Запустить программу во второй раз, сделав снимки до запуска и после завершения программы. Если программа содержит ограничение на число запусков, путем несложного анализа мы сможем легко выявить счетчик запусков. Если программа содержит ограничение по времени использования, то мы можем установить, использует ли программа какие-либо дополнительные механизмы отслеживания времени. О наличии таких механизмов может свидетельствовать появление в реестре новых ключей или изменение уже существующих, появившихся в ходе инсталляции или первого запуска. Если такие ключи обнаружатся, есть вероятность, что программа кроме даты первого запуска отслеживает еще и дату предыдущего запуска, число дней, в течение которых использовалась программа или другую подобную информацию. Для максимальной надежности и достоверности результатов эту операцию можно повторить несколько раз.
- Выяснить, какие изменения в системе происходят, когда программу запускают впервые после истечения триального срока. Это необходимо для поиска меток, которые могли бы воспрепятствовать нормальной работе программы после окончания времени, отведенного на ее пробную эксплуатацию. Важно отметить, что для программ с ограниченным числом запусков необходимо отслеживать изменения не только при первом запуске сверх установленного лимита, но и при последнем "законном" запуске.
- По возможности, необходимо выяснить, как программа реагирует на попытки обойти ограничение времени использования при помощи изменения системной даты. Если программа успешно "проглатывает" любое изменение даты, высока вероятность того, что защита реализована максимально простым способом, и обойти ее будет нетрудно. Разумеется, все эти действия должны сопровождаться созданием снимков системы: если программа обнаружит Ваши манипуляции с системным временем, она может отреагировать на это созданием "метки", свидетельствующей о попытке обойти защиту.
- Проанализировать все собранные данные, выявить подозрительные ключи реестра и другие объекты, которые могли бы использоваться для хранения защитных данных, и затем на основе собранной информации попытаться восстановить работоспособность программы, последовательно удаляя или восстанавливая первоначальные значения подозрительных ключей.
- Проверить, нет ли в программе неочевидных ограничений по времени использования. Нередко встречаются программы (как правило, это демонстрационные, пробные и бета-версии), в которых помимо обычного ограничения на время пользования имеется дополнительная проверка на максимальную дату запуска, после которой программа считается устаревшей и перестает работать.
Вышеперечисленные приемы еще недавно считались "некрасивыми", и рассматривались как побочный результат исследования программы. Однако в последние годы ситуация начала меняться: лавинообразный рост количества защищенных программ привел к тому, что даже довольно известные группы обратили внимание на технологии продления сроков пробного пользования и выпускают launcher'ы, продляющие триальные сроки и сбрасывающие счетчики числа запусков. Чтож, изменившиеся условия требуют новых решений, и если эти решения эффективны, нет никаких причин от них отказываться.
Кроме того, серьезное исследование какой-либо защиты может потребовать неоднократного запуска приложения, и отведенное число запусков может закончиться раньше, чем удастся разобраться в программе. Кроме того, выявление счетчиков и "меток" - это один из путей поиска реализации триальных механизмов непосредственно в коде программы. К примеру, если Вы установили, что имя ключа, отвечающего за триальные ограничения, фиксировано, Вы можете попытаться найти имя этого ключа в тексте программы, затем выявить все ссылки на эту строку в программе и, в итоге, добраться до кода, реализующего защитные механизмы. Также при помощи API-шпиона можно проследить за вызовами функций обращения к реестру, проанализировать параметры, передаваемые этим функциям и таким образом попытаться выяснить, какой из этих вызовов непосредственно связан с реализацией ограничений в программе. А затем, зная, каким образом можно сбросить счетчик, ограничивающий возможность работы с программой, останется лишь воспроизвести этот эффект путем модификации кода программы. © CyberManiac
Теоретические основы крэкинга: Глава 3. «Критические дни» программ.
Дата публикации 13 янв 2004