Blog. Just Blog

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

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

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

Скачиваем дистрибутив, устанавливаем, смотрим. Через меню настроек программы попробуем зарегистрировать ее с каким-нибудь левым серийником. Получим вот такое сообщение:

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

Теперь поищем, где оно находится. А находится оно в ресурсах исполняемого файла с десятичным индексом 40003 или же 9C43, если считать в шестнадцатеричной системе.

Строка в ресурсах
Строка в ресурсах

Вы ведь уже отправили файл в дизассемблер, в сотой статье об этом напоминать не надо? Отлично. Поищем в нем место, где этот индекс используется.
  1. .text:004313CE                 mov     eax, [ecx-0Ch]
  2. .text:004313D1                 test    eax, eax
  3. .text:004313D3                 jz      short loc_431438
  4. .text:004313D5                 push    eax
  5. .text:004313D6                 push    [ebp+var_30]
  6. .text:004313D9                 push    ecx
  7. .text:004313DA                 call    sub_58CDBF
  8. .text:004313DF                 add     esp, 0Ch
  9. .text:004313E2                 test    eax, eax
  10. .text:004313E4                 jz      short loc_431438
  11. .text:004313E6                 lea     ecx, [ebp+var_2C]
  12. .text:004313E9                 call    sub_4078F0
  13. .text:004313EE                 push    [ebp+var_30]
  14. .text:004313F1                 lea     eax, [ebp+var_2C]
  15. .text:004313F4                 mov     byte ptr [ebp+var_4], 4
  16. .text:004313F8                 push    dword ptr [esi+0A8h]
  17. .text:004313FE                 push    9C4Ch
  18. .text:00431403                 push    eax
  19. .text:00431404                 call    sub_448C0C
  20. .text:00431409                 push    9C4Ch           ; int
  21. .text:0043140E                 push    10h             ; uType
  22. .text:00431410                 push    [ebp+var_2C]    ; int
  23. .text:00431413                 call    sub_43E611
  24. .text:00431418                 mov     edx, [ebp+var_2C]
  25. .text:0043141B                 mov     eax, edi
  26. .text:0043141D                 mov     byte ptr [ebp+var_4], 3
  27. .text:00431421                 add     edx, 0FFFFFFF0h
  28. .text:00431424                 lock xadd [edx+0Ch], eax
  29. .text:00431429                 dec     eax
  30. .text:0043142A                 test    eax, eax
  31. .text:0043142C                 jg      short loc_431446
  32. .text:0043142E                 mov     ecx, [edx]
  33. .text:00431430                 push    edx
  34. .text:00431431                 mov     eax, [ecx]
  35. .text:00431433                 call    dword ptr [eax+4]
  36. .text:00431436                 jmp     short loc_431446
  37. .text:00431438 ; ---------------------------------------
  38. .text:00431438 loc_431438:
  39. .text:00431438                 push    0FFFFFFFFh
  40. .text:0043143A                 push    10h
  41. ; Индекс строки из ресурсов
  42. .text:0043143C                 push    9C43h
  43. .text:00431441                 call    sub_43E5AF
  44. .text:00431446
Над этим кодом очень много условных переходов, я привел тут лишь два. Прокрутите листинг на пару экранов вверх и убедитесь в этом сами. Ладно, а что если посмотреть, при каком условии появляется сообщение об успешной регистрации? Его индекс в ресурсах на единичку меньше. Вот это уже лучше:
  1. ; Вызвать функцию проверки
  2. .text:0043134F                 call    sub_420050
  3. .text:00431354                 add     esp, 0Ch
  4. ; Если она вернула AL!=0, то регистрация прошла успешно
  5. .text:00431357                 test    al, al
  6. .text:00431359                 jnz     loc_43146C
  7. ...
  8. ...
  9. ...
  10. .text:0043146C loc_43146C:
  11. .text:0043146C                 push    0FFFFFFFFh
  12. .text:0043146E                 push    40h
  13. ; Сообщение об успешной регистрации
  14. .text:00431470                 push    9C42h
  15. .text:00431475                 call    sub_43E5AF
  16. .text:0043147A                 mov     ecx, esi
  17. .text:0043147C                 call    sub_44D5FD
Посмотрим функцию проверки. Она не такая и большая.
  1. .text:00420050 sub_420050      proc near
  2. .text:00420050                 push    ebp
  3. .text:00420051                 mov     ebp, esp
  4. .text:00420053                 push    0FFFFFFFFh
  5. .text:00420055                 push    offset sub_5D2AF0
  6. .text:0042005A                 mov     eax, large fs:0
  7. .text:00420060                 push    eax
  8. .text:00420061                 sub     esp, 8
  9. .text:00420064                 push    ebx
  10. .text:00420065                 push    esi
  11. .text:00420066                 push    edi
  12. .text:00420067                 mov     eax, ___security_cookie
  13. .text:0042006C                 xor     eax, ebp
  14. .text:0042006E                 push    eax
  15. .text:0042006F                 lea     eax, [ebp+var_C]
  16. .text:00420072                 mov     large fs:0, eax
  17. .text:00420078                 mov     esi, [ebp+arg_0]
  18. .text:0042007B                 lea     eax, [ebp+var_14]
  19. .text:0042007E                 push    esi
  20. .text:0042007F                 push    eax
  21. .text:00420080                 call    sub_420240
  22. .text:00420085                 mov     edi, eax
  23. .text:00420087                 lea     eax, [ebp+var_10]
  24. .text:0042008A                 mov     [ebp+var_4], 0
  25. .text:00420091                 push    esi
  26. .text:00420092                 push    eax
  27. .text:00420093                 call    sub_4201B0
  28. .text:00420098                 push    [ebp+arg_8]
  29. .text:0042009B                 mov     byte ptr [ebp+var_4], 1
  30. .text:0042009F                 push    [ebp+arg_4]
  31. .text:004200A2                 push    edi
  32. .text:004200A3                 push    eax
  33. ; Вызвать следующую функцию проверки
  34. .text:004200A4                 call    sub_41FE60
  35. .text:004200A9                 mov     edx, [ebp+var_10]
  36. .text:004200AC                 or      esi, 0FFFFFFFFh
  37. .text:004200AF                 add     esp, 20h
  38. .text:004200B2                 mov     byte ptr [ebp+var_4], 0
  39. ; Сохранить результат проверки из AL в BL
  40. .text:004200B6                 mov     bl, al
  41. .text:004200B8                 add     edx, 0FFFFFFF0h
  42. .text:004200BB                 mov     ecx, esi
  43. .text:004200BD                 lock xadd [edx+0Ch], ecx
  44. .text:004200C2                 dec     ecx
  45. .text:004200C3                 test    ecx, ecx
  46. .text:004200C5                 jg      short loc_4200CF
  47. .text:004200C7                 mov     ecx, [edx]
  48. .text:004200C9                 push    edx
  49. .text:004200CA                 mov     eax, [ecx]
  50. .text:004200CC                 call    dword ptr [eax+4]
  51. .text:004200CF loc_4200CF:
  52. .text:004200CF                 mov     edx, [ebp+var_14]
  53. .text:004200D2                 mov     [ebp+var_4], 0FFFFFFFFh
  54. .text:004200D9                 add     edx, 0FFFFFFF0h
  55. .text:004200DC                 lock xadd [edx+0Ch], esi
  56. .text:004200E1                 dec     esi
  57. .text:004200E2                 test    esi, esi
  58. .text:004200E4                 jg      short loc_4200EE
  59. .text:004200E6                 mov     ecx, [edx]
  60. .text:004200E8                 push    edx
  61. .text:004200E9                 mov     eax, [ecx]
  62. .text:004200EB                 call    dword ptr [eax+4]
  63. .text:004200EE loc_4200EE:
  64. ; Вернуть сохраненный результат проверки из BL в AL
  65. .text:004200EE                 mov     al, bl
  66. .text:004200F0                 mov     ecx, [ebp+var_C]
  67. .text:004200F3                 mov     large fs:0, ecx
  68. .text:004200FA                 pop     ecx
  69. .text:004200FB                 pop     edi
  70. .text:004200FC                 pop     esi
  71. .text:004200FD                 pop     ebx
  72. .text:004200FE                 mov     esp, ebp
  73. .text:00420100                 pop     ebp
  74. .text:00420101                 retn
  75. .text:00420101 sub_420050      endp
Комментариями я отметил важные места кода. Вызывается следующая по глубине функция проверки, ее результат на время сохраняется из регистра AL в регистр BL, а при выходе из функции записывается обратно. Идем глубже.
  1. .text:0041FE8E                 push    ebx
  2. .text:0041FE8F                 push    esi
  3. ; Следующая функция проверки
  4. .text:0041FE90                 call    sub_420B50
  5. .text:0041FE95                 add     esp, 8
  6. .text:0041FE98                 test    al, al
  7. .text:0041FE9A                 jnz     short loc_41FEF0
  8. .text:0041FE9C                 push    30h             ; uType
  9. ; Выдать сообщение с бибикалкой и зависнуть
  10. .text:0041FE9E                 call    ds:MessageBeep
  11. .text:0041FEA4                 call    sub_441A5C
  12. .text:0041FEA9                 mov     ecx, [eax+4]
  13. .text:0041FEAC                 call    sub_43D138
  14. .text:0041FEB1                 imul    eax, dword_65DC18, 3E8h
  15. .text:0041FEBB                 push    eax             ; dwMilliseconds
  16. .text:0041FEBC                 call    ds:Sleep
  17. .text:0041FEC2                 mov     eax, dword_65DC18
  18. .text:0041FEC7                 cmp     eax, 3Ch
Это точно сделано не просто так. Шагнем еще на шаг глубже, что мы там видим?
  1. .text:00420B9C      xor     eax, eax
  2. .text:00420B9E      mov     [ebp+var_98], offset off_5E2990
  3. .text:00420BA8      mov     [ebp+var_94], offset aR29krmfkzxi ; "R29kRmFkZXI="...
  4. .text:00420BB2      mov     [ebp+var_90], offset aW3bjdf0 ; "W3BjdF0="...
  5. .text:00420BBC      mov     [ebp+var_8C], offset aW1rfwf0 ; "W1RFWF0="...
  6. .text:00420BC6      mov     [ebp+var_88], offset off_5E2AF0
  7. .text:00420BD0      mov     [ebp+var_84], offset aW0zsdwtlxq ; "W0ZsdWtlXQ=="...
  8. .text:00420BDA      mov     [ebp+var_80], offset aU2lyyvg ; "U2lyYVg="...
  9. .text:00420BE1      mov     [ebp+var_7C], offset aS2lmtge ; "S2lMTGE="...
Куча строчек, по виду похожих на base64-кодирование. Берем пару наугад. Так и есть, строки превращаются в "GodFader", "SiraX", "KiLLa", "[Fluke]" и подобные. Нетрудно догадаться, что это черный список регистрационных имен, точнее никнеймов крякеров, на которые программа будет ругаться. Моего имени там нет, так что эта проверка, считай, пройдена успешно :) Возвращаемся на шаг назад, смотрим по коду ниже:
  1. .text:0041FEF0                 push    esi
  2. .text:0041FEF1                 push    [ebp+arg_4]
  3. .text:0041FEF4                 lea     eax, [ebp+var_14]
  4. .text:0041FEF7                 push    [ebp+arg_0]
  5. .text:0041FEFA                 push    eax
  6. .text:0041FEFB                 call    sub_420540
  7. .text:0041FF00                 lea     eax, [ebp+var_14]
  8. .text:0041FF03                 mov     [ebp+var_4], 0
  9. .text:0041FF0A                 push    ebx
  10. .text:0041FF0B                 push    eax
  11. ; Вывать функцию проверки
  12. .text:0041FF0C                 call    sub_4045E0
  13. .text:0041FF11                 add     esp, 18h
  14. .text:0041FF14                 or      esi, 0FFFFFFFFh
  15. ; По ее результатам перейти на завершение или продолжить выполнение
  16. .text:0041FF17                 test    al, al
  17. .text:0041FF19                 jz      short loc_41FF27
  18. .text:0041FF1B                 call    sub_4208C0
  19. .text:0041FF20                 xor     bl, bl
  20. .text:0041FF22                 jmp     loc_420017
Вот стало еще интереснее, но в статическом анализе ничего не понятно. Поэтому запустим программу под отладчиком, поставим точку останова на адрес 0041FEF0 и попробуем зарегистрировать программу с левыми данными. В пошаговом режиме зарулим в sub_4045E0.

Вызов функции сравнения строк
Вызов функции сравнения строк

Вызывается функция сравнения строк. При этом, если обратить внимание на регистры, то один из них указывает на введенный левый серийник:

Регистр указывает на серийный номер
Регистр указывает на серийный номер

Есть подозрение, что это именно он должен с чем-то сравниваться. Заруливаем в функцию сравнения. Там выполняется еще одно сравнение, но на этот раз регистр указывает вот на такую интересную строку:

Регистр указывает на серийный номер
Регистр указывает на серийный номер

Именно с ней сравнивается введенный серийный номер и по результатам этого итогового сравнения выносится вердикт о правильности или неправильности регистрации. Получается, что для регистрационного имени "ManHunter / PCL" правильный серийный номер будет "201BFDA2AEF05FB3360D1DA47BA55F17". Закрываем программу, выходим из отладчика и пробуем зарегистрировать программу с найденными данными:

Сообщение об успешной регистрации
Сообщение об успешной регистрации

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

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

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

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

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

Комментарии

Отзывы посетителей сайта о статье
ManHunter (01.09.2016 в 10:14):
ЦитатаШел 2016 год, шароварщики продолжают юзать strcmp :) facepalm

Тише, не спугни :)
DimitarSerg (31.08.2016 в 22:58):
ЦитатаМожно сделать кейген ;)

Лол, если программа сравнивает верный и неверный серийники, то кейген уже априори возможен - это лишь дело времени и желания.
Шел 2016 год, шароварщики продолжают юзать strcmp :) facepalm
TheCracker (27.08.2016 в 14:00):
Подскажу идею: похоже, в программе используется видоизмененный MD5. Так называемый, MD5 с солью. Надо отследить что происходит с введенными символами имени и куда они передаются.
Предполагаю, что символы каким-то образом изменяются и скармливаются алгоритму md5. После чего получаем валидный серийник.
Можно сделать кейген ;)
ManHunter (22.08.2016 в 10:29):
Патч текстовой строки из черного списка всегда будет предпочтительнее патча самого кода. Во-первых, при таких раскладах нарисовать универсальный патчер легче легкого, сигнатура строки неизменна. Во-вторых, в этом случае целостность алгоритма регистрации сохраняется, ведь фактически это валидный серийник, который должен проходить все проверки, в том числе отложенные, хитро запрятанные и т.д. Я не говорю именно про эту программу, тут таких извратов нет, я вообще про принцип.
Doxtur (21.08.2016 в 12:25):
ЦитатаХотя бы для того, чтобы избежать этого:
"Не удивлюсь, если в какой-нибудь очередной версии программы мой ник также добавят в список запрещенных."


Хоспода патчеры, а на ум вам не приходит, что при выпуске новой версии (например с именем manhunter в ч0рном списке) патчить вам придется еще раз ?
wetal (20.08.2016 в 18:57):
pawel97, ну да, что то такое я имел в виду.
А на счет слабой защиты - я тоже не сторонник извращённых криптографий, дорогих защит и прочих сложностей. Если программу надо сломать, то всё равно сломают, а для честных людей защита не нужна. Покупают то всё равно честные, другие по любому деньги не платят, так зачем для них стараться, защищать?
pawel97 (19.08.2016 в 09:49):
wetal, "А можно ли сделать не спортивно и грубо?"
Пытаемся создать более 5 напоминаний - получаем облом. Находим сообщение в листинге и перед ним классика жанра вида call xxx; test al,al; jnz...
Идём в функцию проверки и видим, что там просто в al заносится байт из [eax+374]
Смотрим, где похожий байт инициализируется нулём и меняем ноль на единицу.
Однобайтовый патч и даже ключ вводить не надо.
p.s. Вот думаю, автор специально .pdb забыл, чтобы ида имена функций показывала? Он бы ещё исходник приложил.
ManHunter (18.08.2016 в 17:01):
Из IDA только текстовые листинги, а серенькие скриншоты - это OllyDbg.
Noobie (18.08.2016 в 16:58):
Толково, жаль что редко так бывает, имеется в виду самогенерация серийников программой. Но и не без этого, как видим. Давно хотел спросить - скриншоты дизассемблера, это IDA? Просто ни разу ее не юзал, поэтому не знаком с таким фейсом. HIEW и олька - наше фсё! :-)
ManHunter (18.08.2016 в 13:48):
Патч черного списка легко решает эту проблему. В конце концов для домашнего использования можно сгенерить ключик на любое имя, главное не расшаривать его.
wetal (18.08.2016 в 13:36):
Хотя бы для того, чтобы избежать этого:
"Не удивлюсь, если в какой-нибудь очередной версии программы мой ник также добавят в список запрещенных."
ManHunter (18.08.2016 в 09:06):
Можно, наверное. Но зачем?
wetal (18.08.2016 в 07:54):
Красиво и спортивно подобрать валидный код регистрации. А можно ли сделать не спортивно и грубо?
Вот тут Вы писали:
"Именно с ней сравнивается введенный серийный номер и по результатам этого итогового сравнения выносится вердикт о правильности или неправильности регистрации."
Просто подправить код, чтобы любой введённый серийник возвращал правильный вердикт?
SHREEF (17.08.2016 в 22:42):
Молодец как всегда!

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

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

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