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


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

WinSnap от NTWind Software - удобная программа для создания скриншотов. От множества аналогов отличается тем, что корректно захватывает окна непрямоугольной формы, позволяет сразу же добавлять эффект тени, наносить водяные знаки на изображение, захватывать несколько последовательных окон, а также имеет другие полезные функции, которых нет у конкурентов. Но в пробной версии показывает всякие наг-скрины и маркирует все создаваемые скриншоты своим логотипом. Для исследования защиты нам потребуется дизассемблер и дистрибутив, на момент публикации последняя версия WinSnap 3.0.8 от мая 2009 года.

Устанавливаем и запускаем программу. Нас тут же встречает наг-скрин с предложением потратить наше бабло на покупку или ввести регистрационные данные. Нажимаем кнопку "Зарегистрировать", вводим имя и любой левый серийник, получаем отлуп "Лицензионный ключ неверен!". Отлично, образец "нехорошей" строки у нас есть. Загоняем exe-файл в дизассемблер, и пока он работает, посмотрим где эта строчка имеется. В папке "lang" лежат файлы локализации программы на разных языках, нас интересует русский. В нем и находится наша строчка:

32052="Лицензионный ключ неверен!"


Число 32052 - это уникальный идентификатор строки, по которому она запрашивается из основной программы. Дизассемблер уже закончил свою работу, попробуем поискать число 32052 в коде, только предварительно его надо перевести в шестнадцатеричное представление (получится 7D34h). Найдется только одно вхождение:
; Тут и выше всякие манипуляции с текстовыми строчками
.text:0040188D                 push    edx
.text:0040188E                 lea     eax, [ebp+var_1590]
.text:00401894                 push    eax             ; int
.text:00401895                 lea     edi, [ebp+var_55C]
.text:0040189B                 lea     ecx, [ebp+String] ; lpWideCharStr
.text:004018A1                 mov     [ebp+var_1590], ebx
.text:004018A7                 mov     [ebp+var_1594], ebx
; Вызов функции проверки, результат которой влияет на дальнейшую работу
.text:004018AD                 call    sub_40A6F0
.text:004018B2                 add     esp, 8
.text:004018B5                 test    al, al
.text:004018B7                 jnz     short loc_4018C8
; Вот тут загружается "нехорошая" строка из языкового файла и выводится
; диалогово окно с сообщением об ошибке
.text:004018B9                 mov     ecx, 7D34h  ; <-- код строки 32052
.text:004018BE                 call    sub_408930
.text:004018C3                 jmp     loc_401A83
.text:004018C8
; Сюда мы попадаем, если функция проверки вернула AL=1, то есть все нормально
.text:004018C8 loc_4018C8:
.text:004018C8                 lea     ecx, [ebp+String]
.text:004018CE                 push    ecx
; Дальше по тексту вывод сообщения с благодарностью за регистрацию, запись
; введенных данных в ключевой файл и прочие ништяки для зарегистрированного
; пользователя программы

Теперь посмотрим саму функцию проверки:
.text:0040A6F0                 sub     esp, 114h
.text:0040A6F6                 mov     eax, dword_450050
.text:0040A6FB                 xor     eax, esp
.text:0040A6FD                 mov     [esp+114h+var_8], eax
.text:0040A704                 mov     eax, [esp+114h+arg_4]
.text:0040A70B                 push    ebp
.text:0040A70C                 mov     ebp, [esp+118h+arg_0]
.text:0040A713                 push    esi
.text:0040A714                 push    7Fh             ; Size
.text:0040A716                 mov     esi, ecx
.text:0040A718                 lea     ecx, [esp+120h+Dst]
.text:0040A71F                 push    0               ; Val
.text:0040A721                 push    ecx             ; Dst
.text:0040A722                 mov     [esp+128h+var_110], eax
.text:0040A726                 mov     [esp+128h+MultiByteStr], 0
.text:0040A72E                 call    _memset
.text:0040A733                 push    7Fh             ; Size
.text:0040A735                 lea     edx, [esp+12Ch+var_10B]
.text:0040A739                 push    0               ; Val
.text:0040A73B                 push    edx             ; Dst
.text:0040A73C                 mov     [esp+134h+var_10C], 0
.text:0040A741                 call    _memset
.text:0040A746                 add     esp, 18h
.text:0040A749                 push    0               ; lpUsedDefaultChar
.text:0040A74B                 push    0               ; lpDefaultChar
.text:0040A74D                 push    80h             ; cchMultiByte
.text:0040A752                 lea     eax, [esp+128h+MultiByteStr]
.text:0040A759                 push    eax             ; lpMultiByteStr
.text:0040A75A                 push    0FFFFFFFFh      ; cchWideChar
.text:0040A75C                 push    esi             ; lpWideCharStr
.text:0040A75D                 mov     esi, ds:WideCharToMultiByte
.text:0040A763                 push    0               ; dwFlags
.text:0040A765                 push    0FDE9h          ; CodePage
.text:0040A76A                 call    esi ; WideCharToMultiByte
.text:0040A76C                 test    eax, eax
; Какое-то имя введено, продолжить проверку
.text:0040A76E                 jnz     short loc_40A789
; Если строка имени пустая, то вернуть AL=0, то есть все плохо
.text:0040A770 loc_40A770:
; Вернуть AL=0 если не введено имя или серийный номер
.text:0040A770                 xor     al, al
.text:0040A772                 pop     esi
.text:0040A773                 pop     ebp
.text:0040A774                 mov     ecx, [esp+114h+var_8]
.text:0040A77B                 xor     ecx, esp
.text:0040A77D                 call    sub_432AD6
.text:0040A782                 add     esp, 114h
.text:0040A788                 retn
.text:0040A789 loc_40A789:
; Проверить введен или нет какой-нибудь серийный номер
.text:0040A789                 push    0               ; lpUsedDefaultChar
.text:0040A78B                 push    0               ; lpDefaultChar
.text:0040A78D                 push    80h             ; cchMultiByte
.text:0040A792                 lea     ecx, [esp+128h+var_10C]
.text:0040A796                 push    ecx             ; lpMultiByteStr
.text:0040A797                 push    0FFFFFFFFh      ; cchWideChar
.text:0040A799                 push    edi             ; lpWideCharStr
.text:0040A79A                 push    0               ; dwFlags
.text:0040A79C                 push    0FDE9h          ; CodePage
.text:0040A7A1                 call    esi ; WideCharToMultiByte
.text:0040A7A3                 test    eax, eax
; Если строка серийника пустая, то вернуть AL=0, то есть все плохо
.text:0040A7A5                 jz      short loc_40A770
; Записать в стек указатели на имя и серийный номер
.text:0040A7A7                 mov     edx, [esp+11Ch+var_110]
.text:0040A7AB                 push    edx
.text:0040A7AC                 lea     eax, [esp+120h+var_10C]
.text:0040A7B0                 push    eax
.text:0040A7B1                 mov     edx, ebp
.text:0040A7B3                 lea     ecx, [esp+124h+MultiByteStr]
; Вот тут вызывается вторая функция проверки, которая и выставляет
; окончательный диагноз правильности регистрационных данных
.text:0040A7BA                 call    sub_409EC0
; После вызова функции AL=0 - регистрационные данные неправильные
; или AL=1 - введенные ключ и имя правильные
.text:0040A7BF                 mov     ecx, [esp+124h+var_8]
.text:0040A7C6                 add     esp, 8
.text:0040A7C9                 pop     esi
.text:0040A7CA                 pop     ebp
.text:0040A7CB                 xor     ecx, esp
.text:0040A7CD                 call    sub_432AD6
.text:0040A7D2                 add     esp, 114h
.text:0040A7D8                 retn
.text:0040A7D8 sub_40A6F0      endp

Если посмотреть вторую функцию проверки по адресу 409EC0, то можно обнаружить в ней множество всяких арифметических действий, проверок и вычислений. При большом желании и наличии кучи свободного времени можно попытаться отреверсить алгоритм проверки ключа, но похоже, что он завязян на нехилой криптографии, поэтому проще пропатчить исполняемый файл, чтобы любые регистрационные данные считались правильными. Это лучше сделать или в первой функции проверки по адресу 0040A6F0 или во второй по адресу 00409EC0, заменив первые команды на MOV AL,1; RET. После этих манипуляций WinSnap будет принимать в качестве регистрационных данных любое имя и серийный номер. Можно даже выделить сигнатуру и нарисовать универсальный патч для обычной и портативной версии WinSnap, но это уже сделайте самостоятельно.
Теги:
защита, взлом
Добавлено: 21 Сентября 2013 06:18:14 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...