Blog. Just Blog

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

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

ExtraCHM - неплохая замена стандартному просмотрщику CHM-файлов, который используется в Windows. Программа обладает удобным многовкладочным интерфейсом, возможностью поиска по файлу справки, даже если в нем отсутствует поисковый индекс, с помощью ExtraCHM можно декомпилировать CHM-файл и даже подключить его к голосовому движку для чтения содержимого. Такая куча ништяков просто обязана быть бесплатной, но аффтар почему-то имеет на этот счет другое мнение. Я же, в свою очередь, это мнение не поддерживаю.

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

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

Юникодная строка сообщения в исполняемом файле находится легко.

Строка сообщения найдена
Строка сообщения найдена

К этому времени дизассемблер закончил свою работу, и мы можем посмотреть участок кода, который ссылается на эту строку. Ну и конечно же посмотреть условия срабатывания этой ветки алгоритма.
  1. ; Вызывать функцию проверки регистрации
  2. .text:0040C809                 call    sub_421F20
  3. .text:0040C80E                 push    0               ; int
  4. .text:0040C810                 push    0               ; uType
  5. ; Если она вернула AL=0, то регистрация неправильная
  6. .text:0040C812                 test    al, al
  7. .text:0040C814                 jnz     short loc_40C822
  8. .text:0040C816                 push    offset aThisDoesNotApp
  9. ; "This does not appear to be a valid regi"...
  10. .text:0040C81B                 call    ?AfxMessageBox@@YGHPB_WII@Z
  11. ; AfxMessageBox(wchar_t const *,uint,uint)
  12. .text:0040C820                 jmp     short loc_40C85A
  13. .text:0040C822 ; -----------------------------------------
  14. .text:0040C822 loc_40C822:
  15. ; Сообщение об успешной регистрации
  16. .text:0040C822                 push    offset aThankYouForReg
  17. ; "Thank you for registering your copy of "...
  18. .text:0040C827                 call    ?AfxMessageBox@@YGHPB_WII@Z
  19. ; AfxMessageBox(wchar_t const *,uint,uint)
  20. .text:0040C82C                 mov     edi, dword_5E1DC0
Вся проверка уместилась в несколько строчек. Простой и максимально эффективный способ решения нашей проблемы - пропатчить функцию проверки по адресу 00421F20, записав в ее начало две любимые команды - MOV AL,1 и RET. После этого программа будет с радостью принимать любые регистрационные данные. Быстро, надежно, но некрасиво. Чтобы стало красиво, посмотрим функцию проверки введенных регистрационных данных. Желательно под отладчиком, так будет гораздо интереснее и понятнее.
  1. .text:00421F20                 push    0FFFFFFFFh
  2. .text:00421F22                 push    offset loc_572C18
  3. .text:00421F27                 mov     eax, large fs:0
  4. .text:00421F2D                 push    eax
  5. .text:00421F2E                 sub     esp, 78h
  6. .text:00421F31                 mov     eax, dword_5D8760
  7. .text:00421F36                 xor     eax, esp
  8. .text:00421F38                 mov     [esp+84h+var_10], eax
  9. .text:00421F3C                 push    ebx
  10. .text:00421F3D                 push    esi
  11. .text:00421F3E                 mov     eax, dword_5D8760
  12. .text:00421F43                 xor     eax, esp
  13. .text:00421F45                 push    eax
  14. .text:00421F46                 lea     eax, [esp+90h+var_C]
  15. .text:00421F4D                 mov     large fs:0, eax
  16. .text:00421F53                 xor     ebx, ebx
  17. .text:00421F55                 mov     esi, ecx
  18. .text:00421F57                 cmp     [edi], bx
  19. ; Серийный номер вообще введен?
  20. .text:00421F5A                 jz      short loc_421FD2
  21. ; Вызвать функцию проверки серийного номера
  22. .text:00421F5C                 push    edi
  23. .text:00421F5D                 call    sub_421EB0
  24. .text:00421F62                 add     esp, 4
  25. .text:00421F65                 test    al, al
  26. ; Если он неправильный, то переход на возврат AL=0
  27. .text:00421F67                 jz      short loc_421FD2
  28. .text:00421F69                 push    8               ; size_t
  29. .text:00421F6B                 lea     eax, [esp+94h+Buffer]
  30. ...
Дальше смотреть нет смысла, там только работа с файлом ключа и все такое прочее. Это неинтересно, так как непосредственно к проверке регистрации никак не относится. Зато нас интересует следующий уровень проверки - функция по адресу 00421EB0.
  1. .text:00421EB0                 push    ecx
  2. .text:00421EB1                 mov     eax, esi
  3. ; Подсчитать длину строки серийного номера
  4. .text:00421EB3                 lea     edx, [eax+2]
  5. .text:00421EB6 loc_421EB6:
  6. .text:00421EB6                 mov     cx, [eax]
  7. .text:00421EB9                 add     eax, 2
  8. .text:00421EBC                 test    cx, cx
  9. .text:00421EBF                 jnz     short loc_421EB6
  10. .text:00421EC1                 sub     eax, edx
  11. ; Длина пополам, так как строка в юникоде
  12. .text:00421EC3                 sar     eax, 1
  13. ; Первая проверка - длина серийного номера должна быть 8 символов
  14. .text:00421EC5                 cmp     eax, 8
  15. .text:00421EC8                 jz      short loc_421ECE
  16. ; Иначе выход с ошибкой
  17. .text:00421ECA                 xor     al, al
  18. .text:00421ECC                 pop     ecx
  19. .text:00421ECD                 retn
  20. .text:00421ECE ; -------------------------------------------------
  21. .text:00421ECE loc_421ECE:
  22. .text:00421ECE                 mov     ecx, [esp+4+arg_0]
  23. ; Сгенерировать из регистрационного имени проверочную строку
  24. .text:00421ED2                 call    sub_421E20
  25. .text:00421ED7                 mov     [esp+4+var_4], eax
  26. .text:00421EDA                 xor     ecx, ecx
  27. .text:00421EDC                 push    edi
  28. .text:00421EDD                 lea     ecx, [ecx+0]
  29. .text:00421EE0 loc_421EE0:
  30. ; Сравнить по два символа из серийного номера с проверочной строкой
  31. .text:00421EE0                 movzx   eax, byte ptr [esp+ecx+8+var_4]
  32. .text:00421EE5                 movzx   edx, word ptr [esi+ecx*4]
  33. .text:00421EE9                 mov     edi, eax
  34. .text:00421EEB                 and     edi, 0Fh
  35. .text:00421EEE                 add     edi, 41h
  36. ; EDX = правильный символ серийного номера
  37. .text:00421EF1                 cmp     edx, edi
  38. ; Не совпало, возврат с ошибкой
  39. .text:00421EF3                 jnz     short loc_421F0F
  40. .text:00421EF5                 movzx   edx, word ptr [esi+ecx*4+2]
  41. .text:00421EFA                 shr     eax, 4
  42. .text:00421EFD                 add     eax, 41h
  43. ; EDX = правильный символ серийного номера
  44. .text:00421F00                 cmp     edx, eax
  45. ; Не совпало, возврат с ошибкой
  46. .text:00421F02                 jnz     short loc_421F0F
  47. .text:00421F04                 inc     ecx
  48. ; Проверить 4 пары (8 символов серийного номера)
  49. .text:00421F05                 cmp     ecx, 4
  50. .text:00421F08                 jl      short loc_421EE0
  51. .text:00421F0A                 mov     al, 1
  52. .text:00421F0C                 pop     edi
  53. .text:00421F0D                 pop     ecx
  54. .text:00421F0E                 retn
  55. .text:00421F0F ; ----------------------------------------------------
  56. .text:00421F0F loc_421F0F:
  57. .text:00421F0F                 xor     al, al
  58. .text:00421F11                 pop     edi
  59. .text:00421F12                 pop     ecx
  60. .text:00421F13                 retn
Честно скажу, мне лениво разбирать процедуру получения проверочной строки из регистрационного имени. Поэтому ограничусь сниффингом правильного серийника под отладчиком. Для этого достаточно поставить точки останова по адресам 00421EF1 и 00421F00, ввести нужное имя и произвольный восьмизначный серийный номер, а затем за четыре прохода узнать все правильные символы. Так, для регистрационного имени "manhunter@pcl" регистрационный код будет "BCOFAFOK". Можно получить все символы и за один проход, достаточно в отладчике заменить условные переходы после сравнения символов на команды NOP. Проверим найденный серийный номер:

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

Все прекрасно работает. Точно так же вы можете подобрать серийный номер для любого другого имени. Но вариант с патчем тоже нельзя списывать со счетов, ведь в этом случае программа становится портативной.

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

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

Комментарии

Отзывы посетителей сайта о статье
ManHunter (22.05.2013 в 11:46):
Да, можно и там. Еще как вариант можно перебить XOR al,al на MOV al,1
Как раз инструкции совпадают по двухбайтовому размеру.
irokkezz (22.05.2013 в 11:42):
Все правильно, только патчить нужно функцию 00421EB0 )

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

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

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