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


Скриншот программы PDF Password Remover

PDF Password Remover от компании VeryPDF Inc - очень нужная и полезная в компьютерном хозяйстве программа. Она позволяет снимать с PDF-файлов защиту паролем и различные ограничения, например, запрет копирования текста или печати, которые особо одаренные аффтары устанавливают для защиты своих "аффтарских прав". И все бы хорошо, но PDF Password Remover за свои услуги требует денег, а в пробном режиме запускается всего 50 раз.

Скачиваем с сайта дистрибутив (последняя версия на момент публикации 3.1), запускаем, устанавливаем. Предварительный осмотр пациента указывает, что исполняемый файл упакован обычным UPX, но после упаковки в нем были затерты названия секций и служебные данные упаковщика, так что простым "upx -d" тут дело не обойдется. Можно распаковать вручную, или же воспользоваться каким-нибудь универсальным или специализированным распаковщиком, выбор оружия оставляю за вами. Готовый распакованный файл загоняем в дизассемблер, параллельно запустим его, чтобы посмотреть на внешние проявления защиты.


Окно ввода регистрационных данных

Вах, "Machine ID"! Как все серьезно! :) По идее, такой способ регистрации используется, чтобы привязывать каждую копию программы к определенной уникальной машине. Расстраиваться не будем, посмотрим что нам скажет программа на ввод какого-нибудь левака. "Your registration key is wrong, please double check it and try again." Ну да, вполне ожидаемо. Теперь поищем нехорошую строку в распакованном файле.


"Нехорошая" строка найдена

И посмотрим код, который на нее ссылается. Тут все просто и понятно, никаких сюрпризов нет.
seg000:00405375                 mov     edi, 4B94F0h
seg000:0040537A                 push    4B94F0h
seg000:0040537F                 push    3FBh
seg000:00405384                 push    esi
seg000:00405385                 rep stosd
seg000:00405387                 call    ds:dword_4883FC
seg000:0040538D                 push    4B94F0h
; Вызвать процедуру проверки введенных регистрационных данных
seg000:00405392                 call    sub_404BF0   ; <---- Проверка
seg000:00405397                 add     esp, 4
; Если она вернула EAX=0, то введенный код неправильный
seg000:0040539A                 test    eax, eax
seg000:0040539C                 jz      short loc_4053E2
seg000:0040539E                 push    40h
; Сообщение об успешной регистрации "Thank you."
seg000:004053A0                 push    offset aThankYou_
; "Thanks for purchasing the PDF Password "...
seg000:004053A5                 push    offset aThanksForPurch
seg000:004053AA                 push    esi
seg000:004053AB                 call    ds:dword_488404
seg000:004053B1                 push    ecx
seg000:004053B2                 mov     ecx, esp
seg000:004053B4                 mov     [esp+0E8h+var_D8], esp
seg000:004053B8                 push    (offset byte_4B9418+0D8h) ; Src
seg000:004053BD                 call    sub_47BC59
seg000:004053C2                 call    sub_404FC0
seg000:004053C7                 add     esp, 4
seg000:004053CA                 mov     dword ptr ds:byte_4B9418+1A0h, 1
seg000:004053D4                 push    1
seg000:004053D6                 push    esi
seg000:004053D7                 call    ds:dword_488400
seg000:004053DD                 jmp     loc_405665
seg000:004053E2 ; -------------------------------------------------------
seg000:004053E2 loc_4053E2:
seg000:004053E2                 push    10h
seg000:004053E4                 push    0
; "Your registration key is wrong, please "...
seg000:004053E6                 push    offset aYourRegistrati
seg000:004053EB                 push    esi
seg000:004053EC                 call    ds:dword_488404
seg000:004053F2                 push    3FBh
seg000:004053F7                 push    esi

Теперь есть два пути. Первый - просто пропатчить процедуру проверки ключа, чтобы она всегда возвращала EAX=1, или же попробовать разобрать алгоритм проверки. Плюсы есть в каждом способе. Пропатченная версия становится портабельной и замечательно работает с любых съемных носителей. Зарегистрированная версия хорошо ставится на стационарную машину и не требует никаких вмешательств в исполняемый код. Посмотрим саму процедуру проверки одновременно под отладчиком и в дизассемблере. Сразу бросается в глаза, что ей передается только введенный код, а грозный "Machine ID" вообще нигде не используется. Получается, что привязка к железу - простая пустышка для создания видимости навороченной защиты.
; Если будете патчить, то это делается здесь
seg000:00404BF0                 sub     esp, 18h ; <-- MOV AL,1; RET
seg000:00404BF3                 or      ecx, 0FFFFFFFFh
seg000:00404BF6                 xor     eax, eax
seg000:00404BF8                 push    ebx
seg000:00404BF9                 push    esi
seg000:00404BFA                 mov     esi, [esp+20h+arg_0]
seg000:00404BFE                 push    edi
seg000:00404BFF                 mov     edi, esi
seg000:00404C01                 repne scasb
; Собственная функция для подсчета длины строки
seg000:00404C03                 not     ecx
seg000:00404C05                 dec     ecx
; Длина введенного серийника должны быть 14h (десятичное 20) символов
seg000:00404C06                 cmp     ecx, 14h
seg000:00404C09                 jz      short loc_404C12
; Иначе EAX=0 и на выход
seg000:00404C0B                 pop     edi
seg000:00404C0C                 pop     esi
seg000:00404C0D                 pop     ebx
seg000:00404C0E                 add     esp, 18h
seg000:00404C11                 retn

Теперь мы знаем длину правильного серийного номера - ровно 20 символов.
seg000:00404C12 loc_404C12:
; Взять первый и второй символ
seg000:00404C12                 mov     al, [esi]
seg000:00404C14                 mov     cl, [esi+1]
seg000:00404C17                 lea     edx, [esp+24h+Str]
seg000:00404C1B                 xor     bl, bl
seg000:00404C1D                 push    edx             ; Str
seg000:00404C1E                 mov     [esp+28h+var_C], al
seg000:00404C22                 mov     [esp+28h+var_B], bl
seg000:00404C26                 mov     [esp+28h+Str], cl
seg000:00404C2A                 mov     [esp+28h+var_17], bl
; Перевести второй символ в цифру
seg000:00404C2E                 call    _atoi
; Записать его в EDI
seg000:00404C33                 mov     edi, eax
seg000:00404C35                 lea     eax, [esp+28h+var_C]
seg000:00404C39                 push    eax             ; Str
; Перевести первый символ в цифру
seg000:00404C3A                 call    _atoi
; Прибавить ко второму
seg000:00404C3F                 add     edi, eax
seg000:00404C41                 add     esp, 8
; Результат = 10?
seg000:00404C44                 cmp     edi, 0Ah
; Если да, то продолжаем
seg000:00404C47                 jz      short loc_404C52
; Иначе EAX=0 и на выход
seg000:00404C49                 pop     edi
seg000:00404C4A                 pop     esi
seg000:00404C4B                 xor     eax, eax
seg000:00404C4D                 pop     ebx
seg000:00404C4E                 add     esp, 18h
seg000:00404C51                 retn

Первая проверка: берутся первый и второй символ серийника, затем преобразуются в цифры и складываются. В сумме должно получиться 10.
seg000:00404C52 loc_404C52:
; Взять последний и предпоследний символы
seg000:00404C52                 mov     cl, [esi+12h]
seg000:00404C55                 mov     dl, [esi+13h]
seg000:00404C58                 lea     eax, [esp+24h+Str]
seg000:00404C5C                 mov     [esp+24h+var_C], cl
seg000:00404C60                 push    eax             ; Str
seg000:00404C61                 mov     [esp+28h+var_B], bl
seg000:00404C65                 mov     [esp+28h+Str], dl
seg000:00404C69                 mov     [esp+28h+var_17], bl
; Преобразовать последний символ в цифру
seg000:00404C6D                 call    _atoi
seg000:00404C72                 lea     ecx, [esp+28h+var_C]
seg000:00404C76                 mov     edi, eax
; Преобразовать предпоследний символ в цифру
seg000:00404C78                 push    ecx             ; Str
seg000:00404C79                 call    _atoi
seg000:00404C7E                 add     edi, eax
seg000:00404C80                 add     esp, 8
; Сумма цифр = 12?
seg000:00404C83                 cmp     edi, 0Ch
; Если да, то продолжаем
seg000:00404C86                 jz      short loc_404C91
; Иначе EAX=0 и на выход
seg000:00404C88                 pop     edi
seg000:00404C89                 pop     esi
seg000:00404C8A                 xor     eax, eax
seg000:00404C8C                 pop     ebx
seg000:00404C8D                 add     esp, 18h
seg000:00404C90                 retn

Вторая проверка: последний и предпоследний символ переводятся в числовое значение, их сумма должна быть равна 12.
seg000:00404C91 loc_404C91:
; Взять 6-й и 14-й символ (здесь нумерация символов идет с 1)
seg000:00404C91                 mov     dl, [esi+5]
seg000:00404C94                 mov     al, [esi+0Dh]
seg000:00404C97                 lea     ecx, [esp+24h+Str]
seg000:00404C9B                 mov     [esp+24h+var_C], dl
seg000:00404C9F                 push    ecx             ; Str
seg000:00404CA0                 mov     [esp+28h+var_B], bl
seg000:00404CA4                 mov     [esp+28h+Str], al
seg000:00404CA8                 mov     [esp+28h+var_17], bl
seg000:00404CAC                 call    _atoi
seg000:00404CB1                 lea     edx, [esp+28h+var_C]
seg000:00404CB5                 mov     edi, eax
seg000:00404CB7                 push    edx             ; Str
seg000:00404CB8                 call    _atoi
seg000:00404CBD                 add     edi, eax
seg000:00404CBF                 add     esp, 8
; Их сумма должна быть равна 11
seg000:00404CC2                 cmp     edi, 0Bh
; Если да, то продолжаем
seg000:00404CC5                 jz      short loc_404CD0
seg000:00404CC7                 pop     edi
seg000:00404CC8                 pop     esi
seg000:00404CC9                 xor     eax, eax
seg000:00404CCB                 pop     ebx
seg000:00404CCC                 add     esp, 18h
seg000:00404CCF                 retn

Третья проверка: 6-й и 14-й символ в сумме должны давать 11.
seg000:00404CD0 loc_404CD0:
; 13-й символ должен быть = 'K'
seg000:00404CD0                 cmp     byte ptr [esi+0Ch], 4Bh
seg000:00404CD4                 jz      short loc_404CDF
seg000:00404CD6                 pop     edi
seg000:00404CD7                 pop     esi
seg000:00404CD8                 xor     eax, eax
seg000:00404CDA                 pop     ebx
seg000:00404CDB                 add     esp, 18h
seg000:00404CDE                 retn
seg000:00404C12 ; ------------------------------------------------------
seg000:00404CDF loc_404CDF:
; 15-й символ должен быть = '3'
seg000:00404CDF                 cmp     byte ptr [esi+0Eh], 33h
seg000:00404CE3                 jz      short loc_404CEE
seg000:00404CE5                 pop     edi
seg000:00404CE6                 pop     esi
seg000:00404CE7                 xor     eax, eax
seg000:00404CE9                 pop     ebx
seg000:00404CEA                 add     esp, 18h
seg000:00404CED                 retn
seg000:00404C12 ; ------------------------------------------------------
seg000:00404CEE loc_404CEE:
; 16-й символ должен быть = '1'
seg000:00404CEE                 mov     cl, [esi+0Fh]
seg000:00404CF1                 xor     eax, eax
seg000:00404CF3                 cmp     cl, 31h
seg000:00404CF6                 pop     edi
seg000:00404CF7                 pop     esi
seg000:00404CF8                 pop     ebx
seg000:00404CF9                 setz    al
seg000:00404CFC                 add     esp, 18h
seg000:00404CFF                 retn

Теперь у нас есть алгоритм генерации правильного серийного номера. Первый и второй символы в сумме должны давать 10, последний и предпоследний - 12, 6-й и 14-й символ в сумме 11, 13-й символ должен быть 'K', 15-й и 16-й символы, соответственно, '3' и '1'. Остальные символы серийного номера вообще нигде не учитываются и могут заполняться как вам нравится. Готовый серийник может быть, например, таким: 55PCL5RULEZ!K631MH66.


Программа успешно зарегистрирована

Программа его с радостью примет и поблагодарит за покупку. Ну а рабочий кейген теперь вы можете написать самостоятельно.
Теги:
защита, взлом
Добавлено: 21 Сентября 2013 03:35:37 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...