Всем доброе утро! Задача такая - при записи в файл нулевого размера предварительно записать туда 4-х байтную сигнатуру и установить endoffile в 4, затем пропустить запись дальше. При этом в кэше сигнатуры быть не должно, только на диске. Итак, при записи сначала идёт пакет с флагами 0xa00 - его я пропускаю, отмечая у себя, что с данным FCB я буду работать. Если я всё правильно понял, это запись в кэш. Следом за ним идёт пакет с флагами 0x43 - (IRP_NOCACHE | IRP_PAGING_IO | IRP_SYNCHRONOUS_PAGING_IO). Это, очевидно, запись непосредственно на диск. Именно в ней я и вставляю сигнатуру. Итак, я создаю пакет IRP_MJ_WRITE со своей сигнатурой, и следом за ней отпрвляю IRP_MJ_SET_INFORMATION, сдвигающий конец файла на 4 единицы вперёд. После всего этого я сдвигаю в параметрах исходного irp на 4 смещение, по которому осуществится запись и спокойно передаю управление дальше. Какие проблемы - запись вроде проходит нормально (status_success, и information=4), пока точно не проверил, т.к. дальше постоянно читаются данные из кэша, который сигнатуру в любом случае пропускает. А вот с раздвижением конца файла проблемы - в IoStatus всё по нулям, т.е. никакая информация не записывается. Это и подтверждает последующий перехват IRP_MJ_SET_INFORMATION, который система отправляет после оригинальной записи. Вот код из DispatchWrite: Код (Text): KeInitializeEvent(&event2, SynchronizationEvent, FALSE); MyIrp = IoAllocateIrp(DeviceObject->StackSize,FALSE); if(!MyIrp) { return ERROR_CREATE_IRP; } MyBuffer=(PVOID)ExAllocatePool(NonPagedPool,BUFFER_SIZE); MyIrp->AssociatedIrp.SystemBuffer=MyBuffer; if(pDiskDeviceExtension->DiskDeviceObject->Flags & DO_DIRECT_IO) { MyMDL=IoAllocateMdl( MyBuffer, 4, FALSE, FALSE, // TRUE for highest level driver MyIrp ); if(MyMDL==NULL) { return ERROR_CREATE_IRP; } // MmBuildMdlForNonPagedPool(MyMDL); // MmProbeAndLockPages(MyMDL, KernelMode,IoReadAccess); } MyIrp->UserEvent = &event2; MyIrp->UserBuffer=MyBuffer; MyIrp->Cancel=FALSE; MyIrp->UserIosb = &IoStatusBlock; MyIrp->Tail.Overlay.Thread = PsGetCurrentThread(); MyIrp->Tail.Overlay.OriginalFileObject = p_IO_STK->FileObject; MyIrp->RequestorMode = KernelMode; // changed MyIrp->Flags |= (IRP_NOCACHE | IRP_PAGING_IO | IRP_SYNCHRONOUS_PAGING_IO); RtlCopyMemory(MyBuffer,"ABCD",4); if(MyMDL!=NULL) { MmBuildMdlForNonPagedPool(MyMDL); } IoSetNextIrpStackLocation(MyIrp); p_IO_NextSTK = IoGetCurrentIrpStackLocation(MyIrp); p_IO_NextSTK->DeviceObject = DeviceObject; p_IO_NextSTK->FileObject=p_IO_STK->FileObject; p_IO_NextSTK =IoGetNextIrpStackLocation(MyIrp); p_IO_NextSTK->MajorFunction=IRP_MJ_WRITE; p_IO_NextSTK->MinorFunction = 0; p_IO_NextSTK->DeviceObject = DeviceObject; p_IO_NextSTK->FileObject=p_IO_STK->FileObject; p_IO_NextSTK->Parameters.Write.Length = 4; p_IO_NextSTK->Parameters.Write.ByteOffset.QuadPart = 0; IoSetCompletionRoutine(MyIrp, OnCreateWriteCompletion, &DeviceObject, TRUE, TRUE, TRUE); IoCallDriver(((PSFILTER_DEVICE_EXTENSION) DeviceObject->DeviceExtension)->AttachedToDeviceObject,MyIrp); KeWaitForSingleObject(&event2, Executive, KernelMode, TRUE, 0); KeClearEvent(&event2); // теперь устанавливаем новый размер KeInitializeEvent(&event2, SynchronizationEvent, FALSE); MyIrp = IoAllocateIrp(DeviceObject->StackSize,FALSE); if(!MyIrp) { return ERROR_CREATE_IRP; } MyBuffer=(PVOID)ExAllocatePool(NonPagedPool,sizeof(FILE_END_OF_FILE_INFORMATION)); ((PFILE_END_OF_FILE_INFORMATION)MyBuffer)->EndOfFile.QuadPart=4; MyIrp->AssociatedIrp.SystemBuffer=MyBuffer; MyIrp->UserEvent = &event2; MyIrp->UserBuffer=MyBuffer; MyIrp->Cancel=FALSE; MyIrp->UserIosb = &IoStatusBlock; MyIrp->Tail.Overlay.Thread = PsGetCurrentThread(); MyIrp->Tail.Overlay.OriginalFileObject = p_IO_STK->FileObject; MyIrp->RequestorMode = KernelMode; // MyIrp->Flags = 0; MyIrp->Flags |= (IRP_PAGING_IO | IRP_SYNCHRONOUS_PAGING_IO); IoSetNextIrpStackLocation(MyIrp); p_IO_NextSTK =IoGetNextIrpStackLocation(MyIrp); p_IO_NextSTK->MajorFunction=IRP_MJ_SET_INFORMATION; p_IO_NextSTK->MinorFunction = 0; p_IO_NextSTK->DeviceObject = DeviceObject; p_IO_NextSTK->FileObject=p_IO_STK->FileObject; p_IO_NextSTK->Parameters.SetFile.FileObject=0; p_IO_NextSTK->Parameters.SetFile.Length=sizeof(FILE_END_OF_FILE_INFORMATION); p_IO_NextSTK->Parameters.SetFile.ReplaceIfExists=FALSE; p_IO_NextSTK->Parameters.SetFile.AdvanceOnly=TRUE; p_IO_NextSTK->Parameters.SetFile.FileInformationClass=FileEndOfFileInformation; IoSetCompletionRoutine(MyIrp, OnSetCompletion, &DeviceObject, TRUE, TRUE, TRUE); IoCallDriver(((PSFILTER_DEVICE_EXTENSION) DeviceObject->DeviceExtension)->AttachedToDeviceObject,MyIrp); KeWaitForSingleObject(&event2, Executive, KernelMode, TRUE, 0); KeClearEvent(&event2); if(p_IO_STK->Parameters.Write.ByteOffset.HighPart != -1) { p_IO_STK->Parameters.Write.ByteOffset.QuadPart+=4; p_IO_STK->FileObject->CurrentByteOffset.QuadPart+=4; }
Кстати, если кто знает, хотел бы узнать, за что отвечает первый и второй из перехваченных пакетов. Я думал, первый отвечает за запись в кэш, а второй генериться при записи на диск, но когда я модифицировал содержимое буфера второго, эти изменения отразились в кэше.
Отказался от этой идеи, и так всё работает корректно. Сейчас возникла новая проблема, надеюсь, одна из последних: При запуске антируткитов, например gmer, rootkit unhooker или антивируса - например dr.web, система зависает. Если всё это дело гнать под windbg, он выдает следующее, например для гмера: Access violation - code c0000005 (!!! second chance !!!) nt!RtlUnicodeToMultiByteN+0xec: 805885e8 0fb7581c movzx ebx,word ptr [eax+1Ch] *** ERROR: Module load completed but symbols could not be loaded for gmer.sys Есть хоть какие-нибудь идеи, в чём может быть проблема? Заранее благодарен за любую помощь
Всё наконец заработало - проблема была в неправильном вызове у меня RtlUnicodetoAnsi Следующий вопрос - при записи в файл я перехватываю irp_mj_write, пишу свою 4-хбайтную сигнатуру в начало и затем сдвигаю offset, на который идёт запись на 4 все нормально работает с большинством файлов, но например с темповым файлом ворда ~WRD0000... он выдаёт ошибку 0xc0000002, и при всех последующих попытках записи - 0xc0000054 Есть идеи, что надо проверять/делать, чтобы этого избежать? Отказаться от обработки не могу
Прошу прощения, что долго не отвечал Нашёл, в чём была ошибка - у меня некорректно обрабатываются файлы, записываемые файловыми потоками (stream) - а это всегда, если записываем больше 0x1000 байт в этом случае у меня при первой записи, скажем 0х3000 байт, непосредственно на диск (флаги 0x43) выдаёт в IoStatus 0x0xc000000d После этого начинается запись по кускам по 0х1000 байт - первая обламывается с тем же кодом, остальные две идут без проблем Если не сдвигать оффсет, по которому осуществляется запись, то всё пучком. Отвечаю на вопросы: в блокноте все работает, когда пишу меньше 0х1000 байт, фастиошные записи не обрабатываю, т.к. подразумевается, что в кэше у меня нет этой сигнатуры, она идёт только на диск и убирается при считывании только с диска (irp_nocache) Есть у кого-нибудь идеи, в чём проблема?
нашёл, в чём ошибка - файловый поток может писать лишь по смещениям, кратным размеру сектора (512) т.е. если я буду иметь сигнатуру размером 512, тогда всё будет ок но это совсем не вариант, на полкилобайта увеличивать размер всех файлов, когда мне нужно всего 4 байта на примете 2 идеи - 1) при перехвате записи отправлять свой пакет на запись с нормальными флагами, а этот скипить - но может не получится, т.к. файловый объект такой левый попался 2) всё-таки как-то заставить писать 4 байта без ошибки - только как? Все предположения и идеи приветствуются =)
Есть ещё одна идея - модифицировать записываемый буфер, чтобы в начале шла моя сигнатура, и писать всё это по нулевому смещению. Пожалуй, самый грамотный вариант