
Скриншот программы TopStyle 4
TopStyle - лучшая программа для работы с каскадными таблицами стилей CSS. Предоставляет разработчику такие мощные инструменты, как автодополнение, предпросмотр стилей во встроенном браузере, валидацию стилей, поддержку юникода, позволяет обновлять стили прямо на сервере и совместима со всеми современными браузерами. Но раз программа появилась в этом разделе, значит у нее все-таки есть недостатки. Она требует регистрацию, естественно, за некоторую сумму денег.
Для работы нам потребуется дистрибутив последней версии 4.0.0.62 и дизассемблер. Устанавливаем, запускаем. Налицо все признаки триальности: надпись "Trial" в заголовке программы, триальные надписи и ссылка на покупку в окне About, сообщения об ограничениях в редакторе и еще целая куча подобных прелестей.

Триальные надписи в окне "О программе"
Смотрим исполняемый файл. По характерным названиям секций визуально определяем, что он накрыт ASPack. Анализаторы исполняемых файлов это подтверждают.

Файл упакован ASPack
Распаковываем его или вручную, или с помощью инструментов типа QuickUnpack или Abstersiver, проверяем работоспособность после распаковки и загоняем в дизассемблер. Файл достаточно большой, так что времени на его полную обработку тоже уйдет немало. Когда дизассемблер закончит работу, начнем поиски "нехороших строк" и ссылающегося на них кода.

"Нехорошая строка"
Ссылающийся на строчку код:
...
.text:008F0E77 loc_8F0E77:
; Вызов функции проверки регистрации
.text:008F0E77 call sub_8F0C3C
.text:008F0E7C test al, al
; Если она вернула 1, то программа зарегистрирована
.text:008F0E7E jnz short loc_8F0E8D
.text:008F0E80 lea eax, [ebp+var_4]
; Ссылка на строку "trial mode (unregistered)"
.text:008F0E83 mov edx, offset aTrialModeUnreg
.text:008F0E88 call sub_405A00
.text:008F0E8D
.text:008F0E8D loc_8F0E8D:
.text:008F0E8D cmp [ebp+var_4], 0
...
Забиваем в начало процедуры по адресу 008F0C3C команды MOV AL,1; RET, запускаем, строка пропала. Но все остальные триальные признаки остались. Поищем другой признак, например, строку "Trial" в заголовке:
...
; Вызов функции проверки регистрации
.text:0096FB17 call sub_96F968
.text:0096FB1C test al, al
.text:0096FB1E jnz short loc_96FB2D
.text:0096FB20 lea eax, [ebp+var_4]
; Ссылка на строку "Trial"
.text:0096FB23 mov edx, offset aTrial ; " Trial"
.text:0096FB28 call sub_405C60
.text:0096FB2D loc_96FB2D:
.text:0096FB2D mov eax, ebx
.text:0096FB2F call sub_9749F0
.text:0096FB34 test eax, eax
...
Смотрим процедуру по адресу 0096F968 и видим, что она точно такая же! Не та же, а точно такая же. Пропатчиваем ее таким же образом, надпись в заголовке пропала. Попробуем теперь поискать по сигнатуре все аналогичные процедуры проверки. Сразу скажу, что их будет около полутора десятков, в этом плане автор явно большой шутник. Запускаем и видим, что внешние триальные признаки пропали, но через секунду после открытия главного окна появляется сообщение "TopStyle failed a data integrity check, which means either that an error occurred while downloading or that the EXE has been tampered with. Please download this program again." и программа закрывается. Значит еще присутствует проверка целостности кода. Давайте поищем ее. Строка сообщения об ошибке содержится в ресурсах с индексом 0FCEFh, а ссылающийся код сделан в виде такой конструкции:
.text:00581E70 off_581E70 dd offset hInstance
.text:00581E74 dd 0FCEFh ; <-- наш индекс
В свою очередь на эту конструкцию ссылается указатель в сегменте данных:
.data:009E8764 off_9E8764 dd offset off_581E70
А вот на этот указатель ссылается уже 5 процедур, и снова все они однотипные:
.text:00972E44 push ebp
.text:00972E45 mov ebp, esp
.text:00972E47 xor ecx, ecx
.text:00972E49 push ecx
.text:00972E4A push ecx
.text:00972E4B push ecx
.text:00972E4C push ecx
.text:00972E4D push ecx
.text:00972E4E push ecx
.text:00972E4F push ebx
.text:00972E50 mov ebx, eax
.text:00972E52 xor eax, eax
.text:00972E54 push ebp
.text:00972E55 push offset loc_972EFD
.text:00972E5A push dword ptr fs:[eax]
.text:00972E5D mov fs:[eax], esp
.text:00972E60 push ebx
.text:00972E61 lea edx, [ebp+var_4]
; Здесь выводится окно с сообщением о нарушении целостности, после этого
; программа закрывается
.text:00972E64 mov eax, off_9E8764
.text:00972E69 call sub_408254
.text:00972E6E mov eax, [ebp+var_4]
.text:00972E71 push eax
.text:00972E72 lea eax, [ebp+var_10]
.text:00972E75 call sub_9AF3E0
.text:00972E7A mov eax, [ebp+var_10]
.text:00972E7D mov [ebp+var_C], eax
.text:00972E80 mov [ebp+var_8], 0Bh
.text:00972E84 lea edx, [ebp+var_C]
.text:00972E87 xor ecx, ecx
.text:00972E89 pop eax
.text:00972E8A call sub_40F35C
.text:00972E8F push 10h
.text:00972E91 lea eax, [ebp+var_18]
.text:00972E94 call sub_9AF390
.text:00972E99 mov eax, [ebp+var_18]
.text:00972E9C lea edx, [ebp+var_14]
.text:00972E9F call sub_40E3A4
.text:00972EA4 mov eax, [ebp+var_14]
.text:00972EA7 call sub_405E24
.text:00972EAC push eax
.text:00972EAD mov eax, [ebx]
.text:00972EAF call sub_405E24
.text:00972EB4 mov edx, eax
.text:00972EB6 mov eax, off_9E8518
.text:00972EBB mov eax, [eax]
.text:00972EBD pop ecx
.text:00972EBE call sub_4E86E0
.text:00972EC3 mov eax, off_9E70DC
.text:00972EC8 mov dword ptr [eax], 17h
.text:00972ECE mov eax, off_9E8518
.text:00972ED3 mov eax, [eax]
.text:00972ED5 call sub_4E85E0
.text:00972EDA xor eax, eax
.text:00972EDC pop edx
.text:00972EDD pop ecx
.text:00972EDE pop ecx
.text:00972EDF mov fs:[eax], edx
.text:00972EE2 push offset loc_972F04
.text:00972EE7 loc_972EE7:
.text:00972EE7 lea eax, [ebp+var_18]
.text:00972EEA mov edx, 3
.text:00972EEF call sub_40598C
.text:00972EF4 lea eax, [ebp+var_4]
.text:00972EF7 call sub_405968
.text:00972EFC retn
.text:00972EFD loc_972EFD:
.text:00972EFD jmp loc_4050F8
.text:00972F02 jmp short loc_972EE7
.text:00972F04 loc_972F04:
.text:00972F04 pop ebx
.text:00972F05 mov esp, ebp
.text:00972F07 pop ebp
.text:00972F08 retn
Уже зная повадки автора, можно предположить, что и здесь все было сделано простым копированием исходников. А поскольку процедура не содержит условных переходов и просто выводит окно с сообщением, то надо смотреть код, который ее вызывает.
...
; Тут какая-то движуха с вычислениями с плавающей запятой
.text:00972FB2 call sub_48AEE8
.text:00972FB7 fstp [ebp+var_10]
.text:00972FBA wait
.text:00972FBB push dword ptr [ebp+var_10+4]
.text:00972FBE push dword ptr [ebp+var_10] ; double
.text:00972FC1 call sub_410F28
.text:00972FC6 add esp, 0FFFFFFF8h
.text:00972FC9 fstp [esp+74h+var_74]
.text:00972FCC wait
; Какая-то функция проверки
.text:00972FCD call sub_8856EC
.text:00972FD2 cmp eax, 3
; Этот условный переход надо пропатчить на безусловный
.text:00972FD5 jl short loc_97300B
; Этот код выполняется, когда проверка целостности не пройдена
.text:00972FD7 mov [ebp+var_1], 1
.text:00972FDB lea eax, [ebp+var_18]
; Вызвать окно с сообщением об ошибке
.text:00972FDE call sub_972E44
.text:00972FE3 lea eax, [ebp+var_28]
.text:00972FE6 mov dl, 1
.text:00972FE8 call sub_41B710
.text:00972FED lea edx, [ebp+var_28]
...
По очереди смотрим все участки кода и заменяем условные переходы, которые предшествуют вызовам сообщений об ошибке целостности. Таких участков будет пять. Сохраняем изменения, запускаем. Все работает как часы.