Работаю над подменой буферов и раньше была проблема при чтении — вылетал БСОД.
PreRead возвращал FLT_PREOP_SUCCESS_WITH_CALLBACK. В таком случае PostRead процедура выполнялась на DPC уровне. Но в PostRead я использую — FltSendMessage, которая выполняется не выше APC. Нужна она для того что бы кусок зашифрованного файла переслать в юзер мод, где он преобразуется к оригиналу и потом этот кусок запихнуть в новый подменяемый буфер.
Я это исправил с помощью возвращаемого значения FLT_PREOP_SYNCHRONIZE в PreRead. Теперь PostRead выполняется на APC уровне.
Что написано на msdn про FLT_PREOP_SYNCHRONIZE:
The minifilter driver is returning the I/O operation to the filter manager for further processing, but it is not completing the operation. In this case, the filter manager calls the minifilter's post-operation callback in the context of the current thread at IRQL <= APC_LEVEL.
БСОДа больше нету и с текстовыми файлам все норм, почти все норм. Но с картинками почему-то беда при чтении.
Сохраняються в папке, т.е. шифруются она правильно. Это проверял. Записывается хедер с нужной информацией и само содержимое файла.
Но открыть у меня картинку не получается. Отображает ошибку в окне просмотра, что файл поврежден.
Если рассмотреть на примере картинки с названием 14kb.jpg, у которой AllocationSize = 16384, а EndOfFile = 13023(значение изменял принудительно) вот что вижу в DbgView:
00000103 SB!SwapPreRead: Name = C:\Private\14kb.jpg, readLen = 4096.
00000104 SB!SwapPreRead: Pid = 2444 newB = 84354000 newMdl = 86210D60 oldB = 06C285FC oldMdl = 00000000 len = 4096 byteOffset = 4096(0).
00000105 SB!SwapPreRead: Name = C:\Private\14kb.jpg, readLen = 4096.
00000106 SB!SwapPreRead: Pid = 2444 newB = 842E6000 newMdl = 86210E30 oldB = 00000000 oldMdl = 8428A388 len = 4096 byteOffset = 4096(0).
00000107 SB!SwapPostRead: Pid = 2444 i = 0 CopySize = 4080 ReplySize = 0 OffsetOrig = 0 OffsetEnc = 0.
00000108 SB!SwapPostRead: Pid = 2444 newB = 842E6000 status = 0x0 info = 13023 byteOffset = 0(0) Freeing.
00000109 SB!SwapPreRead: Name = C:\Private\14kb.jpg, readLen = 12288.
00000110 SB!SwapPreRead: Pid = 4 newB = 862A9000 newMdl = 86210E30 oldB = 00000000 oldMdl = 8428A388 len = 12288 byteOffset = 12288(4096).
00000111 SB!SwapPostReadWhenSafe: Pid = 2444 newB = 84354000 status = 0x0 info = 13023 byteOffset = 0(0) Freeing.
00000112 SB!SwapPostRead: Pid = 4 i = 0 CopySize = 8928 ReplySize = 8927 OffsetOrig = 0 OffsetEnc = 0.
00000113 SB!SwapPostRead: Pid = 4 newB = 862A9000 status = 0x0 info = 13023 byteOffset = 4096(0) Freeing.
Почему-то всегда сначала проскакивает PreRead с 4096, потом 12288 байтами. В сумме будет 16384, что соответствует AllocationSize.
Пара наблюдений:
1. При клике на картинку, проскакивают Read запросы, в то время как на текстовые файлы нет.
2. В памяти подменяемый буфер соответствует оригиналу картинки. Так как пробывал, в то время когда драйвер мониторит папку, копировать картинку в другую папку. Копируется норм, потому что потом этот скопировавшийся файл я могу открыть и увижу оригинальное изображение.
И еще одно, как правильно делать смещение, когда у тебя в файле есть хеадер с дополнитеьной информацией.
В PostCreate считую хеадер с помощью FltReadFile с флагом FLTFL_IO_OPERATION_DO_NOT_UPDATE_BYTE_OFFSET. Далее в PostQueryInformation изменял
fileAllInformation->PositionInformation.CurrentByteOffset.QuadPart = FILE_HEADER_LENGTH;
и
filePositionInformation->CurrentByteOffset.QuadPart = FILE_HEADER_LENGTH;
В PreRead же делала так:
iopb->Parameters.Read.ByteOffset.QuadPart = FILE_HEADER_LENGTH;
получалось вечное зацикливание и сейчас просто добавляю FILE_HEADER_LENGTH:
RtlCopyMemory(bufToUserMode, encryptBuf + FILE_HEADER_LENGTH, size);
S>Почему-то всегда сначала проскакивает PreRead с 4096, потом 12288 байтами. В сумме будет 16384, что соответствует AllocationSize
S>Пара наблюдений:
S>1. При клике на картинку, проскакивают Read запросы, в то время как на текстовые файлы нет.
Я ставлю на неверно обрабатываемые запросы чтения или позиционирования.
S>И еще одно, как правильно делать смещение, когда у тебя в файле есть хеадер с дополнитеьной информацией.
S>В PostCreate считую хеадер с помощью FltReadFile с флагом FLTFL_IO_OPERATION_DO_NOT_UPDATE_BYTE_OFFSET. Далее в PostQueryInformation изменял
S>S>fileAllInformation->PositionInformation.CurrentByteOffset.QuadPart = FILE_HEADER_LENGTH;
S>
S>и
S>S>filePositionInformation->CurrentByteOffset.QuadPart = FILE_HEADER_LENGTH;
S>
Один раз? А как обрабатывается ситуация, когда вызывающий код делает seek + read?
S>В PreRead же делала так:
S>iopb->>Parameters.Read.ByteOffset.QuadPart = FILE_HEADER_LENGTH;
S>
S>получалось вечное зацикливание и сейчас просто добавляю FILE_HEADER_LENGTH:
S>S>RtlCopyMemory(bufToUserMode, encryptBuf + FILE_HEADER_LENGTH, size);
S>
Почему присвоение, а не корректировка смещения? Опять же: как обрабатывается seek + read с произвольной позиции файла?
Предлагаю вам все упростить: храните свой заголовок в конце файла. Это позволит убрать манипуляции с текущим смещением. Придется только обработать размер файла и переносить служебные данные при расширении. ИМХО так будет проще.
А еще проще хранить свои мета-данные рядом в срытом файле или ADS. Но тут нужно разруливать ситуацию, когда пользователь перезаписывает мета-данные.
S>Переместил я метаданные в конец файла, переписал Read/Write, но все та же беда с картинками и все те же странности, которые я описывал ранее. Если с текстовыми файлами все нормально получается, а с картинками нет, то видимо я что-то упустил в процедурах чтения. Подскажите на что нужно обратить внимание в таком случае?
Причин может быть много. Попробуйте
Process Monitor: даже если по логу будет не понятно, то зная шаги можно написать тест, который будет читать два одинаковых файла (один через фильтр) и сравнивать результат. А дальше нужно будет внимательно протрассировать в отладчике первое чтение, расходящееся эталонным.
ETI>>А еще проще хранить свои мета-данные рядом в срытом файле или ADS. Но тут нужно разруливать ситуацию, когда пользователь перезаписывает мета-данные.
S>Такой вариант я не рассматривал, так как пока у меня в метаданных только оригинальный размер файла.
А его нельзя вычислить?
Здравствуйте, EreTIk, Вы писали:
ETI>Причин может быть много. Попробуйте Process Monitor: даже если по логу будет не понятно, то зная шаги можно написать тест, который будет читать два одинаковых файла (один через фильтр) и сравнивать результат. А дальше нужно будет внимательно протрассировать в отладчике первое чтение, расходящееся эталонным.
За Process Monitor не додумался. И в нем, я думаю, увидел ответ. Картинка 56 128 байт открывается так:
ReadFile Offset: 0, Length: 4096, Priority: Normal
ReadFile Offset: 4096, Length: 4096, Priority: Normal
ReadFile Offset: 8192, Length: 4096, Priority: Normal
ReadFile Offset: 12288, Length: 4096, Priority: Normal
...
ReadFile Offset: 53248, Length: 2878, Priority: Normal
Спасибо, надеюсь я продвинулся. И теперь пару месяцев уйдет, что бы тут что-то придумать.
Т.е. как я понимаю каждый ReadFile это новый IRP_MJ_READ. Соответственно Pre- и PostRead нужно будет подстроить под такой сценарий. И IRP_MJ_WRITE тоже походу
ETI>А его нельзя вычислить?
Я не находил формулы, которая может вычислить расшифрованный размер файла, если он зашифрован с помощью AES. А зашифрованный размер файла можно вычислить без проблем.