Исследование защиты программы ICL-Icon Extractor
Скриншот программы ICL-Icon Extractor
Программа ICL-Icon Extractor предназначена для быстрого извлечения иконок из исполняемых файлов, архивов и системных файлов. Очень удобно, что иконки можно извлекать как в виде отдельных файлов, так и целиком библиотекой в стандартном формате ICL. Программа не на каждый день, но время от времени такая необходимость возникает, поэтому лучше держать ее под рукой.
Как обычно, любое исследование начинается с дистрибутива. Скачиваем, устанавливаем, запускаем. Сразу открывается огромное наг-окно, затем окно "О программе" с кнопкой регистрации, и только потом запускается сама программа. При завершении работы снова вылазит наг-окно. Кроме этого в главное окно программы добавляются ссылки на покупку и регистрацию. Это из визуальных признаков незарегистрированной программы. Ограничение по функционалу в том, что триальная версия не может сохранять иконки.
Ограничения незарегистрированной программы
С ограничениями все понятно, теперь надо посмотреть на то, как программа реагирует на неправильную регистрацию. Открываем окно "О программе", пробуем зарегистрировать любыми левыми данными.
Сообщение о неправильной регистрации
На разные варианты неправильного серийного номера мы получаем разные сообщения: на слишком короткий серийник это будет "Key is required", на более длинный "Wrong key". Поищем что-нибудь похожее в исполняемом файле.
Строка сообщения
Файл ничем не упакован, строки обнаруживаются легко. Обратите внимание, что рядом находится еще один вариант сообщения о неправильном серийном номере. Отправляем исполняемый файл в дизассемблер, затем по перекрестным ссылкам находим код, где эти строчки используются.
Code (Assembler) : Убрать нумерацию
- CODE:0054839C call sub_435C38
- CODE:005483A1 mov eax, [ebp+var_24]
- ; Вызывать функцию проверки
- CODE:005483A4 call sub_543A84
- CODE:005483A9 test eax, eax
- ; Если она вернула EAX=0, то сообщение выводить не надо
- CODE:005483AB jz short loc_5483B9
- CODE:005483AD push ebp
- CODE:005483AE mov eax, offset aWrongKey_
- ; "Wrong key."
- CODE:005483B3 call sub_548268
- CODE:005483B8 pop ecx
- CODE:005483B9 loc_5483B9:
- CODE:005483B9 mov eax, [ebp+var_C]
- CODE:005483BC call sub_543AF0
- CODE:005483C1 mov eax, [ebp+var_4]
- CODE:005483C4 mov edx, [eax+308h]
- CODE:005483CA mov eax, [ebp+var_C]
- ; Вызывать функцию проверки
- CODE:005483CD call sub_5438C0
- CODE:005483D2 test eax, eax
- ; Если она вернула EAX=0, то сообщение выводить не надо
- CODE:005483D4 jz short loc_5483E2
- CODE:005483D6 push ebp
- CODE:005483D7 mov eax, offset aWrongKeyForThi
- ; "Wrong key for this application."
- CODE:005483DC call sub_548268
- CODE:005483E1 pop ecx
Code (Assembler) : Убрать нумерацию
- CODE:00543A84 push ebp
- ...
- ...
- CODE:00543A98 push offset loc_543AE0
- CODE:00543A9D push dword ptr fs:[eax]
- CODE:00543AA0 mov fs:[eax], esp
- ; Обнулить глобальное значение результата
- CODE:00543AA3 xor eax, eax
- CODE:00543AA5 mov [ebp+var_8], eax
- ; Количество итераций цикла
- CODE:00543AA8 mov [ebp+var_C], 1
- CODE:00543AAF loc_543AAF:
- CODE:00543AAF mov eax, [ebp+var_4]
- ; Вызвать какую-то функцию
- CODE:00543AB2 call sub_5437B4
- ; Прибавить к глобальному результату результат этой функции
- CODE:00543AB7 add [ebp+var_8], eax
- ; Пауза для имитации напряженной деятельности
- CODE:00543ABA push 64h ; dwMilliseconds
- CODE:00543ABC call Sleep
- ; Увеличить счетчик итераций цикла
- CODE:00543AC1 inc [ebp+var_C]
- ; По всей видимости длина серийника - 0Bh
- CODE:00543AC4 cmp [ebp+var_C], 0Bh
- CODE:00543AC8 jnz short loc_543AAF
- CODE:00543ACA xor eax, eax
- ...
- ...
- ; Записать в EAX глобальный результат
- CODE:00543AE7 mov eax, [ebp+var_8]
- CODE:00543AEA mov esp, ebp
- CODE:00543AEC pop ebp
- CODE:00543AED retn
Самый простой способ обхода этой проверки - пропатчить функцию по адресу 005437B4, чтобы она всегда возвращала 0. Если записать в ее начало команды XOR EAX,EAX и RET, то первая проверка всегда будет успешно проходить, но на второй мы получим текст как на скриншоте - "Wrong key for this application". Смотрим вторую функцию проверки по адресу 005438C0. Она очень напоминает функцию, которая использовалась в первой проверке для суммирования. Поэтому поступим с ней аналогичным образом - пропатчим начало парой команд XOR EAX,EAX и RET, чтобы условный переход сработал. Как вариант, можно пропатчить сам условный переход, заменив его на безусловный. Почему так? Потому что в первой проверке функция вызывается несколько раз и из разных мест, то есть, скорее всего, это и есть основная проверка серийника при запуске. Во второй проверке функция вызывается только один раз, то есть с большой вероятностью больше нигде не используется и можно ограничиться патчем условного перехода. Сохраняем изменения, запускаем программу и пробуем зарегистрироваться с любыми данными. Единственное условие, чтобы серийник был длиннее 10 символов. Эта проверка тоже легко обходится патчем, но на сегодня хирургии и так больше чем достаточно.
Сообщение об успешной регистрации
Пропатченная программа принимает серийник без ругани, но просит перезапуститься. Не вопрос, перезапускаем программу. Никаких наг-окон, сообщений о регистрации и других признаков не наблюдается. Иконки сохраняются, значит и функциональных ограничений тоже больше нет.
Программа успешно "зарегистрирована"
С патчами закончили, теперь попробуем отреверсить алгоритм проверки, чтобы подобрать правильный регистрационный номер или же выяснить алгоритм генерации таких серийников. Начнем с первой функции проверки. Выше я уже написал, где она находится и что должна возвращать, теперь посмотрим, что она из себя представляет. Для этого запустим программу под отладчиком и поставим точку останова по адресу 005437B4, то есть на начало функции. После этого попробуем зарегистрировать, например, с такими данными: имя = "ManHunter / PCL", email = "manhunter@pcl.pcl", серийник = "1234567890". Когда точка останова сработает, пошаговой трассировкой выходим на следующий код:
Code (Assembler) : Убрать нумерацию
- CODE:0054381B sub eax, 2
- CODE:0054381E jl short loc_543841
- CODE:00543820 inc eax
- CODE:00543821 mov [ebp+var_1C], eax
- CODE:00543824 mov [ebp+var_10], 2
- ; В цикле перебираются символы серийника, начиная с "3" и до "7"
- CODE:0054382B loc_54382B:
- CODE:0054382B mov eax, [ebp+var_4]
- CODE:0054382E mov edx, [ebp+var_10]
- ; Получить отдельно символ
- CODE:00543831 movzx eax, byte ptr [eax+edx-1]
- ; ПроXORить этим байтом первый символ серийника
- CODE:00543836 xor [ebp+var_18], eax
- CODE:00543839 inc [ebp+var_10]
- CODE:0054383C dec [ebp+var_1C]
- ; Следующий символ
- CODE:0054383F jnz short loc_54382B
- CODE:00543841 loc_543841:
- ; Загрузить в EDX:EAX значение первого байта серийника после всех XOR
- CODE:00543841 mov eax, [ebp+var_18]
- CODE:00543844 mov ecx, 1Eh
- CODE:00543849 cdq
- ; Поделить на 1Eh
- CODE:0054384A idiv ecx
- ; Нафига этот INC, если EDX все равно потом уменьшается на 1???
- CODE:0054384C inc edx
- ; Загрузить символ из строки, который стоит на позиции EDX-1
- CODE:0054384D mov eax, offset a2345679qwert_0
- ; Контрольная строка "2345679qwertyupadfghjkzxcvbnms"
- CODE:00543852 mov al, [eax+edx-1]
- CODE:00543856 mov [ebp+var_9], al
- CODE:00543859 mov eax, [ebp+var_4]
- CODE:0054385C mov edx, [ebp+var_14]
- CODE:0054385F mov al, [eax+edx-1]
- ; Сравнить загруженный символ с символом "9" из серийника
- CODE:00543863 cmp al, [ebp+var_9]
- CODE:00543866 jz short loc_54386B
- ; Значение результата функции проверки будет не равно нулю
- CODE:00543868 inc [ebp+var_8]
- CODE:0054386B loc_54386B:
- CODE:0054386B xor eax, eax
- CODE:0054386D pop edx
Переходим ко второй проверке. Она длиннее, чем первая, поэтому разберем ее по частям. Ставим точку останова на адрес 005438C0, тут будет первая часть:
Code (Assembler) : Убрать нумерацию
- CODE:00543933 xor eax, eax
- CODE:00543935 mov [ebp+var_18], eax
- CODE:00543938 mov eax, [ebp+var_8]
- CODE:0054393B call sub_404178
- CODE:00543940 dec eax
- CODE:00543941 test eax, eax
- CODE:00543943 jle short loc_543965
- CODE:00543945 mov [ebp+var_20], eax
- CODE:00543948 mov [ebp+var_14], 1
- CODE:0054394F loc_54394F:
- CODE:0054394F mov eax, [ebp+var_8]
- CODE:00543952 mov edx, [ebp+var_14]
- ; Загрузить символ из строки
- CODE:00543955 movzx eax, byte ptr [eax+edx-1]
- ; Просуммировать символы
- CODE:0054395A add [ebp+var_18], eax
- CODE:0054395D inc [ebp+var_14]
- CODE:00543960 dec [ebp+var_20]
- ; Следующий символ
- CODE:00543963 jnz short loc_54394F
- CODE:00543965 loc_543965:
- ; Загрузить сумму в EDX:EAX
- CODE:00543965 mov eax, [ebp+var_18]
- CODE:00543968 mov ecx, 1Eh
- CODE:0054396D cdq
- ; Поделить на 1Eh
- CODE:0054396E idiv ecx
- CODE:00543970 inc edx
- ; Загрузить символ из строки, который стоит на позиции EDX-1
- CODE:00543971 mov eax, offset a2345679qwert_1
- ; Контрольная строка "2345679qwertyupadfghjkzxcvbnms"
- CODE:00543976 mov al, [eax+edx-1]
- CODE:0054397A mov [ebp+var_D], al
- CODE:0054397D mov eax, [ebp+var_4]
- CODE:00543980 mov al, [eax+1]
- ; Сравнить загруженный символ с символом "3" из серийника
- CODE:00543983 cmp al, [ebp+var_D]
- CODE:00543986 jz short loc_54398B
- CODE:00543988 inc [ebp+var_C]
- CODE:0054398B loc_54398B:
- CODE:0054398B lea edx, [ebp+var_1C]
Code (Assembler) : Убрать нумерацию
- CODE:005439C5 xor eax, eax
- CODE:005439C7 mov [ebp+var_18], eax
- CODE:005439CA mov eax, [ebp+var_8]
- CODE:005439CD call sub_404178
- CODE:005439D2 dec eax
- CODE:005439D3 test eax, eax
- CODE:005439D5 jle short loc_5439F7
- CODE:005439D7 mov [ebp+var_20], eax
- CODE:005439DA mov [ebp+var_14], 1
- CODE:005439E1 loc_5439E1:
- CODE:005439E1 mov eax, [ebp+var_8]
- CODE:005439E4 mov edx, [ebp+var_14]
- ; Загрузить символ из строки
- CODE:005439E7 movzx eax, byte ptr [eax+edx-1]
- ; ПроXORить символы
- CODE:005439EC xor [ebp+var_18], eax
- CODE:005439EF inc [ebp+var_14]
- CODE:005439F2 dec [ebp+var_20]
- ; Следующий символ
- CODE:005439F5 jnz short loc_5439E1
- CODE:005439F7 loc_5439F7:
- ; Загрузить сумму в EDX:EAX
- CODE:005439F7 mov eax, [ebp+var_18]
- CODE:005439FA mov ecx, 1Eh
- CODE:005439FF cdq
- ; Поделить на 1Eh
- CODE:00543A00 idiv ecx
- CODE:00543A02 inc edx
- ; Загрузить символ из строки, который стоит на позиции EDX-1
- CODE:00543A03 mov eax, offset a2345679qwert_1
- ; Контрольная строка "2345679qwertyupadfghjkzxcvbnms"
- CODE:00543A08 mov al, [eax+edx-1]
- CODE:00543A0C mov [ebp+var_D], al
- CODE:00543A0F mov eax, [ebp+var_4]
- CODE:00543A12 mov al, [eax]
- ; Сравнить загруженный символ с символом "2" из серийника
- CODE:00543A14 cmp al, [ebp+var_D]
- CODE:00543A17 jz short loc_543A1C
- CODE:00543A19 inc [ebp+var_C]
- CODE:00543A1C loc_543A1C:
- CODE:00543A1C xor eax, eax
Программа успешно зарегистрирована
Перезапускаем программу и видим, что все ограничения сняты. Наг-окон нет, иконки и библиотеки сохраняются. Кейген вы теперь можете написать самостоятельно.
Просмотров: 5492 | Комментариев: 8
Метки: исследование защиты, графика
Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье
ManHunter
(14.02.2024 в 19:26):
Лучше AWicons Pro пока ничего не придумали.
user
(14.02.2024 в 02:44):
Вот попалась неплохая вещь для извлечения/создания иконок:
http://old-dos.ru/index.php?pa...ow&id=103633
--upd--
Пробел только из номера в конце убрать.
Вставился случайно
http://old-dos.ru/index.php?pa...ow&id=103633
--upd--
Пробел только из номера в конце убрать.
Вставился случайно
xussr
(13.02.2020 в 17:01):
Я пропачил вот это одно место ввел серийник от болды и все ок!
CPU Disasm
Address Hex dump Command Comments
00533333 00 DB 00
00533334 31C0 ( XOR EAX,EAX ) !!! ; iconextract.00533334(guessed void)
00533336 C3 RETN
00533337 |. 33C9 XOR ECX,ECX
00533339 |. 51 PUSH ECX
0053333A |. 51 PUSH ECX
0053333B |. 51 PUSH ECX
0053333C |. 51 PUSH ECX
0053333D |. 51 PUSH ECX
0053333E |. 53 PUSH EBX
0053333F |. 56 PUSH ESI
00533340 |. 8955 F8 MOV DWORD PTR SS:[EBP-8],EDX
00533343 |. 8945 FC MOV DWORD PTR SS:[EBP-4],EAX
00533346 |. 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4]
00533349 |. E8 C20FEDFF CALL 00404310 ; [iconextract.00404310
0053334E |. 8B45 F8 MOV EAX,DWORD PTR SS:[EBP-8]
00533351 |. E8 BA0FEDFF CALL 00404310 ; [iconextract.00404310
00533356 |. 33C0 XOR EAX,EAX
00533358 |. 55 PUSH EBP
?Зачем патчить в нескольких местах?
CPU Disasm
Address Hex dump Command Comments
00533333 00 DB 00
00533334 31C0 ( XOR EAX,EAX ) !!! ; iconextract.00533334(guessed void)
00533336 C3 RETN
00533337 |. 33C9 XOR ECX,ECX
00533339 |. 51 PUSH ECX
0053333A |. 51 PUSH ECX
0053333B |. 51 PUSH ECX
0053333C |. 51 PUSH ECX
0053333D |. 51 PUSH ECX
0053333E |. 53 PUSH EBX
0053333F |. 56 PUSH ESI
00533340 |. 8955 F8 MOV DWORD PTR SS:[EBP-8],EDX
00533343 |. 8945 FC MOV DWORD PTR SS:[EBP-4],EAX
00533346 |. 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4]
00533349 |. E8 C20FEDFF CALL 00404310 ; [iconextract.00404310
0053334E |. 8B45 F8 MOV EAX,DWORD PTR SS:[EBP-8]
00533351 |. E8 BA0FEDFF CALL 00404310 ; [iconextract.00404310
00533356 |. 33C0 XOR EAX,EAX
00533358 |. 55 PUSH EBP
?Зачем патчить в нескольких местах?
ManHunter
(13.02.2015 в 14:32):
ida pro
md5
(13.02.2015 в 13:35):
Спасибо за статьи, очень познавательно! Хочу спросить, какими инструментами вы чаще всего пользуетесь, в особенности какой дизассемблер предпочитаете (порекомендуйте хороший)?
ManHunter
(03.02.2015 в 10:51):
Здесь asm хватает, иногда хексреем перевожу в псевдокод, но это редко. Остальные инструменты как написано в статье, больше ничего не использовал.
brute
(03.02.2015 в 10:43):
адрес 005437B4 нашел сам, пытался долго патчить следствие (сообщения о неправильном ключе), а не причину. Удалось заставить выводить сообщение о правильном ключе, но прога не регистрировалась после перезапуска.. Как анализируешь процедуры? Читаешь asm или переводишь в псевдокод? Или делфи по идр смотришь? Мне очень помогает выделение в ИДЕ подозрительных блоков разным цветом. Какие ещё "секреты" используешь? Может, условные бряки в ОЛЕ? Дебажишь ли непосредственно в ИДЕ? Имхо, это должно быть лучше ОЛИ, при определенных скиллах..
п.с. регистрация проги прописалась в реестр и деинсталяция не помогает удалить регистрацию. Хотел ещё покрутить прогу, но лень вручную чистить реестр..
п.с. регистрация проги прописалась в реестр и деинсталяция не помогает удалить регистрацию. Хотел ещё покрутить прогу, но лень вручную чистить реестр..
Добавить комментарий
Заполните форму для добавления комментария
Но в актуальной последней версии ватермарку отковырять так и не удалось,
пока отложил её.
Кстати, у них ещё есть довольно безобразный визуальный
компаратор файлов - Hex Comparison. Тот вообще у меня только для коллекции,
не пользуюсь им.