Blog. Just Blog

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

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

Perfect Hotkey - один из многих менеджеров "горячих клавиш" под Windows. Позволяет назначать на различные комбинации клавиш различные действия, такие как запуск программы, открытие ссылки, копирование и вставка текста, управление громкостью динамиков, очистка буфера обмена и тому подобное, в том числе и пакеты из нескольких действий. Я подобными программами не пользуюсь, сравнить особо не с чем, а вот от триальности подлечить смогу.

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

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

При попытке регистрации программа безропотно принимает вообще любые имена и серийники, после чего просит перезапуститься для их проверки. Грамотный ход со стороны автора, так как никаких сообщений о правильной или неправильной регистрации при этом не выводится. Значит действуем иначе. Последовательным поиском по типовым строчкам "registered", "username", "regcode", "license", "trial" и подобным выходим на большую функцию, в которой выполняется активная работа с неким файлом конфигурации. Всю ее приводить не буду, она достаточно объемная.
  1. .text:00450552                 call    sub_401180
  2. .text:00450557                 push    ecx             ; lpKeyName
  3. .text:00450558                 mov     ecx, esp
  4. .text:0045055A                 mov     [ebp+var_1B8], esp
  5. .text:00450560                 push    offset aUsedtimes ; "UsedTimes"
  6. .text:00450565                 mov     byte ptr [ebp+var_4], 4
  7. .text:00450569                 call    sub_401180
  8. .text:0045056E                 push    ecx             ; lpAppName
  9. .text:0045056F                 mov     ecx, esp
  10. .text:00450571                 push    offset aLicense ; "License"
  11. .text:00450576                 mov     byte ptr [ebp+var_4], 5
  12. .text:0045057A                 call    sub_401180
  13. .text:0045057F                 lea     eax, [ebp+var_1A0]
  14. .text:00450585                 push    eax             ; int
  15. .text:00450586                 mov     byte ptr [ebp+var_4], 2
  16. .text:0045058A                 call    sub_416D00
  17. .text:0045058F                 push    [ebp+var_1A0]   ; char *
  18. .text:00450595                 mov     byte ptr [ebp+var_4], 6
  19. .text:00450599                 call    _atol
  20. .text:0045059E                 lea     esi, [eax+1]
  21. .text:004505A1                 push    0FEh            ; size_t
  22. .text:004505A6                 lea     eax, [ebp+FindFileData.cFileName+15h]
  23. .text:004505AC                 push    0               ; int
  24. .text:004505AE                 push    eax             ; void *
  25. .text:004505AF                 mov     [edi+1Ch], esi
  26. .text:004505B2                 mov     [ebp+FindFileData.cFileName+14h], 0
  27. .text:004505B9                 call    _memset
  28. .text:004505BE                 push    0Ah             ; Radix
  29. .text:004505C0                 push    0FFh            ; Size
  30. .text:004505C5                 lea     eax, [ebp+FindFileData.cFileName+14h]
  31. .text:004505CB                 push    eax             ; DstBuf
  32. .text:004505CC                 push    esi             ; Val
  33. .text:004505CD                 call    __ltoa_s
  34. .text:004505D2                 add     esp, 34h
  35. .text:004505D5                 lea     ecx, [ebp+lpKeyName]
  36. .text:004505DB                 push    edi
  37. .text:004505DC                 call    sub_401010
  38. .text:004505E1                 lea     eax, [ebp+FindFileData.cFileName+14h]
  39. .text:004505E7                 push    eax             ; lpString
  40. .text:004505E8                 lea     ecx, [ebp+lpString]
  41. .text:004505EE                 mov     byte ptr [ebp+var_4], 7
  42. .text:004505F2                 call    sub_401180
  43. .text:004505F7                 push    offset aUsedtimes ; "UsedTimes"
  44. .text:004505FC                 lea     ecx, [ebp+lpFileName]
  45. .text:00450602                 mov     byte ptr [ebp+var_4], 8
  46. .text:00450606                 call    sub_401180
  47. .text:0045060B                 push    offset aLicense ; "License"
  48. .text:00450610                 lea     ecx, [ebp+lpAppName]
  49. .text:00450616                 mov     byte ptr [ebp+var_4], 9
  50. .text:0045061A                 call    sub_401180
  51. .text:0045061F                 push    [ebp+lpKeyName] ; lpFileName
  52. .text:00450625                 mov     ebx, ds:WritePrivateProfileStringA
  53. .text:0045062B                 push    [ebp+lpString]  ; lpString
  54. .text:00450631                 push    [ebp+lpFileName] ; lpKeyName
  55. .text:00450637                 push    [ebp+lpAppName] ; lpAppName
  56. .text:0045063D                 call    ebx ; WritePrivateProfileStringA
  57. .text:0045063F                 lea     ecx, [ebp+lpAppName]
  58. .text:00450645                 call    sub_401280
Тут в ini-файл стандартными функциями записываются данные о лицензии, количестве запусков, времени первого старта, код практически линейный. А вот дальше обнаруживается интересная конструкция:
  1. .text:00450866                 mov     ecx, edi
  2. .text:00450868                 mov     [edi+24h], eax
  3. ; Вызывать функцию проверки
  4. .text:0045086B                 call    sub_442180
  5. ; Сохранить ее результат
  6. .text:00450870                 mov     [edi+28h], eax
  7. .text:00450873                 test    eax, eax
  8. ; Если результат нулевой, то блок с активацией пропустить
  9. .text:00450875                 jz      loc_450ACB
  10. .text:0045087B                 mov     eax, off_4A3024
  11. .text:00450880                 mov     [ebp+lpFileName], eax
  12. .text:00450886                 lea     eax, [ebp+var_1B0]
  13. .text:0045088C                 push    eax             ; int
  14. .text:0045088D                 mov     ecx, edi        ; lpFileName
  15. .text:0045088F                 mov     byte ptr [ebp+var_4], 12h
  16. .text:00450893                 call    sub_4413A0
  17. .text:00450898                 push    dword ptr [eax]
  18. .text:0045089A                 lea     eax, [ebp+lpFileName]
  19. .text:004508A0                 push    offset a_S_firstactiva
  20. ; "_%s_FirstActivateDate_"
  21. .text:004508A5                 push    eax
  22. .text:004508A6                 mov     byte ptr [ebp+var_4], 13h
  23. .text:004508AA                 call    sub_401830
  24. .text:004508AF                 add     esp, 0Ch
  25. .text:004508B2                 lea     ecx, [ebp+var_1B0]
  26. .text:004508B8                 mov     byte ptr [ebp+var_4], 12h
  27. .text:004508BC                 call    sub_401280
  28. .text:004508C1                 push    ecx             ; lpFileName
  29. .text:004508C2                 mov     ecx, esp
  30. .text:004508C4                 mov     [ebp+var_1B0], esp
  31. .text:004508CA                 push    edi
  32. .text:004508CB                 call    sub_401010
  33. .text:004508D0                 push    ecx             ; lpDefault
  34. .text:004508D1                 mov     ecx, esp
  35. .text:004508D3                 mov     [ebp+var_1A0], esp
  36. .text:004508D9                 push    offset Default  ; lpString
  37. .text:004508DE                 mov     byte ptr [ebp+var_4], 14h
  38. .text:004508E2                 call    sub_401180
  39. .text:004508E7                 push    ecx             ; lpKeyName
  40. .text:004508E8                 lea     eax, [ebp+lpFileName]
  41. .text:004508EE                 mov     ecx, esp
  42. .text:004508F0                 mov     [ebp+lpKeyName], esp
  43. .text:004508F6                 push    eax
  44. .text:004508F7                 mov     byte ptr [ebp+var_4], 15h
  45. .text:004508FB                 call    sub_401010
  46. .text:00450900                 push    ecx             ; lpAppName
  47. .text:00450901                 mov     ecx, esp
  48. .text:00450903                 push    offset aLicense ; "License"
  49. .text:00450908                 mov     byte ptr [ebp+var_4], 16h
  50. .text:0045090C                 call    sub_401180
  51. .text:00450911                 lea     eax, [ebp+var_1B4]
  52. .text:00450917                 push    eax             ; int
  53. .text:00450918                 mov     byte ptr [ebp+var_4], 12h
  54. .text:0045091C                 call    sub_416D00
  55. .text:00450921                 lea     eax, [ebp+var_1BC]
  56. .text:00450927                 push    eax
  57. .text:00450928                 lea     eax, [ebp+var_1C0]
  58. .text:0045092E                 push    eax
  59. .text:0045092F                 lea     eax, [ebp+var_1B8]
  60. .text:00450935                 push    eax
  61. .text:00450936                 push    offset a04d02d02d
  62. ; "%04d-%02d-%02d"
  63. .text:0045093B                 push    [ebp+var_1B4]
  64. .text:00450941                 call    unknown_libname_55
  65. .text:00450946                 add     esp, 28h
  66. .text:00450949                 cmp     eax, 3
  67. .text:0045094C                 jnz     loc_4509D3
  68. .text:00450952                 lea     eax, [ebp+var_40]
  69. .text:00450955                 push    eax             ; lpSystemTime
  70. .text:00450956                 call    esi ; GetLocalTime
  71. .text:00450958                 movzx   eax, word ptr [ebp+var_1B8]
  72. .text:0045095F                 xorps   xmm0, xmm0
  73. .text:00450962                 movq    qword ptr [ebp+var_20.wYear], xmm0
  74. .text:00450967                 mov     [ebp+var_20.wYear], ax
  75. .text:0045096B                 movzx   eax, word ptr [ebp+var_1C0]
  76. .text:00450972                 mov     [ebp+var_20.wMonth], ax
  77. .text:00450976                 movzx   eax, word ptr [ebp+var_1BC]
  78. .text:0045097D                 mov     [ebp+var_20.wDay], ax
  79. .text:00450981                 push    0               ; int
  80. .text:00450983                 lea     eax, [ebp+var_20]
  81. .text:00450986                 push    eax             ; SYSTEMTIME *
  82. .text:00450987                 lea     eax, [ebp+var_40]
  83. .text:0045098A                 push    eax             ; lpSystemTime
  84. .text:0045098B                 lea     eax, [ebp+var_200]
  85. .text:00450991                 push    eax             ; int
  86. .text:00450992                 movq    qword ptr [ebp+var_20.wHour], xmm0
  87. .text:00450997                 call    sub_417110
  88. .text:0045099C                 add     esp, 10h
  89. .text:0045099F                 movq    xmm0, qword ptr [eax]
  90. .text:004509A3                 movq    qword ptr [ebp+var_1E8], xmm0
  91. .text:004509AB                 movq    xmm0, qword ptr [eax+8]
  92. .text:004509B0                 movq    [ebp+var_1E0], xmm0
  93. .text:004509B8                 movq    xmm0, qword ptr [eax+10h]
  94. .text:004509BD                 mov     eax, [ebp+var_1E8]
  95. .text:004509C3                 movq    [ebp+var_1D8], xmm0
  96. .text:004509CB                 mov     [edi+2Ch], eax
Поясню словами. Выполняется некая проверка, в переменную сохраняется ее результат. Затем по результатам этой проверки обрабатывается или перепрыгивается условным переходом блок кода, в котором есть ключ ini-файла с характерным фрагментом "FirstActivateDate". Давайте заглянем в функцию проверки. После нескольких начальных строчек начинается магия. Работа со строкой-маской, нетипичные для "бытового" кода константы, математика, условные переходы. Все говорит о том, что тут проверяется корректность регистрационных данных. Конструкция "%04X%04X-%04X%04X-%04X%04X-F703C3AD-9CE7-40F3-8349-525773D2C5C7-Y" сама по себе уже напоминает серийный номер, надо только ее правильно заполнить. Строка "%04X" говорит о том, что на этом месте в готовой строке должны находиться 4 шестнадцатеричных цифры. Для удобства анализа каждую группу я заполнил символами "1111", "2222" и так далее. Запускаем программу, дожидаемся появления триального окна и регистрируем ее сляпанным вручную серийником. Как и раньше, программа сообщает, что данные сохранены и просит перезапустить ее. В этот раз запускаем программу под отладчиком, ставим точку останова на начало функции проверки по адресу 00442180 и отпускаем программу на выполнение. Когда точка останова сработает, начинаем пошаговую трассировку. Особое внимание на следующий код:
  1. ; Выделить из строки 6 групп по 4 hex-цифры
  2. .text:004421F7                 lea     ecx, [ebp+var_14]
  3. .text:004421FA                 push    ecx
  4. .text:004421FB                 lea     ecx, [ebp+var_18]
  5. .text:004421FE                 push    ecx
  6. .text:004421FF                 lea     ecx, [ebp+var_1C]
  7. .text:00442202                 push    ecx
  8. .text:00442203                 lea     ecx, [ebp+var_20]
  9. .text:00442206                 push    ecx
  10. .text:00442207                 lea     ecx, [ebp+var_24]
  11. .text:0044220A                 push    ecx
  12. .text:0044220B                 lea     ecx, [ebp+var_28]
  13. .text:0044220E                 push    ecx
  14. .text:0044220F                 push    offset a04x04x04x04x04
  15. ; "%04X%04X-%04X%04X-%04X%04X-F703C3AD-9CE"...
  16. .text:00442214                 push    eax
  17. .text:00442215                 call    unknown_libname_55
  18. .text:0044221A                 add     esp, 20h
  19. ; Все извлечено?
  20. .text:0044221D                 cmp     eax, 6
  21. ; Нет, серийный номер неправильный
  22. .text:00442220                 jnz     loc_442361
  23. .text:00442226                 mov     ecx, [ebp+var_28] ; 1-я группа
  24. .text:00442229                 mov     eax, 66666667h
  25. .text:0044222E                 imul    ecx
  26. .text:00442230                 sar     edx, 2
  27. .text:00442233                 mov     eax, edx
  28. .text:00442235                 shr     eax, 1Fh
  29. .text:00442238                 add     eax, edx
  30. .text:0044223A                 lea     eax, [eax+eax*4]
  31. .text:0044223D                 add     eax, eax
  32. .text:0044223F                 sub     ecx, eax
  33. .text:00442241                 mov     eax, [ebp+var_24] ; 2-я группа
  34. .text:00442244                 inc     ecx
  35. .text:00442245                 cdq
  36. .text:00442246                 idiv    ecx
  37. .text:00442248                 cmp     edx, [esi+4] ; 1
  38. ; Нет, серийный номер неправильный
  39. .text:0044224B                 jnz     loc_442361
  40. .text:00442251                 mov     eax, [ebp+var_20] ; 3-я группа
  41. .text:00442254                 cdq
  42. .text:00442255                 idiv    ecx
  43. .text:00442257                 cmp     edx, [esi+8] ; 2
  44. ; Нет, серийный номер неправильный
  45. .text:0044225A                 jnz     loc_442361
  46. .text:00442260                 mov     eax, [ebp+var_1C] ; 4-я группа
  47. .text:00442263                 cdq
  48. .text:00442264                 idiv    ecx
  49. .text:00442266                 cmp     edx, [esi+0Ch] ; 2
  50. ; Нет, серийный номер неправильный
  51. .text:00442269                 jnz     loc_442361
  52. .text:0044226F                 mov     ecx, [ebp+var_18] ; 5-я группа
  53. .text:00442272                 mov     eax, 66666667h
  54. .text:00442277                 imul    ecx
  55. .text:00442279                 sar     edx, 2
  56. .text:0044227C                 mov     eax, edx
  57. .text:0044227E                 shr     eax, 1Fh
  58. .text:00442281                 add     eax, edx
  59. .text:00442283                 lea     eax, [eax+eax*4]
  60. .text:00442286                 add     eax, eax
  61. .text:00442288                 sub     ecx, eax
  62. .text:0044228A                 mov     eax, [ebp+var_14] ; 6-я группа
  63. .text:0044228D                 inc     ecx
  64. .text:0044228E                 cdq
  65. .text:0044228F                 idiv    ecx
  66. .text:00442291                 cmp     edx, [esi+10h] ; 1
  67. ; Нет, серийный номер неправильный
  68. .text:00442294                 jnz     loc_442361
Под отладчиком хорошо видно, как выполняются математические действия над каждой из шести групп чисел, извлеченных из строки серийника. В конце каждого блока операций выполняется сравнение промежуточного результата с фиксированными значениями. Если хоть одно сравнение не прошло, то серийник признается неправильным. Остальные символы серийного номера нигде в проверках не используются, как и регистрационное имя. Чтобы не возиться с математикой, в качестве кейгена я задействовал простенький брутфорс, который берет случайные числа и прогоняет их на предмет соответствия правилам проверки. В результате подбора получился, к примеру, вот такой серийник: 69C357D3-71E49908-7711385D-F703C3AD-9CE7-40F3-8349-525773D2C5C7-Y. Если зарегистрировать программу любым именем и этим серийником, то триальное окно исчезает, а в главном окне появляется информация о регистрации стандартной лицензии.

Во время трассировки на стеке можно обнаружить указатель на строку имени файла типа C:\Users\{USER}\AppData\Roaming\1119HOTK.dat. Если посмотреть его содержимое, то там обнаружится введенное имя, серийник, дата активации и количество запусков. Соответственно, чтобы сбросить регистрацию надо будет просто удалить этот файл.

Возвращаемся к программе. Чутье мне подсказывает, что на стандартной тип лицензии не заканчивается. Прокручиваем листинг немного ниже:
  1. .text:00450ADF                 lea     eax, [ebp+lpFileName]
  2. .text:00450AE5                 push    eax             ; int
  3. .text:00450AE6                 mov     ecx, edi        ; lpFileName
  4. .text:00450AE8                 call    sub_4413A0
  5. .text:00450AED                 lea     ecx, [ebp+lpFileName]
  6. .text:00450AF3                 mov     byte ptr [ebp+var_4], 1Ch
  7. .text:00450AF7                 call    sub_401710
  8. ; Строку серийника в нижний регистр
  9. .text:00450AFC                 push    [ebp+lpFileName] ; lpsz
  10. .text:00450B02                 call    ds:CharLowerA
  11. .text:00450B08                 push    0
  12. ; Найти вхождение подстроки "lifetime"
  13. .text:00450B0A                 push    offset aLifetime ; "lifetime"
  14. .text:00450B0F                 lea     ecx, [ebp+lpFileName]
  15. .text:00450B15                 call    sub_414240
  16. ; Подстрока не найдена
  17. .text:00450B1A                 cmp     eax, 0FFFFFFFFh
  18. .text:00450B1D                 jz      short loc_450B26
  19. ; Подстрока найдена, установить какой-то флаг
  20. .text:00450B1F                 mov     dword ptr [edi+44h], 1
  21. .text:00450B26 loc_450B26:
  22. .text:00450B26                 lea     ecx, [ebp+lpFileName]
  23. .text:00450B2C                 call    sub_401280
  24. .text:00450B31 loc_450B31:
  25. .text:00450B31                 mov     eax, [edi+2Ch]
  26. .text:00450B34                 cmp     eax, [ebp+arg_10]
  27. .text:00450B37                 jle     short loc_450B46
Под отладчиком хорошо видно, что тут происходит. Строка серийника переводится в нижний регистр, после чего в ней ищется подстрока "lifetime". Если она найдена, то взводится какой-то флаг. Отлично, значит финальный вариант серийника со всеми деталями будет следующим: 69C357D3-71E49908-7711385D-MANHUNTER-PCL-LIFETIME-LICENSE.

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

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

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

Комментарии

Отзывы посетителей сайта о статье
Комментариeв нет

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

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

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