Blog. Just Blog

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

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

Программа HTML Password Wizard предназначена для создания защищенных HTML-страниц, содержимое которых отображается только после ввода правильного пароля. Практическую ценность этого я оставлю за рамками этой статьи, тут же будет исследование ее защиты. Проект благополучно скончался, так что даже если у кого-то вдруг возникло бы желание купить эту программу, у него все равно ничего бы не получилось.

Забираем с файлообменника дистрибутив, распаковываем, устанавливаем. Исполняемый файл ничем не упакован, отправляем его на разборку в дизассемблер.

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

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

Триальное окно в ресурсах
Триальное окно в ресурсах

Шаблон триального окна находится в ресурсах исполняемого файла под индексом 205 или 0CDh, если в шестнадцатеричной системе счисления. Поищем в листинге код, где это значение используется, а также чтобы рядом была какая-нибудь функция для работы с ресурсами или диалоговыми окнами. Обнаружится следующий код:
  1. .text:0040A2B0                 push    ebp
  2. .text:0040A2B1                 mov     ebp, esp
  3. .text:0040A2B3                 push    0FFFFFFFFh
  4. .text:0040A2B5                 push    offset loc_46DC98
  5. .text:0040A2BA                 mov     eax, large fs:0
  6. .text:0040A2C0                 push    eax
  7. .text:0040A2C1                 push    ecx
  8. .text:0040A2C2                 mov     eax, dword_498608
  9. .text:0040A2C7                 xor     eax, ebp
  10. .text:0040A2C9                 push    eax
  11. .text:0040A2CA                 lea     eax, [ebp+var_C]
  12. .text:0040A2CD                 mov     large fs:0, eax
  13. .text:0040A2D3                 mov     [ebp+var_10], ecx
  14. .text:0040A2D6                 mov     eax, [ebp+arg_0]
  15. .text:0040A2D9                 push    eax
  16. ; Открыть диалоговое окно с идентификатором 205
  17. .text:0040A2DA                 push    0CDh
  18. .text:0040A2DF                 mov     ecx, [ebp+var_10]
  19. .text:0040A2E2                 call    ??0CDialog@@QAE@IPAVCWnd@@@Z
  20. ; CDialog::CDialog(uint,CWnd *)
  21. .text:0040A2E7                 mov     [ebp+var_4], 0
  22. .text:0040A2EE                 mov     ecx, [ebp+var_10]
  23. .text:0040A2F1                 mov     dword ptr [ecx], offset off_4751A4
  24. .text:0040A2F7                 mov     ecx, [ebp+var_10]
  25. .text:0040A2FA                 add     ecx, 74h
  26. .text:0040A2FD                 call    sub_40A6D0
  27. .text:0040A302                 mov     edx, [ebp+var_10]
  28. .text:0040A305                 mov     dword ptr [edx+0C8h], 0
  29. .text:0040A30F                 mov     [ebp+var_4], 0FFFFFFFFh
  30. .text:0040A316                 mov     eax, [ebp+var_10]
  31. .text:0040A319                 mov     ecx, [ebp+var_C]
  32. .text:0040A31C                 mov     large fs:0, ecx
  33. .text:0040A323                 pop     ecx
  34. .text:0040A324                 mov     esp, ebp
  35. .text:0040A326                 pop     ebp
  36. .text:0040A327                 retn    4
Код вынесен в отдельную функцию, которая, в свою очередь, единственный раз вызывается вот отсюда:
  1. .text:0040DE2A                 mov     ecx, [ebp+var_7B8]
  2. ; Вызвать функцию проверки
  3. .text:0040DE30                 call    sub_40EDD0
  4. ; Сохранить ее результат в переменной
  5. .text:0040DE35                 mov     [ebp+var_818], eax
  6. ; Загрузить в ECX значение переменной
  7. .text:0040DE3B                 mov     ecx, [ebp+var_818]
  8. ; Установить статус зарегистрированности
  9. .text:0040DE41                 mov     dword_4999B8, ecx
  10. .text:0040DE47                 cmp     dword_4999BC, 0
  11. .text:0040DE4E                 jnz     short loc_40DE5A
  12. .text:0040DE50                 mov     dword_4999B8, 0
  13. .text:0040DE5A loc_40DE5A:
  14. ; Программа зарегистрирована?
  15. .text:0040DE5A                 cmp     dword_4999B8, 0
  16. .text:0040DE61                 jnz     loc_40DEEE
  17. ; Нет, показать триальное окно
  18. .text:0040DE67                 push    0
  19. .text:0040DE69                 lea     ecx, [ebp+var_764]
  20. .text:0040DE6F                 call    sub_40A2B0
  21. .text:0040DE74                 mov     byte ptr [ebp+var_4], 12h
  22. .text:0040DE78                 mov     edx, dword_4999C4
  23. .text:0040DE7E                 push    edx
Тут происходит следующее. Вызывается функция проверки регистрации, еще результат сохраняется в переменной, которая затем проверяется на нулевое значение. По результатам этого сравнения или выполняется условный переход, или выводится триальное окно.

Функция проверки регистрации объемная, но вся мякотка заключается вот в этом коде. Проходить его лучше всего под отладчиком.
  1. ; Сформировать строку "htlpassw" из отдельных символов
  2. .text:0040EE80                 mov     [ebp+var_11C], 68h
  3. .text:0040EE87                 mov     [ebp+var_11B], 74h
  4. .text:0040EE8E                 mov     [ebp+var_11A], 6Ch
  5. .text:0040EE95                 mov     [ebp+var_119], 70h
  6. .text:0040EE9C                 mov     [ebp+var_118], 61h
  7. .text:0040EEA3                 mov     [ebp+var_117], 73h
  8. .text:0040EEAA                 mov     [ebp+var_116], 73h
  9. .text:0040EEB1                 mov     [ebp+var_115], 77h
  10. .text:0040EEB8                 mov     [ebp+var_114], 0
  11. .text:0040EEBF                 push    0FFh            ; size_t
  12. .text:0040EEC4                 lea     ecx, [ebp+MultiByteStr]
  13. .text:0040EECA                 push    ecx             ; char *
  14. .text:0040EECB                 lea     edx, [ebp+var_220]
  15. .text:0040EED1                 push    edx             ; char *
  16. .text:0040EED2                 call    _strncpy
  17. .text:0040EED7                 add     esp, 0Ch
  18. .text:0040EEDA                 lea     eax, [ebp+var_220]
  19. .text:0040EEE0                 push    eax             ; char *
  20. .text:0040EEE1                 call    _strlen
  21. .text:0040EEE6                 add     esp, 4
  22. .text:0040EEE9                 mov     [ebp+var_324], eax
  23. .text:0040EEEF                 mov     [ebp+var_8], 0
  24. .text:0040EEF6                 jmp     short loc_40EF01
  25. .text:0040EEF8 ; ---------------------------------------
  26. .text:0040EEF8 loc_40EEF8:
  27. ; Цикл формирования строки правильного серийника из регистрационного имени
  28. .text:0040EEF8                 mov     ecx, [ebp+var_8]
  29. .text:0040EEFB                 add     ecx, 1
  30. .text:0040EEFE                 mov     [ebp+var_8], ecx
  31. .text:0040EF01 loc_40EF01:
  32. .text:0040EF01                 mov     edx, [ebp+var_8]
  33. .text:0040EF04                 cmp     edx, [ebp+var_324]
  34. .text:0040EF0A                 jge     short loc_40EF6C
  35. .text:0040EF0C                 mov     eax, [ebp+var_8]
  36. .text:0040EF0F                 mov     cl, [ebp+eax+var_220]
  37. .text:0040EF16                 mov     [ebp+var_325], cl
  38. .text:0040EF1C                 movsx   eax, [ebp+var_325]
  39. .text:0040EF23                 add     eax, [ebp+var_8]
  40. .text:0040EF26                 add     eax, [ebp+var_324]
  41. .text:0040EF2C                 mov     edx, [ebp+var_8]
  42. .text:0040EF2F                 and     edx, 80000007h
  43. .text:0040EF35                 jns     short loc_40EF3C
  44. .text:0040EF37                 dec     edx
  45. .text:0040EF38                 or      edx, 0FFFFFFF8h
  46. .text:0040EF3B                 inc     edx
  47. .text:0040EF3C loc_40EF3C:
  48. .text:0040EF3C                 movsx   ecx, [ebp+edx+var_11C]
  49. .text:0040EF44                 add     eax, ecx
  50. .text:0040EF46                 cdq
  51. .text:0040EF47                 mov     ecx, 0Ah
  52. .text:0040EF4C                 idiv    ecx
  53. .text:0040EF4E                 add     edx, 30h
  54. .text:0040EF51                 mov     [ebp+var_1], dl
  55. .text:0040EF54                 mov     edx, [ebp+var_324]
  56. .text:0040EF5A                 sub     edx, 1
  57. .text:0040EF5D                 sub     edx, [ebp+var_8]
  58. .text:0040EF60                 mov     al, [ebp+var_1]
  59. .text:0040EF63                 mov     [ebp+edx+var_428], al
  60. .text:0040EF6A                 jmp     short loc_40EEF8
  61. .text:0040EF6C ; ---------------------------------------
  62. .text:0040EF6C loc_40EF6C:
  63. .text:0040EF6C                 mov     eax, [ebp+var_324]
  64. .text:0040EF72                 add     eax, 6Fh
  65. .text:0040EF75                 cdq
  66. .text:0040EF76                 mov     ecx, 0Ah
  67. .text:0040EF7B                 idiv    ecx
  68. .text:0040EF7D                 add     edx, 30h
  69. .text:0040EF80                 mov     eax, [ebp+var_324]
  70. .text:0040EF86                 mov     [ebp+eax+var_428], dl
  71. .text:0040EF8D                 mov     ecx, [ebp+var_324]
  72. .text:0040EF93                 mov     [ebp+ecx+var_427], 0
  73. .text:0040EF9B                 lea     edx, [ebp+var_110]
  74. ; Занести в стек адреса строки правильного серийника и введенного ранее
  75. .text:0040EFA1                 push    edx             ; char *
  76. .text:0040EFA2                 lea     eax, [ebp+var_428]
  77. .text:0040EFA8                 push    eax             ; char *
  78. ; Сравнить строки
  79. .text:0040EFA9                 call    _strcmp
  80. .text:0040EFAE                 add     esp, 8
  81. .text:0040EFB1                 test    eax, eax
  82. .text:0040EFB3                 jz      short loc_40EFD7
Как видите, все вычисления в итоге сводятся к единственному сравнению двух строк. Если поставить точку останова по адресу 0040EFA9, то перед сравнением на стеке окажется адрес строки с введенным левым серийником и строкой серийника, соответствующего регистрационному имени. Таким образом, для имени "ManHunter / PCL" правильный серийник будет 0040021225325966. Закрываем отладчик, повторяем регистрацию с найденным серийным номером, после перезапуска триальное окно больше не появляется. Цель достигнута.

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

А теперь давайте вытащим код генерации правильного серийника. Алгоритм несложный, для удобства я заменю нечитаемые регистры на человекопонятные имена переменных. Код, конечно, далек до оптимального, хоть я его и немного подчистил, но так уж постарался компилятор.
  1. ; regname_len - длина строки регистрационного имени
  2. ; regname_str - строка регистрационного имени
  3. ; htlpassw - строка "htlpassw"
  4. ; serial_str - строка формируемого серийника
  5. .text:0040EEEF                 mov     [position], 0
  6. .text:0040EEF6                 jmp     short loc_40EF01
  7. .text:0040EEF8 ; -------------------------------
  8. .text:0040EEF8 loc_40EEF8:
  9. .text:0040EEF8                 inc     [position]
  10. .text:0040EF01 loc_40EF01:
  11. .text:0040EF01                 mov     edx, [position]
  12. .text:0040EF04                 cmp     edx, [regname_len]
  13. .text:0040EF0A                 jge     loc_done
  14. .text:0040EF0C                 mov     eax, [position]
  15. .text:0040EF1C                 movsx   eax, byte [eax+regname_str]
  16. .text:0040EF23                 add     eax, [position]
  17. .text:0040EF26                 add     eax, [regname_len]
  18. .text:0040EF2C                 mov     edx, [position]
  19. .text:0040EF2F                 and     edx, 80000007h
  20. .text:0040EF35                 jns     short loc_40EF3C
  21. .text:0040EF37                 dec     edx
  22. .text:0040EF38                 or      edx, 0FFFFFFF8h
  23. .text:0040EF3B                 inc     edx
  24. .text:0040EF3C loc_40EF3C:
  25. .text:0040EF3C                 movsx   ecx, [edx+htlpassw]
  26. .text:0040EF44                 add     eax, ecx
  27. .text:0040EF46                 cdq
  28. .text:0040EF47                 mov     ecx, 10
  29. .text:0040EF4C                 idiv    ecx
  30. .text:0040EF4E                 add     edx, '0'
  31. .text:0040EF51                 mov     [temp2], dl
  32. .text:0040EF54                 mov     edx, [regname_len]
  33. .text:0040EF5A                 sub     edx, 1
  34. .text:0040EF5D                 sub     edx, [position]
  35. .text:0040EF60                 mov     al, [temp2]
  36. .text:0040EF63                 mov     [edx+serial_str], al
  37. .text:0040EF6A                 jmp     short loc_40EEF8
  38. .text:0040EF6C ; ---------------------------------------
  39. .text:0040EF6C loc_done:
  40. .text:0040EF6C                 mov     eax, [regname_len]
  41. .text:0040EF72                 add     eax, 6Fh
  42. .text:0040EF75                 cdq
  43. .text:0040EF76                 mov     ecx, 10
  44. .text:0040EF7B                 idiv    ecx
  45. .text:0040EF7D                 add     edx, '0'
  46. .text:0040EF80                 mov     eax, [regname_len]
  47. .text:0040EF86                 mov     [eax+serial_str], dl
Вот и все, этот код можно практически в неизменном виде переносить в кейген. Но это вы уже сделайте самостоятельно. Я попробовал, у меня получилось :)

Поделиться ссылкой ВКонтакте Поделиться ссылкой на Facebook Поделиться ссылкой на LiveJournal Поделиться ссылкой в Мой Круг Добавить в Мой мир Добавить на ЛиРу (Liveinternet) Добавить в закладки Memori Добавить в закладки Google
Просмотров: 789 | Комментариев: 14

Комментарии

Отзывы посетителей сайта о статье
Petya (01.09.2020 в 12:46):
PAQ8, если вы тут ещё появитесь, как успехи?
PAQ8 (01.02.2020 в 22:39):
ManHunter, благодарствую! Попробую поиграться...
ManHunter (01.02.2020 в 13:17):
Вот реализация библиотеки zlib на JS. https://github.com/imaya/zlib.js
Можно с ней поиграться.
PAQ8 (01.02.2020 в 12:48):
HTA не открывается в Firefox.

Есть расширение для FF, называется SingleFile. Позволяет сохранять любую страницу в обычном html файле с использованием data URI. Хотелось бы ещё иметь возможность эту страницу как-то упаковать хотя бы LZ4 и встроить туда inline-JS распаковщик, а-ля UPX для html.
ManHunter (01.02.2020 в 01:15):
А чем обычный hta не радует? Ну да, при энтропийных данных размер получится чутарика больше. Но кого это в наше время беспокоит? Нынче решать софтовые проблемы мощностями железа - это прям стильно модно молодежно.
PAQ8 (01.02.2020 в 01:02):
Немного не в тему, но всё же по теме. Ищу прогу, которая будет сжимать HTML страницы и помещать туда JS-распаковщик. Хочу заиметь формат htmZ, но в обычной html упаковке. Аналог серверного сжатия, но без сервера. Аналог однофайлового CHM, но без CHM. Есть ли такое в природе?
ManHunter (19.01.2020 в 22:13):
Пишешь кейген на ассемблере, вставляешь в него этот код, пользуешься.
Luna ©orporation (19.01.2020 в 21:44):
"в неизменном виде переносить в кейген."

Это как и куда ?!?
xussr (16.01.2020 в 10:26):
Пример пользительный !!!
Ellephant (13.01.2020 в 11:49):
в закладке Protect, можно указать кодировку. Пошло. Теперь читается )
Кстати браузер запоминает страницу в расшифрованном виде, и уже при следующем заходе не надо пароль вводить.
ManHunter (13.01.2020 в 10:49):
Есть такое дело, там надо страницу в win-1251 делать, тогда вроде прокатывает.
Ellephant (13.01.2020 в 10:45):
попробовал эту программку, при шифровании страницы русский шрифт слетает
ManHunter (13.01.2020 в 08:49):
После ввода пароля можно в браузере посмотреть исходный код страницы. А так да, реально шифруется по паролю.
Ellephant (13.01.2020 в 07:04):
А открыть/прочитать саму зашифрованную страницу, созданную этой программой не пробовал?

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

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

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