Техника снятия дампа с защищенных приложений

         

Дамп извне


Прежде, чем читать адресное пространство чужого процесса, до него еще предстоит добраться. Windows изолирует процессы друг от друга на случай непреднамеренного удара по памяти (который сильно досаждал пользователям Windows3.x), но предоставляет специальный набор API-функций для межпроцессорного взаимодействия. Классический путь: получаем обработчик процесса который мы собрались дампить вызовом OpenProcess

и передаем его функции ReadProcessMemory

вместе с остальными параметрами (откуда и сколько байт читать). При этом необходимо учитывать, что некоторые страницы могут быть помечены защитой как недоступные и перед обращением к ним необходимо вызвать функцию VirtualProtectEx, разрешив полный доступ (PAGE_EXECUTE_READWRITE) или, по крайней мере, открыв страницы только на чтение (PAGE_READONLY).

Естественно, функции OpenProcess/ReadProcessMemory/VirtualProtectEx могут быть перехвачены защитой и тогда вместо дампа мы получим error, а то и reboot. Низкоуровневые функции NtOpenProcess/NtReadVirtualMemory/NtProtectVirtualMemory перехватываются с той же легкостью, к тому же некоторые защиты изменяют маркер безопасности процесса, запрещая открытие его памяти на чтение даже администратору!

Считается, что снятие дампа на уровне ядра открывает большие возможности для хакерства и противостоять этому никак невозможно, поскольку драйвер работает с наивысшим уровнем привилегий, который позволяет _все_. На самом деле, война драйверов за ядро только начинается. На голом процессоре далеко не уедешь и драйвер-дампер вынужден обращаться к сервисным функциям ядра. Причем, никаких документированных функций для чтения памяти чужого процесса (за исключением вышеупомянутых) в системе нет!

Чтобы читать память процесса напрямую, драйвер должен к нему подключиться, вызвав функцию KeAttachProcess или ее современный аналог KeStackAttachProcess, появившийся и впервые документированный в Windows 2000. Пользоваться обоими функциями следует с величайшей осторожностью и прежде, чем подключаться к другому процессу, необходимо отсоединится от текущего, вызывав KeDetachProcess/KeStackDeattachProcess.
Однако, эти функции могут быть перехвачены защитой со всеми вытекающими отсюда последствиями (протектор Themida именно так и поступает).

Важно отметить, что универсальных способов перехвата не существует — протектор может модифицировать таблицу экспорта, внедрять свои jmp'ы в начало или даже середину сервисных функций ядра и т. д. А это значит, что на ядро полагаться нельзя и вариантов у нас только два: использовать те функции, которые не догадалась перехватить защита или переключать адресные пространства вручную.

Специальный плагин к PE-TOOLS (http://neox.iatp.by/eXtremeDumper.zip, http://www.wasm.ru/pub/21/files/dumping/eXtremeDumper.rar), написанный MS-REM'ом, пробивается к процессу через следующую цепочку сервисных вызовов PsLookupProcessByProcessId à ObOpenObjectByPointer à ObDereferenceObject, которую пока еще никто не перехватывает, что позволяет снимать дамп даже с очень сильно защищенных программ, однако, сколько этот способ еще продержится сказать невозможно. Создатели протекторов не сидят сложа руки, и на хакерских форумах тоже бывают.

В долговременной перспективе надежнее всего использовать недокументированную (и к тому же неэкспортируемую!) функцию KiSwapProcess, адрес которой меняется от системы к системе, что затрудняет перехват. В то же время, дампер может легко определить его посредством отладочных символов, бесплатно распространяемых Microsoft. Для работы с ними понабиться библиотека dbghelp.dll из комплекта Debugging Tools (http://www.microsoft.com/whdc/devtools/debugging/default.mspx) и утилита symchk.exe, взятая оттуда же.

Функция KiSwapProcess — это одна из самых низкоуровневых функций, напрямую работающих с регистром CR3, в который заносится указатель на каталог страниц выбранного процесса, после чего его адресное пространство можно читать как свое собственное машинной командой MOVSD, в грубом приближении представляющий собой аналог memcpy. Предвидя такой исход событий, некоторые защиты пошли на отчаянный шаг: перехватив SwapContext и ряд других функций, работающих с CR3, они стали разрушать каталог страниц "своего" процесса на время переключения контекстов и вновь восстанавливать его, когда в нем возникает необходимость.Варварство! Настоящее! Обращение к каталогу страниц происходит из десятков недокументированных функций, которые в каждой версии ядра реализованы по своему. А это значит, что такая агрессивная защитная политика рискует свалиться в сплошной BSOD, не оставляющий пользователю никаких шансов для нормальной работы!

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


Содержание раздела