Great И в том, и в другом случае (STATUS_INVALID_HANDLE и STATUS_SUCCESS) hFile равен конкретному значению, к примеру - 0x1320. Но в первом случае - STATUS_INVALID_HANDLE, а во втором - все хорошо. Clerk Мне сейчас нет дела до стабильности перехвата и до возможности его обхода, я не малвару пишу и не коммерческий продукт. Это - просто инструмент, чтобы собрать данные. А собрать их не получается из-за STATUS_INVALID_HANDLE, который возвращает ZwWriteFile.
А кому есть дело до потенциально кривых перехватов, разгребайте сами свой гуан. Придумал ерунду какуюто. Следует спрашивать об альтарнативе, решении которое должно быть реализовано, а не вычитав какойто принцип кричать как его заюзать. А в малваре это нельзя применить. Следует сохранить регистр флагов. Стек сдвигать нужно(из TSS загружать), прерывания необходимо разрешить после перезагрузки указателя на стек. Сегментные регистры Ds и Es необходимо перезагрузить(загрузить KGDT_R3_DATA or RPL_MASK). Установить обработчик исключений для #DB(ибо изза изменённого адреса в MSR будет необработанное трассировочное исключение при вышеприведённом вызове). Если юзаются функции помимо Zw* следует изменить PreviousMode вручную на KernelMode. Но кодес мой вы потестите..
Clerk Спасибо, обязательно вечером попробую. Не кипятись, у меня есть желание разобраться во всем, я только-только начал что-то писать для ring0. Просто литературы мало, а может - я не знаю что читать. Буду признателен за любые ссылки. Я отлично понимаю, что копипастить чужой код, не вникая в смысл, - плохо. Поэтому и обращаюсь к вам за помощью там, где не понимаю.
IceFire Не надо никаких previous mode. открывай хендл как OBJ_KERNEL_HANDLE , чтоб он был валидный из любого контекста.
Никто ничего не должен тебе если явно не укажешь в InitializeObjectAttributes. У кернел хендлов старший бит стоит (80000000) я поэтому у тебя и спрашивал какое числовое значение хендла (!) чтобы посмотреть старший бит. он сброшен - хендл юзермодный. сделай как я говорю, должно работать InitializeObjectAttributes ( &oa, &fileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL );
Great Спасибо! Все, действительно, заработало. Спасибо, что тебя не заломало все подробно объяснить. Я не знал, что у кернел-хендлов стоит старший бит. Сейчас появились другие проблемы, но я пока сам попробую разобраться. Подскажи, если не трудно, что почитать о программировании в кернел-моде, о том, как сделать сплайс безопасным. Я хочу разобраться сам и по пустякам не тревожить вас.
Оказалось, иногда я говорю что-то полезное) Ты просто создавал хендл в одном процессе, а обращался к нему из конткеста произвольного процесса. Поэтому и статус_инвалид_хендл. А я тебе еще больший секрет открою: там еще есть контрольные биты (по-моему, 0 и 1 - поэтому хендлы почти всегда кратны 4, поскольку они сброшены). Практически никак =) Придется исхитряться в каждом конкретном случае и подстраиваться под перехватываемую функцию. Либо сменить метод хука.
Clerk БСОДогенератор получился =) Осталось отучить его делать БСОДы =) Некогда пока, как поковыряю еще - отпишу.
Отписываюсь по поводу БСОДогенератора. Пытаюсь сделать все правильно (по посту Clerk'a). Переписал ф-цию вот так: Код (Text): __declspec(naked) void MyKiFastCallEntry(void) { __asm{ //get SrvNum pop edi mov i, eax pushad pushfd push fs /* Set FS to PCR */ mov ecx, 0x30 //mov ecx, KGDT_R0_PCR mov fs, cx /* Set DS/ES */ mov ecx, KGDT_R3_DATA + RPL_MASK //mov ecx, KGDT_R0_DATA mov ds, cx mov es, cx /* Set the current stack */ //cli //mov ecx, fs:[0x40] //mov esp, ss:[ecx+KTSS_ESP0] //sti } WriteServiceNumber(i); DbgPrint("Get service ID:%X \n",i); __asm{ pop fs popfd popad jmp pMovedSysenterCode } } Если раскомментировать это: Код (Text): //mov ecx, fs:[0x40] //fs:0x40 [fs:KPCR_TSS] //mov esp, ss:[ecx+KTSS_ESP0] //ss:[ecx+KTSS_ESP0] система виснет. Если добавить cli/sti - ребут незамедлительно. Что не так?
Сделать "правильно", это не по посту кого-то там, а как документировано в мсдн через IoConnectInterrupt. Она, точне ене она, а KINTERRUPT:ispatchCode делает всю нужную работу по входу в кернел мод из юзер мода.
Great ...и потом можно будет вызвать оригинальный обработчик KiFastCallEntry? Или сразу нужно вызывать Zw* функцию по коду?
Great Прочитал в MSDN об IoConnectInterrupt и ничего не понял (. Как понял из описания, она регистрирует новый обработчик прерывания. Как ее использовать в перехваченной KiFastCallEntry?
Так, я попутал с другим тредом. Это зачем тебе? Что ты вообще собираешься делать из своего MyKiFastCallEntry? Распиши подробно что тебе надо вызывать оттуда и зачем
Мне нужно определить номер системного сервиса, который сейчас вызывается. После этого дернуть ZwWriteFile и записать номер этого сервиса в файл. Все. В принципе, код написан и даже иногда работает )) Но БСОДит. Даже не БСОДит, а сразу уходит на ребут. Clerk вверху пост написал, в котором перечислил все, что надо делать, чтобы стабильно работало. Пытаюсь сделать по его совету.
Вообще, на самом деле, для работы на высоких IRQL,а в данном случае при выключенных прерываниях, есть механизм DPC и Work Item'ов. Ставишь в очередь воркитем, а в ней уже пишешь в файл. Так делается по-нормальному. Но если так неймется - можно это сделать и из обработчика. Для разрешения прерываний на стеке необходимо иметь валидный KTRAP_FRAME. ЕГо можно создавать вручную, но это страшный геморрой. Слава Биллу, винда предоставляет документированный механизм установки высокоуровневых обработчиков аппаратных прерываний. SYSENTER в принципе не сильно отличается от прерывания, поэтому IoConnectInterrupt для него тоже подойдет. IoConnectInterrupt создает объект KINTERRUPT, в нем есть поле DispatchCode (недокументировано). В него динамически записывается код обработки, который как раз создает валидный треп фрейм, разрешает прерывания и вызывает высокоуровневую ISR. Фактически, выполняет нормальный вход в ядро из режима пользователя. Нам нужен именно этот код. Проще всего выделить свободный вектор через HalGetInterruptVector (на висте работать не будет) и сделать IoConnectInterrupt на этот вектор со своей ISR. В ISR уже делать все, что требуется, а именно - можно, например, и ZwWriteFile вызвать. Правда, придется еще сделать грязный хак с понижением IRQL вручную, но в данном случае это допустимо. После установки этого фейкового вектора ставим хук на sysenter и в качестве обработчика в IA32_SYSENTER_EIP_MSR пишем адрес нашего KINTERRUPT:ispatchCode. Либо можно скопировать код, но проще будет оставить фейковый вектор. Он никому не мешает. Примерный код "как это делать" можно найти в исходниках моего отладчика, простите за саморекламу, http://www.google.com/codesearch/p?...terrupt package:http://ngdbg\.googlecode\.com Он там закомментирован, поскольку не используется, но он в принципе должен быть рабочим. Только там таким образом ставится вектор 03 (#DB), но разницы с SYSENTER там не будет практически. Вот адрес &InterruptObject->DispatchCode нужно установить будет как обработчик SYSENTER.
Great Делаю по твоему коду. IoConnectInterrupt возвращает STATUS_INVALID_PARAMETER. Хотя код я не менял. HalGetInterruptVector вернул TempVector=0x30, Irql = 0x1b, Affinity = 1.
Обработчик выполняется в DPC-стеке, его нужно переключить загрузив из TSS. Прерывания инструкция Sysenter маскирует. Всё подробно описано: http://files.virustech.org/indy/Code/Sysenter/CsDbg/Trap.asm