LSSender, detours и боянный сплайсинг


Давно ничего не писал в связи с отсутствием интересных идей, поэтому решил написать эту статью, чтобы развеять пустоту.
Люди, пишущие софт на продажу, любят накрывать свои продукты протекторами, однако редко собственноручно проверяют качество защиты. Они, конечно, по-своему правы, так как обычный человек вряд ли примется читать статьи, например, на wasm, чтобы убрать защиту с программы. Рассмотрим способы "обмана" защиты одной из программ для всеми любимых социалочек.
Программа называется LSSender, последние версии которой накрыты DotFix NiceProtect от небезызвестного GPcH. В сети существуют мануалы по снятию этого протектора, но это слегка занудно, и поэтому мы займемся более детальным изучением системы привязки.

Откроем программу в OllyDbg:

Как мы видим, программа действительно защищена протектором, однако, если продолжить выполнение программы, то после запуска мы увидим, что структура программы в памяти почти полностью восстановилась в читабельный вид. Также мне удалось найти более старую версию программы, которая не была защищена никакими протекторами, что позволило, в общем-то, целиком посмотреть структуру защиты с помощью Delphi RTTI eXtractor (DRX).
Как и ожидалось, автор не стал изобретать велосипед и воспользовался готовыми модулями для получения информации о компьютере и дальнейшей генерации серийного номера на основе неё. Это видно, во-первых, по данным, полученным с помощью DRX (DRX создала ассемблерные листинги модулей с "говорящими" названиями HDDInfo, LbCipher и т.д.),

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

Вызов по адресу 00578590 соответствует вызову TLbRijndael.SetKey (очевидно путем сравнения тел методов из LbClass.pas и по адресу 00578590). Если посмотреть серийные номера, которые выдает программа при запуске на неактивированном оборудовании, то мы увидим, что это base64-строки размером 64 или 88 символов. То есть программа получает некоторые данные о компьютере, хэширует их и обрабатывает алгоритмом base64. Конечно, можно было бы подменить содержимое, возвращаемое функциями кодирования в Base64 или шифрования, но это неинтересно, поэтому будем разбираться дальше. Определим, какие данные использует программа для генерации серийного номера. Во-первых, это серийный номер HDD (модуль HDDInfo). В программе используется метод из модуля, который получает информацию о hdd, используя DeviceIoControl. Во-вторых, имя текущего пользователя системы (функция GetUserName).
Казалось бы, надежный метод, но не в случае с виртуальными машинами. Кто-то уже купил у автора привязку к виртуальной машине VMWare, так что у меня программа оказалась "активированной" после запуска. Также следует отметить, что при запуске никакой сетевой активности не наблюдается, так как все серийные номера содержатся внутри программы в открытом виде.

Что все это дает? Можно сделать, чтобы вызовы функций DeviceIoControl и GetUserName возвращали нужные нам данные (тем более есть, откуда сделать слепок данных), а можно просто вписать свой серийный номер в тело программы. Сделаем частично то и другое. Подменим данные, возвращаемые функциями, на данные с виртуальной машины и расширим лицензию до самой полной (которая стоит 250$). Выделываться с ассемблером и драйверами в этот раз не будем, а воспользуемся старой доброй Detours. Но для начала проанализируем вызовы DeviceIoControl и CreateFile (т.к. предыдущей функции нужен хендл) на виртуальной машине:

Как видно из лога, программа пытается получить серийные номера устройств PhysicalDrive0-7 и Scsi0-3. Но так как в моей виртуальной машине только один жесткий диск, то имеет смысл только чтение PhysicalDrive0. Функция DeviceIoControl вызывается с разными dwIoControlCode: 0х00074080, 0х002D1400, 0х000700A0). nOutBufferSize тоже варьируется. На основе анализа лога, а также содержимого lpOutBuffer можно составить свою функцию, которая всегда будет возвращать нужные данные. Но для начала опишем прототипы функций:

Теперь опишем функцию MyDeviceIoControl

hDrive - это хендл после вызова CreateFileW("\\.\PhysicalDrive0",... , code1 и code2 - содержимое буферов, которые возвращаются при запуске на виртуальной машине, вызов с dwIoControlCode равным 0х00074080 не срабатывает.
Для функции GetUserName все совсем просто:

Теперь сделаем свою функцию для CreateFileW. В ней нам необходимо возвращать хендл только при обращении к PhysicalDrive0 и сохранять его для дальнейшего использования в MyDeviceIoControl.

И, наконец, DllMain

Теперь у нас есть готовая dll, которую требуется загрузить в адресное пространство процесса до начала проверки серийного номера. Можно, конечно, написать лоадер, но мы просто поправим таблицу импорта с помощью CFF Explorer, благо, она не искажена протектором. Чтобы добавить нашу dll в таблицу импорта - создадим пустую экспортируемую функцию в ней

Теперь отредактируем таблицу импорта

После этого мы получим работоспособную стандартную версию, но нам ведь нужна версия за 250$ (если бы мы взяли данные, которые возвращают DeviceIoControl и GetUserName с компьютера, для которого была приобретена самая полная версия, то дальнейшие манипуляции не потребовались бы). Чтобы её получить, необходимо знать ключ, который генерировался для виртуальной машины, на которой я её запускал (данные в base64). Если знаем ключ, то просто открываем какой-нибудь hex-редактор и вписываем этот ключ поверх другого ключа, сразу после которого идет строка +fullplugin. Старый ключ на всякий случай лучше затереть.

Конечно, можно было не заморачиваться с dll, а сразу вписать ключ компьютера в тело программы. В любом случае, сразу после вписывания мы наконец-то получаем самую полную версию программы.

Исходный код dll: скачать

LSSender, detours и боянный сплайсинг: 32 комментария

  1. Браво =)
    Только софт я особо и не старался защитить.
    Так как в софте вечно есть глюки, которые я всегда и правлю =)
    Да и плюшки я добавляю по просьбе пользователей.
    На это и идёт расчёт.

      1. Тут от мудаков помельче защита, которые только портят мнение о софте.
        После которых софт лагает непонятно как.

        1. Как-раз таки от шаловливых ручек.
          Потому как одно дело когда прога взломана и лежит в привате, а другое когда все туда лезут и ковыряют.

  2. прогу непонятно откуда качать, ссылка которую давали не рабочая,
    ещё с этой dll разбираться надо,
    сделай так чтобы сразу можно было скачать архив с работающей программой, заранее спасибо)))

  3. Хорошая работа Kiami! Был бы очень благодарен если ты выложил эксешник.

    PS: Насчет выше написанных сообщений... Они просто сейчас завидуют, что некоторые получат программу бесплатно а некоторые должны заплатить по 50 у.е

      1. O_o Как ты узнал пароль?

        Да вот еще... Извините, но вашего серииника нет в базе! Обратитесь к разработчику за покупкои... Как исправить?

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

  4. Для Вас ведь это не составит труда? :)
    Как два пальца об асфальт?

    Да. Как вы узнали пароль?

    1. Составит, да и зачем, в очередной раз гоняться с автором? Ему то проще, скачал крякнутый протектор и в очередной раз сменил защиту.
      Пароль...Владельцы лицензии сообщили.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *