Отправление IRP_MJ_SET_INFORMATION из обработки IRP_MJ_WRITE

Тема в разделе "WASM.NT.KERNEL", создана пользователем Just_Neko, 6 апр 2009.

  1. Just_Neko

    Just_Neko New Member

    Публикаций:
    0
    Регистрация:
    12 фев 2009
    Сообщения:
    22
    Всем доброе утро!
    Задача такая - при записи в файл нулевого размера предварительно записать туда 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):
    1. KeInitializeEvent(&event2, SynchronizationEvent, FALSE);
    2.                             MyIrp = IoAllocateIrp(DeviceObject->StackSize,FALSE);
    3.                             if(!MyIrp)
    4.                             {
    5.                                 return ERROR_CREATE_IRP;
    6.                             }
    7.                             MyBuffer=(PVOID)ExAllocatePool(NonPagedPool,BUFFER_SIZE);
    8.                             MyIrp->AssociatedIrp.SystemBuffer=MyBuffer;
    9.                             if(pDiskDeviceExtension->DiskDeviceObject->Flags & DO_DIRECT_IO)
    10.                             {
    11.                                 MyMDL=IoAllocateMdl(
    12.                                     MyBuffer,
    13.                                     4,
    14.                                     FALSE,
    15.                                     FALSE, // TRUE for highest level driver
    16.                                     MyIrp
    17.                                     );
    18.                                 if(MyMDL==NULL)
    19.                                 {
    20.                                     return ERROR_CREATE_IRP;
    21.                                 }
    22.                         //      MmBuildMdlForNonPagedPool(MyMDL);
    23.                         //                  MmProbeAndLockPages(MyMDL, KernelMode,IoReadAccess);
    24.                             }
    25.                             MyIrp->UserEvent = &event2;
    26.                             MyIrp->UserBuffer=MyBuffer;
    27.                             MyIrp->Cancel=FALSE;
    28.                             MyIrp->UserIosb = &IoStatusBlock;
    29.                             MyIrp->Tail.Overlay.Thread = PsGetCurrentThread();
    30.                             MyIrp->Tail.Overlay.OriginalFileObject = p_IO_STK->FileObject;
    31.                             MyIrp->RequestorMode = KernelMode; // changed
    32.                             MyIrp->Flags |= (IRP_NOCACHE | IRP_PAGING_IO | IRP_SYNCHRONOUS_PAGING_IO);
    33.                    
    34.                            
    35.                             RtlCopyMemory(MyBuffer,"ABCD",4);
    36.                             if(MyMDL!=NULL)
    37.                             {
    38.                                 MmBuildMdlForNonPagedPool(MyMDL);
    39.                             }
    40.                             IoSetNextIrpStackLocation(MyIrp);
    41.                             p_IO_NextSTK = IoGetCurrentIrpStackLocation(MyIrp);
    42.                            
    43.                             p_IO_NextSTK->DeviceObject = DeviceObject;
    44.                             p_IO_NextSTK->FileObject=p_IO_STK->FileObject;
    45.                            
    46.                             p_IO_NextSTK =IoGetNextIrpStackLocation(MyIrp);        
    47.                             p_IO_NextSTK->MajorFunction=IRP_MJ_WRITE;
    48.                             p_IO_NextSTK->MinorFunction = 0;
    49.                             p_IO_NextSTK->DeviceObject = DeviceObject;
    50.                             p_IO_NextSTK->FileObject=p_IO_STK->FileObject;
    51.                             p_IO_NextSTK->Parameters.Write.Length = 4;
    52.                             p_IO_NextSTK->Parameters.Write.ByteOffset.QuadPart = 0;
    53.  
    54.                             IoSetCompletionRoutine(MyIrp,
    55.                                                 OnCreateWriteCompletion,
    56.                                                 &DeviceObject,
    57.                                                 TRUE,
    58.                                                 TRUE,
    59.                                                 TRUE);
    60.                                        
    61.                             IoCallDriver(((PSFILTER_DEVICE_EXTENSION) DeviceObject->DeviceExtension)->AttachedToDeviceObject,MyIrp);
    62.  
    63.                             KeWaitForSingleObject(&event2, Executive, KernelMode, TRUE, 0);                    
    64.                             KeClearEvent(&event2);
    65.                            
    66.                             // теперь устанавливаем новый размер
    67.                            
    68.                             KeInitializeEvent(&event2, SynchronizationEvent, FALSE);
    69.                             MyIrp = IoAllocateIrp(DeviceObject->StackSize,FALSE);
    70.                             if(!MyIrp)
    71.                             {
    72.                                 return ERROR_CREATE_IRP;
    73.                             }
    74.                             MyBuffer=(PVOID)ExAllocatePool(NonPagedPool,sizeof(FILE_END_OF_FILE_INFORMATION));
    75.                             ((PFILE_END_OF_FILE_INFORMATION)MyBuffer)->EndOfFile.QuadPart=4;
    76.                             MyIrp->AssociatedIrp.SystemBuffer=MyBuffer;
    77.                             MyIrp->UserEvent = &event2;
    78.                             MyIrp->UserBuffer=MyBuffer;
    79.                             MyIrp->Cancel=FALSE;
    80.                             MyIrp->UserIosb = &IoStatusBlock;
    81.                             MyIrp->Tail.Overlay.Thread = PsGetCurrentThread();
    82.                             MyIrp->Tail.Overlay.OriginalFileObject = p_IO_STK->FileObject;
    83.                             MyIrp->RequestorMode = KernelMode;
    84.                         //  MyIrp->Flags = 0;
    85.                             MyIrp->Flags |= (IRP_PAGING_IO | IRP_SYNCHRONOUS_PAGING_IO);
    86.                                                    
    87.                             IoSetNextIrpStackLocation(MyIrp);
    88.                                                        
    89.                             p_IO_NextSTK =IoGetNextIrpStackLocation(MyIrp);        
    90.                             p_IO_NextSTK->MajorFunction=IRP_MJ_SET_INFORMATION;
    91.                             p_IO_NextSTK->MinorFunction = 0;
    92.                             p_IO_NextSTK->DeviceObject = DeviceObject;
    93.                             p_IO_NextSTK->FileObject=p_IO_STK->FileObject;
    94.                             p_IO_NextSTK->Parameters.SetFile.FileObject=0;
    95.                             p_IO_NextSTK->Parameters.SetFile.Length=sizeof(FILE_END_OF_FILE_INFORMATION);
    96.                             p_IO_NextSTK->Parameters.SetFile.ReplaceIfExists=FALSE;
    97.                             p_IO_NextSTK->Parameters.SetFile.AdvanceOnly=TRUE;
    98.                             p_IO_NextSTK->Parameters.SetFile.FileInformationClass=FileEndOfFileInformation;
    99.  
    100.                             IoSetCompletionRoutine(MyIrp,
    101.                                                 OnSetCompletion,
    102.                                                 &DeviceObject,
    103.                                                 TRUE,
    104.                                                 TRUE,
    105.                                                 TRUE);
    106.                                        
    107.                             IoCallDriver(((PSFILTER_DEVICE_EXTENSION) DeviceObject->DeviceExtension)->AttachedToDeviceObject,MyIrp);
    108.  
    109.                             KeWaitForSingleObject(&event2, Executive, KernelMode, TRUE, 0);
    110.                             KeClearEvent(&event2);
    111.                             if(p_IO_STK->Parameters.Write.ByteOffset.HighPart != -1)
    112.                             {
    113.                                 p_IO_STK->Parameters.Write.ByteOffset.QuadPart+=4;
    114.                                 p_IO_STK->FileObject->CurrentByteOffset.QuadPart+=4;
    115.                             }
     
  2. Just_Neko

    Just_Neko New Member

    Публикаций:
    0
    Регистрация:
    12 фев 2009
    Сообщения:
    22
    Кстати, если кто знает, хотел бы узнать, за что отвечает первый и второй из перехваченных пакетов. Я думал, первый отвечает за запись в кэш, а второй генериться при записи на диск, но когда я модифицировал содержимое буфера второго, эти изменения отразились в кэше.
     
  3. Just_Neko

    Just_Neko New Member

    Публикаций:
    0
    Регистрация:
    12 фев 2009
    Сообщения:
    22
    Отказался от этой идеи, и так всё работает корректно.
    Сейчас возникла новая проблема, надеюсь, одна из последних:
    При запуске антируткитов, например 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

    Есть хоть какие-нибудь идеи, в чём может быть проблема? Заранее благодарен за любую помощь
     
  4. Just_Neko

    Just_Neko New Member

    Публикаций:
    0
    Регистрация:
    12 фев 2009
    Сообщения:
    22
    Всё наконец заработало - проблема была в неправильном вызове у меня RtlUnicodetoAnsi

    Следующий вопрос - при записи в файл я перехватываю irp_mj_write, пишу свою 4-хбайтную сигнатуру в начало и затем сдвигаю offset, на который идёт запись на 4

    все нормально работает с большинством файлов, но например с темповым файлом ворда ~WRD0000... он выдаёт ошибку 0xc0000002, и при всех последующих попытках записи - 0xc0000054
    Есть идеи, что надо проверять/делать, чтобы этого избежать? Отказаться от обработки не могу
     
  5. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    На Блокноте проверял (чтение/запись)? Работает корректно?
     
  6. z0mailbox

    z0mailbox z0

    Публикаций:
    0
    Регистрация:
    3 фев 2005
    Сообщения:
    635
    Адрес:
    Russia СПБ
    а фаст-иошные записи обрабатываешь?
     
  7. Just_Neko

    Just_Neko New Member

    Публикаций:
    0
    Регистрация:
    12 фев 2009
    Сообщения:
    22
    Прошу прощения, что долго не отвечал
    Нашёл, в чём была ошибка - у меня некорректно обрабатываются файлы, записываемые файловыми потоками (stream) - а это всегда, если записываем больше 0x1000 байт

    в этом случае у меня при первой записи, скажем 0х3000 байт, непосредственно на диск (флаги 0x43) выдаёт в IoStatus 0x0xc000000d

    После этого начинается запись по кускам по 0х1000 байт - первая обламывается с тем же кодом, остальные две идут без проблем
    Если не сдвигать оффсет, по которому осуществляется запись, то всё пучком.

    Отвечаю на вопросы: в блокноте все работает, когда пишу меньше 0х1000 байт, фастиошные записи не обрабатываю, т.к. подразумевается, что в кэше у меня нет этой сигнатуры, она идёт только на диск и убирается при считывании только с диска (irp_nocache)

    Есть у кого-нибудь идеи, в чём проблема?
     
  8. Just_Neko

    Just_Neko New Member

    Публикаций:
    0
    Регистрация:
    12 фев 2009
    Сообщения:
    22
    нашёл, в чём ошибка - файловый поток может писать лишь по смещениям, кратным размеру сектора (512)
    т.е. если я буду иметь сигнатуру размером 512, тогда всё будет ок
    но это совсем не вариант, на полкилобайта увеличивать размер всех файлов, когда мне нужно всего 4 байта

    на примете 2 идеи -
    1) при перехвате записи отправлять свой пакет на запись с нормальными флагами, а этот скипить - но может не получится, т.к. файловый объект такой левый попался
    2) всё-таки как-то заставить писать 4 байта без ошибки - только как?
    Все предположения и идеи приветствуются =)
     
  9. Just_Neko

    Just_Neko New Member

    Публикаций:
    0
    Регистрация:
    12 фев 2009
    Сообщения:
    22
    Есть ещё одна идея - модифицировать записываемый буфер, чтобы в начале шла моя сигнатура, и писать всё это по нулевому смещению.
    Пожалуй, самый грамотный вариант
     
  10. z0mailbox

    z0mailbox z0

    Публикаций:
    0
    Регистрация:
    3 фев 2005
    Сообщения:
    635
    Адрес:
    Russia СПБ
    а почему бы тебе свои сигнатуры не писать в отдельный стрим, так как это положено?
     
  11. Just_Neko

    Just_Neko New Member

    Публикаций:
    0
    Регистрация:
    12 фев 2009
    Сообщения:
    22
    а если у меня не нтфс?
     
  12. Just_Neko

    Just_Neko New Member

    Публикаций:
    0
    Регистрация:
    12 фев 2009
    Сообщения:
    22
    Да и вообще, сигнатура есть только на диске, в памяти её быть не должно