Исследование защиты программы Sothink SWF Decompiler


Скриншот программы Sothink SWF Decompiler

Sothink SWF Decompiler от компании SourceTec Software - одна из лучших программа для декомпиляции Flash-файлов в формате SWF и Flash EXE, извлечения из них ресурсов, скриптов, графики, музыки, восстановления исходных кодов проектов и т.д. Незаменимый инструмент при изучении чужих разработок и восстановления своих исходников в случае их утери. Было бы странным предполагать, что авторы будут распространять такую прелесть "за красивые глазки", так оно и есть, стоимость Sothink SWF Decompiler почти 80 вечнозеленых денег.

Скачиваем дистрибутив и устанавливаем его. Предварительный анализ исполняемого файла показывает, что он упакован навесным протектором Armadillo. Для распаковки воспользуемся программой ArmaGeddon. К сожалению, она пока не работает под Windows 7, так что придется запускать ее под какой-нибудь виртуальной машиной с установленной Windows XP.


Распаковываем файл

В логе видно, что для защиты использованы почти все опции, но ArmaGeddon успешно с ними справляется. Через несколько секунд получаем распакованный файл размером почти в два раза превышающий исходный. Попробуем немного сократить размер, удалив из него уже ненужные секции протектора. Сделать это можно при помощи программы CFF Explorer, которая входит в состав Explorer Suite.


Удаляем из файла секции протектора

В нашем случае не использовалась опция протектора, когда имена секций заменяются на случайный набор символов, это немного облегчит работу. Секции протектора имеют имена, похожие на имена оригинальных секций, но с добавлением в конец цифры, к тому же они идут подряд: .text1, .adata, .data1, .pdata. Отрезайте их по одной, предварительно сделав резервную копию распакованного файла и проверяя каждый раз работоспособность полученного файла. Опытным путем установлено, что безболезненно можно отрезать секции .text1, .adata, .pdata, после чего файл сразу "похудел" наполовину. Загоняем его в дизассемблер и вернемся к теории. Протектор Armadillo предоставляет функции регистрации защищаемых программ своими средствами. Для взаимодействия с защищаемой программой используются переменные окружения, в которые записываются данные об имени пользователя, ключе регистрации (если он найден в системе), триальном времени работы, количестве одновременно запущенных копий и другую информацию. Эти переменные имеют неизменные имена, значит их можно поискать в файле.


Найдены имена переменных окружения

Имена переменных найдены, они хранятся в файле в юникоде. Переменная EXPIRED устанавливается, когда триальный срок закончился, в переменной DAYSLEFT записано количество оставшихся дней, USERKEY содержит регистрационный ключ, если он установлен. Подробнее о наименованиях переменных и их значениях можете почитать в документации к Armadillo, если интересно, нас же интересует только переменная USERKEY. Посмотрим, где и как она обрабатывается.
; Процедура проверки переменной окружения USERKEY. Возвращает EAX=1,
; если такая переменная установлена (т.е. программа зарегистрирована),
; и EAX=0, если нет.
.text:00446310                 sub     esp, 20Ch
.text:00446316                 mov     eax, dword_9F18B8
.text:0044631B                 xor     eax, esp
.text:0044631D                 mov     [esp+20Ch+var_4], eax
.text:00446324                 push    esi
.text:00446325                 mov     esi, [esp+210h+arg_0]
.text:0044632C                 push    104h            ; nSize
.text:00446331                 lea     eax, [esp+214h+Src]
.text:00446335                 push    eax             ; lpBuffer
; Получить переменную окружения USERKEY
.text:00446336                 push    offset aUserkey ; lpName
.text:0044633B                 call    ds:GetEnvironmentVariableW
.text:00446341                 test    eax, eax
; Такая переменная не установлена
.text:00446343                 jbe     short loc_446387
.text:00446345                 lea     eax, [esp+210h+Src]
.text:00446349                 lea     edx, [eax+2]
.text:0044634C                 lea     esp, [esp+0]
.text:00446350 loc_446350:
.text:00446350                 mov     cx, [eax]
.text:00446353                 add     eax, 2
.text:00446356                 test    cx, cx
.text:00446359                 jnz     short loc_446350
.text:0044635B                 sub     eax, edx
.text:0044635D                 sar     eax, 1
.text:0044635F                 push    eax             ; int
.text:00446360                 lea     ecx, [esp+214h+Src]
.text:00446364                 push    ecx             ; Src
.text:00446365                 mov     ecx, esi
.text:00446367                 call    sub_4024D0
; Переменная есть, установить флаг EAX=1
.text:0044636C                 mov     eax, 1
.text:00446371                 pop     esi
.text:00446372                 mov     ecx, [esp+20Ch+var_4]
.text:00446379                 xor     ecx, esp
.text:0044637B                 call    sub_7BE489
.text:00446380                 add     esp, 20Ch
.text:00446386                 retn
.text:00446387 ; -----------------------------------------------
.text:00446387 loc_446387:
.text:00446387                 mov     ecx, [esp+210h+var_4]
.text:0044638E                 pop     esi
.text:0044638F                 xor     ecx, esp
; Переменной нет, установить флаг EAX=0
.text:00446391                 xor     eax, eax
.text:00446393                 call    sub_7BE489
.text:00446398                 add     esp, 20Ch
.text:0044639E                 retn
.text:0044639E sub_446310      endp

По перекрестным ссылкам смотрим, что эта процедура проверки вызывается из другой процедуры, которая в свою очередь вызывается уже как минимум из трех мест. Логично предположить, что основной процедурой, возвращающей признак "зарегистрировано" является именно родительская процедура. Под отладчиком видно, что флаг зарегистрированности возвращается в регистре EAX. Значит пропатчим родительскую процедуру, записав в ее начало команды MOV EAX,1; RET. Сохраняем изменения, запускаем программу. Стартовое наг-окно пропало. Теперь проверяем функционал программы. Оппа, при попытке декомпиляции любого ролика выдается следующее сообщение:


Собщение незарегистрированной программы

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


Строка сообщения в ресурсах

Код строки 302, или в шестнадцатеричном виде 12Eh. Поищем в дизассемблированном листинге строку "12Eh".
; Вызвать какую-то функцию проверки чего-то
.text:00455C28                 call    sub_4466F0
.text:00455C2D                 test    al, al
; Если она вернула AL=0, то окно с сообщением о незарегистрированной
; программе не выводить
.text:00455C2F                 jz      short loc_455C5F
.text:00455C31                 cmp     byte ptr word_9FD804+1, 0
.text:00455C38                 jz      short loc_455C5F
.text:00455C3A                 lea     eax, [esp+14h+var_10]
; Загрузить строку с кодом 302 (12Eh) из ресурсов
.text:00455C3E                 push    12Eh
.text:00455C43                 push    eax
.text:00455C44                 call    sub_4629D0
.text:00455C49                 mov     ecx, [esp+1Ch+var_10]
.text:00455C4D                 add     esp, 8
; Вывести окно сообщения
.text:00455C50                 push    0               ; int
.text:00455C52                 push    41h             ; uType
.text:00455C54                 push    ecx             ; int
.text:00455C55                 call    ?AfxMessageBox@@YGHPB_WII@Z
; AfxMessageBox(wchar_t const *,uint,uint)
.text:00455C5A                 cmp     eax, 1
.text:00455C5D                 jnz     short loc_455C0D
.text:00455C5F loc_455C5F:

На вывод окна влияет результат процедуры sub_4466F0, для активации нужной нам ветки алгоритма она должна вернуть EAX=0:
.text:004466F0                 call    sub_445B50
.text:004466F5                 mov     ecx, eax
.text:004466F7                 call    sub_446690
.text:004466FC                 neg     eax
.text:004466FE                 sbb     eax, eax
.text:00446700                 inc     eax
.text:00446701                 retn

Что она делает? Первая процедура интереса не представляет, так как не влияет на результат, а вот вторая, sub_446690, как раз и проверяет по очереди установленные переменные навесной защиты - наличие ключа и окончание триального срока. Для обхода всей этой канители нужно, чтобы sub_446690 вернула EAX=1. Второй патч - записываем в начало sub_446690 команды MOV EAX,1; RET. Сохраняем изменения, запускаем. Все признаки триальности исчезли, программа работает на полную мощность. Цель достигнута. Очень похожим способом обходятся защиты и других программ SourceTec, хотя и со своими тонкостями.

Про наличие кейгенов для навесных защит Armadillo, в том числе и для программ SourceTec, я прекрасно знаю, но информация о способах и алгоритмах кейгенинга для широкой публики недоступна, да и без навесного протектора программы обычно работают гораздо шустрее.
Теги:
защита, взлом
Добавлено: 20 Сентября 2013 08:56:22 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...