On-line patching в секретах и советах Крис касперски Хакер, номер #093, стр. 093-080-4 С переменными (к которым, в частности, относятся флаги регистрации) все сложнее и они могут модифицироваться многократно. Первый раз — при конструировании объекта (если мы имеем дело с переменной-членом класса), второй раз — при явной инициализации (если только программист не забыл о ней), третий раз — при записи результатов проверки регистрационного ключа (файла, записи в реестре и т.д.). Поэтому, одного-единственного вызова WriteProcessMemory явно не достаточно и приходится мотать бесконечный цикл. Цикл — дело не сложное, но слишком дурное. Неплохо бы выделить признак, что проверка регистрации уже прошла и переменная больше изменяться не будет, а, значит, ее можно не писать. Таким признаком может быть и появление главного окна программы (которое легко отследить функцией FindWindow), и вызов некоторой API-функции (чуть позже мы покажем как их перехватывать), и просто время распаковки. Естественно, чем медленнее машина, тем больше ей требуется времени. В данном случае, циклу записи хватает 100 "тиков" даже при запуске NtExplorer'а под VM Ware на P-III 733 Mhz. Перехват API-функций как сигналинг Сигналом к атаке, тьфу, к началу модификации может служить вызов какой-нибудь API-функции. Перехватываем функцию, вызываемую сразу же после распаковки (обычно ей становится GetVersion) и навешиваем на нее "сигнализатор", извещающей нас о ее вызове. Это намного надежнее и эффективнее тупого ожидания или "гонок на опережение", только следует учесть, что GetVersion обычно вызывается по меньшей мере дважды — первый раз из распаковщика, и второй — уже из стартового кода (start-up code) распакованной программы Патч из стартового кода это, так сказать, хак с большого расстояния и в некоторых случаях желательно подобраться к защитному механизму как можно ближе. Для программ, защищенных ключевым файлом, хорошим решением будет перехват CreateFileA/CreateFileW (для 9x/NT соответственно), так же не помешает перехватить функции работы с реестром: RegOpenKey/RegEnumKey/RegEnumValue. Чтобы отличить вызовы защитного механизма от всех остальных, мы можем опираться как передаваемые API-функции параметры, так и на адрес возврата. Дождавшись "своего" вызова, мы модифицируем защитный код по своему усмотрению, а в API-функции, вызываемой после проверки валидности ключа, восстанавливаем все обратно. Этим мы обламываем проверки целостности, разбросанные по всей программе, гоняться за которыми нам лениво да и не фиг, когда можно просто взять и восстановить. На проверки, выполняемые _между_ вызовами API-функций, эта сентенция не распространяется и их приходится хачить вместе с остальным модифицированным кодом или… воспользоваться установкой аппаратных точек останова. Алгоритм перехвата значительно упрощает тот факт, что библиотека KERNEL32.DLL во всех процессах грузится по одному и тому же адресу, а это значит, чтобы определить адрес API-функции в хакаемом процессе, достаточно определить его в своем! Оба полученных адреса будут идентичны! В отношении остальных библиотек такой уверенности нет, USER32.DLL и GDI332.DLL, как правило, грузятся по одним и тем же адресам по всех процессах, но без 100% гарантии, а вот прикладные библиотеки могут гулять по памяти в широких пределах — все зависит от того, заняты ли базовые адреса загрузки другими библиотеками или нет. |