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


Скриншот программы DeblurMyImage

Программа DeblurMyImage позволяет усилить резкость фотографий при ошибочном выборе точки фокусировки или при съемке в движении. Чудесного и кристально четкого результата, конечно, ожидать не стоит, но немного улучшить качество снимков для печати или публикации вполне можно. Особенно, когда это единственный кадр, а переснять нет никакой возможности. Главная шутка юмора в том, что DeblurMyImage по сути - всего лишь графическая надстройка над бесплатной библиотекой для работы с изображениями FreeImage. Так какого хрена мы должны выкладывать за эту надстройку почти 15 евро? Тем более, что со стороны аффтара DeblurMyImage были допущены грубейшие нарушения лицензии и условий использования библиотеки FreeImage.

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


Окно регистрации

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


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

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


Строка сообщения найдена

Переходим к дизассемблеру. Посмотрим, где и как эта строка используется.
.text:0042187B                 push    ecx             ; lpFileName
.text:0042187C                 push    400h            ; nSize
.text:00421881                 push    offset word_4A481C
; lpReturnedString
.text:00421886                 push    offset aCannotSaveTheI
; "Cannot save the image due to unregister"...
.text:0042188B                 push    offset aString72 ; "string72"
.text:00421890                 lea     edx, [esp+830h+Dst]
.text:00421894                 push    edx             ; lpAppName
.text:00421895                 call    esi ; GetPrivateProfileStringW

Если посмотреть документацию по функции GetPrivateProfileString, то станет ясно, что тут программа пытается загрузить строку из внешнего языкового файла, а, если такого не найдено, то по умолчанию используется искомая строка. И word_4A481C - это указатель на участок памяти, куда эта строка будет записана для дальнейшего использования. Значит теперь посмотрим на него:
.data:004A481C ; const WCHAR word_4A481C
.data:004A481C word_4A481C     dw ?
; DATA XREF: sub_40DDB0+2276
; sub_420F10+971

Всего две перекрестные ссылки. Одна, как мы уже выяснили, это инициализация строки. Очевидно, что оставшаяся - место, где эта строка используется, то есть выводится на экран в виде сообщения. Так и есть:
; Вызвать какую-то функцию проверки
.text:00410011                 call    sub_40D170
; Если она вернула AL=0, то вывести сообщение на экран, иначе перейти
; к сохранению файла 
.text:00410016                 test    al, al
.text:00410018                 mov     byte_4C5734, al
.text:0041001D                 jnz     short loc_41004B
.text:0041001F                 push    0               ; uType
.text:00410021                 push    offset word_49481C ; lpCaption
; Вот она наша строка сообщения
.text:00410026                 push    offset word_4A481C ; lpText
.text:0041002B                 push    edi             ; hWnd
; А вот и функция показа сообщения
.text:0041002C                 call    ds:MessageBoxW
.text:00410032                 xor     eax, eax
.text:00410034                 pop     edi
.text:00410035                 pop     esi
.text:00410036                 pop     ebx
.text:00410037                 mov     ecx, [esp+3DF4h+var_4]
.text:0041003E                 xor     ecx, esp
.text:00410040                 call    sub_425146
.text:00410045                 mov     esp, ebp
.text:00410047                 pop     ebp
.text:00410048                 retn    10h
.text:0041004B ; ------------------------------------------
.text:0041004B loc_41004B:
.text:0041004B                 push    800h            ; size_t
.text:00410050                 lea     eax, [esp+3E04h+Dst]
.text:00410057                 push    0               ; int
.text:00410059                 push    eax             ; void *
...

Дальше и ходить никуда не надо, все и так ясно. Вызывается функция проверки, по ее результату или выводится на экран сообщение о невозможности сохранения по причине незарегистрированности или выполняется переход на сохранения файла. Осталось посмотреть на функицю проверки по адресу 40D170:
.text:0040D170                 push    ecx
.text:0040D171                 push    ebx
.text:0040D172                 push    1
.text:0040D174                 call    sub_40C980
.text:0040D179                 push    0
.text:0040D17B                 mov     bl, al
.text:0040D17D                 call    sub_40C980
.text:0040D182                 add     esp, 8
.text:0040D185                 mov     [esp+8+var_1], al
.text:0040D189                 call    sub_40D030
.text:0040D18E                 test    bl, bl
.text:0040D190                 pop     ebx
.text:0040D191                 jnz     short loc_40D19A
.text:0040D193                 cmp     [esp+4+var_1], 0
.text:0040D198                 jz      short loc_40D1A5
.text:0040D19A loc_40D19A:
.text:0040D19A                 test    al, al
.text:0040D19C                 jnz     short loc_40D1A5
.text:0040D19E                 mov     eax, 1
.text:0040D1A3                 pop     ecx
.text:0040D1A4                 retn
.text:0040D1A5 ; ---------------------------------------------------
.text:0040D1A5 loc_40D1A5:
.text:0040D1A5                 xor     eax, eax
.text:0040D1A7                 pop     ecx
.text:0040D1A8                 retn

Если посмотреть все перекрестные ссылки на нее, то видно, что все они так или иначе связаны с триальным статусом. Это показ сообщений, открытие первого диалогового окна с регистрацией, активация пунктов меню. И везде используется регистр AL. Значит просто пропатчим эту функцию, чтобы она всегда возвращала AL=1. Это уже хорошо знакомая нам пара команд MOV AL,1 и RET, которые надо записать по адресу 0040D170. Сохраняем изменения, запускаем. Окно с предложением регистрации пропало, а при сохранении отредактированного файла вместо сообщения об ошибке появляется диалог выбора имени сохраняемого файла.

Все, защиту мы обошли, справедливость восстановлена. А на месте разработчиков различных бесплатных компонентов я бы запрещал их использование в составе коммерческих продуктов. Ибо нефиг пытаться нарубить капусты на чужом энтузиазме.
Добавлено: 14 Сентября 2013 02:40:03 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...