Blog. Just Blog

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

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

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

Начинаем со скачивания дистрибутива. Устанавливаем, смотрим. По всем признакам исполняемый файл накрыт пакером PECompact. Можно воспользоваться какой-нибудь готовой утилитой для его снятия, но больше пользы будет, если распаковать его ручками. Загружаем файл в отладчик, но не запускаем.

Установка SEH-кадра
Установка SEH-кадра

В PECompact используется антиотладочный трюк, основанный на установке SEH-кадра, адрес которого является адресом перехода на следующий код. Более подробно можете посмотреть здесь. В регистр EAX заносится адрес перехода, затем выполняется запись в запрещенный участок памяти, срабатывает обработчик ошибок и управление передается на адрес перехода.

Адрес перехода из SEH
Адрес перехода из SEH

Поставим сюда точку останова и запустим программу. Если сработает исключение (а оно сработает), то надо принудительно продолжить исполнение программы в обход исключения (Shift+F9).

Переход на OEP
Переход на OEP

Проматываем пару экранов вниз, пока не доберемся до характерной команды JMP EAX, после которой следует куча нулевых байт. Это и есть переход на OEP. Ставим точку останова на JMP EAX и снова запускаем программу.

OEP
OEP

После срабатывания точки останова делаем одну пошаговую трассировку и попадаем на OEP. Все, программа готова для снятия дампа и восстановления импорта.

Делаем дамп
Делаем дамп

Делаем дамп. Я использую для этого плагин OllyDump, но никто не мешает использовать для этого какие-нибудь другие инструменты, суть от этого не меняется.

Загружаем таблицу импорта
Загружаем таблицу импорта

Ищем и загружаем таблицу импорта. Адрес OEP вычисляется вычитанием базы кода из виртуального адреса OEP (00428A01 - 00400000 = 28A01), подставляем его в ImpREC, дальше два клика на "IAT AutoSearch" и "Get Imports". таблица импорта не повреждена, можно сразу же прикручивать ее к дампу.

Исправляем дамп
Исправляем дамп

Клик на "Fix Dump", выбираем созданный файл дампа и через пару секунд получаем полностью распакованный и работоспособный файл. Точно по такому же алгоритму распаковываются и другие файлы, накрытые PECompact. На описание ушло гораздо больше времени, чем на саму распаковку.

Все навесы с файла сняты, можно отправлять распакованный и восстановленный файл в дизассемблер. Регистрация работает следующим образом: программа принимает любой серийный номер, но после этого требует перезапуск. Никаких сообщений о правильности и неправильности введенных данных не выводится. Ориентироваться можно только по надписям, например, в заголовке. В файле ничего подобного не нашлось, зато нашлось в языковом файле English.ini в папке \Language. Надпись, которая выводится в заголовок, состоит из нескольких частей.

IDS_SUBMAIN1=(Unregistered - Day
IDS_SUBMAIN2=of 15)
IDS_SUBMAIN3=(Function-Limited)

Значит надо искать не сами строки, а их индексы. По первому же индексу обнаружится вот такой код:
  1. ; Проверить значение в ячейке памяти
  2. .text:0041C190                 cmp     dword_469DA4, ebx
  3. .text:0041C196                 jnz     short loc_41C1A9
  4. ; Если оно не нулевое, то перейти на добавление в заголовок плохих надписей
  5. .text:0041C198                 push    offset Caption  ; "Privacy Inspector"
  6. .text:0041C19D                 mov     ecx, esi
  7. .text:0041C19F                 call    sub_43D788
  8. .text:0041C1A4                 jmp     loc_41C33F
  9. .text:0041C1A9 ; --------------------------------------------------------
  10. .text:0041C1A9 loc_41C1A9:
  11. .text:0041C1A9                 mov     eax, dword_469DA8
  12. .text:0041C1AE                 lea     ecx, [esp+0Ch]
  13. .text:0041C1B2                 push    ecx
  14. .text:0041C1B3                 push    ecx
  15. .text:0041C1B4                 test    eax, eax
  16. .text:0041C1B6                 mov     ecx, esp
  17. .text:0041C1B8                 jnz     loc_41C2DF
  18. .text:0041C1BE                 mov     [esp+2Ch], esp
  19. ; Загрузить строку по индексу
  20. .text:0041C1C2                 push    offset aIds_submain1 ; "IDS_SUBMAIN1"
  21. .text:0041C1C7                 call    sub_439BD0
  22. .text:0041C1CC                 push    ecx
  23. .text:0041C1CD                 mov     byte ptr [esp+3Ch], 2
  24. .text:0041C1D2                 mov     ecx, esp
  25. .text:0041C1D4                 mov     [esp+2Ch], esp
  26. .text:0041C1D8                 push    offset aMain    ; "Main"
  27. .text:0041C1DD                 call    sub_439BD0
Проверяется значение в какой-то переменной, если оно не нулевое, то программа считается триальной и в заголовок добавляются всякие посторонние надписи. Следующим шагом ищем, где и как инициализируется эта переменная. По перекрестным ссылкам попадаем вот на такой интересный код:
  1. .text:0041955D                 push    ecx
  2. .text:0041955E                 mov     ecx, ebx
  3. ; Вызвать функцию проверки
  4. .text:00419560                 call    sub_419DB0
  5. .text:00419565                 test    eax, eax
  6. ; По ее результатам записать в переменную 0 или 1
  7. .text:00419567                 jz      short loc_41957B
  8. .text:00419569                 mov     eax, [ebp+lpszUrl]
  9. .text:0041956C                 mov     dword_469DA4, 1
  10. .text:00419576                 cmp     eax, 4
  11. .text:00419579                 jnb     short loc_419585
  12. .text:0041957B loc_41957B:
  13. .text:0041957B                 mov     dword_469DA4, 0
  14. .text:00419585 loc_419585:
  15. .text:00419585                 lea     edx, [ebp+var_128]
  16. .text:0041958B                 mov     ecx, ebx
  17. .text:0041958D                 push    edx
  18. ; Вызвать еще одну функцию проверки
  19. .text:0041958E                 call    sub_41A110
  20. .text:00419593                 test    eax, eax
  21. ; Если она вернула 0, то перезаписать переменную этим нулевым значением
  22. .text:00419595                 jnz     loc_419715
  23. .text:0041959B                 push    eax
  24. .text:0041959C                 lea     ecx, [ebp+var_11F8]
  25. .text:004195A2                 mov     dword_469DA4, eax
  26. .text:004195A7                 call    sub_41CB00
  27. .text:004195AC                 lea     ecx, [ebp+var_11F8]
  28. .text:004195B2                 mov     byte ptr [ebp+var_4], 0Bh
Дважды выполняются какие-то проверки, по их результатам несколько раз в переменную записываются различные значения. Если заглянуть под отладчиком в первую функцию проверки, то там обнаружится преобразование регистрационного имени в нечто, очень похожее на серийный номер, который, в свою очередь, сравнивается с введенным серийным номером. Чтобы не тратить ваше время, скажу, что это подлянка от аффтара. При любом результате сравнения, даже если вытащить под отладчиком валидную пару под конкретное имя, эта проверка на регистрацию не влияет. Значит есть смысл посмотреть на вторую проверку, которая расположена ниже.
  1. .text:0041A110                 mov     eax, 2264h
  2. .text:0041A115                 call    __alloca_probe
  3. .text:0041A11A                 mov     ax, word_464AA8
  4. .text:0041A120                 push    ebx
  5. .text:0041A121                 push    esi
  6. .text:0041A122                 push    edi
  7. .text:0041A123                 mov     word ptr [esp+2270h+var_2262], ax
  8. .text:0041A128                 mov     ecx, 226h
  9. .text:0041A12D                 xor     eax, eax
  10. .text:0041A12F                 lea     edi, [esp+2270h+var_1130]
  11. .text:0041A136                 rep stosd
  12. .text:0041A138                 mov     ecx, 226h
  13. .text:0041A13D                 lea     edi, [esp+2270h+var_2260]
  14. .text:0041A141                 rep stosd
  15. .text:0041A143                 mov     ecx, 226h
  16. .text:0041A148                 lea     edi, [esp+2270h+var_19C8]
  17. .text:0041A14F                 rep stosd
  18. .text:0041A151                 mov     ecx, 226h
  19. .text:0041A156                 lea     edi, [esp+2270h+var_898]
  20. .text:0041A15D                 rep stosd
  21. .text:0041A15F                 or      ecx, 0FFFFFFFFh
  22. .text:0041A162                 mov     edi, offset aDcji77cfDf1g75
  23. ; "DCJI77CF,DF1G752F,GGD24KF7,9FGKD85H,88H"...
  24. .text:0041A167                 repne scasb
  25. .text:0041A169                 not     ecx
  26. .text:0041A16B                 sub     edi, ecx
  27. .text:0041A16D                 lea     edx, [esp+2270h+var_1130]
  28. .text:0041A174                 mov     eax, ecx
  29. .text:0041A176                 mov     esi, edi
  30. .text:0041A178                 shr     ecx, 2
  31. .text:0041A17B                 mov     edi, edx
  32. .text:0041A17D                 lea     edx, [esp+2270h+var_2260]
  33. .text:0041A181                 rep movsd
  34. .text:0041A183                 mov     ecx, eax
  35. .text:0041A185                 xor     eax, eax
  36. .text:0041A187                 and     ecx, 3
  37. .text:0041A18A                 rep movsb
  38. .text:0041A18C                 mov     edi, offset aNbgd3eeqEb3hme
  39. ; "NBGD3EEQ,EB3HMEQM,C3GH7N3F,IIE3D7HI,BHV"...
  40. .text:0041A191                 or      ecx, 0FFFFFFFFh
  41. .text:0041A194                 repne scasb
  42. .text:0041A196                 not     ecx
  43. .text:0041A198                 sub     edi, ecx
  44. .text:0041A19A                 mov     eax, ecx
  45. .text:0041A19C                 mov     esi, edi
  46. .text:0041A19E                 mov     edi, edx
  47. .text:0041A1A0                 lea     edx, [esp+2270h+var_19C8]
  48. .text:0041A1A7                 shr     ecx, 2
  49. .text:0041A1AA                 rep movsd
  50. .text:0041A1AC                 mov     ecx, eax
  51. .text:0041A1AE                 xor     eax, eax
  52. .text:0041A1B0                 and     ecx, 3
  53. .text:0041A1B3                 rep movsb
  54. .text:0041A1B5                 mov     edi, offset aBqjgbbej5548zg
  55. ; "BQJGBBEJ,5548ZGB3,5HHF5BIM,2JJE3GZJ,GFB"...
  56. .text:0041A1BA                 or      ecx, 0FFFFFFFFh
  57. .text:0041A1BD                 repne scasb
  58. .text:0041A1BF                 not     ecx
  59. .text:0041A1C1                 sub     edi, ecx
  60. .text:0041A1C3                 mov     eax, ecx
  61. .text:0041A1C5                 mov     esi, edi
  62. .text:0041A1C7                 mov     edi, edx
  63. .text:0041A1C9                 lea     edx, [esp+2270h+var_898]
  64. .text:0041A1D0                 shr     ecx, 2
  65. .text:0041A1D3                 rep movsd
  66. .text:0041A1D5                 mov     ecx, eax
  67. .text:0041A1D7                 xor     eax, eax
  68. .text:0041A1D9                 and     ecx, 3
  69. .text:0041A1DC                 rep movsb
  70. .text:0041A1DE                 mov     edi, offset aMmv7mb1eGfgj5g
  71. ; "MMV7MB1E,GFGJ5GJ7,7JDEE6EB,NMHJ12A1,DAA"...
  72. .text:0041A1E3                 or      ecx, 0FFFFFFFFh
  73. .text:0041A1E6                 repne scasb
  74. .text:0041A1E8                 not     ecx
Если зарулить сюда под отладчиком, то становится видно, как введенный серийный номер поочередно сравнивается со строчками из довольно объемных списков. Есть мнение, что это зашитые в программу валидные серийники. Проверяем. Регистрационное имя любое, серийный номер любой из любого списка. Перезапускаем программу. Вуаля!

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

Осталось непонятным, для чего нужно было делить список серийников на несколько частей? Это абсолютно точно не проказы компилятора, так написана исходная программа. И зачем пускать реверсера по ложному следу с генерацией фейкового серийника, если несколькими строчками ниже эта ловушка сама себя нейтрализует? Навесной пакер используется, по всей видимости, чтобы спрятать весь этот ужоснах от глаз посторонних. Кейген же сводится к выбору случайного серийника из списка валидных. Точно так же обходятся защиты остальных программ разработчика, там только набор серийников будет другой. Хотя назвать это защитами можно только с большой натяжкой. Зато немного попрактиковались в ручной распаковке.

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

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

Комментарии

Отзывы посетителей сайта о статье
ManHunter (26.10.2017 в 08:26):
В этом разделе софт появляется не потому что он такой распрекрасный, а потому что можно потренироваться на реальных примерах вместо синтетических крякмисов.
xussr (26.10.2017 в 06:57):
Где ты откапал это овно на редкость ....неушто больше софта нет .Утиль кто вооще такое качает
ManHunter (10.10.2017 в 14:20):
И никогда не будет.
ромка (10.10.2017 в 13:23):
шикарный блог, только нет поля для емейлов чтоб уведомления приходили.
ManHunter (07.10.2017 в 16:13):
Нет желания правила почитать?
pc (07.10.2017 в 13:33):
нет желания исследовать вот эту поделку ?
hxxp://www.lab128.com/lab128_download.html
было бы интересно почитать
Noobie (06.10.2017 в 12:13):
Программа - 100% барахло, а вот описание весьма полезно для раздумий и тренировок по части анпака, за что и выражаю благодарность ManHunter.
xussr (05.10.2017 в 20:30):
Про ресурсы понятноа а функионал скудный это точно..лучшее это Auslogics BoostSpeed v5 а это очередной клон и не самый продвинутый даж не интересно как и чем ее лечить
Bannan (05.10.2017 в 14:01):
Цитатаесли расскажете про приведение ресурсов в нормальный вид

Про приведение ресурсов в нормальный вид, рассказывал vnekrilov (CRACKL@B) в своих статьях по распаковке Asprotect. Смысл в чем. Прежде чем прикручивать импорт, в файле дампа удаляются все секции, связанные с пакером, в том числе и секция ресурсов. После восстановления импорта секция ресурсов прикручивается обратно.

Но как и написал ManHunter, юзверю абсолютно по-барабану, гланое что работает. Единственное, кому это может доставить неудобство, так это локализаторщику.
ManHunter (05.10.2017 в 00:00):
Перфекционизм не всегда хорошо. По большому счету конечному юзеру начхать, сколько весит поломанный файл, главное, что софтина работает и не требует денег. Лично я никогда не заморачивался на тему отрезания дублей ресурсов, в крайнем случае ненужный участок можно тупо забить нулями и потом упаковать отломанный файл.
pawel97 (04.10.2017 в 23:24):
По мне, лучше Auslogics BoostSpeed v5 (именно 5 версия) ничего лучше так и не придумали. Чистка в 1 клик на любителя, а вот удобнейший твикер и советник - вещь. Всё по категориям, с описаниями, на русском (не гуглтранслейт). Конечно, он тоже не бесплатен...
Что по основной теме, будет ну прям очень полезно, если расскажете про приведение ресурсов в нормальный вид после ентого PECompact. Разумеется, если секция ресурсов под 10 МБ, чтобы она не дублировалась в файле дважды. Пример упакованной жертвы с жирной секцией ресурсов дам, если не будет бан. Анпакер это решает, но мы же сами хотим :)
Импорт же восстанавливаю scylla - импрек под 7-ками рисует в импорте всякие api-ms-win, после чего анпакнутый файл не пашет в xp.

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

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

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