Blog. Just Blog

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

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

Программа HDD Thermometer позволяет в реальном времени контролировать температуру жестких дисков вашего компьютера. Заявлена вроде бы даже как бесплатная, но так это или нет, давайте посмотрим.

Офсайт программы давно сдох, проект больше не развивается, поэтому вот полный комплект, необходимый для запуска. Благо, что программа небольшая.

HDD Thermometer 1.3HDD Thermometer 1.3

HDD.Thermometer.1.3.zip (194,350 bytes)

Запускаем термометр и сразу получаем наг-скрин со странным текстом на смеси "французского с нижегородским".

Наг-скрин
Наг-скрин

Бесплатная программа и тут же навязчивое требование доната с регистрацией. Аффтар, ты уж определись в этой жизни. Как говорится, или сними крест или надень трусы. Посмотрим, с чего лучше всего начать исследование.

Окно "О программе"
Окно "О программе"

В окне "О программе" сразу бросается в глаза строчка "НЕЗАРЕГИСТРИРОВАННАЯ ВЕРСИЯ". Программа мультиязычная с внешними языковыми файлами, поэтому нужную строчку сперва надо искать в них. Поиском обнаруживается файл lang\rus.lng с блоком:

;-- about form ----------------------------
About_Title = О программе
About_Version = Версия
About_build = билд
About_TheAuthorIs = Автор программы:
About_RegisteredTo = Заргистрировано на
About_ProgId = Номер программы
About_UNREGISTERED = НЕЗАРЕГИСТРИРОВАННАЯ ВЕРСИЯ

Значит в исполняемом файле надо искать строчку "About_UNREGISTERED". Ссылка на эту строчку в дизассемблере находится легко:
  1. CODE:004244B2                 mov     eax, ds:off_426984
  2. CODE:004244B7                 mov     eax, [eax]
  3. CODE:004244B9                 push    eax
  4. CODE:004244BA                 lea     eax, [ebp+var_2A8]
  5. CODE:004244C0                 push    eax
  6. CODE:004244C1                 mov     ecx, offset _str_About_UNREGISTE.Text
  7. CODE:004244C6                 mov     edx, [ebp+var_C]
  8. CODE:004244C9                 mov     eax, [ebx+68h]
  9. CODE:004244CC                 call    sub_411794
  10. CODE:004244D1                 mov     edx, [ebp+var_2A8]
  11. CODE:004244D7                 mov     eax, ds:off_426984
  12. CODE:004244DC                 call    @System@@LStrAsg$qqrpvpxv
  13. ; System::__linkproc__ LStrAsg(void *,void *)
Но тут есть небольшая проблема. Здесь не условия и не проверки, а просто последовательно загружаются строки из языкового файла для дальнейшего использования. Зато есть очень приметные адреса, по которым эти строки загружаются. В нашем случае это mov eax, ds:off_426984.

Перекрестные ссылки на указатель
Перекрестные ссылки на указатель

Перекрестные ссылки на этот указатель показывают, что кроме двух адресов инициализации есть еще два места, где этот указатель используется. И первый же участок кода дает нам все необходимое для понимания:
  1. CODE:00421430                 mov     eax, [eax]
  2. CODE:00421432                 mov     eax, [eax+3Ch]
  3. ; Вызвать какую-то функцию проверки
  4. CODE:00421435                 call    sub_413958
  5. CODE:0042143A                 test    al, al
  6. ; Если она вернула AL=0, то перейти на ветку алгоритма со строкой о
  7. ; незарегистрированной программе
  8. CODE:0042143C                 jz      short loc_42146F
  9. CODE:0042143E                 mov     eax, ds:off_426A48
  10. CODE:00421443                 push    dword ptr [eax]
  11. CODE:00421445                 push    offset _str____.Text
  12. CODE:0042144A                 lea     eax, [ebp+var_28] ; int
  13. CODE:0042144D                 call    sub_413B18
  14. CODE:00421452                 push    [ebp+var_28]
  15. CODE:00421455                 lea     eax, [ebp+var_24]
  16. CODE:00421458                 mov     edx, 3
  17. CODE:0042145D                 call    @System@@LStrCatN$qqrv
  18. ; System::__linkproc__ LStrCatN(void)
  19. CODE:00421462                 mov     edx, [ebp+var_24]
  20. CODE:00421465                 mov     eax, [ebx+18h]
  21. CODE:00421468                 call    sub_40BB0C
  22. CODE:0042146D                 jmp     short loc_42147F
  23. CODE:0042146F ; -----------------------------------------------
  24. CODE:0042146F loc_42146F:
  25. ; Указатель на строку "Незарегистрированная версия"
  26. CODE:0042146F                 mov     edx, ds:off_426984
  27. CODE:00421475                 mov     edx, [edx]
  28. CODE:00421477                 mov     eax, [ebx+18h]
  29. CODE:0042147A                 call    sub_40BB0C
Если теперь пропатчить функцию проверки по адресу 00413958 парой команд MOV AL,1 и RET, то программа должна почувствовать себя зарегистрированной. Проверим, так ли это.

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

Действительно, окно с требованием регистрации при запуске программы исчезло, в окне "О программе" отображается, что она на кого-то зарегистрирована. Вариант с патчем оказался успешный. Посмотрим, можно ли обратить алгоритм проверки серийного номера. Эту часть исследований надо начать с уже знакомой нам функции проверки серийника.
  1. CODE:00413958                 push    ebp
  2. CODE:00413959                 mov     ebp, esp
  3. CODE:0041395B                 push    0
  4. CODE:0041395D                 push    0
  5. CODE:0041395F                 push    0
  6. CODE:00413961                 push    ebx
  7. CODE:00413962                 mov     [ebp+var_4], eax
  8. CODE:00413965                 mov     eax, [ebp+var_4]
  9. ; Загрузить из реестра имя пользователя и серийный номер
  10. CODE:00413968                 call    @System@@LStrAddRef$qqrpv
  11. ; System::__linkproc__ LStrAddRef(void *)
  12. CODE:0041396D                 xor     eax, eax
  13. CODE:0041396F                 push    ebp
  14. CODE:00413970                 push    offset loc_4139DA
  15. CODE:00413975                 push    dword ptr fs:[eax]
  16. CODE:00413978                 mov     fs:[eax], esp
  17. CODE:0041397B                 push    0               ; int
  18. CODE:0041397D                 lea     eax, [ebp+var_8]
  19. CODE:00413980                 push    eax             ; int
  20. CODE:00413981                 mov     ecx, offset _str_user.Text ; int
  21. CODE:00413986                 mov     edx, offset _str_Software_RSD_So.Text ; int
  22. CODE:0041398B                 mov     eax, 80000001h  ; hKey
  23. CODE:00413990                 call    sub_411B64
  24. CODE:00413995                 push    0               ; int
  25. CODE:00413997                 lea     eax, [ebp+var_C]
  26. CODE:0041399A                 push    eax             ; int
  27. CODE:0041399B                 mov     edx, offset _str_Software_RSD_So.Text ; int
  28. CODE:004139A0                 mov     ecx, offset _str_key.Text ; int
  29. CODE:004139A5                 mov     eax, 80000001h  ; hKey
  30. CODE:004139AA                 call    sub_411B64
  31. CODE:004139AF                 mov     ecx, [ebp+var_C]
  32. CODE:004139B2                 mov     edx, [ebp+var_8]
  33. CODE:004139B5                 mov     eax, [ebp+var_4]
  34. ; Функция проверки правильности серийника
  35. CODE:004139B8                 call    sub_413828
  36. ; Сохранить результат в EBX
  37. CODE:004139BD                 mov     ebx, eax
  38. CODE:004139BF                 xor     eax, eax
  39. CODE:004139C1                 pop     edx
  40. CODE:004139C2                 pop     ecx
  41. CODE:004139C3                 pop     ecx
  42. CODE:004139C4                 mov     fs:[eax], edx
  43. CODE:004139C7                 push    offset loc_4139E1
  44. CODE:004139CC loc_4139CC:
  45. CODE:004139CC                 lea     eax, [ebp+var_C]
  46. CODE:004139CF                 mov     edx, 3
  47. CODE:004139D4                 call    @System@@LStrArrayClr$qqrpvi
  48. ; System::__linkproc__ LStrArrayClr(void *,int)
  49. CODE:004139D9                 retn
  50. CODE:004139DA ; ------------------------------------------
  51. CODE:004139DA loc_4139DA:
  52. CODE:004139DA                 jmp     unknown_libname_43
  53. CODE:004139DF ; ------------------------------------------
  54. CODE:004139DF                 jmp     short loc_4139CC
  55. CODE:004139E1 ; ------------------------------------------
  56. CODE:004139E1 loc_4139E1:
  57. ; Восстановить результат проверки из EBX в EAX
  58. CODE:004139E1                 mov     eax, ebx
  59. CODE:004139E3                 pop     ebx
  60. CODE:004139E4                 mov     esp, ebp
  61. CODE:004139E6                 pop     ebp
  62. CODE:004139E7                 retn
Переходим ко второй функции проверки, где, собственно, и происходят все вычисления и сравнения:
  1. CODE:00413828                 push    ebp
  2. CODE:00413829                 mov     ebp, esp
  3. CODE:0041382B                 push    ecx
  4. CODE:0041382C                 mov     ecx, 4
  5. CODE:00413831 loc_413831:
  6. CODE:00413831                 push    0
  7. CODE:00413833                 push    0
  8. CODE:00413835                 dec     ecx
  9. CODE:00413836                 jnz     short loc_413831
  10. CODE:00413838                 push    ecx
  11. CODE:00413839                 xchg    ecx, [ebp+var_4]
  12. CODE:0041383C                 push    ebx
  13. CODE:0041383D                 mov     [ebp+var_C], ecx
  14. CODE:00413840                 mov     [ebp+var_8], edx
  15. CODE:00413843                 mov     [ebp+var_4], eax
  16. CODE:00413846                 mov     eax, [ebp+var_4]
  17. CODE:00413849                 call    @System@@LStrAddRef$qqrpv
  18. ; System::__linkproc__ LStrAddRef(void *)
  19. CODE:0041384E                 mov     eax, [ebp+var_8]
  20. CODE:00413851                 call    @System@@LStrAddRef$qqrpv
  21. ; System::__linkproc__ LStrAddRef(void *)
  22. CODE:00413856                 mov     eax, [ebp+var_C]
  23. CODE:00413859                 call    @System@@LStrAddRef$qqrpv
  24. ; System::__linkproc__ LStrAddRef(void *)
  25. CODE:0041385E                 xor     eax, eax
  26. CODE:00413860                 push    ebp
  27. CODE:00413861                 push    offset loc_41392E
  28. CODE:00413866                 push    dword ptr fs:[eax]
  29. CODE:00413869                 mov     fs:[eax], esp
  30. CODE:0041386C                 lea     eax, [ebp+var_10]
  31. CODE:0041386F                 mov     ecx, [ebp+var_4]
  32. CODE:00413872                 mov     edx, [ebp+var_8]
  33. CODE:00413875                 call    @System@@LStrCat3$qqrv
  34. ; System::__linkproc__ LStrCat3(void)
  35. CODE:0041387A                 mov     eax, [ebp+var_10]
  36. CODE:0041387D                 call    sub_4035A4
  37. CODE:00413882                 mov     [ebp+var_1C], eax
  38. CODE:00413885                 fild    [ebp+var_1C]
  39. CODE:00413888                 fdiv    flt_41393C
  40. CODE:0041388E                 call    @System@@TRUNC$qqrv
  41. ; System::__linkproc__ TRUNC(void)
  42. CODE:00413893                 mov     ebx, eax
  43. CODE:00413895                 lea     eax, [ebp+var_14]
  44. CODE:00413898                 push    eax
  45. CODE:00413899                 mov     ecx, ebx
  46. CODE:0041389B                 mov     edx, 1
  47. CODE:004138A0                 mov     eax, [ebp+var_10]
  48. CODE:004138A3                 call    @System@@LStrCopy$qqrv
  49. ; System::__linkproc__ LStrCopy(void)
  50. CODE:004138A8                 lea     eax, [ebp+var_18]
  51. CODE:004138AB                 push    eax
  52. CODE:004138AC                 mov     ecx, ebx
  53. CODE:004138AE                 add     ecx, ecx
  54. CODE:004138B0                 lea     edx, [ebx+1]
  55. CODE:004138B3                 mov     eax, [ebp+var_10]
  56. CODE:004138B6                 call    @System@@LStrCopy$qqrv
  57. ; System::__linkproc__ LStrCopy(void)
  58. CODE:004138BB                 push    offset _str_HT_.Text
  59. CODE:004138C0                 mov     eax, [ebp+var_14]
  60. CODE:004138C3                 call    sub_411F88
  61. CODE:004138C8                 lea     edx, [ebp+var_24]
  62. CODE:004138CB                 call    sub_412010
  63. CODE:004138D0                 push    [ebp+var_24]
  64. CODE:004138D3                 push    offset _str___1.Text
  65. CODE:004138D8                 mov     eax, [ebp+var_18]
  66. CODE:004138DB                 call    sub_411F88
  67. CODE:004138E0                 lea     edx, [ebp+var_28]
  68. CODE:004138E3                 call    sub_412010
  69. CODE:004138E8                 push    [ebp+var_28]
  70. CODE:004138EB                 lea     eax, [ebp+var_20]
  71. CODE:004138EE                 mov     edx, 4
  72. CODE:004138F3                 call    @System@@LStrCatN$qqrv
  73. ; System::__linkproc__ LStrCatN(void)
  74. CODE:004138F8                 mov     edx, [ebp+var_20]
  75. CODE:004138FB                 mov     eax, [ebp+var_C]
  76. ; Сравнить две строчки
  77. CODE:004138FE                 call    @System@@LStrCmp$qqrv
  78. ; По результатам сравнения установить регистр BL
  79. CODE:00413903                 setz    bl
  80. CODE:00413906                 xor     eax, eax
  81. CODE:00413908                 pop     edx
  82. CODE:00413909                 pop     ecx
  83. CODE:0041390A                 pop     ecx
  84. CODE:0041390B                 mov     fs:[eax], edx
  85. CODE:0041390E                 push    offset loc_413935
  86. CODE:00413913 loc_413913:
  87. CODE:00413913                 lea     eax, [ebp+var_28]
  88. CODE:00413916                 mov     edx, 3
  89. CODE:0041391B                 call    @System@@LStrArrayClr$qqrpvi
  90. CODE:00413920                 lea     eax, [ebp+var_18]
  91. CODE:00413923                 mov     edx, 6
  92. CODE:00413928                 call    @System@@LStrArrayClr$qqrpvi
  93. CODE:0041392D                 retn
  94. CODE:0041392E ; ------------------------------------------------------
  95. CODE:0041392E loc_41392E:
  96. CODE:0041392E                 jmp     unknown_libname_43
  97. CODE:00413933                 jmp     short loc_413913
  98. CODE:00413935 loc_413935:
  99. ; Восстановить результат сравнения их EBX в EAX
  100. CODE:00413935                 mov     eax, ebx
  101. CODE:00413937                 pop     ebx
  102. CODE:00413938                 mov     esp, ebp
  103. CODE:0041393A                 pop     ebp
  104. CODE:0041393B                 retn
Тут вся защита сводится к функции сравнения по адресу 004138FE. Запустим программу под отладчиком и поставим там точку останова. Но поставим не сразу, а только когда окно ввода серийника уже будет открыто, имя уже будет набрано и будет введен какой-нибудь левый серийный номер. Почему нельзя поставить точку останова сразу? Проверка вызывается после каждой нажатой клавиши в полях ввода, задолбаетесь переключаться из отладчика в программу. Итак, вводим имя, любой серийник, останавливаемся на функции сравнения двух строк. Смотрим на содержимое стека и регистров.

Содержимое стека перед проверкой
Содержимое стека перед проверкой

В регистрах EAX и EDX лежат указатели на наш введенный левый серийный номер и строчку, с которой он сравнивается. Для регистрационного имени "ManHunter / PCL" это будет строка "HT-FA40-1AAE". Перезапустим программу и попробуем зарегистрировать ее с найденной парой имя-серийник.

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

На этот раз у нас "честная" регистрация. Мы ничего не патчили, а отловили правильный серийник в отладчике. Обратите внимание на указатели на строчки в стеке. Там используется строчка "A52F99BD10441434" из окна "О программе", обозначенная как "Номер программы". На разных компьютерах это значение разное, я проверил. Поэтому правильную пару имя-серийный номер придется каждый раз подбирать заново. Это, конечно, не вариант, поэтому будем реверсить дальше. Под отладчиком видно, что части серийного номера в регистре EAX возвращаются из процедуры 00411F88.
  1. ; Регистрационное имя
  2. CODE:004138C0                 mov     eax, [ebp+var_14]
  3. ; Подсчитать хэш
  4. CODE:004138C3                 call    sub_411F88
  5. CODE:004138C8                 lea     edx, [ebp+var_24]
  6. CODE:004138CB                 call    sub_412010
  7. CODE:004138D0                 push    [ebp+var_24]
  8. CODE:004138D3                 push    offset _str___1.Text ; "-"
  9. ; Номер программы
  10. CODE:004138D8                 mov     eax, [ebp+var_18]
  11. ; Подсчитать хэш
  12. CODE:004138DB                 call    sub_411F88
  13. CODE:004138E0                 lea     edx, [ebp+var_28]
  14. CODE:004138E3                 call    sub_412010
Всю процедуру подсчета хэша приводить не буду, а только ее значимую часть, которая и отвечает за генерацию каждой из частей серийного номера. На вход подается строка, на выходе 16-битный хэш в младшем слове регистра EAX.
  1. ; EAX - накопительный регистр для хэша
  2. CODE:00411FB8                 mov     ebx, 1
  3. ; Первый цикл - поочередно перебираются байты переданной строчки
  4. CODE:00411FBD loc_411FBD:
  5. ; EDX - указатель на строку
  6. CODE:00411FBD                 mov     edx, [ebp+var_4]
  7. CODE:00411FC0                 movzx   edx, byte ptr [edx+ebx-1]
  8. CODE:00411FC5                 shl     edx, 8
  9. CODE:00411FC8                 xor     eax, edx
  10. CODE:00411FCA                 mov     edx, 8
  11. ; Второй цикл - 8 раз регистр EAX или умножается на 2 или XORится с 8005h
  12. CODE:00411FCF loc_411FCF:
  13. ; Выбрать вариант действия на основании установленного бита в регистре AH 
  14. CODE:00411FCF                 test    ah, 80h
  15. CODE:00411FD2                 jz      short loc_411FDD
  16. ; EAX умножается на 2 и XORится с константой 8005h
  17. CODE:00411FD4                 add     eax, eax
  18. CODE:00411FD6                 xor     eax, 8005h
  19. CODE:00411FDB                 jmp     short loc_411FDF
  20. CODE:00411FDD ; -----------------------------------------
  21. CODE:00411FDD loc_411FDD:
  22. ; EAX умножается на 2
  23. CODE:00411FDD                 add     eax, eax
  24. CODE:00411FDF loc_411FDF:
  25. ; Следующая итерация второго цикла
  26. CODE:00411FDF                 dec     edx
  27. CODE:00411FE0                 jnz     short loc_411FCF
  28. ; Следующая итерация первого цикла
  29. CODE:00411FE2                 inc     ebx
  30. CODE:00411FE3                 dec     ecx
  31. CODE:00411FE4                 jnz     short loc_411FBD
  32. CODE:00411FE6 loc_411FE6:
  33. ; Оставить только младшее слово, это и есть искомая часть серийника
  34. CODE:00411FE6                 and     eax, 0FFFFh
Для первой части серийника передается регистрационное имя, для второй части серийника используется строка "номер программы". Алгоритм генерации хэша простенький, его можно прямо из дизассемблера скопировать в кейген с минимальными допиливаниями. Готовый серийный номер начинается с символов "HT-", а обе хэшированные части разделяются символом "-". Вот и все, можете написать кейген. На входе должны быть две строки - регистрационное имя и номер программы из окна "О программе".

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

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

Комментарии

Отзывы посетителей сайта о статье
DimitarSerg (22.04.2014 в 15:35):
рега на CRC-16, переписал с хекс-рейза, вот такая генерация у меня получилась :)
http://pastebin.com/mVRgqP8L
ManHunter (21.04.2014 в 18:35):
А там блоки практически одинакового повторяющегося кода, меняются только по два указателя в каждом блоке. Два тыка мышкой на меняющийся указатель - и вышел. На одном блоке да, не очень наглядно получилось.
irokkezz (21.04.2014 в 17:30):
"Здесь не условия и не проверки, а просто последовательно загружаются строки из языкового файла для дальнейшего использования" - очень часто попадаются такие программы.
Прости, не совсем понял, как ты вышел на адрес 426984?

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

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

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