SentinelLM!WlscGen_CRK_2

Дата публикации 10 сен 2003

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

Дорогие коллеги, предлагаю вашему вниманию заключительную статью из цикла о SentinelLM. Вы уже знаете, что от полного счастья нас отделяет одна единственная функция SLM API. Итак, пришло время нанести смертельный удар по SLM SDK, т.е. пропатчить функцию RNBOsproQuery.

Я наивно полагаю, что вы уже изучили "SentinelSuperPro 6.0 Developer's Guide" и прекрасно представляете себе работу этой функции, но "повторение -- мать учения" (© русский народ). RNBOsproQuery уподобается чёрному ящику, в который поступают произвольные данные и выходят данные не менее произвольные. Количество байт во входном массиве равно количеству байт в выходном. Последние 4 байта выходного массива дублируются в 32-битной ячейке памяти.

RNBOsproQuery(packet, address, *queryData, *response, *response32, length)

address -- это номер ячейки донгла, с которой начинается алгоритм; queryData -- входной массив; response -- выходной массив; response32 -- последние 4 байта выходных данных, представленные в виде 32-битной переменной; length -- длинна (в байтах) как входного, так и выходного массивов.

Чтоб окончательно вас запутать, далее представлен "графический эквивалент" описания RNBOsproQuery:

А что всё-таки там за алгоритм кроется в недрах донгла? Каким образом выходные данные связаны со входными? Кто застрелил Дж. Ф. Кеннеди? Что было вначале: яйцо или курица? Надеюсь, вы теперь понимаете почему хак RNBOsproQuery порой представляет собой изрядную сложность даже для опытного реверсера.

CyberHeg в своей статье предлагает очень интересный, но довольно сложный, подход к решению этой проблемы. Правда, в случае с WlscGen.exe обращения к RNBOsproQuery осуществляются в стиле

Код (Text):
  1.  
  2.  if(!isQueryOK()) goto fig_vam;

т.е. пропатчить этот код не просто, а очень просто! Причём RNBOsproQuery вызывается всего лишь 4 раза и обработка результата почти одинакова во всех четырёх случаях. Итак, грузим WlscGen.exe в IDA, применяем соответствующие сигнатуры и задаём поиск вызовов RNBOsproQuery. Вот вам и первый результат:

Код (Text):
  1.  
  2. 00423611 loc_423611:
  3. 00423611             xor    ebx, ebx
  4. 00423613             push   ebx
  5. 00423614             call   _time
  6. 00423619             add    esp, 4
  7. 0042361C             push   eax
  8. 0042361D             call   _srand
  9. 00423622             add    esp, 4
  10. 00423625             call   _rand     <span class=y>; Генерируем случайное число (X)</span>
  11. 0042362A             cdq
  12. 0042362B             mov    ecx, 0Ah
  13. 00423630             idiv   ecx       <span class=y>; dx = X%10 (остаток от деления)</span>
  14. 00423632             movzx  eax, dx
  15. 00423635             imul   eax, 9
  16. 00423638             mov    [var_A], dx   <span class=y>; Сохраняем случайное число</span>
  17.                      . . .
  18. 00423659             lea    ecx, [var_18]
  19. 0042365C             lea    eax, [var_94]
  20. 00423662             lea    edx, [var_D0]
  21. 00423668             push   4                    <span class=y>; length</span>
  22. 0042366A             push   ecx                  <span class=y>; *response32</span>
  23. 0042366B             push   eax                  <span class=y>; *response</span>
  24. 0042366C             lea    ecx, [var_4D4]
  25. 00423672             push   edx                  <span class=y>; *queryData</span>
  26. 00423673             push   0Ch                  <span class=y>; address</span>
  27. 00423675             push   ecx                  <span class=y>; packet</span>
  28. 00423676             call   <strong>_RNBOsproQuery@24</strong>
  29. 0042367B             lea    ecx, [var_58]
  30. 0042367E             lea    edx, [var_94]
  31. 00423684             push   ecx
  32. 00423685             push   4
  33. 00423687             push   edx
  34.                      ; Конвертируем response32 в строку
  35. 00423688             call   sub_42394F
  36. 0042368D             add    esp, 0Ch
  37. 00423690             lea    ecx, [var_58]
  38.                      ; Извлекаем наше случайное число
  39. 00423693             movzx  eax, [var_A]
  40. 00423697             imul   eax, 9
  41. 0042369A             push   4
  42. 0042369C             add    eax, OFFSET a3a70b51a
  43. 004236A1             push   eax
  44. 004236A2             push   ecx
  45. 004236A3             call   <strong>_strncmp</strong>              <span class=y>; Оно или не оно?</span>
  46. 004236A8             add    esp, 0Ch
  47. 004236AB             mov    edi, eax
  48. 004236AD             test   edi, edi
  49. 004236AF             jz     short loc_4236C4      <span class=y>; Оно!!!</span>

Что делает этот код? Ладно, объясняю:

  1. генерируем случайное число стандартным сишным методом;
  2. колдуем над этим числом и переводим его в массив;
  3. подсовываем этот массив в RNBOsproQuery для обработки алгоритмом 0Ch (адрес начальной ячейки алгоритма);
  4. результат обработки конвертируем в ASCII-строку;
  5. используем случайное число из пункта 1 для адресации фиксированного в экзешнике массива со строковыми константами;
  6. сравниваем обе строки;
  7. если строки совпадают, продолжаем (последний переход JZ).

Тот фиксированный массив в программе является своеобразным рангом алгоритма 0Ch, т.е. он хранит все возможные результаты данного алгоритма. Я рекомендую вам пройтись по данному участку кода под отладчиком и убедиться в тривиальности всей проблемы. Что нам мешает исправить тот последний переход? Ну, вообще говоря, правильнее будет поксорить регистр EAX на месте вызова _strncmp, как будто строки равны. Заодно можно убрать вызов RNBOsproQuery чтоб лишний раз не беспокоить драйвер. Тривиальный патч:

Код (Text):
  1.  
  2. 00423668             push   4
  3. 0042366A             push   ecx
  4. 0042366B             push   eax
  5. 0042366C             lea    ecx, [var_4D4]
  6. 00423672             push   edx
  7. 00423673             push   0Ch
  8. 00423675             push   ecx
  9. 00423676 <span class=b>83C418</span>      add    esp, 18h    <span class=y>; Восстанавливаем стек</span>
  10. 00423679 <span class=b>90</span>          nop                <span class=y>; вместо вызова RNBOsproQuery</span>
  11. 00423679 <span class=b>90</span>          nop
  12. 0042367B             lea    ecx, [var_58]
  13. 0042367E             lea    edx, [var_94]
  14. 00423684             push   ecx
  15. 00423685             push   4
  16. 00423687             push   edx
  17. 00423688             call   sub_42394F
  18. 0042368D             add    esp, 0Ch
  19. 00423690             lea    ecx, [var_58]
  20. 00423693             movzx  eax, [var_A]
  21. 00423697             imul   eax, 9
  22. 0042369A             push   4
  23. 0042369C             add    eax, OFFSET a3a70b51a
  24. 004236A1             push   eax
  25. 004236A2             push   ecx
  26. 004236A3 <span class=b>33С0</span>        xor    eax, eax     <span class=y>; обнуляем EAX</span>
  27. 004236A5 <span class=b>90</span>          nop                 <span class=y>; вместо вызова strncmp</span>
  28. 004236A6 <span class=b>90</span>          nop
  29. 004236A7 <span class=b>90</span>          nop
  30. 004236A8             add    esp, 0Ch
  31. 004236AB             mov    edi, eax
  32. 004236AD             test   edi, edi
  33. 004236AF             jz     short loc_4236C4

Остальные 3 вызова RNBOsproQuery фиксятся аналогичным образом. Справедливости ради стоит заметить что подобных глюков (иначе и не назовёшь явное сравнение через _strncmp) вы больше не увидите. RNBOsproQuery кроет в себе громадный потенциал, который по достоинству ценят лишь немногие пользователи SLM, хакеры и мы с вами. Чего только нельзя сделать используя ячейки с алгоритмами, содержание которых недоступно реверсеру?! Даже идея со случайным числом, хеш-алгоритмами и массивом строк можно было бы назвать удачной, если б не то [нецензурный эпитет] сравнение сразу после RNBOsproQuery.

Ну вот и всё: WlscGen.exe к употреблению готов! Попробуйте создать пробную лицензию (задайте параметры по вашему усмотрению) и убедитесь в работоспособности генератора. Получилось? Тогда достаньте ваш любимый патчегенератор (Patch Creation Wizard, например) и сделайте универсальный патч для WlscGen.exe (не фиксить же его вручную при каждой смене VId?!). Не распространяйте ваш патч потом в сети, ладно?

Давайте подытожим наши знания. Для этого рассмотрим два типичных случая использования SLM.

1. SentinelSuperPro API

Пример: WlscGen.exe.
Документация: "SentinelSuperPro 6.0 Developer's Guide".
Приложение использует функции работы с донглом: RNBOsproRead, RNBOsproWrite, RNBOsproQuery и т.д. Задача исследователя заключается в обнаружении и последующем обезвреживании данных функций, как мы и поступили с WlscGen. Данный случай можно назвать низкоуровневой защитой (приложение явно опирается на архитектуру донгла).

2. SLM Client API и иже с ним

Пример: мой таргет и все-все-все.
Документация: "SentinelLM Programmer's Reference Manual", "SentinelLM Developer's Guide".
Приложение использует высокоуровневые функции, вроде LSRequest. Всю грязную работу (чтение лицензионного файла, общение с донглом и т.д.) выполняет API. Обратите внимание на то, что API может и не обращаться к донглу если лицензионный файл того не требует. Типичный подход к решению проблемы требует получения VId жертвы и некоторой информации о самой лицензии (тип лицензии, версия лицензируемой фичи, наименование фичи и т.д.) Полученная информация передаётся в WlscGen и создаётся новая лицензия (без триального срока... без донгла... :smile3: Стоп! А откуда взять эту дополнительную информацию о самой лицензии? В самом простом случае её можно выудить из оригинального лицензионного файла. Имя по умолчанию для лиц. файлов -- lservrc (без расширения). Вот, например, демо-версия моей жертвы досталась мне с файлом следующего содержания (некоторая информация удалена по понятным причинам):
Код (Text):
  1.  
  2.  # XXX for: Quantum Sent with Order: YYY
  3.  N2V3R7MXTCCQRM2VQGDSJLXEDJSR88N33SM4QZ# "BPR" version "0"
  4.  1Z26N2ZXJ5ANS95HMPGOEYX46HPSTB9Y7V274Z# "DRC" version "0"
  5.  WA18DMVBR8NGDOXW9ZAUDLBAPXHNKORQPUWWET2FBA# "BPR" version "91"
  6.  5QM2OCB28W63R3XYIF473Z2PFY73XOTZ5O872JH5CY# "DRC" version "91"</pre>
  7. </blockquote>
  8. <p>
  9. Итого: 4 лицензии. Вся необходимая WlscGen'у информация любезно предоставлена в каждой строчке после '#'. А что если файла нет? Или он есть но без полной информации? Тогда чуть сложнее... Придётся задействовать IDA + SoftIce и перехватить вызовы LSRequest. Вот вам типичный пример использования LSRequest (фрагмент взят из первой попавшейся под руку демки):
  10. <blockquote><pre>
  11. 00463804             push   eax
  12. 00463805             mov    ecx, esi
  13. 00463807             mov    BYTE PTR [3BCh+var_4], 0Bh
  14. 0046380F             call   sub_461810
  15. 00463814             mov    ebp, [eax]
  16. 00463816             lea    ecx, [3B8h+var_330]
  17. 0046381D             push   OFFSET unk_4E10B0
  18. 00463822             push   ecx
  19. 00463823             mov    BYTE PTR [3C0h+var_4], 0Ch
  20. 0046382B             call   sub_464090
  21. 00463830             mov    eax, [eax]
  22. 00463832             push   ebx                  <span class=y>; *handle</span>
  23. 00463833             push   0                    <span class=y>; challenge</span>
  24. 00463835             lea    edx, [3C8h+var_39C]
  25. 00463839             push   0                    <span class=y>; log comment</span>
  26. 0046383B             push   edx                  <span class=y>; tokens</span>
  27. 0046383C             push   edi                  <span class=y>; feature version</span>
  28. 0046383D             push   ebp                  <span class=y>; feature name</span>
  29. 0046383E             push   eax                  <span class=y>; publisher</span>
  30. 0046383F             push   0                    <span class=y>; licsystem</span>
  31. 00463841             call   _LSRequest
  32. 00463846             add    esp, 28h

Параметры LSRequest напоминают искомую нами информацию... Да, так оно и есть:

LSRequest(licsystem,publisher,feature name,feature version, tokens,log comment,challenge,*handle)

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

Теперь вы скажете: "А какого @#% мы столько возились с WlscGen, ведь можно было просто найти и пофиксить LSRequest в коде нашей жертвы?!". Хмм... Я предпочитаю оставить этот вопрос вам на засыпку. Помедитируйте над ним :smile3:

Существуют и другие вариации SLM, как-то: сетевой сервер SLM, новомодный SentinelLM Shell (тоже входит в SDK). Но это уже темы для отдельных статей. Короче, бросайте всё и бегите добивать ваш таргет!

Неужели это всё?!

Наверное я не затронул и десятой доли того, что входит в теорию взлома SentinelLM. Вы дочитываете последнюю главу вступления в SLM! Если вы смогли удачно воплотить в код то, что я тут описал, плюс поняли суть самой защиты и её снятия, значит я не зря потратил время. Как говаривал Фокс Мольдер, "Я хочу верить" :smile3:

Для дальнейшего изучения рекомендую кучу / уйму туториалов по взлому конкретных таргетов под защитой Sentinel. Особенно хороши статьи CyberHeg, CrackZ и Goatass, которые можно найти... в сети. Нет, всё это добро конечно лежит на сайте CrackZ, но сам сайт CrackZ постоянно кочует. Тут (http://66.98.132.48/krobar/collections/crackz.zip) можно качнуть оффлайновую версию всего сайта. На Krobars (http://krobars.reverse-engineering.info/) можно найти многие статьи по SLM и донглам вообще. Ещё эти статьи прозеркалены на других сайтах, даже в переводе. На испанском, например, это добро можно скачать с сайта Karpoff (http://hackindex.com/~karpoff/Manuales.htm#Dongles).

Теперь о главном...

Премного благодарствую всем писателям статей по Sentinel (too many и всех не перечислить), а также коллективу WASM.RU, включая уважаемых членов форума. Отдельной благодарности заслуживают volodya (щедрый поощритель начинающих писателей) и главные редакторы (вы их и сами знаете :smile3:. Большое спасибо и вам, дорогой читатель и коллега. Да пребудет с вами сила Дзена и свобода мысли! © Quantum


0 1.403
archive

archive
New Member

Регистрация:
27 фев 2017
Публикаций:
532