Карта сайта Хакер в RSS Энциклопедия Хакера PDA версия сайта Почтовые рассылки Хакера    Хакер в Twitter Хакер в ВКонтакте Приложение Хакер для Facebook Хакер на Formspring.me
Журнал Новости Форум Видео Life Xakep Live (блоги)
Bugtrack Статьи Блог Поиск English
Взлом как образ мысли Взлом как образ мысли
Интервью с человеком, который, как оказалось, является не только талантливым пентестером в одной из крупных ИБ-компании, но и хакером-ветераном, который уверенными шагами вышел на свет и прикоснулся к истории российской хак-сцены....
Полный гид по накрутке онлайн-голосований Полный гид по накрутке онлайн-голосований
Конкурсы с голосованием привлекают большое количество посетителей, а трафик, как известно, — это деньги. Особый интерес вызывают конкурсы, где за победу предлагаются лакомые призы....

AntiHASP: эмулируем ключ аппаратной защиты HASP

Bookmark and Share

В этой статье описаны способы обхода аппаратных систем защиты. В качестве примера рассмотрена технология HASP (Hardware Against Software Piracy), разработанная компанией Aladdin Knowledge Systems Ltd. В прошлом данная технология являлась одной из самых популярных аппаратных систем защиты ПО.

Мощью аппаратной защиты HASP пользуются многие серьезные разработчики софта, которые не хотят, чтобы их продукт несанкционированно распространялся. Хаспом, например, защищаются пакеты "1С.Бухгалтерия" или "1С.Предприятие", без которых не может прожить ни одно более или менее организованное дело. Популярный юридический справочник "КонсультантПлюс" также защищает доступ к данным с помощью электронных ключиков. Чтобы воспользоваться вышеупомянутым или другим не менее дорогостоящим софтом, не платя никому ни копейки, недостаточно просто полазить по Сети в поисках txt’шника с ключиками. Однако хакер всегда разберется, что делать с защитой, пусть и аппаратной. И паяльник ему для этого не понадобится.

Взглянем

Утрируя, можно сказать, что HASP состоит из двух частей: аппаратной и программной. Аппаратная часть — это электронный ключик в виде USB-брелка, PCMCIA-карты, LTP-девайса или вообще внутренней PCI-карты. Установленный софт будет работать только на той машине, в которую воткнут электронный ключ. Собственно, неплохо было бы отучить софт от такой неприятной для кошелька привычки.

Программная часть — это драйвера электронного ключа и различный софт, привязывающий электронные ключи с их драйверами непосредственно к защищаемому продукту или к каким-то зашифрованным данным. В статье мы рассмотрим и обойдем защиту, использующую USB-брелок — наверное, наиболее популярный электронный ключ на сегодня.

Механизм системы защиты

Сам брелок нас почти не интересует, в отличие от ПО в его комплекте. Для нас наибольший интерес представляет модуль hardlock.sys. Не углубляясь в подробности, отмечу, что этот драйвер отвечает за взаимодействие с аппаратным ключом. Он имеет два объекта устройства, один из которых обладает символьным именем \Device\FNT0. Используя этот объект, защищенное приложение посредством диспетчера ввода-вывода проверяет лицензию на использование данного ПО.

Главным недостатком такой системы защиты является возможность перехвата вызовов диспетчера ввода-вывода и эмулирования аппаратного ключа. Существует также вариант разработки драйвера виртуального ключа, но это гораздо более сложная техническая задача, нежели перехват вызовов.
Как тебе известно, модель драйвера описывается в структуре DRIVER_OBJECT при загрузке модуля. Она хранит массив обработчиков сообщений. Причем никто не мешает переписать эти адреса и получить управление, выполнив наш код. Таким образом, можно перехватывать и подменять IRP-пакеты, подставляя лицензионные данные. Другими словами, имея дамп ключа защиты, можно передать его программе, проверяющей верность лицензионных данных!

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

Перехват и эмуляция

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

NTSTATUS HookDevice(LPWSTR lpDevice)

UNICODE_STRING DeviceName;
PDEVICE_OBJECT DeviceObject;
PFILE_OBJECT FileObject;

RtlInitUnicodeString(&DeviceName, lpDevice);
IoGetDeviceObjectPointer(&DeviceName, 1u, &FileObject, &DeviceObject);

Получив указатель на структуру DEVICE_OBJECT, имеем указатель на DRIVER_OBJECT. Теперь заменим адреса обработчиков и функций выгрузки драйвера на свои:

NTSTATUS HookDevice(LPWSTR lpDevice)

gDriverObject = DeviceObject-> DriverObject;

gDeviceControl = gDriverObject-> MajorFunction[IRP_MJ_DEVICE_CONTROL];
gDriverObject-> MajorFunction[IRP_MJ_DEVICE_CONTROL] = HookDispatch;

gInternalDeviceControl = gDriverObject-> MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL];
gDriverObject-> MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = HookDispatch;

gDriverUnload = gDriverObject->DriverUnload;
gDriverObject->DriverUnload = HookUnload;

ObfDereferenceObject(FileObject);

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

Так как указатель на объект драйвера защиты сохранeн, то чтобы снять ловушку, нужно просто восстановить прежние обработчики IRP-пакетов:

void UnhookDevice(void)

gDriverObject-> MajorFunction[IRP_MJ_DEVICE_CONTROL] = gDeviceControl;
gDriverObject-> MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = gInternalDeviceControl;
gDriverObject->DriverUnload = gDriverUnload;

Конечно, надо добавить соответствующие проверки на валидность указателей и прочее.

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

void HookUnload(PDRIVER_OBJECT DrvObj)

UnhookDevice();
gDriverUnload(DrvObj);

Здесь происходит восстановление полей структуры DRIVER_OBJECT, и передаeтся управление на оригинальный код выгрузки драйвера перехваченного устройства.

Аналогично поступаем, если наш драйвер завершает работу раньше системы защиты. Только нужно высвободить захваченные ресурсы и не вызывать сохранeнный gHookUnload.


Принцип работы эмулятора

Перехватчик

Зная основные принципы простейшего перехвата IRP-пакетов, приступим к реализации пока только самого перехватчика для дальнейшего анализа. Для этого создадим объект драйвера, который содержит символьное имя (например \DosDevices\Hook) и точки входа CREATE, CLOSE, READ.

IoCreateDevice(DriverObject, 0, &usDeviceName, FILE_DEVICE_NULL, 0, 0, &pDeviceObject);
IoCreateSymbolicLink(&usSymbolicDeviceName, &usDeviceName);

DriverObject->MajorFunction[IRP_MJ_CREATE] = DriverDispatch;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = DriverDispatch;
DriverObject->MajorFunction[IRP_MJ_READ] = DriverDispatch;
DriverObject->DriverUnload = DriverUnload;

Это нужно для того, чтобы работать с нашим перехватчиком как с файлом, используя функции CreateFile\ReadFile\CloseHandle. При такой реализации обмена данными между приложением и перехватчиком невозможно сразу же отправить их пользовательской программе, поэтому необходимо создать некоторую структуру для хранения необходимых данных о пойманном пакете. Например односвязный список, как это реализовано мной. Теперь следует определиться, какую информацию нужно буферизировать. Это общая информация о пакете (тип, флаги, прочее) и, конечно, буферы. Также можно добавить время перехвата. При копировании содержимого буферов нужно помнить об их типе, иначе — крах. Забегая вперед, отмечу, что драйвер защиты использует буферизированный ввод-вывод, это немного упрощает код.

Код HookDispatch

if (idlTail->IrpData.InputLength)
{
    idlTail->InputBuffer = ExAllocatePool(NonPagedPool, idlTail->IrpData.InputLength);
    RtlCopyMemory(idlTail->InputBuffer, Irp->AssociatedIrp.SystemBuffer, idlTail->IrpData.InputLength);
}

if (IoSL->MajorFunction == IRP_MJ_DEVICE_CONTROL)
    Status = pHookedDriverDispatch[IRP_MJ_DEVICE_CONTROL]( DeviceObject, Irp);

if (idlTail->IrpData.OutputLength)
{
    idlTail->OutputBuffer = ExAllocatePool(NonPagedPool, idlTail-> IrpData.OutputLength);
    RtlCopyMemory(idlTail->OutputBuffer, lpBuffer, idlTail->IrpData.OutputLength);
}

Осталось реализовать чтение из драйвера. Так как пакет содержит буферы, чье содержимое представляет интерес, то размер сообщений заранее не известен. Поэтому поступим следующим образом: при первом чтении получаем общую информацию о пакете и размере буферов; при повторном читаем содержимое, удаляем звено из списка пакетов и не забываем про спиновые блокировки для последовательной работы с данными:

Код DriverDispatch

Length = IoSL->Parameters.Read.Length;
if (Length == sizeof(IRP_DATA) && idlHead)
    RtlCopyMemory(Irp->UserBuffer, &idlHead->IrpData, Length);
else if (idlHead && Length == (idlHead-> IrpData.InputLength + idlHead-> IrpData.OutputLength))
{
    RtlCopyMemory(Irp->UserBuffer, idlHead-> InputBuffer, idlHead->IrpData.InputLength);
    RtlCopyMemory((PVOID)((ULONG)Irp->UserBuffer + idlHead->IrpData.InputLength), idlHead-> OutputBuffer, idlHead->IrpData.OutputLength);
}
else if (Length == 1 && idlHead)
{
    if (idlHead->InputBuffer)
        ExFreePool(idlHead->InputBuffer);
    if (idlHead->OutputBuffer)
        ExFreePool(idlHead->OutputBuffer);

    idlTemp = idlHead->ldlNext;
    ExFreePool(idlHead);
    idlHead = idlTemp;
    if (!idlTemp)
    idlTail = NULL;
}

Когда перехватчик готов, запускаем сначала его, а затем — защищенное приложение с ключами и без. Из полученных логов становится видно, какие управляющие коды посылаются и их результаты. Также можно видеть, что запросы и ответы на два различных кода (9c402450, 9c4024a0) не изменяются. Казалось бы, можно построить табличный эмулятор, но после серии запусков убеждаемся, что это невозможно, так как содержимое буферов различно, и неизвестно, как оно образуется.


Перехваченные пакеты без ключа


Перехваченные пакеты с ключом

Затем возможны несколько вариантов дальнейших действий:

  • изучать дебри драйвера защиты;
  • воспользоваться информацией самих разработчиков системы.

Оба варианта дают необходимую информацию. Итак, оказывается, содержимое пакетов шифруется публичным симметричным алгоритмом AES (Advanced Encryption Standard). Логичной целью является получение ключа шифрования.

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


Пример дампа ключа

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

unsigned short Key;
unsigned char RefKey[8], VerKey[8];

for (Key = 0; Key <= 0x7fff, Key++)
{
    if (!HL_LOGIN(Key, 1, RefKey, VerKey))
    {
        HL_LOGOUT();
        Break;
    }
}

return Key;

Далее ключ (MODAD) используется для снятия дампа: тип, идентификатор, порт подключения и так далее. Для этого есть функции, определенные разработчиками.

Функции HL_LOGIN, HL_LOGOUT доступны из HASP SDK для разработчиков приложений, защищенных на этой платформе, и имеют следующие прототипы:

WORD HL_LOGIN(WORD ModAd, Word Access, Byte *RefKey, Byt *VerKey);
WORD HL_LOGOUT(void);

Первая функция служит для открытия сессии работы с ключом защиты посредством драйвера, вторая – завершает сессию. Это прототипы старых версий HASP SDK, но работают они и с новыми типами ключей, так как разработчики обеспечили обратную совместимость.

Новый API мало отличается от старого, и это никак не сказывается на принципе работы брутфорса. Подробную документацию Hasp API, готовые реализации брутфорса и дампера ключей можно найти на диске.

Обработчик

Теперь есть все необходимое для корректной работы модуля. Осталось реализовать подстановку лицензионной информации. Причем можно перехватывать лишь некоторые IRP-пакеты. Здесь все уже зависит от конкретной версии ключа и защищаемой программы.

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

NTSTATUS HookDispatch():

PIO_STACK_LOCATION Stack = Irp-> Tail.Overlay.CurrentStackLocation;
ULONG IoControlCode;
if (Stack->MajorFunction == 14)
{
    IoControlCode = Stack.DeviceIoControl.IoControlCode;
    If (IoControlCode != 0x9c402458)
    {
        Return gDeviceControl(DeviceObject, Irp);
    }
    else
    {
        Encrypt(Irp->AssociatedIrp.SystemBuffer);
        Crypt(Irp->AssociatedIrp.SystemBuffer, Key, DumpMemory);
    }
}

Return STATUS_FAILED;

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

Код Encrypt()

void Encrypt(BYTE * Buffer)
{
    WORD Seed = *((WORD*)Buffer + 0x5e);
    WORD Ver = *((WORD*)Buffer + 0xba);

    if (Ver)
    {
        for (int i = 0; i < 0xB9; i++) {
            *(WORD*)(Buffer + i) += Seed;
            Seed = (Seed >> 15) | (Seed << 1);
            Seed -= *(WORD*)(Buffer + i) ^ i;
        }
   
        for (int i = 0xBE; i < 0xFF; i++) {
            *(WORD*)(Buffer + i) -= Seed;
            Seed = (Seed >> 15) | (Seed << 1);
            Seed += *(WORD*)(Buffer + i) ^ i;
        }

        *((WORD*)Buffer + 0xba) = Seed;
    }
}

Видно, что алгоритм гораздо сложнее, чем обычный сдвиг и исключающее "или". А вот алгоритм дешифрования:

Код Decrypt()

void Decrypt(BYTE* Buffer)
{
    WORD Seed = *((WORD*)Buffer + 0x5e);
    WORD Ver = *((WORD*)Buffer + 0xba);

    if (Ver) {
        for (int i = 0xFE; i > 0xBD; i--) {
            Seed -= *(WORD*)(Buffer + i) ^ i;
            Seed = (Seed << 15) | (Seed >> 1);
            *(WORD*)(Buffer + i) += Seed;
        }
       
        for (int i = 0xB8; i >= 0; i--) {
            Seed += *(WORD*)(Buffer + i) ^ i;
            Seed = (Seed << 15) | (Seed >> 1);
            *(WORD*)(Buffer + i) -= Seed;
        }

        *((WORD*)Buffer + 0xba) = Seed;
    }
}

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

В заключение отмечу, что построение табличного эмулятора, основанного на перехвате DeviceIoControl, — достаточно трудная задача. Но такой принцип эмулятора можно использовать и на другом уровне взаимодействия: создать виртуальную USB-шину.

Заключение

Это не единственный способ избавиться от системы защиты. Существуют и другие, более совершенные методы. Изложенные в статье принципы можно использовать и для анализа работы драйверов, перехватывая IRP-пакеты. Таким образом можно добавить неплохой инструмент в свой сделанный на коленке набор. Удачи!



Теги: взлом , дизассемблирование , эмулятор





СЛЕДУЮЩИЕ СТАТЬИ
Китайские закладки: непридуманная история о виртуализации, безопасности и шпионах
Отчеты о сбоях от Apple помогают хакерам создавать эксплойт для джейлбрейка
ПРЕДЫДУЩИЕ СТАТЬИ
Компании опаздывают с безопасностью встраиваемых устройств
Ситибанк не играет в кости: уязвимость TAN кодов
Прав достаточно: 8 приемов для обхода групповых политик в домене
Чем больше эксплоитов выставлено на продажу, тем выше уровень безопасности
PHP-дайвинг: низкоуровневый поиск уязвимостей в веб-приложениях
SCADA под прицелом: анализ защищенности АСУ ТП
Hack TV: взлом телевизора и изучение его кишок на примере Samsung LE650B
Роботы: на пороге следующей революции
Файлы-призраки: как криминалисты восстанавливают надежно удаленные данные?
Продам 0day: как выгодно продать свой эксплоит
ОБСУЖДЕНИЕ СТАТЬИ
Логин:
Пароль:
Если у вас есть форумный логин - вы можете использовать его, иначе анонимный гостевой доступ.

Для оставления комментария вы можете зарегистрироваться по упрощенной процедуре.

Обсуждение этой статьи на forum.xakep.ru
Для отправки сообщения введите код, указанный на картинке
Сообщение

UserГость
30.11.2011 15:18:18
Ответить Ссылка
в общем идея такова, что если ключ реализует серьезное шифрование , защиту кода драйвера и использует динамическую генерацию данных для проверки ключа то вам потребуется сил и денег в разы больше чем купить этот ключ посыл статьи : "собрались ломать ключи HASP - удачи"
Avatarrgo
30.11.2011 19:14:40
Ответить Ссылка
quote:

ORIGINAL: Guest
в общем идея такова, что если ключ реализует серьезное шифрование , защиту кода драйвера и использует динамическую генерацию данных для проверки ключа то вам потребуется сил и денег в разы больше чем купить этот ключ

А сколько может принести денег продажа виртуальных ключей? Или если мне надо 20 копий софта, то что дешевле: разработать виртуальный ключ или купить двадцать настоящих?
UserГость
30.11.2011 16:22:35
Ответить Ссылка
хренов HAPS
UserГость
30.11.2011 19:02:37
Ответить Ссылка
Молодчина!
UserГость
01.12.2011 15:36:41
Ответить Ссылка
Вы вообще понимаете что в статье написан полный бред надерганный из разных источников, человеком который никогда не работал с HASP?

Сначала разбирается технология создания драйвер-фильтра для старых ключей hasp4 и hl, а потом речь идет вообще про ключи hardlock.
Avatarrgo
04.12.2011 17:46:19
Ответить Ссылка
quote:

ORIGINAL: Guest
Вы вообще понимаете что в статье написан полный бред надерганный из разных источников, человеком который никогда не работал с HASP?

Нет, не понимаю. Я человек, который никогда не работал с HASP.

quote:

ORIGINAL: Guest
Сначала разбирается технология создания драйвер-фильтра для старых ключей hasp4 и hl, а потом речь идет вообще про ключи hardlock.

Какие вы умные слова знаете... Может статейку напишете? Расскажете что эти слова значат?
UserГость
01.12.2011 19:19:08
Ответить Ссылка
Статья - говно. Компиляция из не сильно связанных между собой фрагментов. Как писать драйвер-фильтры можно и так без проблем нагуглить. При чём здесь хасп? К слову, на последних реализациях хаспа эмулятор в виде драйвера вообще не катит - там динамическое шифрование трафика ключ-апи. Даже если будет только логин-логаут, каждый раз контент irp-пакетов будет разный, эмулятор не сделаешь. Брутфорс вообще описан для ключей Hardlock, древних, как говно мамонта, и к хаспам совсем никаким боком не относится. Похоже, автор решил просто бабла срубить с xakep'а по-быстрому, а те тиснули непроверенный материал - типа, и так сойдет. Отстой...
UserГость
01.12.2011 21:40:18
Ответить Ссылка
Хорошая статья, у меня теперь есть представление, в каком направлении двигаться. Не все понятно, но разберусь.
UserГость
02.12.2011 11:08:58
Ответить Ссылка
Часть, в которой описан брут лишь дополняет статью, не является её основной частью, а лишь объясняет принцип. Это потому, что статья адресована не профессионалам и специалистам этой области, а новичкам и людям просто заинтересованным. А спецы могли бы сделать статью лучше, дополнить её.
UserГость
04.12.2011 13:00:50
Ответить Ссылка
Статья хорошая) дает общее представление, а более и не надо) есть тут люди им все готовое подавай и только тогда будут довольны)спасибо автору) сентинел держись)))
UserГость
06.12.2011 6:54:29
Ответить Ссылка
нужно защищать положительную сторону здравого смысла
UserГость
16.12.2011 0:44:20
Ответить Ссылка
Интересует возможность эмулировать ключ в GNU/Linux.
Что посоветуете?
UserГость
14.05.2012 3:53:06
Ответить Ссылка
Здравствуй!!!
помоги пожалуйсто сэмулировать ключь Hasp HL 3.25
UserГость
20.05.2012 22:56:38
Ответить Ссылка
http://www.cadshop.ru - поможем с эмуляцией HASP 3.25
UserГость
14.05.2012 3:55:41
Ответить Ссылка
кто может помочь сэмулировать ключь пишите garik-gari@bk.ru
UserГость
20.05.2012 22:55:31
Ответить Ссылка
www.cadshop.ru Эмуляторы электронного ключа Hasp, Sentinel, Hardlock, Guardant, Wibu, Codemeter, FlexLM, Hasp SRM




Keywords: zPOSTz zHOMEz, zHACKz, zOTHERHACKz, zINFOz, zYANDEXz z57901z
Для Авторов: edit Lock delete Lock



    Rambler's Top100