Clerk Хм, интересная штука с запрещением записи, если потребуеться обязательно применю, а обойти как ее можно? закрыть хендел?
SPA Никак, можно проделать обратные действия, тоесть заменить проекции не файловой секции на приватную память, но это доселе видимо никто не юзал.
MSoft Ну автор же сказал, что не знает, какие именно функции восстанавливать. Clerk Интересный способ. Странно, что после этого ZwProtectVirtualMemory не работает... Т.е. мне странно. Я не ковыряюсь в ядре. Но не сработает, если приложению самому требуется писать в секции, в которые пишет чит. Хотя выглядит гораздо проще, чем всякие морфинги.
l_inc Почемуже не сработает запись самого приложения, создана разделяемая память и для записи в секцию кода нужно писать во вторую проекцию секции, данные отображаются в файл подкачки, а из него во вторую проекцию сразу. Тоесть пишём по одному адресу, а данные появляются по другому. Это кстати и может являться способом обнаружения снятия подобной защиты - взводим флажёк во второй проекции и читаем его с первой, которая на запись не доступна. Если он изменился - значит защита не снята.
Можно проэмулировать запись, тоесть чтобы инструкция пишущая по адресу в проекцию защищённую от записи выполнилась успешно без исключений. Делается элементрано - устанавливается диспетчер исключений, который проверит адрес куда выполнялась запись и выполнит трассировку инструкции с заменой селектора. Либо что более сложно сам запишет необходимые данные во вторую проекцию.
Clerk Я имел в виду тот код, ссылку на который Вы дали. Вы ведь потом освобождаете проекцию с копиями секций. А если устанавливать диспетчер исключений, то в обработчике надо ещё проверять, кто именно пытался писать в защищённые секции. А это по идее может быть нелегко. Да и одним обработчиком исключений в юзермоде, если я правильно понимаю, не обойтись. Надо ещё за NtWriteVirtualMemory следить. Или нет?
Нет. Секция то одна(обьект секция), просто мапяться разные блоки из неё. Освобождается сдесь, просто мне не нужно было писать туда вот и анмапнул. Обработчика исключений вполне достаточно и весьма просто реализуется, там гдето был код уже не помню и статья на вт. Ядро тут не причём и про NtWriteVirtualMemory ничего знать не нужно и следить за ним.
Clerk Если приложению требуется записать код в защищённую секцию, и оно использует для этого WriteProcessMemory, то исключение не возникнет. Просто будет возвращена ошибка.
Если средствами процессора. Например подобным способом лдр защищалась - при её парсинге/изменении например при загрузке модуля возникают исключения, которые обрабатывались, заменялся селектор и инструкция перезапускалась в пошаговом режиме. Это позволяло писать в копию блока.
Clerk Над Вашими постами надо долго медитировать, чтобы вникнуть в смысл. В общем 15 минут медитировал и ни слова не понял. Даже не уверен, мне ли это ответ. Чисто интуитивно могу предположить, что имеется в виду аппаратный брейкпоинт на ZwProtectVirtualMemory и на ZwWriteVirtualMemory. Но так всё-таки надо за ними следить?
Аналогично. Возможно предложение и тупо но что если задействовать сплайсинг всех API ? Прошлый вариант с 3 ф-ями не помог - чит пашет.
Clerk Ещё раз. Защищаемое приложение пытается записать в свою секцию (защищённую Вашей процедурой с помощью двойного копирования) с помощью WriteProcessMemory. Но WriteProcessMemory обламывается при вызове ZwProtectVirtualMemory и возвращает ошибку. Исключение при этом не возникает. Как Вы предлагаете обрабатывать такую ситуацию? Ведь приложение ожидает, что WriteProcessMemory выполнится успешно?
l_inc Зачем приложению себе писать в память посредством сервиса, может есчо текущий процесс открыть а потом хэндл в этот сервис передать
Clerk Ну зачем - это уже второй вопрос. ИМХО вполне реальная ситуация. Особенно если не хочется задумываться о правах доступа на секцию, вызываешь себе WriteProcessMemory и не ожидаешь никаких проблем. Собсно об этом я и писал в посте 26.
Clerk Вооот... с чего начали, к тому и пришли. Т.е. установка перехвата на ZwWriteProcessMemory. В купе с обработкой исключений обычной записи да ещё проверкой, а не чит ли эту запись пытается выполнить (проверка по идее нетривиальная), получится нехилых себе размеров код. Так вот к чему это я всё... Вместо изобретения панацеи, проще посмотреть, что же делает чит. Для частного случая всё может оказаться гораздо проще. Хотя Ваш метод двойного копирования довольно удачный. Если приложению не нужно писать в себя, то от юзермодного перехвата отлично защищает. Особенно если учесть, что Ваш код нагружен сплошь и рядом проверками на трассировку, то по сути код получается компактный и несложный.
l_inc Какие перехваты, это защита от записи, а не её обход. Не пишет - вот и отлично. Легальное приложение в секции кода не пишет(IAT лоадер заполняет). В аттаче простой пример хорошо отражающий запись если приложению она будет нужна в защищённую проекцию. Единственная проблема это инструкция movs, хотя можно её эмулировать.
...Ребята, я нашёл "свой" способ перехватывания API-функций. Ну, он, конечно, может не совсем мой, но нашёл я его самостоятельно. Мэтры, может, и не обратят внимания, а новичкам пригодится, пусть ковыряются. Не без недостатков, конечно. Так, если api-функции перехватываются несколькими потоками, то он не годится. То есть его надо много усовершенствовать в этом случае. Зато он прост и понятен. Никаких тебе подмен dll Увидел тему и решил сюда его пихнуть. Поделиться хочется. Суть. 1) Узнаём библиотеку *.dll, в которой прописана функция, которую нам надо перехватить 2) Открываем эту библиотеку в отладчике OllyDbg (способов много. Допустим, пишем минимальную прогу, к которой статически присоединяем эту библиотеку. И открываем эту прогу в OllyDbg) 3) В OllyDbg ищем эту библиотеку, секцию кода, в частности. 4) "Идём" в конец этой секции, в незадействованное пространство, где они ноли. 5)Пишем по понравившемуся нам адресу (например, 0xcafebabe) код, который должен выполниться вместо перехваченной функции (Ну, то есть в различных вариантах, найденных в интернете, свободное место для кода выделяет специальная функция- я забыл, какая, поскольку ей не пользовался. А в моём варианте вручную ищем это свободное место, где одни ноли.) 6)Дампируем этот участок. Сохраняем, допустим, в какой-нибудь текстовый файл 7)Запускаем прогу, в которой необходимо осуществить перехват api-функции 8)С помощью функции WriteProcessMemory прописываем дампированный нами код по адресу 0xcafebabe (помним, что там одни ноли и нет никаокого полезного кода) 9)С помощью функции WriteProcessMemory прописываем в начало перехватываемой функции прыжок на 0xcafebabe (а там уже "наш" код) Всё, при следующем вызове api-функции, о которой идёт речь, перехват сработает ...А вот насколько он успешно завершится- зависит от написанного нами кода. Так, в конце его наверное (!), должно быть что-то типа Код (Text): mov edi, edi push ebp mov ebp, esp jmp <адрес перехватываемой функции+5> Про оконцовку кода: вопрос этот для себя я решил, кто и так знает, ему объяснять не надо, а кто не знает, пусть сами это освоят. Простые перехваты делает на "ура". А для более сложных нужно разбираться самим. Так, в многопоточном приложении мне не удалось (пока) корректно вызвать из прописанного кода функцию (CreateProcess) Наконец, если возможно запустить прогу непосредственно в отладчике, то ещё все проще. Запускаем её в отладчике, прописываем по адресу 0xcafebabe нужный нам код (вручную, понятно) и прописываем по адресу функции прыжок на этот код. Недостаток: если код длинный, то устанешь каждый раз прописывать (вручную ведь). Достоинство: и отладка и внедрение api-функции- всё в одном флаконе. Наблюдай за поведением программы, изменяй, что тебе надо он-лайн, что называется. Только не увлекайся слишком, а то закалебёшься отладчик перезапускать.