Исследование защиты программы Product Key Explorer


Скриншот программы Product Key Explorer

Программа Product Key Explorer предназначена для извлечения из реестра системы информации о регистрационных ключах более 3000 разных программных продуктов, игр и операционных систем (полный список выложен на офсайте). При наличии администраторских привилегий эти данные можно получать и с других машин локальной сети. Также очень удобно, что готовый список можно сохранить в текстовый файл. В общем, Product Key Explorer пригодится как системным администраторам, так и забывчивым пользователям. И опять бы все хорошо, если б разработчики не требовали за нее денег. Хотя для твердолобых поборников аффтарских прав есть другая причина: все было бы хорошо, если бы программа с навешенным протектором запускалась при наличии отладчика в системе. Как вам такой аргумент?

Скачиваем дистрибутив, устанавливаем, смотрим на главный исполняемый файл. Первичный анализ показывает, что он упакован навесным протектором Armadillo. На каждую хитрую защиту есть противодействие, для Armadillo это универсальный распаковщик ArmaGeddon. С его помощью без труда отдираем протектор от программы. Если триальный срок уже прошел, то перед распаковкой придется почистить реестр при помощи Registry Trash Keys Finder.


Распаковываем программу

Затем с помощью CFF Explorer VII удаляем ненужные секции протектора для сокращения размера файла. Восстановленную секцию импорта ".Geddon" переименуйте в ".idata" или оставьте как есть. Должны остаться только те секции, которые показаны на скриншоте. Файл, естественно, должен остаться работоспособным.


Удаляем секции протектора

После распаковки файла Product Key Explorer остается незарегистрированным, но в окне About пишет интересную фразу: "Program probably unprotected!". То есть программа как-то взаимодействует с навесным протектором, и скорее всего через переменные окружения Armadillo. Кнопка "Register" в окне About также перестала работать, это только лишний раз подтверждает, что для лицензирования используются средства навесного протектора. Поиск в распакованном файл по стандартным названиям переменных окружения Armadillo сразу же наводит нас на следующий блок данных:


Переменные окружения Armadillo в файле

Теперь загоняем файл в дизассемблер и посмотрим в нем поподробнее, как эти переменные используются. Обычно регистрационное имя записывается в USERNAME или ALTUSERNAME. На ALTUSERNAME есть только одна перекрестная ссылка из длиннющей процедуры, в которой кроме ALTUSERNAME запрашивается значение USERKEY, сравнивается со значением DEFAULT, куда-то записывается строка "No Key!", проверяется количество лицензий из установленной пользовательской переменной NSALIC, в общем идет активная движуха по проверке регистрации. На выходе из нее получаем EAX=1, если программа зарегистрирована, и EAX=0 в случае с триальным вариантом.
.text:0042C480                 push    0FFFFFFFFh
.text:0042C482                 push    offset SEH_42C480
.text:0042C487                 mov     eax, large fs:0
.text:0042C48D                 push    eax
.text:0042C48E                 mov     large fs:0, esp
.text:0042C495                 sub     esp, 31Ch
.text:0042C49B                 mov     dl, byte_486F70
.text:0042C4A1                 push    ebx
.text:0042C4A2                 push    ebp
.text:0042C4A3                 mov     ebx, ecx
.text:0042C4A5                 push    edi
.text:0042C4A6                 mov     ecx, 3Fh
.text:0042C4AB                 xor     eax, eax
.text:0042C4AD                 lea     edi, [esp+334h+var_20B]
.text:0042C4B4                 mov     [esp+334h+Str1], dl
.text:0042C4BB                 mov     [esp+334h+var_30C], dl
.text:0042C4BF                 rep stosd
.text:0042C4C1                 stosw
.text:0042C4C3                 stosb
.text:0042C4C4                 mov     ecx, 3Fh
.text:0042C4C9                 xor     eax, eax
.text:0042C4CB                 lea     edi, [esp+334h+var_30B]
.text:0042C4CF                 mov     [esp+334h+Src], dl
.text:0042C4D6                 rep stosd
.text:0042C4D8                 stosw
.text:0042C4DA                 stosb
.text:0042C4DB                 mov     ecx, 3Fh
.text:0042C4E0                 xor     eax, eax
.text:0042C4E2                 lea     edi, [esp+334h+var_10B]
.text:0042C4E9                 mov     ebp, ds:GetEnvironmentVariableA
.text:0042C4EF                 rep stosd
.text:0042C4F1                 stosw
.text:0042C4F3                 stosb
.text:0042C4F4                 mov     ecx, 40h
.text:0042C4F9                 xor     eax, eax
.text:0042C4FB                 lea     edi, [esp+334h+Str1]
.text:0042C502                 push    0FFh            ; nSize
.text:0042C507                 rep stosd
.text:0042C509                 mov     ecx, 40h
.text:0042C50E                 lea     edi, [esp+338h+var_30C]
.text:0042C512                 rep stosd
.text:0042C514                 mov     ecx, 40h
.text:0042C519                 lea     edi, [esp+338h+Src]
.text:0042C520                 rep stosd
.text:0042C522                 lea     eax, [esp+338h+Str1]
.text:0042C529                 push    eax             ; lpBuffer
.text:0042C52A                 push    offset aAltusername ; "ALTUSERNAME"
.text:0042C52F                 call    ebp ; GetEnvironmentVariableA
.text:0042C531                 test    eax, eax
.text:0042C533                 jnz     short loc_42C5AB
.text:0042C535                 mov     ecx, off_482C24
.text:0042C53B                 mov     [esp+334h+var_324], ecx
.text:0042C53F                 mov     edi, offset off_468914
.text:0042C544                 push    84h             ; uID
.text:0042C549                 lea     ecx, [esp+338h+var_324]
.text:0042C54D                 mov     [esp+338h+var_4], eax
.text:0042C554                 mov     [esp+338h+var_328], edi
.text:0042C558                 call    ?LoadStringA@CString@@QAEHI@Z
; CString::LoadStringA(uint)
.text:0042C55D                 lea     eax, [esp+334h+var_328]
.text:0042C561                 lea     edx, [esp+334h+var_324]
.text:0042C565                 neg     eax
.text:0042C567                 sbb     eax, eax
.text:0042C569                 lea     ecx, [ebx+0FCh]
.text:0042C56F                 and     eax, edx
.text:0042C571                 mov     [esp+334h+var_4], 1
.text:0042C57C                 push    eax
.text:0042C57D                 call    sub_456585
.text:0042C582                 lea     ecx, [esp+334h+var_328]
.text:0042C586                 lea     eax, [esp+334h+var_324]
.text:0042C58A                 neg     ecx
.text:0042C58C                 sbb     ecx, ecx
.text:0042C58E                 mov     [esp+334h+var_4], 0FFFFFFFFh
.text:0042C599                 and     ecx, eax
.text:0042C59B                 mov     [esp+334h+var_328], edi
.text:0042C59F                 call    sub_45644C
.text:0042C5A4                 xor     eax, eax
.text:0042C5A6                 jmp     loc_42CB09
.text:0042C5AB ; ------------------------------------------
.text:0042C5AB loc_42C5AB:
.text:0042C5AB                 push    esi
.text:0042C5AC                 lea     ecx, [esp+338h+var_30C]
.text:0042C5B0                 push    0FFh            ; nSize
.text:0042C5B5                 push    ecx             ; lpBuffer
.text:0042C5B6                 push    offset aUserkey_0 ; "USERKEY"
.text:0042C5BB                 call    ebp ; GetEnvironmentVariableA
.text:0042C5BD                 test    eax, eax
.text:0042C5BF                 jnz     short loc_42C5E5
.text:0042C5C1                 mov     edi, offset aNoKey ; "No key!"
.text:0042C5C6                 or      ecx, 0FFFFFFFFh
.text:0042C5C9                 repne scasb
.text:0042C5CB                 not     ecx
.text:0042C5CD                 sub     edi, ecx
.text:0042C5CF                 lea     edx, [esp+338h+var_30C]
.text:0042C5D3                 mov     eax, ecx
.text:0042C5D5                 mov     esi, edi
.text:0042C5D7                 mov     edi, edx
.text:0042C5D9                 shr     ecx, 2
.text:0042C5DC                 rep movsd
.text:0042C5DE                 mov     ecx, eax
.text:0042C5E0                 and     ecx, 3
.text:0042C5E3                 rep movsb
.text:0042C5E5 loc_42C5E5:
.text:0042C5E5                 lea     ecx, [esp+338h+Str1]
.text:0042C5EC                 push    offset aDefault ; "DEFAULT"
.text:0042C5F1                 push    ecx             ; Str1
.text:0042C5F2                 call    __strcmpi
.text:0042C5F7                 add     esp, 8
.text:0042C5FA                 test    eax, eax
.text:0042C5FC                 jnz     short loc_42C678
.text:0042C5FE                 mov     edx, off_482C24
.text:0042C604                 mov     [esp+338h+var_324], edx
.text:0042C608                 mov     edi, offset off_468914
.text:0042C60D                 push    83h             ; uID
.text:0042C612                 lea     ecx, [esp+33Ch+var_324]
.text:0042C616                 mov     [esp+33Ch+var_4], 2
.text:0042C621                 mov     [esp+33Ch+var_328], edi
.text:0042C625                 call    ?LoadStringA@CString@@QAEHI@Z
; CString::LoadStringA(uint)
.text:0042C62A                 lea     eax, [esp+338h+var_328]
.text:0042C62E                 lea     ecx, [esp+338h+var_324]
.text:0042C632                 neg     eax
.text:0042C634                 sbb     eax, eax
.text:0042C636                 lea     esi, [ebx+0FCh]
.text:0042C63C                 and     eax, ecx
.text:0042C63E                 mov     ecx, esi
...

Пропатчим начало функции проверки, записав туда команды MOV EAX,1; RET. Сохраняем изменения, запускаем, проверяем. Информация в About стала получше, теперь там нет сообщения, что с программы отодран навесной протектор. Но в остальном ограничения остались - не показываются целиком ключи, нельзя записать найденные ключи в файл. Ищем дальше. Есть еще одна функция, где проверяется значение другой переменной - USERNAME. Тут тоже все очень наглядно:
.text:0042D7E0                 push    0FFFFFFFFh
.text:0042D7E2                 push    offset SEH_42D7E0
.text:0042D7E7                 mov     eax, large fs:0
.text:0042D7ED                 push    eax
.text:0042D7EE                 mov     large fs:0, esp
.text:0042D7F5                 push    ecx
.text:0042D7F6                 mov     eax, off_482C24
.text:0042D7FB                 mov     [esp+10h+Str1], eax
.text:0042D7FF                 lea     edx, [esp+10h+Str1]
.text:0042D803                 mov     [esp+10h+var_4], 0
.text:0042D80B                 push    edx             ; int
.text:0042D80C                 push    offset aUsername_3 ; "USERNAME"
.text:0042D811                 call    sub_42D880
.text:0042D816                 test    eax, eax
.text:0042D818                 jz      short loc_42D85E
.text:0042D81A                 mov     eax, [esp+10h+Str1]
.text:0042D81E                 push    offset aDefault ; "DEFAULT"
.text:0042D823                 push    eax             ; Str1
.text:0042D824                 call    __mbscmp
.text:0042D829                 add     esp, 8
.text:0042D82C                 test    eax, eax
.text:0042D82E                 jz      short loc_42D85E
.text:0042D830                 call    sub_42D6B0
.text:0042D835                 test    eax, eax
.text:0042D837                 jz      short loc_42D85E
.text:0042D839                 lea     ecx, [esp+10h+Str1]
.text:0042D83D                 mov     [esp+10h+var_4], 0FFFFFFFFh
.text:0042D845                 call    sub_45644C
.text:0042D84A                 mov     eax, 1
.text:0042D84F                 mov     ecx, [esp+10h+var_C]
.text:0042D853                 mov     large fs:0, ecx
.text:0042D85A                 add     esp, 10h
.text:0042D85D                 retn
.text:0042D85E ; ----------------------------------------------
.text:0042D85E loc_42D85E:
.text:0042D85E                 lea     ecx, [esp+10h+Str1]
.text:0042D862                 mov     [esp+10h+var_4], 0FFFFFFFFh
.text:0042D86A                 call    sub_45644C
.text:0042D86F                 mov     ecx, [esp+10h+var_C]
.text:0042D873                 xor     eax, eax
.text:0042D875                 mov     large fs:0, ecx
.text:0042D87C                 add     esp, 10h
.text:0042D87F                 retn

На выходе EAX=1 - программа зарегистрирована, EAX=0 - регистрации нет. С этой функцией поступаем аналогичным образом, то есть записываем в начало пару команд MOV EAX,1 и RET. Сохраняем изменения, запускаем. Вот теперь наблюдаем красоту, все ключи найдены, а список сохраняется в файл без каких-либо ограничений.


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

Вот и все, программа "зарегистрирована". В качестве дополнительного приятного бонуса в отломанном виде она становится портативной и может работать с любого съемного носителя. Это особенно удобно, когда приходится иметь дело с чужими компьютерами.
Теги:
защита, взлом
Добавлено: 19 Сентября 2013 12:29:41 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...