Blog. Just Blog

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

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Темная сторона Силы | Автор: ManHunter
Скриншот программы WinImage
Скриншот программы WinImage

WinImage – одна из лучших программ для создания, чтения и редактирования образов всевозможных дисков и файловых систем, включая DMF, VHD, VMDK, FAT, ISO, NTFS и Linux. С помощью WinImage вы сможете создать образ любого носителя, просматривать его содержание, извлекать необходимые файлы и добавлять новые, а также дефрагментировать и менять формат. Но цена в 30$ и ограничения пробной версии портят все впечатление.

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

Триальное окно
Триальное окно

При попытке регистрации неправильным серийником программа выводит вот такое сообщение:

Сообщение о неправильной регистрации
Сообщение о неправильной регистрации

Строка сообщения обнаруживается в ресурсах. Рядом с ней находится строка о правильной регистрации. Но нас пока интересует неправильная регистрация, точнее индекс строки. Он равен 1067 в десятичной системе счисления или 42Bh в шестнадцатеричной.

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

Теперь поищем в коде место, где используется этот индекс. Найдется только один участок кода:
  1. ; Получить регистрационное имя и введенный серийник
  2. .text:0044AD79                 call    esi ; GetDlgItemTextA
  3. .text:0044AD7B                 push    ebx
  4. .text:0044AD7C                 mov     eax, edi
  5. ; Вызвать функцию проверки
  6. .text:0044AD7E                 call    sub_452224
  7. .text:0044AD83                 xor     edx, edx
  8. .text:0044AD85                 pop     ecx
  9. .text:0044AD86                 mov     ecx, dword_4B4060
  10. .text:0044AD8C                 mov     dword_4B4BD8, eax
  11. ; Если результат проверки EAX=0, то серийник неправильный
  12. .text:0044AD91                 cmp     eax, edx
  13. .text:0044AD93                 jz      short loc_44AD9B
  14. .text:0044AD95                 mov     dword_4B3CC8, ecx
  15. .text:0044AD9B loc_44AD9B:
  16. .text:0044AD9B                 mov     dword_4B4380, ecx
  17. .text:0044ADA1                 cmp     dword_4B3CC8, edx
  18. .text:0044ADA7                 jnz     short loc_44ADAE
  19. .text:0044ADA9                 mov     dword_4B4380, eax
  20. .text:0044ADAE loc_44ADAE:
  21. .text:0044ADAE                 xor     esi, esi
  22. .text:0044ADB0                 inc     esi
  23. .text:0044ADB1                 cmp     eax, edx
  24. .text:0044ADB3                 jnz     short loc_44ADDE
  25. ; Загрузить из ресурсов строку о неправильной регистрации
  26. .text:0044ADB5                 push    2010h
  27. .text:0044ADBA                 push    42Dh
  28. .text:0044ADBF                 mov     dword_4B48D4, esi
  29. .text:0044ADC5                 mov     dword_4B4378, esi
  30. .text:0044ADCB                 mov     byte_4B4818, dl
  31. .text:0044ADD1                 mov     byte_4B44B0, dl
  32. .text:0044ADD7                 push    42Bh
  33. .text:0044ADDC                 jmp     short loc_44ADF9
  34. .text:0044ADDE ; -------------------------------------
  35. .text:0044ADDE loc_44ADDE:
  36. .text:0044ADDE                 push    2040h           ; uType
  37. .text:0044ADE3                 push    42Dh            ; int
  38. .text:0044ADE8                 mov     dword_4B48D4, edx
  39. .text:0044ADEE                 mov     dword_4B4378, edx
  40. .text:0044ADF4                 push    42Ah            ; int
Настала очередь отладчика. Загружаем в него программу, ставим точку останова на вызов функции проверки по адресу 0044AD7E и пройдем ее в пошаговом режиме. Ее код целиком я приводить здесь не буду, только самое начало:
  1. .text:00452224                 push    ebp
  2. .text:00452225                 mov     ebp, esp
  3. .text:00452227                 and     dword_4B4060, 0
  4. .text:0045222E                 sub     esp, 200h
  5. .text:00452234                 push    esi
  6. .text:00452235                 lea     ecx, [ebp+sz]   ; lpsz
  7. .text:0045223B                 call    sub_45213D
  8. .text:00452240                 mov     eax, [ebp+arg_0]
  9. ; Вызвать функцию генерации правильного серийника
  10. .text:00452243                 call    sub_45215E
  11. .text:00452248                 mov     esi, eax
  12. .text:0045224A                 cmp     esi, 0B8DCDD26h
  13. .text:00452250                 jz      loc_452461
  14. .text:00452256                 lea     eax, [ebp+sz]
  15. .text:0045225C                 push    eax
  16. .text:0045225D                 lea     eax, [ebp+var_200]
  17. .text:00452263                 push    esi
  18. .text:00452264                 push    eax
  19. ; Сравнить введенный серийник с правильным
  20. .text:00452265                 call    sub_4521D8
  21. .text:0045226A                 pop     ecx
  22. .text:0045226B                 pop     ecx
  23. .text:0045226C                 push    eax
  24. .text:0045226D                 call    sub_474E60
  25. .text:00452272                 pop     ecx
  26. ...
В пошаговом режиме отладчика хорошо видно, что на основании регистрационного имени по очереди генерируются различные серийные номера, которые, в свою очередь сравниваются с введенной строкой серийника.

Сравнение серийников на стеке
Сравнение серийников на стеке

Сравнение серийников на стеке
Сравнение серийников на стеке

Сравнение серийников на стеке
Сравнение серийников на стеке

Я проверил, можно брать любой из них, он подойдет для регистрации. В принципе, на этом можно и остановиться, но давайте посмотрим, как генерируется проверочный серийник, например, самый первый.
  1. .text:0045215E sub_45215E      proc near
  2. .text:0045215E                 push    ebp
  3. .text:0045215F                 mov     ebp, esp
  4. .text:00452161                 sub     esp, 108h
  5. .text:00452167                 lea     ecx, [ebp+sz]   ; lpsz
  6. ; Начальное значение серийника
  7. .text:0045216D                 mov     [ebp+var_4], 0047694Ch
  8. ; Перевести регистрационное имя в верхний регистр
  9. .text:00452174                 call    sub_45213D
  10. .text:00452179                 lea     eax, [ebp+sz]
  11. .text:0045217F                 push    eax             ; lpString
  12. .text:00452180                 call    ds:lstrlenA
  13. .text:00452186                 xor     ecx, ecx
  14. ; Длина регистрационного имени
  15. .text:00452188                 mov     [ebp+var_8], eax
  16. .text:0045218B                 test    eax, eax
  17. .text:0045218D                 jle     short loc_4521D3
  18. .text:0045218F                 push    ebx
  19. .text:00452190                 push    esi
  20. .text:00452191                 mov     esi, [ebp+var_8]
  21. .text:00452194                 push    edi
  22. ; Указатель на регистрационное имя
  23. .text:00452195                 lea     edi, [ebp+sz]
  24. .text:0045219B loc_45219B:
  25. ; Цикл вычисления правильного серийника
  26. .text:0045219B                 mov     eax, ecx
  27. .text:0045219D                 push    0Eh
  28. .text:0045219F                 cdq
  29. .text:004521A0                 pop     ebx
  30. .text:004521A1                 idiv    ebx
  31. .text:004521A3                 test    edx, edx
  32. .text:004521A5                 jnz     short loc_4521AA
  33. .text:004521A7                 push    27h
  34. .text:004521A9                 pop     esi
  35. .text:004521AA loc_4521AA:
  36. .text:004521AA                 lea     eax, [ecx+3]
  37. .text:004521AD                 movzx   edx, byte ptr [edi+eax-3]
  38. .text:004521B2                 imul    edx, esi
  39. .text:004521B5                 add     [ebp+var_4], edx
  40. .text:004521B8                 push    0Eh
  41. .text:004521BA                 cdq
  42. .text:004521BB                 pop     ebx
  43. .text:004521BC                 idiv    ebx
  44. .text:004521BE                 test    edx, edx
  45. .text:004521C0                 jz      short loc_4521C7
  46. .text:004521C2                 imul    esi, 3
  47. .text:004521C5                 jmp     short loc_4521CA
  48. .text:004521C7 loc_4521C7:
  49. .text:004521C7                 imul    esi, 7
  50. .text:004521CA loc_4521CA:
  51. .text:004521CA                 inc     ecx
  52. .text:004521CB                 cmp     ecx, [ebp+var_8]
  53. .text:004521CE                 jl      short loc_45219B
  54. .text:004521D0                 pop     edi
  55. .text:004521D1                 pop     esi
  56. .text:004521D2                 pop     ebx
  57. .text:004521D3 loc_4521D3:
  58. ; EAX = правильный серийник
  59. .text:004521D3                 mov     eax, [ebp+var_4]
  60. .text:004521D6                 leave
  61. .text:004521D7                 retn
  62. .text:004521D7 sub_45215E      endp
Процедура настолько очевидная, что для создания кейгена ее можно копировать прямо из дизассемблера. После небольшой чистки и коррекции адресов, генерация серийника сводится вот к такому компактному коду:
  1.         ; Длина имени
  2.         mov     [len],eax
  3.         mov     [key],0047694Ch
  4.         mov     edi,regname
  5.         xor     ecx,ecx
  6. loc_45219B:
  7.         mov     eax, ecx
  8.         cdq
  9.         mov     ebx,0Eh
  10.         idiv    ebx
  11.         test    edx, edx
  12.         jnz     loc_4521AA
  13.         mov     esi,27h
  14. loc_4521AA:
  15.         lea     eax,[ecx+3]
  16.         movzx   edx,byte [edi+ecx]
  17.         imul    edx,esi
  18.         add     [key],edx
  19.         cdq
  20.         mov     ebx,0Eh
  21.         idiv    ebx
  22.         test    edx,edx
  23.         jz      short loc_4521C7
  24.         imul    esi,3
  25.         jmp     short loc_4521CA
  26. loc_4521C7:
  27.         imul    esi,7
  28. loc_4521CA:
  29.         inc     ecx
  30.         cmp     ecx,[len]
  31.         jl      short loc_45219B
  32.         ; [key] -> серийник
После этого значение DWORD из переменной [key] переводится в шестнадцатеричную строку, она же и является правильным серийным номером. Так, для имени "ManHunter / PCL" серийник будет "412DBD22". Проверим, что у нас получилось:

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

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

Поделиться ссылкой ВКонтакте
Просмотров: 5971 | Комментариев: 15

Внимание! Статья опубликована больше года назад, информация могла устареть!

Комментарии

Отзывы посетителей сайта о статье
Petya (02.02.2024 в 16:32):
Пытался восстановить имя. Ничего вменяемого, слишком много коллизий. Лучший кандидат из найденного -
ЦитатаNM DF SB XWJMOWYVUH
. Не называйте так своих детей, или они не смогут купить WinImage!
ManHunter (26.01.2024 в 13:24):
Именно так, странно только, что лишь один серийник.
Petya (26.01.2024 в 13:22):
Меня вот сравнение с B8DCDD26 заинтересовало. Чёрный список? Не пропускать имя, "хэш" которого такой-то?
ManHunter (14.06.2019 в 17:53):
В статье всё подробно написано, приведены все адреса и все необходимые фрагменты кода, даже выделен отдельно алгоритм генерации серийника. Если это непонятно, то я ничем помочь не могу. Делай свою курсовую самостоятельно.
ManGoL (14.06.2019 в 17:45):
Вы же писали эту статью бесплатно. Хотя бы просто объяснить какие способы защиты применяются. либо давайте договоримся не бесплатно
ManHunter (14.06.2019 в 15:26):
Серьезно? Сидеть рисовать блок-схему, да еще поди и бесплатно? Я лучше с детьми в парк схожу погулять.
ManGoL (14.06.2019 в 04:04):
Здравствуйте! Огромное спасибо за Вашу статью! Не могли бы вы описать полный механизм защиты программы? Если можно в виде блок схемы.
P.S. заранее СПАСИБО!!!
othy (21.07.2015 в 19:16):
ManHunter, из парочки 9.x не того. Да и "412DBD22" не катит.. это задумка такая..
ManHunter (15.04.2015 в 00:05):
Там проверяются два серийника для Pro-версии и штук пять для Standard. У меня в статье серийник для Standard.
DimitarSerg (15.04.2015 в 00:01):
Я в начале 2011 кейгенил (очень громко сказано), одна из первых закейгененных прог была :)
Только у меня 9 едитов для серийников, видимо разные виды.
user (14.04.2015 в 15:03):
ЦитатаДержи еще парочку для коллекции:

Спасибо. Взаимообразно - rghost.ru/7GF2TwDxg
ЦитатаА вот генератор с исходниками кому интересно.

Спасибо too. Для коллекции.
Movic (14.04.2015 в 09:17):
А вот генератор с исходниками кому интересно.
http://nashdisk.ru/0acc43
ManHunter (14.04.2015 в 07:15):
ЦитатаПопадалось два кейгена:

Держи еще парочку для коллекции: http://rghost.ru/7rjMMvBRH
user (14.04.2015 в 02:30):
Да, и ещё - ключи бывают двух видов - Standard и Pro.
Я не вдавался в подробности, чем они отличаются, но факт.
Вообще, пользовался патченной старой версией 6(?), мне хватало.
А с этими ключами задолбаешься их вводить на каждой машине..
user (14.04.2015 в 02:11):
Попадалось два кейгена:
- от HOMBO/CORE (1998 г.) - для версии 4.х
- от ТМG (2006 г.) - для версии 8.х
Оба они нормально работают и с этой версией 9.0.
Это кстати внушает уважение к Gilles Vollant'у.
Правда, не вполне понятно, зачем там тогда приверчен демо-режим..
Хорошая программа.

Добавить комментарий

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

*Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п., а также флуд и сообщения не по теме, будут удаляться. Нарушителям может быть заблокирован доступ к сайту.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2024
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.3 сек. / MySQL: 2 (0.0102 сек.) / Память: 4.5 Mb
Наверх