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

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

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

http://s013.radikal.ru/i324/1710/d6/4c5bca88af72.png
Установка SEH-кадра

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

http://i013.radikal.ru/1710/de/c9853fcacab7.png
Адрес перехода из SEH

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

http://s013.radikal.ru/i324/1710/70/9d9883afe5fe.png
Переход на OEP

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

http://s019.radikal.ru/i613/1710/37/564b91080797.png
OEP

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

http://s019.radikal.ru/i622/1710/3b/702506345e2d.png
Делаем дамп

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

http://s018.radikal.ru/i528/1710/cb/669e19cde942.png
Загружаем таблицу импорта

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

http://s019.radikal.ru/i613/1710/e1/1d89b4f6fd4f.png
Исправляем дамп

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

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

Код:
IDS_SUBMAIN1=(Unregistered - Day
IDS_SUBMAIN2=of 15)
IDS_SUBMAIN3=(Function-Limited)

Значит надо искать не сами строки, а их индексы. По первому же индексу обнаружится вот такой код:

Цитата:

; Проверить значение в ячейке памяти
.text:0041C190 cmp dword_469DA4, ebx
.text:0041C196 jnz short loc_41C1A9
; Если оно не нулевое, то перейти на добавление в заголовок плозх надписей
.text:0041C198 push offset Caption ; "Privacy Inspector"
.text:0041C19D mov ecx, esi
.text:0041C19F call sub_43D788
.text:0041C1A4 jmp loc_41C33F
.text:0041C1A9 ; ——————————————————–
.text:0041C1A9 loc_41C1A9:
.text:0041C1A9 mov eax, dword_469DA8
.text:0041C1AE lea ecx, [esp+0Ch]
.text:0041C1B2 push ecx
.text:0041C1B3 push ecx
.text:0041C1B4 test eax, eax
.text:0041C1B6 mov ecx, esp
.text:0041C1B8 jnz loc_41C2DF
.text:0041C1BE mov [esp+2Ch], esp
; Загрузить строку по индексу
.text:0041C1C2 push offset aIds_submain1 ; "IDS_SUBMAIN1"
.text:0041C1C7 call sub_439BD0
.text:0041C1CC push ecx
.text:0041C1CD mov byte ptr [esp+3Ch], 2
.text:0041C1D2 mov ecx, esp
.text:0041C1D4 mov [esp+2Ch], esp
.text:0041C1D8 push offset aMain ; "Main"
.text:0041C1DD call sub_439BD0

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

Цитата:

.text:0041955D push ecx
.text:0041955E mov ecx, ebx
; Вызвать функцию проверки
.text:00419560 call sub_419DB0
.text:00419565 test eax, eax
; По ее результатам записать в переменную 0 или 1
.text:00419567 jz short loc_41957B
.text:00419569 mov eax, [ebp+lpszUrl]
.text:0041956C mov dword_469DA4, 1
.text:00419576 cmp eax, 4
.text:00419579 jnb short loc_419585
.text:0041957B loc_41957B:
.text:0041957B mov dword_469DA4, 0
.text:00419585 loc_419585:
.text:00419585 lea edx, [ebp+var_128]
.text:0041958B mov ecx, ebx
.text:0041958D push edx
; Вызвать еще одну функцию проверки
.text:0041958E call sub_41A110
.text:00419593 test eax, eax
; Если она вернула 0, то перезаписать переменную этим нулевым значением
.text:00419595 jnz loc_419715
.text:0041959B push eax
.text:0041959C lea ecx, [ebp+var_11F8]
.text:004195A2 mov dword_469DA4, eax
.text:004195A7 call sub_41CB00
.text:004195AC lea ecx, [ebp+var_11F8]
.text:004195B2 mov byte ptr [ebp+var_4], 0Bh

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

Цитата:

.text:0041A110 mov eax, 2264h
.text:0041A115 call __alloca_probe
.text:0041A11A mov ax, word_464AA8
.text:0041A120 push ebx
.text:0041A121 push esi
.text:0041A122 push edi
.text:0041A123 mov word ptr [esp+2270h+var_2262], ax
.text:0041A128 mov ecx, 226h
.text:0041A12D xor eax, eax
.text:0041A12F lea edi, [esp+2270h+var_1130]
.text:0041A136 rep stosd
.text:0041A138 mov ecx, 226h
.text:0041A13D lea edi, [esp+2270h+var_2260]
.text:0041A141 rep stosd
.text:0041A143 mov ecx, 226h
.text:0041A148 lea edi, [esp+2270h+var_19C8]
.text:0041A14F rep stosd
.text:0041A151 mov ecx, 226h
.text:0041A156 lea edi, [esp+2270h+var_898]
.text:0041A15D rep stosd
.text:0041A15F or ecx, 0FFFFFFFFh
.text:0041A162 mov edi, offset aDcji77cfDf1g75
; "DCJI77CF,DF1G752F,GGD24KF7,9FGKD85H,88H"…
.text:0041A167 repne scasb
.text:0041A169 not ecx
.text:0041A16B sub edi, ecx
.text:0041A16D lea edx, [esp+2270h+var_1130]
.text:0041A174 mov eax, ecx
.text:0041A176 mov esi, edi
.text:0041A178 shr ecx, 2
.text:0041A17B mov edi, edx
.text:0041A17D lea edx, [esp+2270h+var_2260]
.text:0041A181 rep movsd
.text:0041A183 mov ecx, eax
.text:0041A185 xor eax, eax
.text:0041A187 and ecx, 3
.text:0041A18A rep movsb
.text:0041A18C mov edi, offset aNbgd3eeqEb3hme
; "NBGD3EEQ,EB3HMEQM,C3GH7N3F,IIE3D7HI,BHV"…
.text:0041A191 or ecx, 0FFFFFFFFh
.text:0041A194 repne scasb
.text:0041A196 not ecx
.text:0041A198 sub edi, ecx
.text:0041A19A mov eax, ecx
.text:0041A19C mov esi, edi
.text:0041A19E mov edi, edx
.text:0041A1A0 lea edx, [esp+2270h+var_19C8]
.text:0041A1A7 shr ecx, 2
.text:0041A1AA rep movsd
.text:0041A1AC mov ecx, eax
.text:0041A1AE xor eax, eax
.text:0041A1B0 and ecx, 3
.text:0041A1B3 rep movsb
.text:0041A1B5 mov edi, offset aBqjgbbej5548zg
; "BQJGBBEJ,5548ZGB3,5HHF5BIM,2JJE3GZJ,GFB"…
.text:0041A1BA or ecx, 0FFFFFFFFh
.text:0041A1BD repne scasb
.text:0041A1BF not ecx
.text:0041A1C1 sub edi, ecx
.text:0041A1C3 mov eax, ecx
.text:0041A1C5 mov esi, edi
.text:0041A1C7 mov edi, edx
.text:0041A1C9 lea edx, [esp+2270h+var_898]
.text:0041A1D0 shr ecx, 2
.text:0041A1D3 rep movsd
.text:0041A1D5 mov ecx, eax
.text:0041A1D7 xor eax, eax
.text:0041A1D9 and ecx, 3
.text:0041A1DC rep movsb
.text:0041A1DE mov edi, offset aMmv7mb1eGfgj5g
; "MMV7MB1E,GFGJ5GJ7,7JDEE6EB,NMHJ12A1,DAA"…
.text:0041A1E3 or ecx, 0FFFFFFFFh
.text:0041A1E6 repne scasb
.text:0041A1E8 not ecx

Если зарулить сюда под отладчиком, то становится видно, как введенный серийный номер поочередно сравнивается со строчками из довольно объемных списков. Есть мнение, что это зашитые в программу валидные серийники. Проверяем. Регистрационное имя любое, серийный номер любой из любого списка. Перезапускаем программу. Вуаля!

http://i013.radikal.ru/1710/66/fa81a19ecb30.png
Программа успешно зарегистрирована

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

• Author: ManHunter

Оставьте комментарий