Издательский дом ООО "Гейм Лэнд"ЖУРНАЛ ХАКЕР #132, ДЕКАБРЬ 2009 г.

Разбиваем PURAN DEFRAG. Особенности крекинга 64-битных приложений


С момента появления 64-разрядных версий Windows прошло немало времени. Существенно увеличилось число пользователей новой платформы, но информации по исследованию софта по-прежнему немного. Это нехорошо, так как тут есть своя специфика. О ней и поговорим.

Preparations

Я несколько лет занимался исследованием 32-битных приложений и, оказавшись в 64-битной винде, понял, что здесь все будет не так просто. Первая проблема — это привычный крекеру инструментарий. Большинство тулз не портировано под Win64. Часть приложений, конечно, как работали, так и работают и свою функцию выполняют, например, CFF Explorer (PE-редактор, довольно мощный и удобный) — его можно применять как для работы с PE-форматом, так и с PE32+. Но одно дело редактор исполняемого формата, а другое — отладчик. Начнем с того, что от OllyDbg (полюбившегося многим ресечерам) придется отказаться: он же 32-битный! А также отказаться от множества плагинов, скриптов и всего, что было нужно для ресеча и распаковки 32-разрядных приложений.

Здесь видится три варианта замены Олли.

1. Отладчик fdbg с открытым исходным кодом (написан на ассемблере, исходник для fasm, fdbg.x86asm.net). Очевидно, что по сравнению с OllyDbg — это земля и небо. Первое время работать с ним жутко непривычно и неудобно, хоть и трассировка, как в Ольге по <F8>. Проект, правда, перспективный и активно развивающийся. Разработчики потихоньку добавляют фичи для скрытия дебаггера, но пока от разных детских шалостей вроде проверок с помощью IsDebuggerPresent или FindWindow.

2. Встроенный отладчик в IDA 64 (в поставке про-версии Иды есть 64-битная и 32-битная версия). Здесь все гораздо удобнее, чем в fdbg, однако и к специфике отладки в Иде тоже надо попривыкнуть (особенно тем, кто, как и я, юзал OllyDbg). Для этого рекомендую утащить видео-маны от TiGa по отладке 64-битных приложений в ida. Там также есть маны по распаковке 64-битных пакеров, что тоже очень полезно (tuts4you.com/download.php?list.71).

3. Debugging Tools for Windows (microsoft.com/whdc/devtools/debugging/install64bit.mspx). Windbg предоставляет неплохие возможности для отладки. О многочисленных расширениях сего отладчика можно прочесть в поставляемой вместе с ним справке. Мне больше всего понравился вариант с Идой. Сразу оговорюсь, что использую IDA64 версии 5.2. Вообще, какой дебаггер юзать — дело вкуса, да и, в конечном счете, успешность решения задачи зависит от того, в чьих руках тот или иной инструмент.

Хорошо, с дизассемблером и отладчиком можно сказать, проблема решена. Но это еще не все. Чтобы комфортно патчить — нужен хекс-редактор со встроенным дизасмдвижком. Я привык к hiew, но версии, которая позволяет работать с 64-разрядным кодом, у меня не было. Поэтому я нашел альтернативу — Hex Editor Neo. Здесь есть дизассемблер для 64-битного кода, ну и патчить можно, не отходя от кассы. Этакая гуи-замена Хью :). К сожалению, программа платная и ее можно взять на new-hex-editor.com. Желающие могут заказать и восьмой hiew с поддержкой 64 бит (hiew.ru). Можно и в 32-битном Хью патчить 64-разрядный код, но это занятие для извращенцев.

По софту, нужному для реверса, пока достаточно. Вторая проблема — это система команд, к которой надо привыкнуть. В общем-то, с 32-битами, казалось бы, отличий немного. Только что регистры в 2 раза стали больше. Ан, нет, изменений немало. Исследователь обязательно должен иметь под рукой оригинальную документацию от производителя, чтобы в случае возникновения вопросов мог бы к ней обратиться.

Обладателям процессоров фирмы «Интел» читать следующую литературу: intel.com/products/processor/manuals/index.htm (Intel® 64 and IA-32 Architectures Software Developer's Manuals). И, соответственно, аналогичная документация от AMD: developer.amd.com/documentation/guides/Pages/default.aspx. В частности, стоит обратить внимание на руководство AMD64 Architecture Programmer's Manual Volume 3, — различия между 32 и 64 описаны довольно подробно. Понятное дело, что для чтения манов нужно знание английского. Кто еще не успел выучить — может почитать статью Криса Касперски «64-битный привет», там обозначены основные моменты, необходимые для начала работы.

Research

Ну вот, подошли к самому главному — реверсу конкретного софта. По ходу дела буду пояснять различные 64-разрядные нововведения. Собственно жертвой исследований станет софтина Purag Defrag. Защита здесь несложная, как раз чтобы привыкнуть к 64-битному крекингу. Работает 30 дней. Все это время в заголовке красуется надпись xx Day(s) Remaining. На вкладке Buy Now нам предлагают ввести регистрационный код и при ошибочном вводе выдают сообщение о неверном коде.

В папке с программой мы видим 2 экзешника — PuranDefragGUI.exe и PuranADT.exe. Второе — это для показа иконки в трее, поэтому загружаем в IDA64 первое. К сожалению, попытки найти строки «Invalid registration key», «Trial Remaining» ничего не дали. Что ж, подготовимся к отладке. В директории с Идой лежит файл win64_remotex64.exe, запускаем его. Это отладочный сервер. Затем настраиваем клиент. В меню Debugger„~Process options прописываем путь к отлаживаемой программе, а также адрес сервера — 127.0.0.1 (в нашем случае все локально) и порт — 23946.

Все готово к дебагу. Теперь определимся с постановкой бряков. Сообщение, выдаваемое программой при неверном коде, напоминает то, что выводится функцией MessageBoxA(W). Отправимся в окно Imports Иды. Ага, и правда! Импортируется функция MessageBoxW. Ставим на нее точку останова. Здесь это делается так же, как и в OllyDbg — нажатием <F2> (и удаляется ей же). Запускаем программу нажатием <F9>. Во время запуска возникает ряд эксепшнов, которые нужно игнорировать (чтобы не отвлекали :)). Для этого зайдем в Debugger Debugger options, EXCEPTIONS „{ Edit. Существует два варианта обращения с эксепшенами: обработать самим или передать приложению. Для EXCEPTION_ACCESS_VIOLATION (0xFFFFFFFFC0000005) выбираем второй вариант — «Pass to application».
После запуска приложения делаем попытку ввести какойнибудь код и брякаемся на таком фрагменте:

.text:000000000042D039 loc_42D039:
.text:000000000042D039 mov r9d, edi
.text:000000000042D03C mov r8, rsi
.text:000000000042D03F mov rdx, r12
.text:000000000042D042 mov rcx, r13
.text:000000000042D045 call cs:MessageBoxW
.text:000000000042D04B mov esi, eax

Первое, что бросается в глаза (за исключением новых регистров), — это модель вызова функций. Первые 4 аргумента в регистрах (rcx, rdx, r8, r9), остальные в стеке. У MessageBox всего четыре, значит, все в регистрах :). Далее смотрим в стек (его можно просмотреть в окне IDAView — RSP) и переходим по адресу возврата, чтобы узнать, откуда вызывается эта процедура, показывающая сообщение.
Окей, еще раз переходим по адресу возврата и видим, что ругательство выводит код:

.text:0000000000407094 invalid_reg_code proc near ; CODE XREF: sub_406DF0+5B j
.text:0000000000407094 lea r8, Caption ; "Puran Defrag"
.text:000000000040709B lea rdx, aInvalidRegistr ; "Invalid Registration Key"
.text:00000000004070A2 mov r9d, 40h
.text:00000000004070A8 mov rcx, rsi
.text:00000000004070AB call sub_42D600

Прокрутим листинг чуть выше invalid_reg_code и увидим код, который считывает и проверяет введенный регистрационный код:

.text:0000000000406E2B call ?GetDlgItem@CWnd@@QEBAPEAV1@H@Z ; CWnd::GetDlgItem(int)
.text:0000000000406E30 mov r8d, 7FFFh
.text:0000000000406E36 mov rdx, rdi
.text:0000000000406E39 mov rcx, rax
.text:0000000000406E3C call sub_42B098; в этой процедуре берем текст из эдита
.text:0000000000406E41 mov rcx, rdi
.text:0000000000406E44 call check_reg_code
.text:0000000000406E49 test eax, eax
.text:0000000000406E4B jz invalid_reg_code
.text:0000000000406E51 mov ecx, 800h

В случае если в eax будет ненулевое значение, то программа поблагодарит за регистрацию и запишет в файл npd6.pdk («спрятанный» в \WINDOWS\system32\) введенный ключ. Этот же ключ проверяется при запуске приложения.

Функция, обозначенная у меня как check_reg_code, вызывается только из двух мест: при старте программы и при проверке введенного кода. В этом ты можешь убедиться, если заглянешь в окно ссылок на функцию (xrefs) в IDA.

.text:00000000004091D0 check_reg_code proc near
.text:00000000004091D0 mov [rsp+arg_0], rcx
.text:00000000004091D5 mov r11, rsp
.text:00000000004091D8 sub rsp, 0A8h
.text:00000000004091DF mov [r11-8], rdi
.text:00000000004091E3 xor eax, eax
.text:00000000004091E5 mov [r11-18h], r13
.text:00000000004091E9 mov r13, rcx
.text:00000000004091EC mov rcx, 0FFFFFFFFFFFFFFFFh
.text:00000000004091F3 mov rdi, r13
.text:00000000004091F6 repne scasw
.text:00000000004091F9 not rcx
.text:00000000004091FC sub rcx, 1
.text:0000000000409200 cmp rcx, 19h; сколько символов регистрационный код? если не 25 (19h), то нас посылают сразу
.text:0000000000409204 jnz length_not_match.text:000000000040920A checking_:; проверка введенного кода
.text:000000000040940F cmp rbx, rdi
.text:0000000000409412 mov rbx, [rsp+0A8h+arg_8]
.text:000000000040941A setz al
.text:000000000040941D length_not_match:
.text:000000000040941D mov r13, [rsp+0A8h+var_18]
.text:0000000000409425 mov rdi, [rsp+0A8h+var_8]
.text:000000000040942D add rsp, 0A8h
.text:0000000000409434 retn

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

sub eax,eax
inc eax
ret

В опкодах это будет выглядеть как 2B C0 FF C0 C3. Кстати, в 64-битном режиме однобайтовые инструкции inc, которые применялись для работы с регистрами в 32-разрядном коде (inc eax, inc edx etc), не поддерживаются. Дело тут в rex-префиксах, в диапазон которых и попадают однобайтовые команды инкремента. Почитать об этом можно в уже упомянутом мной третьем томе руководства программиста AMD, ну или у Интелов.

Как я говорил, для патча будем юзать Hex Editor Neo. Грузим файл PuranDefragGUI.exe в хекс-редактор. Запускаем дизассемблер (меню Tools „‰ Run disassembler). В настройках указываем дизассемблируемую секцию и набор команд. Помимо 64-битного кода, Neo editor может дизасмить msil и 32-битный код.

Жмем <Ctrl+G> (Go to), чтобы перейти по нужному адресу, выбираем Virtual Address (по умолчанию Neo Hex Editor предлагает вводить Raw Address) и вводим 00000000004091D0, Это соответствует адресу начала функции check_reg_code. Что тут можно сказать — Neo Hex Editor штука с перегруженным интерфейсом и непривычная (после Хью или OllyDbg), но для патча вполне применимая. После всех этих манипуляций программа будет «зарегана».

Сonclusion

Вот и познакомились с патчем и исследованием 64-битных программ. И это только начало (причем пример был очень простой), так как есть 64-битные протекторы исполняемых файлов (например, PeSpin x64), уже знакомые крекеру по 32-битному опыту. C распаковкой тоже свои тонкости. Так, для дампа и последующей реконструкции импорта потребуется другой софт, привычные LordPe / PeTools и Imprec здесь бессильны. Но об этом в следующих статьях. Удачи в исследованиях!

Links

• Подробнее о модели вызова функций и о PE32+ можно прочитать в замечательной статье Improving Automated Analysis of Windows x64 Binaries (uninformed.org/?v=4&a=1&t=pdf).
• На русском будет полезна статья «Общие сведения о соглашениях о вызовах для архитектуры x64» (msdn.microsoft.com/ru-ru/library/ms235286.aspx).
• Свои вопросы, касающиеся x64, можно задать на форуме wasm в одноименном разделе. Да и вообще, там много полезной информации по указанной теме: wasm.ru/forum/viewforum.php?id=31.

Warning

Внимание! Информация представлена исключительно с целью ознакомления! Ни автор, ни редакция за твои действия ответственности не несут!

Содержание