SentinelLM!WlscGen_Crk_1 — Архив WASM.RU

Все статьи

SentinelLM!WlscGen_Crk_1 — Архив WASM.RU

Это первая часть последней главы из цикла о SentinelLM, но уже после её прочтения вы должны быть в состоянии "зарегистрировать" и/или отучить от заглушки в порту (aka донгл) некоторые простенькие программы, продавшие душу Rainbow Tech.

Итак, на данный момент имеем установленный SentinelLM SDK 7.1, эксклюзивно настроенный на наш таргет, т.е. в нём жёстко прописан VId нашей жертвы. Для того, чтобы изменить этот VId можно просто переустановить SDK или найти и пропатчить эти значения в бинарниках, что вовсе не тривиально. После нескольких неудачных попыток поменять VId, я решил всегда переустанавливать SDK и вам советую так поступать.

Пока я усердно работал над этой главой, вы уже прочитали объёмные PDF'ы из документации и узнали, что генератор лицензий SLM (он же WlscGen.exe) так просто нас не наградит халявными лицензиями для нашей жертвы. Оказывается, что он сам защищён SLM и требует наличия донгла! Смешно и обидно... Но не отчаивайтесь -- сегодняшний практикум многому вас научит и поможет устранить защиту SLM даже в патологически сложных случаях, в которых кроме ратификации лицензионного файла программа активно использует EEPROM-память донгла. У меня даже есть готовый патч для "исправления" WlscGen, но я настаиваю на необходимости хотя бы один раз поработать над этим вручную. Чем не ритуал посвящения в Sentinel? :-)

Кроме двух PDF'ов, входящих в комплект поставки SDK, вам нужно прочитать ещё один ОЧЕНЬ важный документ: "SentinelSuperPro 6.0 Developers Guide" (6,4 Мб), который можно скачать на сайте www.rainbow.com. Документ посвящён API Sentinel SuperPro, с помощью которой SLM "общается" с донглами семейства SuperPro. Особого внимания заслуживает глава 14: "API Function Reference".

Перед штурмом WlscGen, хочу добавить пару слов о принципе работы этой программы (особенно для тех лентяев, которые -- как и я в своё время -- не прочитали документацию ;-) Маркетинговая политика радужной компании основана вовсе не на продаже CD с SentinelLM SDK в красивых упаковках. Эти капиталисты взимают дань со своих клиентов за КАЖДУЮ выпущенную лицензию. Справедливости ради стоит заметить, что многие другие компании тоже так поступают... В общем, вместе с SDK компания выдаёт (вроде, первый раз бесплатно) своеобразный электронный счётчик, который автодекрементируется при каждом употреблении. При создании постоянных лицензий для одного PC, счётчик уменьшается на определённое количество единиц; при выпуске корпоративных лицензий для нескольких PC -- теряется соответственно большее количество единиц. Всё зависит от типа лицензии, срока годности и т.д. Эти единицы теряются безвозвратно, даже если пользователь по ошибке создаст бракованную лицензию. При полном истощении счётчика, приходится идти к Rainbow и покупать новый. Вам это не напоминает картриджи для принтеров HP? Так вот, счётчик этот реализован в виде нескольких ячеек памяти в ранее упомянутом донгле и WlscGen "видит" эти ячейки через API, которая общается с донглом через драйвер.

На следующем изображении упрощённо показана зависимость WlscGen от донгла. На большее у нас с Paint'ом не хватило воображения :-)

Обратите внимание на ячейку "Vendor Id" (или "Developer Id") -- это тот самый VId!!! Таким образом, каждый лицензионный донгл "привязан" к своему хозяину и отказывается работать на "чужих" владельцев. Так, по крайней мере, считают в Rainbow. Ячейка "Уникальный S/N" -- это вовсе не то, о чём вы сразу подумали. Нам данный S/N абсолютно безразличен (не путать с серийником для SDK). Область "N/A" не доступна приложениям и, в основном, представляет собой зарезервированные ячейки. В области "Произвольные данные" находится, например, вышеупомянутый счётчик.

SLM API в данном случае реализована статически, т.е. нужные функции внедрены в WlscGen.exe. Наличие lsapiw32.dll не должно сбивать вас с толку. Наша задача -- пропатчить генератор лицензий, вернее пропатчить SLM API для того, чтобы генератор "видел" несуществующий донгл и признавал его своим. Потом мы "заполним" счётчик и получим неистощимый запас лицензий на зависть всем клиентам Rainbow!

Единственный известный мне рабочий метод взлома WlscGen -- это метод описанный в статье CyberHeg "Removing need for dongle in Sentinel LM Wlscgen". Вообще, SentinelLM!WlscGen_CRK_1 можно считать частичным переводом статьи CyberHeg.

Итак, запускаем WlscGen.exe и убеждаемся в его неработоспособности без донгла. Я настоятельно рекомендую вам сделать паузу в чтении этой статьи и помедитировать над кодом программы как в IDA (не забудьте наложить сигнатуру статической SLM API), так и под софтайсом. Можете запомнить текст сообщения об ошибке и попытаться оттрассировать его под отладчиком. Попробуйте угадать какие функции из SLM API могут/должны вызываться для обнаружения донгла.

Сдаётесь? Так быстро? Ладно... в IDA > Names ищем те самые функции из "SentinelSuperPro 6.0 Developer's Guide". При помощи дизассемблера, отладчика и хекс-редактора мы постепенно заставим некоторые из этих функций работать с несуществующим донглом :-) По мере необходимости мы будем заглядывать в SoftIce (как обычно, MAP > SYM > NMS и т.д.)

RNBOsproFindFirstUnit(packet, VendorID)

Первым делом ставим BPX на RNBOsproFindFirstUnit(), так-как эта функция предназначена для поиска донгла с заданным VId. Для большей уверенности можете поставить бряк сразу на все 16 функций из этой API. Наше предположение оказывается верным и SoftIce выскакивает на входе в RNBOsproFindFirstUnit(). Трассируем до RETN и получаем 3 в аккумуляторе (EAX = 3), что означает отсутствие донгла и объясняет сообщение об ошибке. Не теряя времени, идём в IDA и правим это безобразие:

00435B00 _RNBOsproFindFirstUnit@8 proc near
00435B00 push ebx
00435B01 push esi
00435B02 mov eax, [packet]
00435B06 or eax, eax
00435B08 jnz short loc_435B13
00435B0A mov ax, 2
00435B0E pop esi
00435B0F pop ebx
00435B10 retn 8
. . .

При успешном выполнении RNBOsproFindFirstUnit возвращает SP_SUCCESS, т.е. ноль. Блиц-патч:

00435B00 _RNBOsproFindFirstUnit@8 proc near
00435B00 push ebx
00435B01 push esi
00435B02 mov eax, [packet]
00435B06 33C0 xor eax, eax ; Обнуляем eax (SP_SUCCESS)
00435B08 90 nop ; Забиваем переход
00435B09 90 nop
00435B0A 90 nop ; Забиваем mov ax, 2
00435B0B 90 nop
00435B0C 90 nop
00435B0D 90 nop
00435B0E pop esi
00435B0F pop ebx
00435B10 retn 8
. . .

Элементарно, не правда ли? Вместо исправления кода внутри функции RNBOsproFindFirstUnit можно поправить условные переходы после каждого её вызова, но гораздо проще и быстрее поступить вышеописанным образом. По ходу дела, не забывайте осуществлять изменения в самом файле WlscGen.exe при помощи HIEW, WinHex или подобной утилиты.

RNBOsproRead(packet, address, *data)

После успешного "обнаружения" донгла с помощью RNBOsproFindFirstUnit, WlscGen пытается прочитать 16-битные ячейки донгловой памяти через RNBOsproRead. Второй параметр функции задаёт относительное местоположение запрашиваемой ячейки. Полученное значение возвращается через указатель в третьем параметре. Так-как данная функция возвращает принципиально различные значения через указатель, нам её так просто не пропатчить. Опираясь на статьи Goatass и CrackZ, CyberHeg предложил внедрить в конец RNBOsproRead массив из 128 байт для эмуляции памяти донгла. Естественно, код самой функции нужно исправить и заменить вызов драйвера донгла на чтение локального, так сказать, массива. "Правильные" значения ячеек в данном массиве определяются путём долгих мучений с отладчиком. В большинстве случаев, WlscGen проверяет значение считанной ячейки вскоре после возврата из RNBOsproRead и вы можете его перехватить и добавить в массив. Правда, иногда проверка значений происходит иным, менее элементарным образом. Далее представлен исправленный вариант RNBOsproRead:

00435CD0 _RNBOsproRead@12 proc near
00435CD0 push esi
00435CD1 push edi
00435CD2 mov eax, [packet]
00435CD6 or eax, eax
00435CD8 jnz @F
00435CDA mov ax, 2
00435CDE pop edi
00435CDF pop esi
00435CE0 retn 0Ch
00435CE3 @@: push eax
00435CE4 call sub_42F940
00435CE9 mov esi, eax
00435CEB cmp word ptr [esi], 7242h
; Здесь начинаются изменения:
00435CF0 90 nop
00435CF1 90 nop
00435CF2 55 push ebp
00435CF3 E800000000 call $+5
00435CF8 5D pop ebp ; Получить EIP
; (1Eh = 00435D16 - 00435CF8)
00435CF9 8D551E lea edx, [ebp+1Eh] ; Адрес начала
; нашего массива
00435CFC 5D pop ebp ; Восстановить стек
00435CFD 0FB74C2410 movzx ecx, [address]
; Каждая ячейка представляет собой 16-битное слово, т.е. 2 байта
; Поэтому ECX следует умножить на 2
00435D02 D1E1 shl ecx, 1
00435D04 0FB7040A movzx eax, [edx+ecx] ; Помещаем в EAX значение
; считанное из ячейки
00435D08 8B7C2414 mov edi, [*data]
00435D0C 668907 mov [edi], ax ; Сохранить результат
00435D0F 33C0 xor eax, eax ; Обнуляем eax (SP_SUCCESS)
00435D11 5F pop edi
00435D12 5E pop esi
00435D13 C20C00 retn 0000C
; А вот и наш массив:
00435D16 0000 dw 00000h ; №0
00435D18 0000 dw 00000h
00435D1A 0000 dw 00000h
00435D1C 0000 dw 00000h
00435D1E 0000 dw 00000h
00435D20 0000 dw 00000h
00435D22 0000 dw 00000h
00435D24 0000 dw 00000h
00435D26 FFFF dw 0FFFFh ; №8
00435D28 FFFF dw 0FFFFh ; №9
00435D2A 0000 dw 00000h
00435D2C FFFF dw 0FFFFh ; №11
00435D2E 0000 dw 00000h
00435D30 0000 dw 00000h
00435D32 0000 dw 00000h
00435D34 0007 dw 00700h ; №15
00435D36 0000 dw 00000h
. . . ; Забить нулями
00435D5C 0000 dw 00000h
00435D5E FFFF dw 0FFFFh ; №36
00435D60 0000 dw 00000h
. . . ; Забить нулями
00435D94 0000 dw 00000h ; №63

Обратите внимание на 4 ячейки с 0FFFFh и одну с 0700h. Эти значения были получены путём трассирования каждого вызова RNBOsproRead.

Если снова запустить WlscGen, программа должна заметно тормознуть (!) и показать окно с приглашением "Please Login". Эта задержка при запуске служит явным признаком того, что нам ещё рано праздновать. Действительно, пора заняться RNBOsproQuery, RNBOsproFindNextUnit и RNBOsproDecrement. Хотя, стоп!!! Я по себе чувствую, что вы подустали :-) Поэтому оставим эти три API для следующей главы. Я вам даже больше скажу: с RNBOsproFindNextUnit и RNBOsproDecrement вы должны быть в состоянии разобраться сами! Это будет своеобразным домашним заданием :-) Отдыхайте.

2002-2013 (c) wasm.ru