Blog. Just Blog

Исследование защиты программы Becky! Internet Mail

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

В Японии умеют делать не только качественную электронику, но еще и очень интересные программы. Например, Becky! Internet Mail, серьезная альтернатива для других популярных почтовых клиентов. В ней есть много функций, которые до сих пор не реализованы у конкурентов: поддержка нескольких профилей для формирования писем, штатная портативная установка на сменные носители, отсроченная отправка писем, сравнительно небольшой размер, и другие прелести. Огорчает только цена в 40 вечнозеленых рублей и 30 дней пробного периода.

Качаем дистрибутив, устанавливаем или распаковываем, запускаем. После первоначальных настроек нам предлагают зарегистрироваться, вводим любые левые данные и получаем вполне ожидаемый отлуп "Illegal Passcode". Осмотр пациента показывает, что главный исполняемый файл ничем не упакован, а "нехорошая" строка находится в ресурсах под номером 60469:

"Нехорошая" строка в ресурсах
"Нехорошая" строка в ресурсах

Там же рядом находятся строки сообщения об успешной регистрации, но они нам пока не нужны. Теперь перейдем непосредственно к кодокопанию. Загоняем исполняемый файл в дизассемблер и, когда он закончит анализ, поищем шестнадцатеричное значение идентификатора ресура с нужной строкой.
  1. ...
  2. .text:005B8CE5 loc_5B8CE5:
  3. .text:005B8CE5                 push    0FFFFFFFFh      ; int
  4. .text:005B8CE7                 push    0               ; uType
  5. ; Идентификатор нашей строки из ресурсов
  6. .text:005B8CE9                 push    0EC35h          ; int = 60469 
  7. ; Показать окно с сообщением
  8. .text:005B8CEE                 call    ?AfxMessageBox@@YGHIII@Z
  9. ...
Тут все предельно ясно. Посмотрим откуда передается управление на этот фрагмент кода:
  1. ...
  2. .text:005B8B91                 mov     [edi], eax
  3. ; Вызвать функцию проверки веденных регистрационных данных
  4. .text:005B8B93                 call    sub_425660
  5. .text:005B8B98                 test    eax, eax
  6. ; Если она вернула не 0, то серийник неправильный
  7. .text:005B8B9A                 jnz     loc_5B8CE5
  8. ; Регистрация прошла успешно, сохранить данные регистрации
  9. .text:005B8BA0                 mov     edi, [esp+34h+var_14]
  10. .text:005B8BA4                 mov     ecx, [edi+78h]
  11. .text:005B8BA7                 add     edi, 78h
  12. .text:005B8BAA                 push    ecx             ; lpData
  13. .text:005B8BAB                 push    offset aUser    ; "User"
  14. .text:005B8BB0                 push    offset aLicense ; "License"
  15. .text:005B8BB5                 mov     ecx, offset unk_687990
  16. .text:005B8BBA                 call    sub_426D20
  17. .text:005B8BBF                 push    esi             ; lpData
  18. .text:005B8BC0                 push    offset aCode    ; "Code"
  19. .text:005B8BC5                 push    offset aLicense ; "License"
  20. .text:005B8BCA                 mov     ecx, offset unk_687990
  21. .text:005B8BCF                 call    sub_426D20
  22. .text:005B8BD4                 mov     edx, [ebp+0]
  23. .text:005B8BD7                 push    edx             ; lpData
  24. .text:005B8BD8                 push    offset aEmail_0 ; "EMail"
  25. .text:005B8BDD                 push    offset aLicense ; "License"
  26. .text:005B8BE2                 mov     ecx, offset unk_687990
  27. ...
Можно просто пропатчить функцию проверки серийного номера, чтобы она постоянно возвращала 0, а можно попробовать разобрать алгоритм генерации ключа. Лучше всего это делать под отладчиком, введя длинный серийный номер с неповторяющимися символами.

Вводим неправильные регистрационные данные
Вводим неправильные регистрационные данные

Первая стадия проверки:
  1. ; Длина серийника должна быть 12h (18 в десятичной системе) символов.
  2. ; При этом надо учитывать, что к серийнику перед проверкой дописывается
  3. ; в начало строка "RBK-" и общая длина считается с ней. Значит длина нашего
  4. ; серийника равна 14 сисволам
  5. .text:0042566B                 cmp     dword ptr [edi-0Ch], 12h
  6. .text:0042566F                 jnz     loc_425800
  7. ; В регистр AL заносится код символа "-"
  8. .text:00425675                 mov     al, 2Dh
  9. ; 4-й, 9-й и 14-й символы в серийнике должны быть "-". Теперь мы знаем формат
  10. ; правильного серийного номера: RBK-XXXX-XXXX-XXXX. Напомню, "RBK-" дописывается
  11. ; автоматически, а нам надо ввести только строку XXXX-XXXX-XXXX
  12. .text:00425677                 cmp     [edi+3], al
  13. .text:0042567A                 jnz     loc_425800
  14. .text:00425680                 cmp     [edi+8], al
  15. .text:00425683                 jnz     loc_425800
  16. .text:00425689                 cmp     [edi+0Dh], al
  17. .text:0042568C                 jnz     loc_425800
Дальше строка разбивается на составляющие блоки по 4 символа:
  1. .text:00425692                 push    esi
  2. .text:00425693                 push    3               ; MaxCount
  3. .text:00425695                 lea     eax, [esp+20h+var_4]
  4. .text:00425699                 push    eax             ; int
  5. .text:0042569A                 lea     ecx, [esp+24h+arg_0]
  6. .text:0042569E                 call    sub_407180
  7. .text:004256A3                 push    4               ; MaxCount
  8. .text:004256A5                 push    4               ; int
  9. .text:004256A7                 lea     ecx, [esp+24h+var_10]
  10. .text:004256AB                 push    ecx             ; int
  11. .text:004256AC                 lea     ecx, [esp+28h+arg_0]
  12. .text:004256B0                 call    sub_407240
  13. .text:004256B5                 push    4               ; MaxCount
  14. .text:004256B7                 push    9               ; int
  15. .text:004256B9                 lea     edx, [esp+24h+var_8]
  16. .text:004256BD                 push    edx             ; int
  17. .text:004256BE                 lea     ecx, [esp+28h+arg_0]
  18. .text:004256C2                 call    sub_407240
  19. .text:004256C7                 push    4               ; MaxCount
  20. .text:004256C9                 push    0Eh             ; int
  21. .text:004256CB                 lea     eax, [esp+24h+var_C]
  22. .text:004256CF                 push    eax             ; int
  23. .text:004256D0                 lea     ecx, [esp+28h+arg_0]
  24. .text:004256D4                 call    sub_407240
  25. ; Тут выполняется сравнение первого блока со строкой "RBK". Зачем это
  26. ; сделано - непонятно, ведь она все равно дописывается автоматически
  27. .text:004256D9                 push    offset aRbk_0   ; unsigned __int8 *
  28. .text:004256DE                 lea     ecx, [esp+20h+var_4]
  29. .text:004256E2                 push    ecx             ; int
  30. .text:004256E3                 call    sub_409A30
  31. .text:004256E8                 test    al, al
  32. .text:004256EA                 jz      loc_4257D4
Следующая проверка:
  1. ; Взять 3-й и 4-й символы из первого блока и перевести их в число
  2. .text:004256F0                 push    2               ; MaxCount
  3. .text:004256F2                 lea     edx, [esp+20h+arg_0]
  4. .text:004256F6                 push    edx             ; int
  5. .text:004256F7                 lea     ecx, [esp+24h+var_10]
  6. .text:004256FB                 call    sub_403670
  7. .text:00425700                 mov     eax, [eax]
  8. .text:00425702                 push    eax             ; char *
  9. .text:00425703                 call    j__atol
  10. .text:00425708                 add     esp, 4
  11. .text:0042570B                 lea     ecx, [esp+1Ch+arg_0]
  12. ; Сохранить вычисленное значение в регистре ESI
  13. .text:0042570F                 mov     esi, eax
  14. .text:00425711                 call    sub_401B30
  15. .text:00425716                 mov     eax, [esp+1Ch+var_10]
  16. .text:0042571A                 push    eax             ; char *
  17. .text:0042571B                 call    j__atol
  18. .text:00425720                 add     esp, 4
  19. ; Первые две цифры не должны быть нулями
  20. .text:00425723                 test    eax, eax
  21. .text:00425725                 jz      loc_4257D4
  22. .text:0042572B                 add     esi, 0FFFFFFFFh
  23. ; Число больше 12? Если да, то серинийк неправильный. Выяснено первое правило
  24. ; генерации серийного номера: число из 3-й и 4-й цифр в десятичной записи
  25. ; должно быть не более 12
  26. .text:0042572E                 cmp     esi, 0Bh
  27. .text:00425731                 ja      loc_4257D4
  28. ; Сравнить второй блок серийника со строкой "3437". Если не равно, то ошибка.
  29. ; Вычислено второе правило генерации серийника: второй блок всегда равен "3437"
  30. .text:00425737                 push    offset a3437    ; "3437"
  31. .text:0042573C                 lea     ecx, [esp+20h+var_8]
  32. .text:00425740                 push    ecx             ; int
  33. .text:00425741                 call    sub_409A30
  34. .text:00425746                 test    al, al
  35. .text:00425748                 jz      loc_4257D4
И последняя проверка. Тут лучше сперва посмотреть дизассемблерный листинг, а потом пройтись в отладчике:
  1. ; Проверяется третий блок. Второй символ блока должен быть цифрой >0
  2. .text:00425762                 movsx   edx, byte ptr [esi+1]
  3. .text:00425766                 push    edx             ; C
  4. .text:00425767                 call    _isdigit
  5. .text:0042576C                 add     esp, 4
  6. .text:0042576F                 test    eax, eax
  7. .text:00425771                 jz      short loc_4257D4
  8. .text:00425773                 cmp     dword ptr [esi-0Ch], 2
  9. .text:00425777                 jge     short loc_425783
  10. .text:00425779                 push    80070057h
  11. .text:0042577E                 call    nullsub_1
  12. .text:00425783
  13. .text:00425783 loc_425783:
  14. ; Третий символ блока должен быть цифрой >0
  15. .text:00425783                 movsx   eax, byte ptr [esi+2]
  16. .text:00425787                 push    eax             ; C
  17. .text:00425788                 call    _isdigit
  18. .text:0042578D                 add     esp, 4
  19. .text:00425790                 test    eax, eax
  20. .text:00425792                 jz      short loc_4257D4
  21. .text:00425794                 cmp     dword ptr [esi-0Ch], 3
  22. .text:00425798                 jge     short loc_4257A4
  23. .text:0042579A                 push    80070057h
  24. .text:0042579F                 call    nullsub_1
  25. .text:004257A4
  26. .text:004257A4 loc_4257A4:
  27. ; Четвертый символ блока должен быть цифрой >0
  28. .text:004257A4                 movsx   ecx, byte ptr [esi+3]
  29. .text:004257A8                 push    ecx             ; C
  30. .text:004257A9                 call    _isdigit
  31. .text:004257AE                 add     esp, 4
  32. .text:004257B1                 test    eax, eax
  33. .text:004257B3                 jz      short loc_4257D4
  34. .text:004257B5                 cmp     [esi-0Ch], ebx
  35. .text:004257B8                 jge     short loc_4257C4
  36. .text:004257BA                 push    80070057h
  37. .text:004257BF                 call    nullsub_1
  38. .text:004257C4
  39. .text:004257C4 loc_4257C4:
  40. ; Первый символ блока должен быть буквой латинского алфавита.
  41. .text:004257C4                 movsx   edx, byte ptr [esi]
  42. .text:004257C7                 push    edx             ; C
  43. .text:004257C8                 call    _isalpha
  44. .text:004257CD                 add     esp, 4
  45. .text:004257D0                 test    eax, eax
  46. .text:004257D2                 jnz     short loc_4257D9
Теперь у нас есть все данные для генерации серийного номера. Первый блок: первые две цифры любые, но больше нуля, вторые две цифры - двузначное число не больше 12. Второй блок - всегда 3437. Третий блок: первый символ - буква латинского алфавита, потом три любые цифры больше нуля. Блоки разделены символом "-". Под эту схему подходит, например, такой серийник: 1101-3437-A111. Вводим его, причем имя и адрес E-mail могут быть любыми, и программа благодарит нас за успешную регистрацию.

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

Рабочий кейген для Becky! Internet Mail можете написать сами, после разбора алгоритма ничего сложного тут уже нет.

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

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

Комментарии

Отзывы посетителей сайта о статье
timsky (04.10.2009 в 21:28):
ЗдОрово :)
INC (03.10.2009 в 01:00):
Thanks
SAY (02.10.2009 в 15:44):
Познавательно!
hoper (01.10.2009 в 20:52):
Благодарю.

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

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

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