Blog. Just Blog

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

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

Chaos Intellect - почтовая программа, менеджер контактов, календарь и планировщик в одном флаконе. Что-то наподобие Outlook'а, только без лишних и никому не нужных наворотов. Зато от мелкомягкого прототипа у Chaos Intellect осталась патологическая тяга к кошельку пользователя. Сейчас мы будем устранять этот досадный недостаток, тем более что цена почти в 60 баксов для подобной программы явно завышена.

Скачиваем последний дистрибутив (на момент написания статьи это версия 4.0.4.7), устанавливаем, смотрим. В папке с программой целая куча исполняемых файлов, но нас интересует только один - Intellect.exe. Предварительным осмотром узнаем, что он упакован бесплатным пакером UPX. Никаких модификаций в код распаковщика не внесено, поэтому он легко распаковывается самим же UPX с ключом "-d". Отправляем бедолагу в дизассемблер, а пока посмотрим как он регистрируется и как реагирует на неправильную регистрацию.

Окно регистрации программы
Окно регистрации программы

Строка легко находится поиском. Рядышком находится строка сообщения-благодарности за правильную регистрацию. Это нам пока не надо.

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

Теперь посмотрим условия появления сообщения о неправильной регистрации (часть малозначительного кода я опустил):
  1. .text:009E89DA                 mov     eax, [ebp-1Ch]
  2. .text:009E89DD                 pop     edx
  3. .text:009E89DE                 pop     ecx
  4. ; Вызвать функцию проверки
  5. .text:009E89DF                 call    sub_78BF54
  6. .text:009E89E4                 cmp     al, 1
  7. ; Если она вернула AL не равный 1, то регистрационный номер неправильный
  8. .text:009E89E6                 jnz     loc_9E8B1E
  9. .text:009E89EC                 xor     eax, eax
  10. .text:009E89EE                 push    ebp
  11. .text:009E89EF                 push    offset loc_9E8B12
  12. .text:009E89F4                 push    dword ptr fs:[eax]
  13. ; ...
  14. ; Часть кода пропущена
  15. ; ...
  16. .text:009E8AF3                 push    0
  17. .text:009E8AF5                 movzx   ecx, ds:word_9E8C28
  18. .text:009E8AFC                 mov     dl, 2
  19. .text:009E8AFE                 mov     eax, offset _str_Thank_you_for_r
  20. ; Указатель на строку "Thank you for registering..."
  21. .text:009E8B03                 call    @Dialogs@MessageDlg
  22. .text:009E8B08 loc_9E8B08:
  23. .text:009E8B08                 xor     eax, eax
  24. .text:009E8B0A                 pop     edx
  25. .text:009E8B0B                 pop     ecx
  26. .text:009E8B0C                 pop     ecx
  27. .text:009E8B0D                 mov     fs:[eax], edx
  28. .text:009E8B10                 jmp     short loc_9E8B58
  29. .text:009E8B12 ; -------------------------------------------
  30. ; Часть кода пропущена
  31. .text:009E8B1E loc_9E8B1E:
  32. .text:009E8B1E                 push    0
  33. .text:009E8B20                 movzx   ecx, ds:word_9E8C28
  34. .text:009E8B27                 mov     dl, 1
  35. .text:009E8B29                 mov     eax, offset _str_Please_try_agai
  36. ; Указатель на строку "Please try again"
  37. .text:009E8B2E                 call    @Dialogs@MessageDlg
  38. .text:009E8B33                 mov     eax, [ebp-0Ch]
  39. .text:009E8B36                 mov     eax, [eax+37Ch]
  40. .text:009E8B3C                 xor     edx, edx
  41. ...
Первый вариант лечения - патч функции проверки по адресу 0078BF54, чтобы она всегда возвращала AL=1. Запишем в начало функции пару команд MOV AL,1 и RET, сохраним изменения и посмотрим, что у нас получилось. Даже без ввода регистрационных данных окно "О программе" заметно изменилось, однако имя, компанию и серийный номер все равно можно ввести. Попробуем после патча зарегистрировать Chaos Intellect с левыми данными:

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

Регистрация прошла успешно, программа действительно принимает любое имя и серийный номер. Патч быстрый и эффективный, но, как сказали бы мои "коллеги по цеху", это слишком простое решение. Посему попробуем разобрать алгоритм проверки серийного номера. Для этого загрузим программу под отладчиком, поставим точку останова на начало функции проверки по адресу 0078BF54 и попробуем вновь зарегистрировать ее.
  1. .text:0078BF54                 push    ebp
  2. .text:0078BF55                 mov     ebp, esp
  3. .text:0078BF57                 add     esp, 0FFFFFFE0h
  4. .text:0078BF5A                 push    ebx
  5. .text:0078BF5B                 push    esi
  6. .text:0078BF5C                 push    edi
  7. .text:0078BF5D                 xor     ebx, ebx
  8. .text:0078BF5F                 mov     [ebp+var_20], ebx
  9. .text:0078BF62                 mov     [ebp+var_18], ebx
  10. .text:0078BF65                 mov     [ebp+var_1C], ebx
  11. .text:0078BF68                 mov     [ebp+var_14], ebx
  12. .text:0078BF6B                 mov     [ebp+var_C], ecx
  13. .text:0078BF6E                 mov     [ebp+var_8], edx
  14. .text:0078BF71                 mov     [ebp+var_4], eax
  15. .text:0078BF74                 mov     eax, [ebp+var_4]
  16. .text:0078BF77                 call    @System@@LStrAddRef$qqrpv
  17. .text:0078BF7C                 mov     eax, [ebp+var_8]
  18. .text:0078BF7F                 call    @System@@LStrAddRef$qqrpv
  19. .text:0078BF84                 mov     eax, [ebp+var_C]
  20. .text:0078BF87                 call    @System@@LStrAddRef$qqrpv
  21. .text:0078BF8C                 xor     eax, eax
  22. .text:0078BF8E                 push    ebp
  23. .text:0078BF8F                 push    offset loc_78C0EF
  24. .text:0078BF94                 push    dword ptr fs:[eax]
  25. .text:0078BF97                 mov     fs:[eax], esp
  26. .text:0078BF9A                 mov     [ebp+var_D], 0
  27. .text:0078BF9E                 lea     eax, [ebp+var_14]
  28. .text:0078BFA1                 mov     ecx, [ebp+var_8]
  29. .text:0078BFA4                 mov     edx, [ebp+var_4]
  30. .text:0078BFA7                 call    @System@@LStrCat3$qqrv
  31. .text:0078BFAC                 cmp     [ebp+var_14], 0
  32. .text:0078BFB0                 jz      loc_78C0C7
  33. .text:0078BFB6                 cmp     [ebp+var_C], 0
  34. .text:0078BFBA                 jz      loc_78C0C7
Вот и первая проверка. В пошаговом режиме под отладчиком хорошо видно, что берется строка регистрационного имени, затем к ней в конец дописывается строка из поля наименования организации. Затем это все проверяется на предмет непустой строки. Этакая оригинальная проверка, чтобы хоть одно поле было заполнено. Значит в проверке участвует или регистрационное имя, или наименование организации.
  1. .text:0078BFC0                 lea     eax, [ebp+var_1C]
  2. .text:0078BFC3                 mov     edx, [ebp+var_C]
  3. .text:0078BFC6                 movzx   edx, byte ptr [edx+5]
  4. .text:0078BFCA                 call    unknown_libname_87
  5. .text:0078BFCF                 mov     eax, [ebp+var_1C]
  6. .text:0078BFD2                 lea     edx, [ebp+var_18]
  7. .text:0078BFD5                 call    @Sysutils@UpperCase$qqrx17System@AnsiString
  8. .text:0078BFDA                 mov     eax, [ebp+var_18]
  9. .text:0078BFDD                 mov     edx, offset _str_G.Text
  10. .text:0078BFE2                 call    @System@@LStrCmp$qqrv
  11. .text:0078BFE7                 jnz     loc_78C0C7
Следующая проверка. В дизассемблере можно посмотреть, что какой-то символ серийника сравнивается со строкой "G". Можно было бы сравнивать с символом, но видимо разработчик лекцию про оптимизацию кода добросовестно прогулял. Из отладчика узнаем, что сравнивается пятый по счету символ введенного серийного номера. Отлично, один символ в серийнике мы знаем. Едем дальше.
  1. .text:0078BFED                 xor     eax, eax
  2. .text:0078BFEF                 push    ebp
  3. .text:0078BFF0                 push    offset loc_78C025
  4. .text:0078BFF5                 push    dword ptr fs:[eax]
  5. .text:0078BFF8                 mov     fs:[eax], esp
  6. .text:0078BFFB                 lea     eax, [ebp+var_20]
  7. .text:0078BFFE                 push    eax
  8. .text:0078BFFF                 mov     ecx, 4
  9. .text:0078C004                 mov     edx, 2
  10. .text:0078C009                 mov     eax, [ebp+var_C]
  11. .text:0078C00C                 call    @System@@LStrCopy$qqrv
  12. .text:0078C011                 mov     eax, [ebp+var_20]
  13. .text:0078C014                 call    @Sysutils@StrToInt$qqrx17System@AnsiString
  14. .text:0078C019                 mov     esi, eax
Здесь придется смотреть и в отладчик, и в дизассемблер. В отладчике видно что из введенного серийника вырезается строка со второго по четвертый символ включительно, а в дизассемблере видно, что она затем рассматривается как запись десятичного числа и переводится уже в число настоящее. Результат преобразования сохраняется в регистре ESI.
  1. .text:0078C034                 xor     ecx, ecx
  2. .text:0078C036                 mov     eax, [ebp+var_4]
  3. .text:0078C039                 test    eax, eax
  4. .text:0078C03B                 jz      short loc_78C042
  5. .text:0078C03D                 sub     eax, 4
  6. .text:0078C040                 mov     eax, [eax]
  7. .text:0078C042 loc_78C042:
  8. .text:0078C042                 test    eax, eax
  9. .text:0078C044                 jle     short loc_78C059
  10. .text:0078C046                 mov     edx, 1
  11. .text:0078C04B loc_78C04B:
  12. .text:0078C04B                 mov     ebx, [ebp+var_4]
  13. .text:0078C04E                 movzx   ebx, byte ptr [ebx+edx-1]
  14. .text:0078C053                 add     ecx, ebx
  15. .text:0078C055                 inc     edx
  16. .text:0078C056                 dec     eax
  17. .text:0078C057                 jnz     short loc_78C04B
  18. .text:0078C059 loc_78C059:
  19. .text:0078C059                 mov     eax, esi
  20. .text:0078C05B                 sub     eax, 7D6h
  21. .text:0078C060                 cmp     ecx, eax
  22. .text:0078C062                 jnz     short loc_78C06A
  23. .text:0078C064                 mov     [ebp+var_D], 1
  24. .text:0078C068                 jmp     short loc_78C07B
Вот и основная проверка. Под отладчиком видно, что последовательно суммируются коды всех символов регистрационного имени. Затем берется посчитанное значение из серийного номера и из него вычитается число 7D6h. Полученный результат должен быть равен сумме символов регистрационного имени. Другими словами, четыре символа серийного номера равняются сумме кодов символов регистрационного имени плюс 7D6h и записанные в десятичной системе счисления. Первый символ серийного номера может быть любым.
  1. .text:0078C06A loc_78C06A:
  2. .text:0078C06A                 mov     eax, esi
  3. .text:0078C06C                 sub     eax, 29Ah
  4. .text:0078C071                 cmp     ecx, eax
  5. .text:0078C073                 jnz     short loc_78C07B
  6. .text:0078C075                 jmp     short loc_78C07B
  7. .text:0078C077 ; ----------------------------------
  8. .text:0078C077                 mov     [ebp+var_D], 1
А вот тут шутка юмора от разработчика. Из значения серийного номера вычитается "число зверя" 666 (29Ah), затем выполняется сравнение с суммой кодов символов регистрационного имени. Но, независимо от результата, переход выполняется на возврат флага о неправильной регистрации. На ум приходят строчки из Библии: "Here is wisdom. Let him that hath understanding count the number of the beast: for it is the number of a man; and his number is Six hundred threescore and six", что в переводе гласит "Здесь мудрость. Кто имеет ум, тот сочти число зверя, ибо это число человеческое; число его шестьсот шестьдесят шесть". Или это такой привет вирмейкерской команде "29A", или намек реверсерам, что при любом раскладе гореть им в аду?

Дальше повтор кода проверки, но на этот раз уже считается сумма кодов символов из названия организации. То есть программу можно регистрировать как на имя + любое название организации, так и на название организации + пустое имя, разницы никакой.
  1. .text:0078C08A                 sub     eax, 4
  2. .text:0078C08D                 mov     eax, [eax]
  3. .text:0078C08F loc_78C08F:
  4. .text:0078C08F                 test    eax, eax
  5. .text:0078C091                 jle     short loc_78C0A6
  6. .text:0078C093                 mov     edx, 1
  7. .text:0078C098 loc_78C098:
  8. .text:0078C098                 mov     ebx, [ebp+var_8]
  9. .text:0078C09B                 movzx   ebx, byte ptr [ebx+edx-1]
  10. .text:0078C0A0                 add     ecx, ebx
  11. .text:0078C0A2                 inc     edx
  12. .text:0078C0A3                 dec     eax
  13. .text:0078C0A4                 jnz     short loc_78C098
  14. .text:0078C0A6 loc_78C0A6:
  15. .text:0078C0A6                 mov     eax, esi
  16. .text:0078C0A8                 sub     eax, 7D6h
  17. .text:0078C0AD                 cmp     ecx, eax
  18. .text:0078C0AF                 jnz     short loc_78C0B7
  19. .text:0078C0B1                 mov     [ebp+var_D], 1
  20. .text:0078C0B5                 jmp     short loc_78C0C7
  21. .text:0078C0B7 ; -----------------------------------------
  22. .text:0078C0B7 loc_78C0B7:
  23. .text:0078C0B7                 sub     esi, 29Ah
  24. .text:0078C0BD                 cmp     ecx, esi
  25. .text:0078C0BF                 jnz     short loc_78C0C7
  26. .text:0078C0C1                 jmp     short loc_78C0C7
Посчитаем сумму символов для регистрационного имени "ManHunter", получается значение 392h, прибавляем к нему 7D6h, получаем результат B68h или в десятичной системе 2920. Значит серийный номер будет наподобие 02920G, остальные символы серийника не учитываются. Попробуем зарегистрировать программу с найденной парой:

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

Как видите, регистрация прошла успешно. Теперь все ограничения сняты, на сэкономленные деньги можно идти пить пиво или купить свечку во спасение души. Ну а кейген вы можете написать самостоятельно.

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

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

Комментарии

Отзывы посетителей сайта о статье
Laki (16.08.2013 в 05:47):
Интересно,но мудрёно,Затык произошол на первых шагах)))
rogue (24.07.2012 в 15:16):
Да Вы красавец каких редко встретиш. Огромное Вам спасибо за труд.
2 (07.07.2012 в 08:16):
Все понятно, автор настолько хорошо все объясняет что вопросов не возникает.
Musika (06.07.2012 в 21:58):
Приветствую,

ничего не понятно, но интересно.
Спасибо.

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

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

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