1. Главная страница » Obsidium что это за программа

Obsidium что это за программа

Автор: | 16.12.2019

Материал из Справочник исследователя программ

Obsidium — программа для обеспечения защиты программного обеспечения и операционных систем от несанкционированной модификации (взлома), а также создания безопасных систем лицензирования и регистрации.

Содержание

Основные возможности

  • защита программного кода;
  • сжатие программного кода;
  • автоматизация генерирования лицензий;
  • защита всех видов ресурсов программы;
  • возможность использования ключей, сопоставимым по стойкости до 2048 разрядных;
  • создание черного списка недействующих ключей;
  • шифрование системы лицензий;
  • регистрация через файл-ключ или текстовой ключ;
  • создание ограниченных по времени версий программ (trial версий);
  • поддержка защиты dll.
  • поддержка 64-битных ОС.

История развития

Obsidium 1.0.0.69 первая версия, которая была доступна широкому кругу лиц. Уже тогда Obsidium поддерживал антиотладочные приемы, защиту оригинальной точки входа, мусорные команды и систему лицензирования. Позже с версии 1.4.0.0 в протектор добавилась, пожалуй самая мощная опция защиты под названием Code Virtualization. На 1 января 2011 года последней версией протектора является 1.4.4.11.

Антиотладка

Obsidium использует достаточно интересные анти-отладочные трюки, в числе которых:

IsDebuggerPresent

API-функция IsDebuggerPresent показывает, находится ли процесс, который её вызывает, в контексте отладчика, то есть отлаживается ли он.Эта функция экспортируется из KERNEL32.dll, и если программа находится под отладкой, то возвращаемое значение равно единице, а если нет, то нулю.

FindWindowA

Находит pодительское окно веpхнего уpовня с совпадающими ClassName и WindowName. Не осуществляет поиск дочеpних окон

CheckRemoteDebuggerPresent

Эта функция, в принципе, аналогична IsDebuggerPresent, но только по возвращаемым результатам. А ее начинка не похожа на IsDebuggerPresent совсем. Она, как видно, может проверять и другой процесс на наличие отладки, и способ проверки отличается от простого просмотра байта в PEB. Впервые она появилась в Windows XP SP1, поэтому ее использование не универсально. Функцию CheckRemoteDebuggerPresent можно, как обычно, перехватывать, а возвращаемые ею значения – подменять.

UnhandledExceptionFilter

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

Проверка установленных брекпоинтов

Obsidium проводит проверку наличия CC в первом байте абсолютно любой апи (непосредственно перед вызовом). Огородить себя от данной анти-отладки можно очень просто: не устанавливать брекпоинты на начало вызова WINAPI Пример

Использование исключений и SEH

Протектор очень активно использует команды приводящие к исключениям (DIV, int3 и т.д).Хоть это и не является очень сильным препятствим, но всё-таки мешает отладке программы. Также Obsidum для очистки аппартных брекпоинтов использует SEH

Потоки

Obsidum создаёт один или два дополнительных потока (Threads), которые в некоторых случаях для нормальной отладки приходиться "убивать".

Антидамп

Защита Оригинальной точки входа (OEP)

Кража OEP не является "фишкой" протектора. Крадёт он байт не много, а в некоторых программах (написанных, например на Borland C++) их даже не нужно восстанавливать. В первых версиях протектора краденные с OEP байты отрабатывались в выделенной памяти, что немного затрудняло распаковку программы.

Защита таблицы импорта

Защита таблицы импорта в Obsidium довольно серьёзная вещь. Протектор умеет получать имена API четырьмя способами (через четыре переходника):

Также протектор активно эмулирует некоторые Windows API (например GetCommandLine, GetVersion, GetCurrentProcessID и т.д), отрабатывает первые команды функций в своём защищённом коде и имеет свои собственные апи.

Runtime Patching

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

Code Virtualization

Опция защиты протектора, которая появилась в версии 1.4. Это своеобразная виртуальная машина которая отрабатывает защищённый код,который для полной распаковки программы приходится восстанавливать. Code Virtualization значительно снижает скорость работы приложения, поэтому данную защиту необходимо применять только в местах особенно критичных для взлома (например, проверка регистрации).

Другие опции

  • Шифрование ресурсов
  • Проверка запуска на виртуальных машинах
  • Случайные имена секций
  • Создание ознакомительных версий программ
Читайте также:  Ga ep45 ud3l ep45 ds3l

Доступные модели лицензирования

При использовании Obsidium для защиты приложения можно воспользоваться одной из встроенных в систему лицензирования моделью или придерживаться своей собственной системы регистрации.

Внутренняя система протектора

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

Внешняя система, созданная программистом

Программист может сам создать стойкий алгоритм и с помощю API протектора setExternalKey использовать его при защите своей программы.

Сохранение лицензии при регистрации программы

Obsidum при регистрации программы позволяет сохранять информацию в следующих местах:

Ключевой файл может иметь любое имя (по умолчанию key.dat), может находиться в папке с программой, в папке Документы пользователя или в папке Общие документы.

Автоматические распаковщики

На данный момент в сети не возможно найти ни один автоматический распаковщик к этому протектору. Радует только то, что к старым версиям протектора можно найти скрипты к OllyDbg для "полу-автомотической" распаковки.

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

Tools: Soft-Ice, HIEW, Lord PE, Import Reconstructor.

Obsidium использует вот такие приколы для затруднения анализа:

  1. Независимо от того, сколько секций было до этого, но после обработки их становиться 5 с затертыми именами (не
    затёрто только название секции .rsrc).
  2. Запакованные ресурсы.
  3. Своеобразные переходники в импорте.
  4. Управление на функции из внешних dll передается обычно на 3-ю от начала инструкцию.
  5. Вызовы GetTickCount для замера времени выполнения некоторых участков.
  6. Определяет наличие отладчика 3 уровня, чтобы он трогал Soft-Ice я не заметил.
  7. Обнаружение драйвера revirgin’а: CreateFileA(“\.RvtracerDevice0”).
  8. Relocation образа исполняемого файла, а не только
    dll.
  9. Динамическая распаковка.
  10. Собственные API.
  11. Вставка в некоторые места программы ложных инструкций, с последующей обработкой этих исключений.З
  12. абирает к себе несколько начальных байт из
    OEP.
  13. Большое количество мусорных инструкций.

Кстати, хочу заметить, что работу с dll данная защита пока не поддерживает.

Практически все производимые операции obsidium реализует на основе нескольких функций, которые записаны вот в такую структуру:

Смешение Описание
+0 Базовый адрес, по которому находится новый образ исполняемого файла.
+20 Вызывает процедуру, CRC имени которой ей передана в качестве параметра.
+24 Определяет длину инструкции, адрес на которую передан в качестве параметра.
+30 Считает контрольную сумму строки переданной в параметре.
+39 Старый базовый адрес исполняемого файла(до обработки защитой)
+40 Ищет адрес функции, по CRC имени.
+44 Ищет адрес начала образа библиотеки.
+48 Базовый адрес библиотеки kernel32.dll
+4C Базовый адрес библиотеки user32.dll
+50 Размер образа исполняемого файла.
+68 Используя релоки, производит настройку кода на новый базовый адрес.
+С8 Полная распаковка необходимого участка.

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

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

Итак, при распаковке происходят следующие вещи:

  1. Выделяется 1-й раз место под переходники для импорта и другую необходимую информацию для защиты.
  2. Выделяется 2-й раз место для хранения промежуточных данных.
  3. Выделяется 3-й раз место для образа исполняемого файла.
  4. Производиться конечная распаковка файла.
  5. Настройка кода исполняемого файла с учетом нового базового адреса.
  6. Выделяется 4-й раз место (для чего я так и не понял).
  7. Удаляется выделенное на 2 этапе место.

Также хочу заметить, что все место, выделяемое защитой для работы исполняемого файла легко выделить, т.к. на этих участках стоит атрибут
Read+Write+Execute.

Итак, ставим бряк на VirtualAlloc (bpx VirtualAlloc+3) и ждем, когда вызов произойдет в 3 раз, потом выходим и топаем до тех пор, пока новый выделенный участок не заполниться данными (у меня он почти всегда находился по адресу 009С0000). Если попутно вы будете обходить все вызовы [ebx+68], то получите данные без использования релоков. Вызов функции [ebx+68] полезен тем, что он дает возможность узнать какие бывшие секции, куда “проецируются”. Узнать это можно посмотрев на передаваемые ей параметры, один из них — это смещение относительно базового адреса и размер. В итоге получаем:

Читайте также:  Huawei p smart фото с камеры
Смещение Размер
1 1000 C1000
2 C2000 C200
3 D3000 200

Поиск OEP и спертых байт

Найти предположительную OEP можно, если после дампа забить все байтом СС и в SI поставить бряк на int 3(bpint 3). Но это только предположительно, т.к. есть еще те байты, которые защита забрал к себе и до них
придется топать самостоятельно. Желательно предварительно поставить бряк на VirtualFree (bpx VirtualFree+3). Выход к OEP выглядит следующим образом:

seg000:007F5C08 mov byte ptr [ebp+eax+40C228h], 0E9h ; ‘щ’
seg000:007F5C16 mov edx, [ebp+40C334h]
seg000:007F5C21 add edx, [esi]
seg000:007F5C26 lea ecx, [ebp+eax+40C22Dh]
seg000:007F5C32 sub edx, ecx
seg000:007F5C38 mov [ebp+eax+40C229h], edx
seg000:007F5C44 popa
seg000:007F5C4A popf
// —————————Далее идут украденные байты
————————— //
seg000:007F5C53 mov eax, ds:0A8208Bh
seg000:007F5C5B shl eax, 2
seg000:007F5C64 mov ds:0A8208Fh, eax
seg000:007F5C6C push edx
seg000:007F5C71 push 0
seg000:007F5C79 jmp near ptr 9C144Ah ;
дальнейшее выполнение программы
(Для хорошей читабельности мусор и постоянные jmp удалены).

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

seg000:007F3E60 pusha
seg000:007F3E61 mov ax, 0 ; смещение в этом Thunck’е
seg000:007F3E65 mov dl, 0 ; Thunck
seg000:007F3E67 jmp loc_7F314C

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

  1. Это API Obsidium’а.
  2. В табличке храниться CRC имени функции.
  3. В табличке храниться по XOR’нный адрес функции.
  4. Адрес функции храниться не в этой табличке и функция вызывается несколько по-другому.
  5. Функции, значение которых не меняется на протяжении всего времени выполнения программы.

Интересный момент, что Obsidium заполняет в IAT на 1 больше ячеек, таким образом если IAT нескольких библиотек шли подряд, то после обработки их Obsidium’ом ImpRec распознает только одну большую IAT. Так же интересным моментом является то, что защита использует нечто вроде «кэширования», т.е. в связи с тем, что операция поиска адреса функции по CRC её имени может занимать достаточно много времени, то чтобы не вызывать эту функцию несколько раз он берет и записывает адрес искомой функции вместо адреса переходника. Я функции, относящиеся ко 2 и 3-му типу, восстанавливал путем написания плагина к ImpRec’ку, который просто создавал приблизительно такую конструкцию

nop
call reducer
nop
ret

где reducer – это текущий переходник, потом вызывал её и после её обработки получал, вместо reducer относительный адрес системной функции.

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

seg000:007F314C call $+5
seg000:007F3155 pop ebx
seg000:007F315C mov ebp, ebx
seg000:007F3161 sub ebp, 411BD2h
seg000:007F316D mov ebx, [ebx-0E9h]
seg000:007F317E call $+5
seg000:007F3187 add dword ptr [esp], 20h ; ‘ ‘
seg000:007F318B mov ecx, [ebp+411BC9h]
seg000:007F3194 call ecx ; последняя инструкция функции AddAtom
seg000:007F319C retn

seg000:007F31A3 mov esi, [ebx+28h]
seg000:007F31A6 movzx edx, dl
seg000:007F31A9 movzx eax, ax
seg000:007F31AC shl edx, 3
seg000:007F31AF mov ecx, edx
seg000:007F31B1 shl edx, 1
seg000:007F31B3 add ecx, edx
seg000:007F31B5 lea edi, [esi+ecx+4]
seg000:007F31B9 cmp dword ptr [edi], 0
seg000:007F31BC jz loc_7F334E
seg000:007F31C2 add esi, [edi+10h]
seg000:007F31C5 lea esi, [esi+eax*8]
seg000:007F31C8 movzx eax, word ptr [esi]
seg000:007F31CB cmp eax, 40h ; API Obsiduim’а ?
seg000:007F31CE jz loc_7F3264
seg000:007F31D4 cmp eax, 4 ; по xor’ная функция?
seg000:007F31D7 jz short loc_7F3238
seg000:007F31D9 cmp eax, 1
seg000:007F31DC jz short loc_7F320D
seg000:007F31DE movzx eax, word ptr [esi+2] ; в таблице храниться CRC

А по адресу 457А55 идет вызов функции, которая производит запись реального адреса функции в call вызвавший наш переходник.

00457F55 50 push eax
00457F56 51 push ecx
00457А57 FFD2 call edx ; вызов приведенной ниже функции

seg000:007F5214 mov edx, [ebx]
seg000:007F521B cmp eax, edx
seg000:007F5220 jb loc_7F5354 ; забиваем прыжок
seg000:007F522A add edx, [ebx+50h]
seg000:007F5232 cmp eax, edx
seg000:007F5239 jnb loc_7F5354 ; забиваем прыжок
seg000:007F5248 cmp word ptr [eax-6], 15FFh
seg000:007F5251 jnz short loc_7F52BF
.
seg000:007F52C2 cmp byte ptr [eax-5], 0E8h
seg000:007F52CB jnz loc_7F5354
seg000:007F52D7 mov edx, eax
seg000:007F52DC add edx, [eax-4]
seg000:007F52E8 mov ecx, [esi+172h]
seg000:007F52F3 add ecx, [ebx]
seg000:007F52F8 cmp edx, ecx
seg000:007F52FF jb short loc_7F5354 ; забиваем прыжок
seg000:007F5305 add ecx, [esi+176h]
seg000:007F530B cmp edx, ecx
seg000:007F5311 jnb short loc_7F5354 ; забиваем прыжок
seg000:007F531D cmp word ptr [edx], 25FFh
seg000:007F5328 jnz short loc_7F5354 ; забиваем прыжок
seg000:007F5333 mov edx, [ebp+0Ch]
seg000:007F5339 mov byte ptr [eax-5], 0E8h
seg000:007F5343 sub edx, eax
seg000:007F5348 mov [eax-4], edx
seg000:007F5357 pop ebx
seg000:007F5358 pop esi
seg000:007F5359 leave
seg000:007F535A retn 8

Читайте также:  Asus pci ex geforce gt 1030

Теперь пару слов о функциях, значение которых не меняется на протяжении всего времени выполнения программы
(GetVersion, GetCommandLineA, GetCurrentProcessId). Они имеют переходники вида:

mov eax,some_value
ret

Для их восстановления достаточно просто по очереди вызвать эти функций и проверить на равенство результата значению, помещаемому в
eax. Таким образом, мы восстановили почти всю таблицу импорта, кроме функции VirtualQuery, т.к. она единственная обрабатывается 4 способом.
Получаем восстановленный импорт(API Obsidium’а пока оставим в покое) и переходим к сборке исполняемого файла с нормальным PE-заголовком.

Я взял PE-заголовок у старого exe’шника и стал добавлять секции. Размеры и RVA могут отличаться от тех, которые мы получили выше, потому что я ставил для себя цель получить для начала работающий исполняемый файл, из-за этого я специально увеличил размер дабы исключить появления дыр между секциями, т.к. разные версии Windows на это по разному реагируют.

1. Первая у нас будет кодовая секция.
Имя: .text
RVA = 1000
Size = C1000

2. Вторая это секция с данными:
Имя: .data
RVA = C2000
Size = E00

3. Так как программа написана на Borland C++ Builder, то третья это tls секция:
Имя: .tls
RVA = D000
Size = 5000

Так же не забудьте перенести из старого исполняемого файла TLS структуру настроив её предварительно на новое местоположение.

4. Четвёртая секция будет с полученным ранее импортом.

5. Пятая секция с ресурсами. В связи с тем, что ресурсы зашифрованы, то берем
и дампим запущенный процесс, и применяем к нему утилиту Resource Rebuilder by Dr.Golova, чтобы получить новую секцию с расшифрованными ресурсами, перестроенными под новый базовый адрес.

6. Необязательная шестая секция с релоками. Релоки в первоначальном виде можно найти в участке памяти, который защита выделяет в первый раз (обычно в районе адреса 7E0000) по характерным байтам: 00 00 10 00 00 10 02 00 00

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

009C20AE push 00000517
009C20B3 call dword ptr [004010A9] ; расшифровка
.
мусор
.
009C25D0 push 00000517
009C25D5 call dword ptr [004010AD] ; обратно зашифровываем

Хочу заметить, что между этими двумя вызовами как раз 517h байт. Теперь просто делаем дамп этого участка после расшифровки и вставляем в наш дамп. Вызовы функция для шифрования теперь можно забить nop’ами.
Таких участков я нашел 7 штук. Вот они:

1. 9C20B9 — 517
2. 9C38FE — 30B
3. 9C54AB — 17
4. 9C5FB6 — D5
5. 9C668E — 8E
6. 9C6ACB — 10
7. 9E874B — 5E

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

  1. getRegInfo – возвращает в зависимости от 1-го параметра, на кого зарегистрирована программа.
  2. isRegistered – возвращает true, если программа зарегистрирована.
  3. CheckRegCode(в документации я её не нашел) – проверяет регистрационный код(вызывается только 1 раз при вводе регистрационного кода).

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

  • Obsidium 1.6 has been released
  • Also available: Cross-platform licensing library (Windows, Linux, MacOS, x86 and x64)

Obsidium is a feature-rich professional software protection and licensing system that was designed as a cost effective and easy to implement, yet reliable and non-invasive way to protect your 32- and 64-bit Windows software applications and games from reverse engineering, unauthorized modifications ("cracking") and redistribution ("software piracy") while providing a secure and flexible licensing/registration system.

It is primarily aimed at software companies and individual developers who would like to provide feature- or time-limited evaluation versions of their software products, but also allows for the implementation of a wide range of custom licensing scenarios.

Visit the Details page for a list of key features.

A functionally limited demo version of Obsidium is available for download and may be evaluated without a time limit.

Раздел: Без рубрики

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

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

*

code