написал драйвер: PHP: #include <Ntddk.h> #include "ntifs.h" #define DEBUG #ifdef DEBUG #define DPRINT DbgPrint #else #define DPRINT #endif typedef UCHAR (BYTE); typedef BYTE* PBYTE; #pragma pack (push, 1) typedef struct _far_jmp{ BYTE PushOp; PVOID PushArg; BYTE RetOp; } far_jmp, *pfar_jmp; typedef struct _OldCode{ USHORT One; ULONG TWO; } OldCode, *POldCode; #pragma pack (pop) OldCode OpPrcOld; NTSTATUS TrueZwTerminateProcess ( IN HANDLE ProcessHandle, IN NTSTATUS ExitStatus ); PVOID NewZwTerminateProcessAdr; //True функция для перехватываемой функции NTSTATUS TrueZwTerminateProcess ( IN HANDLE ProcessHandle, IN NTSTATUS ExitStatus ) { ULONG CR0Reg; NTSTATUS Result; POldCode Func = (POldCode)ZwTerminateProcess; pfar_jmp Fnjp = (pfar_jmp)ZwTerminateProcess; __asm { cli // запрещаем прерывания mov eax, cr0 mov CR0Reg,eax and eax,0xFFFEFFFF // сбросить WP bit mov cr0, eax } // снимаем перехват Func->One = OpPrcOld.One; Func->TWO = OpPrcOld.TWO; Result = ZwTerminateProcess(ProcessHandle, ExitStatus); //устанавливаем перехват Fnjp->PushOp = 0x68; Fnjp->PushArg = NewZwTerminateProcessAdr; Fnjp->RetOp = 0xC3; __asm { mov eax, CR0Reg mov cr0, eax // востановить содержимое CR0 sti // разрешаем прерывания } return Result; } unsigned long get_pid_from_eprocess(PEPROCESS eproc) { unsigned long pid; if (!eproc) return 0xFFFFFFFF; pid=*(ULONG *)(eproc->UniqueProcessId); return pid; } ULONG get_pid_from_process_handle(HANDLE proc) { PVOID obj; NTSTATUS status=ObReferenceObjectByHandle(proc,0,0,KernelMode,&obj,NULL); if (NT_SUCCESS(status)) { ULONG pid=get_pid_from_eprocess((PEPROCESS)obj); ObDereferenceObject(obj); return pid; } return 0xFFFFFFFF; } //функция - обработчик перехвата NTSTATUS NewZwTerminateProcess( IN HANDLE ProcessHandle, IN NTSTATUS ExitStatus ) { if(get_pid_from_process_handle(ProcessHandle)==10904) { return STATUS_ACCESS_DENIED; } else { return TrueZwTerminateProcess(ProcessHandle, ExitStatus); } } VOID DriverUnload(IN PDRIVER_OBJECT DriverObject) { ULONG CR0Reg; NTSTATUS Result; POldCode Func = (POldCode)ZwTerminateProcess; DPRINT("Driver unloaded"); __asm { cli // запрещаем прерывания mov eax, cr0 mov CR0Reg,eax and eax,0xFFFEFFFF // сбросить WP bit mov cr0, eax } // снимаем перехват Func->One = OpPrcOld.One; Func->TWO = OpPrcOld.TWO; __asm { mov eax, CR0Reg mov cr0, eax // востановить содержимое CR0 sti // разрешаем прерывания } return; } NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) { ULONG CR0Reg; POldCode Func = (POldCode)ZwTerminateProcess; pfar_jmp Fnjp = (pfar_jmp)ZwTerminateProcess; DPRINT("Driver loaded"); //устанавливаем перехват __asm { cli // запрещаем прерывания mov eax, cr0 mov CR0Reg,eax and eax,0xFFFEFFFF // сбросить WP bit mov cr0, eax } NewZwTerminateProcessAdr = NewZwTerminateProcess; OpPrcOld.One = Func->One; OpPrcOld.TWO = Func->TWO; Fnjp->PushOp = 0x68; Fnjp->PushArg = NewZwTerminateProcessAdr; Fnjp->RetOp = 0xC3; __asm { mov eax, CR0Reg mov cr0, eax // востановить содержимое CR0 sti // разрешаем прерывания } //назначаем процедуру выгрузки драйвера DriverObject->DriverUnload = DriverUnload; return STATUS_SUCCESS; } если заменить функцию перхватчик на PHP: NTSTATUS NewZwTerminateProcess( IN HANDLE ProcessHandle, IN NTSTATUS ExitStatus ) { return TrueZwTerminateProcess(ProcessHandle, ExitStatus); } то все работает как надо, но если добавить проверку - не завершается ни один процесс. просто не завершается без всяких отказанно в доступе и т.п. по идее если струкртуры EPROCESS и KProcess, из которых берется ID неправильно описанны и отличаются в vista и 7, то завершаться должны все процессы, либо незавершаться какойто другой(хз че там по смещению расположено если структура не правильная ). но не завершается не один. что тут может быть не так. если надо могу хидер ntifs со структурами ядра выложить
да и еще вопрос про хук в ринг0: как снять перехват, установленый через модификацию SDT если ставил его не я? и будет ли корректно прочитать код нужной функции из ntoskrnl.exe и заменить его в памяти? в юзермоде от спласинга такое прокатывает.
Глядя на этот код вердикт таков: за изнасилование ядра Windows повлекшее смерть - казнить! 1) сброс WP бита - карается глюками, которые могут возникнуть при глючной ситуации и в некоторых очень редких случаях порчей файлов. По этому лучше использовать другой способ: - Для вирт страницы которую патчишь получить физ страницу - Для физ страницы выделить вирт страницу без защиты Таким образом непрямую не обращаясь к защищенно вирт странице памяти, можно подправить её и никакие манипуляции хитрые не нужны. Кода не много, но работает стабильно. 2) При каждом вызове оригинальной функции снимать перехват и ставить обратно - это жесть полнейшая. Такое даже в юзермоде не простительно. Чем тебе хук в SDT не понравился? Если хочешь юзать такой способ, то придется дизасм длин юзать и трамплиты или толку мало. 3) получаешь PID процесса както ты странно. Если забить на win 2000. То используй PsGetProcessId которая по PEPROCESS даст тебе PID. напрямую в PEPROCESS лучше не лезь, потому что от каждой версии винды он может менять. 4) снятие хука в SDT - реально тока парсинг ntoskrnl.exe. Да и то, не именно ntoskrnl.exe, а того файла который является ядром. не забывай что ntoskrnl.exe - это дефолтовое ядро для компом однопроцессорных и с малым кол-во памяти т.е. ntoskrnl.exe — однопроцессорное ядро Windows. ntkrnlmp.exe — многопроцессорное ядро Windows. ntkrnlpa.exe — однопроцессорное ядро Windows с более чем 3 ГБ оперативной памяти. ntkrpamp.exe — многопроцессорное ядро Windows с более чем 3 ГБ оперативной памяти. по этому надо еще и boot.ini смотреть или хитро искать какой модуль является ядром. Первоначально проверка на хук проста - адрес который там прописан, должен быть в внутри секции кода ядра. это чисто эвристически проверять можно. 5) снятие сплайсинг - тут всё просто: грузишь в память файл ядра. далее пробегаешься по секциям загруженного файла, которые имеют права на выполнение и сверяешь с тем что реально в памяти. Главное чтобы были права на выполнение и не было прав на запись. чтобы случайно не нарваться на секцию данных. Также надо не забывать про выгружаемые секции. Но опятьже восстановление кода должно быть ооочень аккуратным. Желательно чтобы IRQL был как можно выше и с запретом всех прерываний. Иначе есть шанс что поток восстановления прервется, а другой поток сунется на код который не до конца восстановлен.