Подскажите почему драйвер перестает загружаться если начинаешь записывать в SST ядра адреса своих функций. В приведенном ниже коде если заремарить строчку «NTCALL(48) = CreateProcess;» То драйвер начинает нормально загружаться. Код (Text): typedef NTSTATUS (NTAPI *NTPROC)(); typedef NTPROC *PNTPROC; #define NTCALL(_function) KeServiceDescriptorTable->NtoskrnlTable.ServiceTable[_function] PDEVICE_EXTENSION pDeviceExtension = NULL; NTPROC ntproc = NULL; NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) { PDEVICE_OBJECT DeviceObject = NULL; NTSTATUS Status; UNICODE_STRING uStr; ULONG CR0Reg; pDeviceExtension = NULL; ntproc = NULL; ntprocEx = NULL; RtlInitUnicodeString(&uStr,NT_DEVICE_NAME); Status = IoCreateDevice(DriverObject,sizeofDEVICE_EXTENSION),&uStr,FILE_DEVICE_DRVFLT,0,FALSE,&DeviceObject); if(NT_SUCCESS(Status)){ RtlZeroMemory(DeviceObject->DeviceExtension, sizeof(DEVICE_EXTENSION)); pDeviceExtension = DeviceObject->DeviceExtension; DriverObject->DriverUnload = DrvUnload; ntproc = NTCALL(48); __asm{ cli mov eax, cr0 mov CR0Reg, eax and eax, 0xFFFEFFFF mov cr0, eax } NTCALL(48) = CreateProcess; __asm{ mov eax, CR0Reg mov cr0, eax sti } dprintf("addr: %x\n",ntproc); }else DrvUnload(DriverObject); return Status; }
48 - точно NtCreateProcess на той ОСи под которую пишешь? покажи обработчик CreateProcess, может ты некорректно что-то в нём делаешь, а при загрузку вызывается эта функция, хотя наврядли это помещает загрузке драйвера, но всё-таки.
Спасибо за ответы. Но сейчас неважно, какая это функция «NtCreateProcessEx» или «NtCreateProcess» так как до нее все равно дело не доходит. С драйвером не чего не происходит . В реестре появляется ключ «INITSTARTFAILED REG_DWORD 0x00000001(1)». Такое впечатление, что какой то сервис следит за загрузкой драйверов переопределяющих функции в SST ядра и блокирует их загрузку. Может быть это «Касперский» или «Windows» начала видоизменятся после регулярных апдейтов.
Переписал код драйвера, но все равно таже проблема осталась. Не загружается и все. Только теперь проблема вот в этой строчке «mov ebx, offset CreateProcessEx». Если ее заменить вот так, например «mov ebx, 0» все работает правда потом красивый синий экран, но это уже неважно . PDEVICE_EXTENSION pDeviceExtension = NULL; ULONG proc; NTSTATUS CreateProcessEx(OUT PHANDLE ProcessHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes,IN HANDLE InheritFromProcessHandle,IN ULONG CreateFlags,IN HANDLE SectionHandle OPTIONAL,IN HANDLE DebugPort OPTIONAL,IN HANDLE ExceptionPort OPTIONAL,IN ULONG JobMemberLevel){ dprintf("ZwCreateProcessEx\n"); return ZwCreateProcessEx(ProcessHandle,DesiredAccess,ObjectAttributes,InheritFromProcessHandle,CreateFlags,SectionHandle,DebugPort,ExceptionPort,JobMemberLevel); } NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) { PDEVICE_OBJECT DeviceObject = NULL; NTSTATUS Status; UNICODE_STRING uStr; ULONG a; pDeviceExtension = NULL; proc = 0; dprintf("Loading Driver\n"); RtlInitUnicodeString(&uStr,NT_DEVICE_NAME); Status = IoCreateDevice(DriverObject,sizeof(DEVICE_EXTENSION),&uStr,FILE_DEVICE_DRVFLT,0,FALSE,&DeviceObject); if(NT_SUCCESS(Status)){ RtlZeroMemory(DeviceObject->DeviceExtension, sizeof(DEVICE_EXTENSION)); pDeviceExtension = DeviceObject->DeviceExtension; DriverObject->DriverUnload = DrvUnload; proc = (ULONG)KeServiceDescriptorTable->NtoskrnlTable.ServiceTable[48]; a = 48*4+(ULONG)KeServiceDescriptorTable->NtoskrnlTable.ServiceTable; __asm{ cli mov ecx, CR0 mov edx, ecx and ecx, 0xFFFEFFFF mov CR0, ecx mov eax, a mov ebx, offset CreateProcessEx mov [eax], ebx mov CR0, edx sti } dprintf("addr: %x\n",proc); dprintf("addr: %x\n",a); }else DrvUnload(DriverObject); return Status; } VOID DrvUnload(IN PDRIVER_OBJECT DriverObject){ ULONG a; a = 48*4+(ULONG)KeServiceDescriptorTable->NtoskrnlTable.ServiceTable; __asm{ cli mov ecx, CR0 mov edx, ecx and ecx, 0xFFFEFFFF mov CR0, ecx mov eax, a mov ebx, proc mov [eax], ebx mov CR0, edx sti } IoDeleteDevice(DriverObject->DeviceObject); dprintf("Unloading Driver\n"); }
Смотря какой флаг хочешь сбросить) Кстати, делать AND 0xFFFFFFFF бессмысленно... значение не изменится же
я делал это так (на примере ZwQueryDirectoryFile): Код (Text): #define NUM_ZWQUERY 0x91; typedef NTSTATUS (NTAPI * _ZwQueryDirectoryFile) (HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG FileInformationLength, FILE_INFORMATION_CLASS FileInformationClass, BOOLEAN ReturnSingleEntry, PUNICODE_STRING FileName OPTIONAL, BOOLEAN RestartScan); _ZwQueryDirectoryFile TrueZwQueryDirectoryFile = NULL; PVOID tmpCR0; //================================================================================== void HookCode(int SrvNum, PVOID* TrueAddr, PVOID NewAddr) { __asm { pushad mov edi,KeServiceDescriptorTable mov edi,[edi] mov ecx,[SrvNum] //SrvNum mov eax,[edi+(ecx*4)] cmp eax,[NewAddr] je _skip mov edx,[TrueAddr] //TrueAddr mov [edx],eax cli mov eax,CR0 mov [tmpCR0],eax and eax, -1 mov CR0, eax mov eax, [NewAddr] //NewAddr mov [edi+(ecx*4)], eax mov eax, [tmpCR0] mov CR0, eax sti _skip: popad } return; } //==================================================================================== void UnhookCode(int SrvNum, PVOID TrueAddr){ __asm { pushad mov edi,KeServiceDescriptorTable mov edi,[edi] cli mov eax,CR0 mov [tmpCR0],eax and eax, -1 mov CR0, eax mov eax, [TrueAddr] //TrueAddr mov ecx, [SrvNum] //SrvNum mov [edi+(ecx*4)], eax mov eax, [tmpCR0] mov CR0, eax sti popad } return; } //==================================================================================== NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath ){ //.............. HookCode(NUM_ZWQUERY, (PVOID) &TrueZwQueryDirectoryFile, &NewZwQueryDirectoryFile); //.............. } //==================================================================================== VOID DriverUnload(IN PDRIVER_OBJECT DriverObject){ //.............. UnhookCode(NUM_ZWQUERY, TrueZwQueryDirectoryFile); //.............. }
Great везде, где я видел манипуляции с KeServiceDescriptorTable, выполнялось and reg,-1. В т.ч. и на этом сайте неоднократно. Что это дает - я не вникал, возможно это и бессмысленно, но это работает точно
cresta Это сброс бита WP, насколько я помню. и -1 там быть не должно. А AND reg,-1 смысла не несет.. разве что только флаги меняет
Спасибо за ответы. Но речь идет не о способе сброса бита WP . Почему-то если в драйвер добавить любую из таких, например строчек он перестает загружаться. «ULONG proc = (ULONG)&CreateProcessEx;» или «ULONG proc = (ULONG)CreateProcessEx;» или «mov ebx, offset CreateProcessEx». Функция «CreateProcessEx» действительно «__stdcall».
Пожалуйста, вставил все 3 строчки. А вот как его IDA дизассемблирует: Код (Text): .text:000104D1 mov proc, offset CreateProcessEx .text:000104DB mov proc, offset CreateProcessEx .text:000104E5 mov ecx, ds:KeServiceDescriptorTable .text:000104EB mov edx, [ecx] .text:000104ED mov eax, [edx+0C0h] .text:000104F3 mov proc, eax .text:000104F8 mov ecx, ds:KeServiceDescriptorTable .text:000104FE mov edx, [ecx] .text:00010500 add edx, 0C0h .text:00010506 mov [ebp+var_4], edx .text:00010509 cli .text:0001050A mov ecx, cr0 .text:0001050D mov edx, ecx .text:0001050F and ecx, 0FFFEFFFFh .text:00010515 mov cr0, ecx .text:00010518 mov eax, [ebp+var_4] .text:0001051B mov ebx, offset CreateProcessEx .text:00010520 mov [eax], ebx .text:00010522 mov cr0, edx .text:00010525 sti
Твой драйвер не запустится, посколько к нему прилинкована юзер-модная либа (ntdll.dll), из которой импортируется ZwCreateProcessEx. Когда ты из кода удаляешь mov proc, offset CreateProcessEx, компилятор удаляет из бинарника твою CreateProcessEx, и заодно вместе с ней удаляет вызов ZwCreateProcessEx, тем самым предотвращая линковку ntdll.dll. И драйвер запускается. Сделай как в том коде который я показал, и все будет работать. Т.е. typedef : Код (Text): typedef NTSTATUS (NTAPI * _ZwCreateProcessEx) ( some parameters ); и в нужном месте будешь вызывать _ZwCreateProcessEx, а не ZwCreateProcessEx. Это предотвратит линковку ntdll.
Сresta, большое спасибо. Сделал как ты написал, все заработало. Понравились твои "asm" вставки, но их пришлось немного доработать. А то мучил синий экранчик. В причинах его появления не разбирался, но ниже приведенные вставки работают идеально. Код (Text): __asm{//HookCode pushad mov edi, KeServiceDescriptorTable mov edi, [edi] mov edx, 48 mov eax, [edi+(edx*4)] mov ebx, offset ZwCreateProcessEx mov [ebx], eax cli mov eax, CR0 mov ecx, eax and eax, 0xFFFEFFFF mov CR0, eax mov eax, offset CreateProcessEx mov [edi+(edx*4)], eax mov CR0, ecx sti popad } __asm{ pushad mov edi, KeServiceDescriptorTable mov edi, [edi] mov edx, 48 cli mov eax, CR0 mov ecx, eax and eax, 0xFFFEFFFF mov CR0, eax mov eax, ZwCreateProcessEx mov [edi+(edx*4)], eax mov CR0, ecx sti popad }
Может кто-то написал глупость, другие ее повторяют. Но Может кто-то таким образом хочет восстановить старое значение cr0, но для этого надо бы сохранить его предидущее значение а потом просто восстановить Код (Text): __asm { cli mov eax, cr0 mov CR0Reg,eax //сохранить CR0 and eax,0xFFFEFFFF // сбросить WP bit mov cr0, eax ... mov eax, CR0Reg mov cr0, eax // востановить содержимое CR0 sti } ну если не сохранять CR0, то можно установить тот бит, кот. сбрасывется and eax,0xFFFEFFFF командой or eax, 0x10000, но никак ни and eax, 0xFFFFFFFF, но это тоже не корректно, поскольку бит ВСЕГДА установится, а не понятно был ли он установлен до того как сбрасывался, или может он и был 0 . Работать то оно будет, и если не восстанавливать cr0, но извините, это не совсем корректно, нужно все вернуть как было. Ну а если не сбрасывать бит в cr0 - тоже ИНОГДА будет работать, на компах, где память не защищена от записи.
Deyton, совсем непонятно про что ты пишешь, и причем тут "and eax, 0xFFFFFFFF ". Код (Text): mov eax, CR0 mov ecx, eax // сохраняю "CR0" в регистре "ECX" тоже самое что и "mov CR0Reg, eax" and eax, 0xFFFEFFFF // это не FFFFFFFF тут есть буква "E" mov CR0, eax // сбросить WP bit mov CR0, ecx // востановить содержимое CR0 только не из переменной а из регистра содержание // которого не изменялось. Все работает отлично, что тут некорректно совсем непонятно.
lev вот это мне не понятно: cresta: Код (Text): cli mov eax,CR0 mov [tmpCR0],eax and eax, -1 mov CR0, eax что делает этот код?